Skip to content

Commit bac7f45

Browse files
noabaumaNoah BaumannNoah BaumannNoah Baumannlterrac
authored
Jacobi3d node level (#17)
* this should fix the installation of pytest issue in the CI * adding sleepsort pytaskr example * Label -> TaskId * style fix * updated jacobi with lpf (not yet working) * minor correction in some pytaskr examples * making nosv also with lpf and mpi (even if they don't work now) * working on nosv mpi example * more prints for debugging * removing prints as well as minor improvement in nosv example * commenting out this print as well * more prints for debugging * a better way in allocating the resources * minor more stuff * newer version of the no_mutex hicr branch * adding minor corrections to allow compute resource choose available NUMA (slurm issue) * fixing nosv * adding finally working pthreads and nosv example * cleanup some stuff * code formatting * update hicr version * code cleanup of jacobi example * fixing minor bug and updating the meson.build of jacobi3d * fixing style * fixing style again * fixing style again * fixing style * fixing style and merge main * now, correct core mapping * update hicr and meson.build * fix: lpf jacobi runs, and update git submodules * adding old version of getting compute resources * style: format files --------- Co-authored-by: Noah Baumann <[email protected]> Co-authored-by: Noah Baumann <[email protected]> Co-authored-by: Noah Baumann <[email protected]> Co-authored-by: Luca Terracciano <[email protected]>
1 parent 518f002 commit bac7f45

File tree

35 files changed

+688
-580
lines changed

35 files changed

+688
-580
lines changed

.github/workflows/master-test-workflow.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ jobs:
4242

4343
- name: Build Pybind11
4444
run: |
45-
/usr/bin/python3 -m pip install --upgrade pip pytest
45+
sudo apt-get update
46+
sudo apt-get install -y python3-pytest
4647
4748
cd extern/pybind11
4849
mkdir -p build

.github/workflows/pr-development-workflow.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,8 @@ jobs:
272272

273273
- name: Build Pybind11
274274
run: |
275-
/usr/bin/python3 -m pip install --upgrade pip pytest
275+
sudo apt-get update
276+
sudo apt-get install -y python3-pytest
276277
277278
cd extern/pybind11
278279
mkdir -p build

examples/abcTasks/cpp/abcTasks.hpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ void abcTasks(taskr::Runtime &taskr)
2727
taskr.setTaskCallbackHandler(HiCR::tasking::Task::callback_t::onTaskFinish, [&taskr](taskr::Task *task) { delete task; });
2828

2929
// Creating the execution units (functions that the tasks will run)
30-
auto taskAfc = taskr::Function([](taskr::Task *task) { printf("Task A %ld\n", task->getLabel()); });
31-
auto taskBfc = taskr::Function([](taskr::Task *task) { printf("Task B %ld\n", task->getLabel()); });
32-
auto taskCfc = taskr::Function([](taskr::Task *task) { printf("Task C %ld\n", task->getLabel()); });
30+
auto taskAfc = taskr::Function([](taskr::Task *task) { printf("Task A %ld\n", task->getTaskId()); });
31+
auto taskBfc = taskr::Function([](taskr::Task *task) { printf("Task B %ld\n", task->getTaskId()); });
32+
auto taskCfc = taskr::Function([](taskr::Task *task) { printf("Task C %ld\n", task->getTaskId()); });
3333

3434
// Initializing taskr
3535
taskr.initialize();
@@ -38,17 +38,17 @@ void abcTasks(taskr::Runtime &taskr)
3838
for (size_t r = 0; r < REPETITIONS; r++)
3939
{
4040
// Calculating the base task id for this repetition
41-
auto repetitionLabel = r * ITERATIONS * 3;
41+
auto repetitionTaskId = r * ITERATIONS * 3;
4242

4343
// Our connection with the previous iteration is the last task C, null in the first iteration
4444
taskr::Task *prevTaskC = nullptr;
4545

4646
// Each run consists of several iterations of ABC
4747
for (size_t i = 0; i < ITERATIONS; i++)
4848
{
49-
auto taskA = new taskr::Task(repetitionLabel + i * 3 + 0, &taskAfc);
50-
auto taskB = new taskr::Task(repetitionLabel + i * 3 + 1, &taskBfc);
51-
auto taskC = new taskr::Task(repetitionLabel + i * 3 + 2, &taskCfc);
49+
auto taskA = new taskr::Task(repetitionTaskId + i * 3 + 0, &taskAfc);
50+
auto taskB = new taskr::Task(repetitionTaskId + i * 3 + 1, &taskBfc);
51+
auto taskC = new taskr::Task(repetitionTaskId + i * 3 + 2, &taskCfc);
5252

5353
// Creating dependencies
5454
if (i > 0) taskA->addDependency(prevTaskC);

examples/abcTasks/python/abcTasks.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
def abcTasks(runtime):
77

88
# Create the taskr Tasks
9-
taskAfc = taskr.Function(lambda task : print(f"Task A {task.getLabel()}"))
10-
taskBfc = taskr.Function(lambda task : print(f"Task B {task.getLabel()}"))
11-
taskCfc = taskr.Function(lambda task : print(f"Task C {task.getLabel()}"))
9+
taskAfc = taskr.Function(lambda task : print(f"Task A {task.getTaskId()}"))
10+
taskBfc = taskr.Function(lambda task : print(f"Task B {task.getTaskId()}"))
11+
taskCfc = taskr.Function(lambda task : print(f"Task C {task.getTaskId()}"))
1212

1313
# Initializing taskr
1414
runtime.initialize()
@@ -19,13 +19,13 @@ def abcTasks(runtime):
1919
# Creating the execution units (functions that the tasks will run)
2020
for r in range(REPETITIONS):
2121
# Calculating the base task id for this repetition
22-
repetitionLabel = r * ITERATIONS * 3
22+
repetitionTaskId = r * ITERATIONS * 3
2323

2424
for i in range(ITERATIONS):
2525

26-
taskA = taskr.Task(repetitionLabel + i * 3 + 0, taskAfc)
27-
taskB = taskr.Task(repetitionLabel + i * 3 + 1, taskBfc)
28-
taskC = taskr.Task(repetitionLabel + i * 3 + 2, taskCfc)
26+
taskA = taskr.Task(repetitionTaskId + i * 3 + 0, taskAfc)
27+
taskB = taskr.Task(repetitionTaskId + i * 3 + 1, taskBfc)
28+
taskC = taskr.Task(repetitionTaskId + i * 3 + 2, taskCfc)
2929

3030
# Creating dependencies
3131
if i > 0: taskA.addDependency(prevTaskC)

examples/jacobi3d/meson.build

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,46 @@
11
testSuite = [ 'examples', 'jacobi3d' ]
22

3-
if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType')
4-
threading = executable('threading', [ 'source/pthreads.cpp', 'source/grid.cpp' ], dependencies: [ TaskRBuildDep ], cpp_args: [ TaskRDistributedCppFlag ] )
3+
if distributedEngine == 'mpi'
4+
TaskRDistributedCppFlag = '-D_TASKR_DISTRIBUTED_ENGINE_MPI'
55

6-
if get_option('buildTests')
7-
test('threading', threading, args : [ '-n', '64', '-i', '10' ], suite: testSuite, workdir: threading.path() + '.p' )
6+
mpirunExecutable = HiCRProject.get_variable('mpirunExecutable')
7+
8+
if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType')
9+
threading = executable('threading', [ 'source/pthreads.cpp', 'source/grid.cpp' ], dependencies: [ TaskRBuildDep ], cpp_args: [ TaskRDistributedCppFlag ] )
10+
11+
if get_option('buildTests')
12+
test('threading', mpirunExecutable, args : [ '-n', '2', '--oversubscribe', threading.full_path(), '-px', '1', '-py', '1', '-pz', '2', '-lx', '1', '-ly', '2', '-lz', '2', '-n', '64', '-i', '10'], suite: testSuite, workdir: threading.path() + '.p' )
13+
endif
14+
endif
15+
16+
# TODO: deadlocking (even for mpirun -n 1)
17+
if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType')
18+
nosv = executable('nosv', [ 'source/nosv.cpp', 'source/grid.cpp' ], dependencies: [ TaskRBuildDep ], cpp_args: [ TaskRDistributedCppFlag ] )
19+
20+
if get_option('buildTests')
21+
test('nosv', mpirunExecutable, args : [ '-n', '2', '--oversubscribe', nosv.full_path(), '-px', '1', '-py', '1', '-pz', '2', '-lx', '1', '-ly', '2', '-lz', '2', '-n', '64', '-i', '10'], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' )
22+
endif
23+
endif
24+
25+
elif distributedEngine == 'lpf'
26+
TaskRDistributedCppFlag = '-D_TASKR_DISTRIBUTED_ENGINE_LPF'
27+
28+
mpirunExecutable = find_program('mpirun', '/usr/bin/mpirun', '/usr/local/bin/mpirun', required : true)
29+
30+
if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType')
31+
threading = executable('threading', [ 'source/pthreads.cpp', 'source/grid.cpp' ], dependencies: [ TaskRBuildDep ], cpp_args: [ TaskRDistributedCppFlag ] )
32+
33+
if get_option('buildTests')
34+
test('threading', mpirunExecutable, args : [ '-n', '2', '--oversubscribe', 'env', 'LPF_ENGINE=zero', threading.full_path(), '-px', '1', '-py', '1', '-pz', '2', '-lx', '1', '-ly', '2', '-lz', '2', '-n', '64', '-i', '10'], suite: testSuite, workdir: threading.path() + '.p' )
35+
endif
836
endif
9-
endif
1037

11-
if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType')
12-
nosv = executable('nosv', [ 'source/nosv.cpp', 'source/grid.cpp' ], dependencies: [ TaskRBuildDep ], cpp_args: [ TaskRDistributedCppFlag ] )
38+
39+
if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType')
40+
nosv = executable('nosv', [ 'source/nosv.cpp', 'source/grid.cpp' ], dependencies: [ TaskRBuildDep ], cpp_args: [ TaskRDistributedCppFlag ] )
1341

14-
if get_option('buildTests')
15-
test('nosv', nosv, args : [ '-n', '64', '-i', '10' ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' )
42+
if get_option('buildTests')
43+
test('nosv', mpirunExecutable, args : [ '-n', '2', '--oversubscribe', 'env', 'LPF_ENGINE=zero', nosv.full_path(), '-px', '1', '-py', '1', '-pz', '2', '-lx', '1', '-ly', '2', '-lz', '2', '-n', '64', '-i', '10'], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' )
44+
endif
1645
endif
1746
endif

examples/jacobi3d/mpi/Makefile

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
1-
CFLAGS = -O3 -g -Wfatal-errors
2-
LIBS =
3-
MPICXX = mpicxx
1+
CXX = g++
2+
CXXFLAGS = -O3 -g -Wfatal-errors
3+
INCLUDES = -I/usr/local/include
4+
LIBS = -L/usr/local/lib -lmpi
45

5-
.SECONDARY:
6+
.SECONDARY:
67
BINARIES = jacobi
78

8-
.PHONY: all stage
9+
.PHONY: all clean
10+
911
all: $(BINARIES)
1012

1113
jacobi: jacobi.cpp grid.cpp
12-
$(MPICXX) $(CFLAGS) $(LIBS) -o $@ $^
14+
$(CXX) $(CXXFLAGS) $(INCLUDES) $^ -o $@ $(LIBS)
1315

14-
.PHONY: clean
1516
clean:
16-
$(RM) $(BINARIES) *.o
17-
18-
19-
20-
17+
$(RM) $(BINARIES) *.o

examples/jacobi3d/source/grid.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
* limitations under the License.
1515
*/
1616

17+
#pragma once
18+
1719
#include <vector>
1820
#include <cstdint>
1921
#include <string>
@@ -28,8 +30,8 @@
2830
#include <hicr/frontends/channel/fixedSize/mpsc/locking/consumer.hpp>
2931

3032
#define CHANNEL_DEPTH 10
31-
const int BLOCKZ = 96;
32-
const int BLOCKY = 64;
33+
constexpr int BLOCKZ = 96;
34+
constexpr int BLOCKY = 64;
3335

3436
extern std::unordered_map<size_t, size_t> taskid_hashmap;
3537

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/*
2+
* Copyright 2025 Huawei Technologies Co., Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include <chrono>
18+
#include <hicr/core/instanceManager.hpp>
19+
#include <taskr/taskr.hpp>
20+
21+
#include "grid.hpp"
22+
#include "task.hpp"
23+
24+
void jacobi3d(HiCR::InstanceManager *instanceManager,
25+
taskr::Runtime &taskr,
26+
Grid *g,
27+
size_t gDepth = 1,
28+
size_t N = 128,
29+
ssize_t nIters = 100,
30+
D3 pt = D3({.x = 1, .y = 1, .z = 1}),
31+
D3 lt = D3({.x = 1, .y = 1, .z = 1}))
32+
{
33+
// Getting distributed instance information
34+
const auto instanceCount = instanceManager->getInstances().size();
35+
const auto myInstanceId = instanceManager->getCurrentInstance()->getId();
36+
const auto rootInstanceId = instanceManager->getRootInstanceId();
37+
const auto isRootInstance = myInstanceId == rootInstanceId;
38+
39+
// Initializing the Grid
40+
bool success = g->initialize();
41+
if (success == false) instanceManager->abort(-1);
42+
43+
// Creating grid processing functions
44+
g->resetFc = std::make_unique<taskr::Function>([&g](taskr::Task *task) { g->reset(task, ((Task *)task)->i, ((Task *)task)->j, ((Task *)task)->k); });
45+
g->computeFc =
46+
std::make_unique<taskr::Function>([&g](taskr::Task *task) { g->compute(task, ((Task *)task)->i, ((Task *)task)->j, ((Task *)task)->k, ((Task *)task)->iteration); });
47+
g->receiveFc =
48+
std::make_unique<taskr::Function>([&g](taskr::Task *task) { g->receive(task, ((Task *)task)->i, ((Task *)task)->j, ((Task *)task)->k, ((Task *)task)->iteration); });
49+
g->unpackFc = std::make_unique<taskr::Function>([&g](taskr::Task *task) { g->unpack(task, ((Task *)task)->i, ((Task *)task)->j, ((Task *)task)->k, ((Task *)task)->iteration); });
50+
g->packFc = std::make_unique<taskr::Function>([&g](taskr::Task *task) { g->pack(task, ((Task *)task)->i, ((Task *)task)->j, ((Task *)task)->k, ((Task *)task)->iteration); });
51+
g->sendFc = std::make_unique<taskr::Function>([&g](taskr::Task *task) { g->send(task, ((Task *)task)->i, ((Task *)task)->j, ((Task *)task)->k, ((Task *)task)->iteration); });
52+
g->localResidualFc = std::make_unique<taskr::Function>(
53+
[&g](taskr::Task *task) { g->calculateLocalResidual(task, ((Task *)task)->i, ((Task *)task)->j, ((Task *)task)->k, ((Task *)task)->iteration); });
54+
55+
// Task map
56+
std::map<taskr::taskId_t, std::shared_ptr<taskr::Task>> _taskMap;
57+
58+
printf("Instance %lu: Executing...\n", myInstanceId);
59+
60+
// Creating tasks to reset the grid
61+
for (ssize_t i = 0; i < lt.x; i++)
62+
for (ssize_t j = 0; j < lt.y; j++)
63+
for (ssize_t k = 0; k < lt.z; k++)
64+
{
65+
auto resetTask = new Task("Reset", i, j, k, 0, g->resetFc.get());
66+
taskr.addTask(resetTask);
67+
}
68+
69+
// Initializing TaskR
70+
taskr.initialize();
71+
72+
// Running Taskr initially
73+
taskr.run();
74+
75+
// Waiting for Taskr to finish
76+
taskr.await();
77+
78+
// Creating and adding tasks (graph nodes)
79+
for (ssize_t it = 0; it < nIters; it++)
80+
for (ssize_t i = 0; i < lt.x; i++)
81+
for (ssize_t j = 0; j < lt.y; j++)
82+
for (ssize_t k = 0; k < lt.z; k++)
83+
{
84+
auto localId = g->localSubGridMapping[k][j][i];
85+
auto &subGrid = g->subgrids[localId];
86+
87+
// create new specific tasks
88+
auto computeTask = std::make_shared<Task>("Compute", i, j, k, it, g->computeFc.get());
89+
auto packTask = std::make_shared<Task>("Pack", i, j, k, it, g->packFc.get());
90+
auto sendTask = std::make_shared<Task>("Send", i, j, k, it, g->sendFc.get());
91+
auto recvTask = std::make_shared<Task>("Receive", i, j, k, it, g->receiveFc.get());
92+
auto unpackTask = std::make_shared<Task>("Unpack", i, j, k, it, g->unpackFc.get());
93+
94+
_taskMap[Task::encodeTaskName("Compute", i, j, k, it)] = computeTask;
95+
_taskMap[Task::encodeTaskName("Pack", i, j, k, it)] = packTask;
96+
_taskMap[Task::encodeTaskName("Send", i, j, k, it)] = sendTask;
97+
_taskMap[Task::encodeTaskName("Receive", i, j, k, it)] = recvTask;
98+
_taskMap[Task::encodeTaskName("Unpack", i, j, k, it)] = unpackTask;
99+
100+
// Creating and adding local compute task dependencies
101+
if (it > 0)
102+
if (subGrid.X0.type == LOCAL) computeTask->addDependency(_taskMap[Task::encodeTaskName("Compute", i - 1, j + 0, k + 0, it - 1)].get());
103+
if (it > 0)
104+
if (subGrid.X1.type == LOCAL) computeTask->addDependency(_taskMap[Task::encodeTaskName("Compute", i + 1, j + 0, k + 0, it - 1)].get());
105+
if (it > 0)
106+
if (subGrid.Y0.type == LOCAL) computeTask->addDependency(_taskMap[Task::encodeTaskName("Compute", i + 0, j - 1, k + 0, it - 1)].get());
107+
if (it > 0)
108+
if (subGrid.Y1.type == LOCAL) computeTask->addDependency(_taskMap[Task::encodeTaskName("Compute", i + 0, j + 1, k + 0, it - 1)].get());
109+
if (it > 0)
110+
if (subGrid.Z0.type == LOCAL) computeTask->addDependency(_taskMap[Task::encodeTaskName("Compute", i + 0, j + 0, k - 1, it - 1)].get());
111+
if (it > 0)
112+
if (subGrid.Z1.type == LOCAL) computeTask->addDependency(_taskMap[Task::encodeTaskName("Compute", i + 0, j + 0, k + 1, it - 1)].get());
113+
if (it > 0) computeTask->addDependency(_taskMap[Task::encodeTaskName("Compute", i + 0, j + 0, k + 0, it - 1)].get());
114+
115+
// Adding communication-related dependencies
116+
if (it > 0) computeTask->addDependency(_taskMap[Task::encodeTaskName("Pack", i, j, k, it - 1)].get());
117+
if (it > 0) computeTask->addDependency(_taskMap[Task::encodeTaskName("Unpack", i, j, k, it - 1)].get());
118+
119+
// Creating and adding receive task dependencies, from iteration 1 onwards
120+
if (it > 0) recvTask->addDependency(_taskMap[Task::encodeTaskName("Unpack", i, j, k, it - 1)].get());
121+
122+
// Creating and adding unpack task dependencies
123+
unpackTask->addDependency(_taskMap[Task::encodeTaskName("Receive", i, j, k, it)].get());
124+
unpackTask->addDependency(_taskMap[Task::encodeTaskName("Compute", i, j, k, it)].get());
125+
126+
// Creating and adding send task dependencies, from iteration 1 onwards
127+
packTask->addDependency(_taskMap[Task::encodeTaskName("Compute", i, j, k, it)].get());
128+
if (it > 0) packTask->addDependency(_taskMap[Task::encodeTaskName("Send", i, j, k, it - 1)].get());
129+
130+
// Creating and adding send task dependencies, from iteration 1 onwards
131+
sendTask->addDependency(_taskMap[Task::encodeTaskName("Pack", i, j, k, it)].get());
132+
133+
// Adding tasks to taskr
134+
taskr.addTask(computeTask.get());
135+
if (it < nIters - 1) taskr.addTask(packTask.get());
136+
if (it < nIters - 1) taskr.addTask(sendTask.get());
137+
if (it < nIters - 1) taskr.addTask(recvTask.get());
138+
if (it < nIters - 1) taskr.addTask(unpackTask.get());
139+
}
140+
141+
// Setting start time as now
142+
auto t0 = std::chrono::high_resolution_clock::now();
143+
144+
// Running Taskr
145+
taskr.run();
146+
147+
// Waiting for Taskr to finish
148+
taskr.await();
149+
150+
////// Calculating residual
151+
152+
// Reset local residual to zero
153+
g->resetResidual();
154+
155+
// Calculating local residual
156+
for (ssize_t i = 0; i < lt.x; i++)
157+
for (ssize_t j = 0; j < lt.y; j++)
158+
for (ssize_t k = 0; k < lt.z; k++)
159+
{
160+
auto residualTask = new Task("Residual", i, j, k, nIters, g->localResidualFc.get());
161+
taskr.addTask(residualTask);
162+
}
163+
164+
// Running Taskr
165+
taskr.run();
166+
167+
// Waiting for Taskr to finish
168+
taskr.await();
169+
170+
// Finalizing TaskR
171+
taskr.finalize();
172+
173+
// If i'm not the root instance, simply send my locally calculated residual
174+
if (isRootInstance == false)
175+
{
176+
*(double *)g->residualSendBuffer->getPointer() = g->_residual;
177+
g->residualProducerChannel->push(g->residualSendBuffer, 1);
178+
}
179+
else
180+
{
181+
// Otherwise gather all the residuals and print the results
182+
double globalRes = g->_residual;
183+
184+
for (size_t i = 0; i < instanceCount - 1; i++)
185+
{
186+
while (g->residualConsumerChannel->isEmpty());
187+
double *residualPtr = (double *)g->residualConsumerChannel->getTokenBuffer()->getSourceLocalMemorySlot()->getPointer() + g->residualConsumerChannel->peek(0);
188+
g->residualConsumerChannel->pop();
189+
globalRes += *residualPtr;
190+
}
191+
192+
// Setting final time now
193+
auto tf = std::chrono::high_resolution_clock::now();
194+
std::chrono::duration<float> dt = tf - t0;
195+
float execTime = dt.count();
196+
197+
double residual = sqrt(globalRes / ((double)(N - 1) * (double)(N - 1) * (double)(N - 1)));
198+
double gflops = nIters * (double)N * (double)N * (double)N * (2 + gDepth * 8) / (1.0e9);
199+
printf("%.4fs, %.3f GFlop/s (L2 Norm: %.10g)\n", execTime, gflops / execTime, residual);
200+
}
201+
202+
// Finalizing grid
203+
g->finalize();
204+
}

0 commit comments

Comments
 (0)