diff --git a/.gitignore b/.gitignore index 84788f4..9d449eb 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ build .vscode atlas_*.sh **/matrix/ +**/__pycache__/ +**/ovni/ \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f3d169d..b1f7e11 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,7 +11,7 @@ build: - source /home/hicr/.hicr-env.sh - echo "Building TaskR..." - mkdir build - - meson setup build -Dbuildtype=debug -Db_coverage=true -DbuildTests=true -DbuildExamples=true -DdistributedEngine=mpi -DexecutionStateType=boost,nosv -DprocessingUnitType=pthreads,nosv -DbuildInstrumentation=true -DcompileWarningsAsErrors=true + - meson setup build -Dbuildtype=debug -Db_coverage=true -DbuildTests=true -DbuildExamples=true -DdistributedEngine=mpi -DexecutionStateType=boost,nosv -DprocessingUnitType=pthreads,nosv -DbuildInstrumentation=true -DbuildPyTaskR=true -DcompileWarningsAsErrors=true - meson compile -C build - echo "Running tests..." - meson test -C build diff --git a/.gitmodules b/.gitmodules index 0edcdb2..15a5f18 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,3 +6,7 @@ path = extern/hicr url = https://github.com/Algebraic-Programming/HiCR.git branch = master +[submodule "extern/pybind11"] + path = extern/pybind11 + url = https://github.com/pybind/pybind11.git + branch = stable diff --git a/examples/local/abcTasks/README.rst b/examples/abcTasks/README.rst similarity index 100% rename from examples/local/abcTasks/README.rst rename to examples/abcTasks/README.rst diff --git a/examples/local/abcTasks/source/abcTasks.hpp b/examples/abcTasks/cpp/abcTasks.hpp similarity index 100% rename from examples/local/abcTasks/source/abcTasks.hpp rename to examples/abcTasks/cpp/abcTasks.hpp diff --git a/examples/local/abcTasks/source/nosv.cpp b/examples/abcTasks/cpp/nosv.cpp similarity index 100% rename from examples/local/abcTasks/source/nosv.cpp rename to examples/abcTasks/cpp/nosv.cpp diff --git a/examples/local/abcTasks/source/pthreads.cpp b/examples/abcTasks/cpp/pthreads.cpp similarity index 100% rename from examples/local/abcTasks/source/pthreads.cpp rename to examples/abcTasks/cpp/pthreads.cpp diff --git a/examples/abcTasks/meson.build b/examples/abcTasks/meson.build new file mode 100644 index 0000000..3d8336a --- /dev/null +++ b/examples/abcTasks/meson.build @@ -0,0 +1,27 @@ +testSuite = [ 'examples', 'abcTasks' ] + +if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') + threading = executable('threading', [ 'cpp/pthreads.cpp'], dependencies: [ TaskRBuildDep ]) + + if get_option('buildTests') + test('threading', threading, args : [ ], suite: testSuite, workdir: threading.path() + '.p' ) + endif +endif + +if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') + nosv = executable('nosv', [ 'cpp/nosv.cpp'], dependencies: [ TaskRBuildDep ]) + + if get_option('buildTests') + test('nosv', nosv, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p') + endif +endif + +if get_option('buildPyTaskR') and get_option('buildTests') + test('pyTaskR', + py, + args : [ 'python/main.py' ], + is_parallel : false, + env: ['PYTHONPATH=' + meson.project_build_root() + '/include/pytaskr/'], + suite: testSuite, + workdir: meson.current_source_dir()) +endif \ No newline at end of file diff --git a/examples/abcTasks/python/abcTasks.py b/examples/abcTasks/python/abcTasks.py new file mode 100644 index 0000000..ddecdf4 --- /dev/null +++ b/examples/abcTasks/python/abcTasks.py @@ -0,0 +1,53 @@ +import taskr + +REPETITIONS = 5 +ITERATIONS = 100 + +def abcTasks(runtime): + # TODO: Setting onTaskFinish callback to free up task memory when it finishes (not sure if we will have this) + # runtime.setTaskCallbackHandler(HiCR::tasking::Task::callback_t::onTaskFinish, [&taskr](taskr::Task *task) { delete task; }) + # runtime.setTaskCallbackHandler(taskr.onTaskFinish, lambda task : del task) + + # Create the taskr Tasks + taskAfc = taskr.Function(lambda task : print(f"Task A {task.getLabel()}")) + taskBfc = taskr.Function(lambda task : print(f"Task B {task.getLabel()}")) + taskCfc = taskr.Function(lambda task : print(f"Task C {task.getLabel()}")) + + # Initializing taskr + runtime.initialize() + + # Our connection with the previous iteration is the last task C, null in the first iteration + prevTaskC = taskr.Task(0, taskCfc) + + # Creating the execution units (functions that the tasks will run) + for r in range(REPETITIONS): + # Calculating the base task id for this repetition + repetitionLabel = r * ITERATIONS * 3 + + for i in range(ITERATIONS): + + taskA = taskr.Task(repetitionLabel + i * 3 + 0, taskAfc) + taskB = taskr.Task(repetitionLabel + i * 3 + 1, taskBfc) + taskC = taskr.Task(repetitionLabel + i * 3 + 2, taskCfc) + + # Creating dependencies + if i > 0: taskA.addDependency(prevTaskC) + taskB.addDependency(taskA) + taskC.addDependency(taskB) + + # Adding to taskr runtime + runtime.addTask(taskA) + runtime.addTask(taskB) + runtime.addTask(taskC) + + # Refreshing previous task C + prevTaskC = taskC + + # Running taskr for the current repetition + runtime.run() + + # Waiting current repetition to end + runtime.await_() + + # Finalizing taskr + runtime.finalize() \ No newline at end of file diff --git a/examples/abcTasks/python/main.py b/examples/abcTasks/python/main.py new file mode 100644 index 0000000..f98711d --- /dev/null +++ b/examples/abcTasks/python/main.py @@ -0,0 +1,16 @@ +import taskr +import abcTasks + +def main(): + + # Initialize taskr with the wanted compute manager backend and number of PUs + t = taskr.taskr(taskr.HiCRBackend.threading, 2) + + # Get the runtime + runtime = t.get_runtime() + + # Running simple example + abcTasks.abcTasks(runtime) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/examples/local/cholesky/README.md b/examples/cholesky/README.md similarity index 100% rename from examples/local/cholesky/README.md rename to examples/cholesky/README.md diff --git a/examples/local/cholesky/meson.build b/examples/cholesky/meson.build similarity index 95% rename from examples/local/cholesky/meson.build rename to examples/cholesky/meson.build index bdda624..a30be1b 100644 --- a/examples/local/cholesky/meson.build +++ b/examples/cholesky/meson.build @@ -1,4 +1,4 @@ -testSuite = [ 'examples', 'local', 'cholesky' ] +testSuite = [ 'examples', 'cholesky' ] choleskyDep = declare_dependency( dependencies: [ TaskRBuildDep, dependency('openblas', required: true) ], diff --git a/examples/local/cholesky/ompss/cholesky.hpp b/examples/cholesky/ompss/cholesky.hpp similarity index 100% rename from examples/local/cholesky/ompss/cholesky.hpp rename to examples/cholesky/ompss/cholesky.hpp diff --git a/examples/local/cholesky/ompss/init.hpp b/examples/cholesky/ompss/init.hpp similarity index 100% rename from examples/local/cholesky/ompss/init.hpp rename to examples/cholesky/ompss/init.hpp diff --git a/examples/local/cholesky/ompss/main.cpp b/examples/cholesky/ompss/main.cpp similarity index 100% rename from examples/local/cholesky/ompss/main.cpp rename to examples/cholesky/ompss/main.cpp diff --git a/examples/local/cholesky/ompss/meson.build b/examples/cholesky/ompss/meson.build similarity index 88% rename from examples/local/cholesky/ompss/meson.build rename to examples/cholesky/ompss/meson.build index 00cec01..7a08c74 100644 --- a/examples/local/cholesky/ompss/meson.build +++ b/examples/cholesky/ompss/meson.build @@ -1,4 +1,4 @@ -testSuite = [ 'examples', 'local' ] +testSuite = [ 'examples' ] choleskyompssDep = declare_dependency( compile_args: ['-fompss-2'], diff --git a/examples/local/cholesky/ompss/verify.hpp b/examples/cholesky/ompss/verify.hpp similarity index 100% rename from examples/local/cholesky/ompss/verify.hpp rename to examples/cholesky/ompss/verify.hpp diff --git a/examples/local/cholesky/sequential/cholesky.hpp b/examples/cholesky/sequential/cholesky.hpp similarity index 100% rename from examples/local/cholesky/sequential/cholesky.hpp rename to examples/cholesky/sequential/cholesky.hpp diff --git a/examples/local/cholesky/sequential/init.hpp b/examples/cholesky/sequential/init.hpp similarity index 100% rename from examples/local/cholesky/sequential/init.hpp rename to examples/cholesky/sequential/init.hpp diff --git a/examples/local/cholesky/sequential/main.cpp b/examples/cholesky/sequential/main.cpp similarity index 100% rename from examples/local/cholesky/sequential/main.cpp rename to examples/cholesky/sequential/main.cpp diff --git a/examples/local/cholesky/sequential/meson.build b/examples/cholesky/sequential/meson.build similarity index 86% rename from examples/local/cholesky/sequential/meson.build rename to examples/cholesky/sequential/meson.build index 26df4aa..0f120de 100644 --- a/examples/local/cholesky/sequential/meson.build +++ b/examples/cholesky/sequential/meson.build @@ -1,4 +1,4 @@ -testSuite = [ 'examples', 'local' ] +testSuite = [ 'examples' ] choleskySequentialDep = declare_dependency( dependencies: [ choleskyDep, dependency('openmp', required: true)] diff --git a/examples/local/cholesky/sequential/verify.hpp b/examples/cholesky/sequential/verify.hpp similarity index 100% rename from examples/local/cholesky/sequential/verify.hpp rename to examples/cholesky/sequential/verify.hpp diff --git a/examples/local/cholesky/source/cholesky.hpp b/examples/cholesky/source/cholesky.hpp similarity index 100% rename from examples/local/cholesky/source/cholesky.hpp rename to examples/cholesky/source/cholesky.hpp diff --git a/examples/local/cholesky/source/init.hpp b/examples/cholesky/source/init.hpp similarity index 100% rename from examples/local/cholesky/source/init.hpp rename to examples/cholesky/source/init.hpp diff --git a/examples/local/cholesky/source/nosv.cpp b/examples/cholesky/source/nosv.cpp similarity index 100% rename from examples/local/cholesky/source/nosv.cpp rename to examples/cholesky/source/nosv.cpp diff --git a/examples/local/cholesky/source/pthreads.cpp b/examples/cholesky/source/pthreads.cpp similarity index 100% rename from examples/local/cholesky/source/pthreads.cpp rename to examples/cholesky/source/pthreads.cpp diff --git a/examples/local/cholesky/source/verify.hpp b/examples/cholesky/source/verify.hpp similarity index 100% rename from examples/local/cholesky/source/verify.hpp rename to examples/cholesky/source/verify.hpp diff --git a/examples/local/cholesky/utils.hpp b/examples/cholesky/utils.hpp similarity index 100% rename from examples/local/cholesky/utils.hpp rename to examples/cholesky/utils.hpp diff --git a/examples/local/conditionVariable/README.rst b/examples/conditionVariable/README.rst similarity index 100% rename from examples/local/conditionVariable/README.rst rename to examples/conditionVariable/README.rst diff --git a/examples/local/conditionVariable/source/conditionVariableWait.hpp b/examples/conditionVariable/cpp/conditionVariableWait.hpp similarity index 100% rename from examples/local/conditionVariable/source/conditionVariableWait.hpp rename to examples/conditionVariable/cpp/conditionVariableWait.hpp diff --git a/examples/local/conditionVariable/source/conditionVariableWaitCondition.hpp b/examples/conditionVariable/cpp/conditionVariableWaitCondition.hpp similarity index 100% rename from examples/local/conditionVariable/source/conditionVariableWaitCondition.hpp rename to examples/conditionVariable/cpp/conditionVariableWaitCondition.hpp diff --git a/examples/local/conditionVariable/source/conditionVariableWaitFor.hpp b/examples/conditionVariable/cpp/conditionVariableWaitFor.hpp similarity index 100% rename from examples/local/conditionVariable/source/conditionVariableWaitFor.hpp rename to examples/conditionVariable/cpp/conditionVariableWaitFor.hpp diff --git a/examples/local/conditionVariable/source/conditionVariableWaitForCondition.hpp b/examples/conditionVariable/cpp/conditionVariableWaitForCondition.hpp similarity index 100% rename from examples/local/conditionVariable/source/conditionVariableWaitForCondition.hpp rename to examples/conditionVariable/cpp/conditionVariableWaitForCondition.hpp diff --git a/examples/local/conditionVariable/source/nosv.cpp b/examples/conditionVariable/cpp/nosv.cpp similarity index 100% rename from examples/local/conditionVariable/source/nosv.cpp rename to examples/conditionVariable/cpp/nosv.cpp diff --git a/examples/local/conditionVariable/source/pthreads.cpp b/examples/conditionVariable/cpp/pthreads.cpp similarity index 100% rename from examples/local/conditionVariable/source/pthreads.cpp rename to examples/conditionVariable/cpp/pthreads.cpp diff --git a/examples/conditionVariable/meson.build b/examples/conditionVariable/meson.build new file mode 100644 index 0000000..4d7f344 --- /dev/null +++ b/examples/conditionVariable/meson.build @@ -0,0 +1,63 @@ +testSuite = [ 'examples', 'conditionVariable' ] + +if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') + threading_conditionVariableWait = executable('threading_conditionVariableWait', [ 'cpp/pthreads.cpp'], dependencies: [ TaskRBuildDep ], cpp_args: [ '-D__TEST_FUNCTION_=conditionVariableWait'] ) + threading_conditionVariableWaitFor = executable('threading_conditionVariableWaitFor', [ 'cpp/pthreads.cpp'], dependencies: [ TaskRBuildDep ], cpp_args: [ '-D__TEST_FUNCTION_=conditionVariableWaitFor'] ) + threading_conditionVariableWaitCondition = executable('threading_conditionVariableWaitCondition', [ 'cpp/pthreads.cpp'], dependencies: [ TaskRBuildDep ], cpp_args: [ '-D__TEST_FUNCTION_=conditionVariableWaitCondition'] ) + threading_conditionVariableWaitForCondition = executable('threading_conditionVariableWaitForCondition', [ 'cpp/pthreads.cpp'], dependencies: [ TaskRBuildDep ], cpp_args: [ '-D__TEST_FUNCTION_=conditionVariableWaitForCondition'] ) + + if get_option('buildTests') + test('threading_conditionVariableWait', threading_conditionVariableWait, args : [ ], suite: testSuite, workdir: threading_conditionVariableWait.path() + '.p' ) + test('threading_conditionVariableWaitFor', threading_conditionVariableWaitFor, args : [ ], suite: testSuite, workdir: threading_conditionVariableWaitFor.path() + '.p' ) + test('threading_conditionVariableWaitCondition', threading_conditionVariableWaitCondition, args : [ ], suite: testSuite, workdir: threading_conditionVariableWaitCondition.path() + '.p' ) + test('threading_conditionVariableWaitForCondition', threading_conditionVariableWaitForCondition, args : [ ], suite: testSuite, workdir: threading_conditionVariableWaitForCondition.path() + '.p' ) + endif +endif + +if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') + nosv_conditionVariableWait = executable('nosv_conditionVariableWait', [ 'cpp/nosv.cpp'], dependencies: [ TaskRBuildDep ], cpp_args: [ '-D__TEST_FUNCTION_=conditionVariableWait'] ) + nosv_conditionVariableWaitFor = executable('nosv_conditionVariableWaitFor', [ 'cpp/nosv.cpp'], dependencies: [ TaskRBuildDep ], cpp_args: [ '-D__TEST_FUNCTION_=conditionVariableWaitFor'] ) + nosv_conditionVariableWaitCondition = executable('nosv_conditionVariableWaitCondition', [ 'cpp/nosv.cpp'], dependencies: [ TaskRBuildDep ], cpp_args: [ '-D__TEST_FUNCTION_=conditionVariableWaitCondition'] ) + nosv_conditionVariableWaitForCondition = executable('nosv_conditionVariableWaitForCondition', [ 'cpp/nosv.cpp'], dependencies: [ TaskRBuildDep ], cpp_args: [ '-D__TEST_FUNCTION_=conditionVariableWaitForCondition'] ) + + if get_option('buildTests') + test('nosv_conditionVariableWait', nosv_conditionVariableWait, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv_conditionVariableWait.path() + '.p' ) + test('nosv_conditionVariableWaitFor', nosv_conditionVariableWaitFor, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv_conditionVariableWaitFor.path() + '.p' ) + test('nosv_conditionVariableWaitCondition', nosv_conditionVariableWaitCondition, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv_conditionVariableWaitCondition.path() + '.p' ) + test('nosv_conditionVariableWaitForCondition', nosv_conditionVariableWaitForCondition, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv_conditionVariableWaitForCondition.path() + '.p' ) + endif +endif + +if get_option('buildPyTaskR') and get_option('buildTests') + test('pyTaskR_conditionVariableWait', + py, + args : [ 'python/main.py' ], + is_parallel : false, + env: ['PYTHONPATH=' + meson.project_build_root() + '/include/pytaskr/', '__TEST_FUNCTION_=conditionVariableWait'], + suite: testSuite, + workdir: meson.current_source_dir()) + + test('pyTaskR_conditionVariableWaitFor', + py, + args : [ 'python/main.py' ], + is_parallel : false, + env: ['PYTHONPATH=' + meson.project_build_root() + '/include/pytaskr/', '__TEST_FUNCTION_=conditionVariableWaitFor'], + suite: testSuite, + workdir: meson.current_source_dir()) + + test('pyTaskR_conditionVariableWaitCondition', + py, + args : [ 'python/main.py' ], + is_parallel : false, + env: ['PYTHONPATH=' + meson.project_build_root() + '/include/pytaskr/', '__TEST_FUNCTION_=conditionVariableWaitCondition'], + suite: testSuite, + workdir: meson.current_source_dir()) + + test('pyTaskR_conditionVariableWaitForCondition', + py, + args : [ 'python/main.py' ], + is_parallel : false, + env: ['PYTHONPATH=' + meson.project_build_root() + '/include/pytaskr/', '__TEST_FUNCTION_=conditionVariableWaitForCondition'], + suite: testSuite, + workdir: meson.current_source_dir()) +endif \ No newline at end of file diff --git a/examples/conditionVariable/python/conditionVariableWait.py b/examples/conditionVariable/python/conditionVariableWait.py new file mode 100644 index 0000000..8a8e75f --- /dev/null +++ b/examples/conditionVariable/python/conditionVariableWait.py @@ -0,0 +1,74 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import taskr + +def conditionVariableWait(runtime): + # Contention value + value = 0 + + # Mutex for the condition variable + mutex = taskr.Mutex() + + # Task-aware conditional variable + cv = taskr.ConditionVariable() + + def fc(task): + nonlocal value + + # Waiting for the other task's notification + print("Thread 1: I wait for a notification") + mutex.lock(task) + print("before cv.wait(task, mutex)", flush=True) + cv.wait(task, mutex) + print("after cv.wait(task, mutex)", flush=True) + mutex.unlock(task) + value = 1 + print("Thread 1: I have been notified") + + # Creating task functions + waitFc = taskr.Function(fc) + + def fc(task): + nonlocal value + + # Notifying the other task + print("Thread 2: Notifying anybody interested") + while value != 1: + cv.notifyOne(task) + print("cv.notifyOne(task)", flush=True) + task.suspend() + print("task.suspend()", flush=True) + + notifyFc = taskr.Function(fc) + + task1 = taskr.Task(0, waitFc) + task2 = taskr.Task(1, notifyFc) + + runtime.addTask(task1) + runtime.addTask(task2) + + # Initializing taskr + runtime.initialize() + + # Running taskr + runtime.run() + + # Waiting for task to finish + runtime.await_() + + # Finalizing taskr + runtime.finalize() diff --git a/examples/conditionVariable/python/conditionVariableWaitCondition.py b/examples/conditionVariable/python/conditionVariableWaitCondition.py new file mode 100644 index 0000000..42e2c6a --- /dev/null +++ b/examples/conditionVariable/python/conditionVariableWaitCondition.py @@ -0,0 +1,96 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import taskr + +def conditionVariableWaitCondition(runtime): + # Contention value + value = 0 + + # Mutex for the condition variable + mutex = taskr.Mutex() + + # Task-aware conditional variable + cv = taskr.ConditionVariable() + + def fc(task): + nonlocal value + # Using lock to update the value + print("Thread 1: I go first and set value to 1") + mutex.lock(task) + value += 1 + mutex.unlock(task) + + # Notifiying the other thread + print("Thread 1: Now I notify anybody waiting") + while value != 1: + cv.notifyOne(task) + task.suspend() + + # Waiting for the other thread's update now + print("Thread 1: I wait for the value to turn 2") + mutex.lock(task) + cv.wait(task, mutex, lambda: value == 2) + mutex.unlock(task) + print("Thread 1: The condition (value == 2) is satisfied now") + + # Creating task functions + thread1Fc = taskr.Function(fc) + + def fc(task): + nonlocal value + # Waiting for the other thread to set the first value + print("Thread 2: First, I'll wait for the value to become 1") + mutex.lock(task) + cv.wait(task, mutex, lambda: value == 1) + mutex.unlock(task) + print("Thread 2: The condition (value == 1) is satisfied now") + + # Now updating the value ourselves + print("Thread 2: Now I update the value to 2") + mutex.lock(task) + value += 1 + mutex.unlock(task) + + # Notifying the other thread + print("Thread 2: Notifying anybody interested") + cv.notifyOne(task) + + thread2Fc = taskr.Function(fc) + + task1 = taskr.Task(0, thread1Fc) + task2 = taskr.Task(1, thread2Fc) + + runtime.addTask(task1) + runtime.addTask(task2) + + # Initializing taskr + runtime.initialize() + + # Running taskr + runtime.run() + + # Waiting for task to finish + runtime.await_() + + # Finalizing taskr + runtime.finalize() + + # Value should be equal to concurrent task count + expectedValue = 2 + print(f"Value {value} / Expected {expectedValue}") + + assert value == expectedValue diff --git a/examples/conditionVariable/python/conditionVariableWaitFor.py b/examples/conditionVariable/python/conditionVariableWaitFor.py new file mode 100644 index 0000000..7d4e118 --- /dev/null +++ b/examples/conditionVariable/python/conditionVariableWaitFor.py @@ -0,0 +1,103 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import sys +import time +import taskr + +def conditionVariableWaitFor(runtime): + # Contention value + value = 0 + + # Mutex for the condition variable + mutex = taskr.Mutex() + + # Task-aware conditional variable + cv = taskr.ConditionVariable() + + # Time for timeout checking (Microseconds) + timeoutTimeUs = 100 * 1000 + + # Forever time to wait (for notification-only waits) + forever = 1000 * 1000 * 1000 + + def fc(task): + nonlocal value + + # Waiting for the other task's notification + print("Thread 1: I wait for a notification (Waiting for an hour)") + + mutex.lock(task) + wasNotified = cv.waitFor(task, mutex, forever) + mutex.unlock(task) + if not wasNotified: + sys.stderr.write("Error: I have returned due to a timeout!") + sys.exit(1) + + print("Thread 1: I have been notified (as expected)") + + value = 1 + + # Waiting for a timeout + print(f"Thread 1: I wait for a timeout (Waiting for {timeoutTimeUs}ms) ") + + mutex.lock(task) + startTime = time.time_ns()*1e-3 + wasNotified = cv.waitFor(task, mutex, timeoutTimeUs) + currentTime = time.time_ns()*1e-3 + elapsedTime = currentTime - startTime + mutex.unlock(task) + if wasNotified: + sys.stderr.write("Error: I have returned do to a notification!") + sys.exit(1) + + if elapsedTime < timeoutTimeUs: + sys.stderr.write("Error: I have returned earlier than expected!") + sys.exit(1) + + print(f"Thread 1: I've exited by timeout (as expected in {elapsedTime}us >= {timeoutTimeUs}us)") + + # Creating task functions + waitFc = taskr.Function(fc) + + def fc(task): + nonlocal value + + # Notifying the other task + print("Thread 2: Notifying anybody interested (only once)") + while value != 1: + cv.notifyOne(task) + task.suspend() + + notifyFc = taskr.Function(fc) + + task1 = taskr.Task(0, waitFc) + task2 = taskr.Task(1, notifyFc) + + runtime.addTask(task1) + runtime.addTask(task2) + + # Initializing taskr + runtime.initialize() + + # Running taskr + runtime.run() + + # Waiting for task to finish + runtime.await_() + + # Finalizing taskr + runtime.finalize() diff --git a/examples/conditionVariable/python/conditionVariableWaitForCondition.py b/examples/conditionVariable/python/conditionVariableWaitForCondition.py new file mode 100644 index 0000000..93b107b --- /dev/null +++ b/examples/conditionVariable/python/conditionVariableWaitForCondition.py @@ -0,0 +1,142 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License") + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import sys +import time +import taskr + +def conditionVariableWaitForCondition(runtime): + # Contention value + value = 0 + + # Mutex for the condition variable + mutex = taskr.Mutex() + + # Task-aware conditional variable + cv = taskr.ConditionVariable() + + # Time for timeout checking (Microseconds) + timeoutTimeUs = 100 * 1000 + + # Forever time to wait + forever = 1000 * 1000 * 1000 + + def fc(task): + nonlocal value + + # Using lock to update the value + print("Thread 1: I go first and set value to 1") + mutex.lock(task) + value = 1 + mutex.unlock(task) + + # Notifiying the other thread + print("Thread 1: Now I notify anybody waiting") + while value != 2: + cv.notifyOne(task) + task.suspend() + + # Waiting for the other thread's update now + print("Thread 1: I wait (forever) for the value to turn 2") + mutex.lock(task) + wasNotified = cv.waitFor(task, mutex, lambda : value == 2, forever) + mutex.unlock(task) + + if not wasNotified: + sys.stderr.write("Error: I have returned due to a timeout!") + sys.exit(1) + + print("Thread 1: The condition (value == 2) is satisfied now") + + # Now waiting for a condition that won't be met, although we'll get notifications + print("Thread 1: I wait (with timeout) for the value to turn 3 (won't happen)") + mutex.lock(task) + startTime = time.time_ns()*1e-3 + wasNotified = cv.waitFor(task, mutex, lambda : value == 3, timeoutTimeUs) + currentTime = time.time_ns()*1e-3 + elapsedTime = currentTime - startTime + mutex.unlock(task) + + if wasNotified: + sys.stderr.write("Error: I have returned do to a notification!") + sys.exit(1) + + if elapsedTime < timeoutTimeUs: + sys.stderr.write("Error: I have returned earlier than expected!") + sys.exit(1) + + print(f"Thread 1: I've exited by timeout (as expected in {elapsedTime}us >= {timeoutTimeUs}us)") + + # Updating value to 3 now, to release the other thread + mutex.lock(task) + value = 3 + mutex.unlock(task) + + # Creating task functions + thread1Fc = taskr.Function(fc) + + def fc(task): + nonlocal value + + # Waiting for the other thread to set the first value + print("Thread 2: First, I'll wait for the value to become 1") + mutex.lock(task) + wasNotified = cv.waitFor(task, mutex, lambda : value == 1, forever) + mutex.unlock(task) + if not wasNotified: + sys.stderr.write("Error: I have returned do to a timeout!") + sys.exit(1) + + print("Thread 2: The condition (value == 1) is satisfied now") + + # Now updating the value ourselves + print("Thread 2: Now I update the value to 2") + mutex.lock(task) + value = 2 + mutex.unlock(task) + + # Notifying the other thread + print("Thread 2: Notifying constantly until the value is 3") + while value != 3: + cv.notifyOne(task) + task.suspend() + + + thread2Fc = taskr.Function(fc) + + task1 = taskr.Task(0, thread1Fc) + task2 = taskr.Task(1, thread2Fc) + + runtime.addTask(task1) + runtime.addTask(task2) + + # Initializing taskr + runtime.initialize() + + # Running taskr + runtime.run() + + # Waiting for task to finish + runtime.await_() + + # Finalizing taskr + runtime.finalize() + + # Value should be equal to concurrent task count + expectedValue = 3 + print(f"Value {value} / Expected {expectedValue}") + + assert value == expectedValue diff --git a/examples/conditionVariable/python/main.py b/examples/conditionVariable/python/main.py new file mode 100644 index 0000000..cba7c78 --- /dev/null +++ b/examples/conditionVariable/python/main.py @@ -0,0 +1,51 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import os + +import taskr + +from conditionVariableWait import conditionVariableWait +from conditionVariableWaitCondition import conditionVariableWaitCondition +from conditionVariableWaitFor import conditionVariableWaitFor +from conditionVariableWaitForCondition import conditionVariableWaitForCondition + +def main(): + + # Initialize taskr with the wanted compute manager backend and number of PUs + t = taskr.taskr() + + # Get the runtime + runtime = t.get_runtime() + + runtime.setTaskCallbackHandler(taskr.TaskCallback.onTaskSuspend, lambda task : runtime.resumeTask(task)) + + # Get the enviromnent variable for which function to call + test_function_name = os.getenv('__TEST_FUNCTION_') + + # Get the function from the global namespace + test_function = globals()[test_function_name] + + # Call the function + test_function(runtime) + + # Overwrite the onTaskSuspend fc to be None such that runtime no longer has + # a dependency to the previous fc and runtime can call the destructor + runtime.setTaskCallbackHandler(taskr.TaskCallback.onTaskSuspend, None) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/examples/distributed/meson.build b/examples/distributed/meson.build deleted file mode 100644 index 6c71914..0000000 --- a/examples/distributed/meson.build +++ /dev/null @@ -1,15 +0,0 @@ - -# Handling distributed engine options -if distributedEngine == 'mpi' -TaskRDistributedCppFlag = '-D_TASKR_DISTRIBUTED_ENGINE_MPI' -endif - -if distributedEngine == 'lpf' -TaskRDistributedCppFlag = '-D_TASKR_DISTRIBUTED_ENGINE_LPF' -endif - -if distributedEngine == 'none' -TaskRDistributedCppFlag = '-D_TASKR_DISTRIBUTED_ENGINE_NONE' -endif - -subdir('jacobi3d') \ No newline at end of file diff --git a/examples/distributed/pingPong/meson.build b/examples/distributed/pingPong/meson.build deleted file mode 100644 index 4726b47..0000000 --- a/examples/distributed/pingPong/meson.build +++ /dev/null @@ -1,9 +0,0 @@ -testSuite = [ 'examples', 'distributed' ] - -if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') - pingPong = executable('pingPong', [ 'source/main.cpp'], dependencies: [ TaskRBuildDep ], cpp_args: [ TaskRDistributedCppFlag ] ) - - if get_option('buildTests') - test('pingPong', pingPong, args : [ ], suite: testSuite, workdir: pingPong.path() + '.p' ) - endif -endif diff --git a/examples/local/energySaver/README.rst b/examples/energySaver/README.rst similarity index 100% rename from examples/local/energySaver/README.rst rename to examples/energySaver/README.rst diff --git a/examples/local/energySaver/source/nosv.cpp b/examples/energySaver/cpp/nosv.cpp similarity index 100% rename from examples/local/energySaver/source/nosv.cpp rename to examples/energySaver/cpp/nosv.cpp diff --git a/examples/local/energySaver/source/pthreads.cpp b/examples/energySaver/cpp/pthreads.cpp similarity index 100% rename from examples/local/energySaver/source/pthreads.cpp rename to examples/energySaver/cpp/pthreads.cpp diff --git a/examples/local/energySaver/meson.build b/examples/energySaver/meson.build similarity index 50% rename from examples/local/energySaver/meson.build rename to examples/energySaver/meson.build index 1d3cd26..2397f89 100644 --- a/examples/local/energySaver/meson.build +++ b/examples/energySaver/meson.build @@ -1,7 +1,7 @@ -testSuite = [ 'examples', 'local', 'energySaver' ] +testSuite = [ 'examples', 'energySaver' ] if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') - threading = executable('threading', [ 'source/pthreads.cpp'], dependencies: [ TaskRBuildDep ]) + threading = executable('threading', [ 'cpp/pthreads.cpp'], dependencies: [ TaskRBuildDep ]) if get_option('buildTests') test('threading', threading, args : [ '3', '1', '100' ], suite: testSuite, workdir: threading.path() + '.p' ) @@ -9,9 +9,19 @@ if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('pro endif if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') - nosv = executable('nosv', [ 'source/nosv.cpp'], dependencies: [ TaskRBuildDep ]) + nosv = executable('nosv', [ 'cpp/nosv.cpp'], dependencies: [ TaskRBuildDep ]) if get_option('buildTests') test('nosv', nosv, args : [ '3', '1', '100' ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' ) endif +endif + +if get_option('buildPyTaskR') and get_option('buildTests') + test('pyTaskR', + py, + args : [ 'python/main.py'], + is_parallel : false, + env: ['PYTHONPATH=' + meson.project_build_root() + '/include/pytaskr/'], + suite: testSuite, + workdir: meson.current_source_dir()) endif \ No newline at end of file diff --git a/examples/energySaver/python/energySaver.py b/examples/energySaver/python/energySaver.py new file mode 100644 index 0000000..f404aa5 --- /dev/null +++ b/examples/energySaver/python/energySaver.py @@ -0,0 +1,88 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License") + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import time +import taskr + +def workFc(iterations): + value = 2.0 + for i in range(iterations): + for j in range(iterations): + value = (value + i)**0.5 + value = value * value + +def waitFc(taskr, secondsDelay): + print("Starting long task...\n", flush=True) + time.sleep(secondsDelay) + print("Finished long task...\n", flush=True) + +def energySaver(runtime, workTaskCount, secondsDelay, iterations): + # Creating task work function + workFunction = taskr.Function(lambda task : workFc(iterations)) + + # Creating task wait function + waitFunction = taskr.Function(lambda task : waitFc(runtime, secondsDelay)) + + # Creating a single wait task that suspends all workers except for one + waitTask1 = taskr.Task(0, waitFunction) + + # Building task graph. First a lot of pure work tasks. The wait task depends on these + for i in range(workTaskCount): + workTask = taskr.Task(i + 1, workFunction) + waitTask1.addDependency(workTask) + runtime.addTask(workTask) + + # Creating another wait task + waitTask2 = taskr.Task(2 * workTaskCount + 1, waitFunction) + + # Then creating another batch of work tasks that depends on the wait task + for i in range(workTaskCount): + workTask = taskr.Task(workTaskCount + i + 1, workFunction) + + # This work task waits on the first wait task + workTask.addDependency(waitTask1) + + # The second wait task depends on this work task + waitTask2.addDependency(workTask) + + # Adding work task + runtime.addTask(workTask) + + # Last set of work tasks + for i in range(workTaskCount): + workTask = taskr.Task(2 * workTaskCount + i + 2, workFunction) + + # This work task depends on the second wait task + workTask.addDependency(waitTask2) + + # Adding work task + runtime.addTask(workTask) + + # Adding work tasks + runtime.addTask(waitTask1) + runtime.addTask(waitTask2) + + # Initializing taskr + runtime.initialize() + + # Running taskr + print("Starting (open 'htop' in another console to see the workers going to sleep during the long task)...\n") + runtime.run() + runtime.await_() + print("Finished.\n") + + # Finalizing taskr + runtime.finalize() \ No newline at end of file diff --git a/examples/energySaver/python/main.py b/examples/energySaver/python/main.py new file mode 100644 index 0000000..c74f87c --- /dev/null +++ b/examples/energySaver/python/main.py @@ -0,0 +1,42 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import sys +import taskr +import energySaver + +def main(): + # Getting arguments, if provided + workTaskCount = 3 + secondsDelay = 1 + iterations = 100 + if len(sys.argv) > 1: workTaskCount = int(sys.argv[1]) + if len(sys.argv) > 2: secondsDelay = int(sys.argv[2]) + if len(sys.argv) > 3: iterations = int(sys.argv[3]) + + print(sys.argv, workTaskCount, secondsDelay, iterations) + + # Initialize taskr with the wanted compute manager backend and number of PUs + t = taskr.taskr(taskr.HiCRBackend.threading) + + # Get the runtime + runtime = t.get_runtime() + + # Running simple example + energySaver.energySaver(runtime, workTaskCount, secondsDelay, iterations) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/examples/local/fibonacci/README.md b/examples/fibonacci/README.md similarity index 100% rename from examples/local/fibonacci/README.md rename to examples/fibonacci/README.md diff --git a/examples/local/fibonacci/source/fibonacci.hpp b/examples/fibonacci/cpp/fibonacci.hpp similarity index 100% rename from examples/local/fibonacci/source/fibonacci.hpp rename to examples/fibonacci/cpp/fibonacci.hpp diff --git a/examples/local/fibonacci/source/nosv.cpp b/examples/fibonacci/cpp/nosv.cpp similarity index 100% rename from examples/local/fibonacci/source/nosv.cpp rename to examples/fibonacci/cpp/nosv.cpp diff --git a/examples/local/fibonacci/source/pthreads.cpp b/examples/fibonacci/cpp/pthreads.cpp similarity index 100% rename from examples/local/fibonacci/source/pthreads.cpp rename to examples/fibonacci/cpp/pthreads.cpp diff --git a/examples/fibonacci/meson.build b/examples/fibonacci/meson.build new file mode 100644 index 0000000..8cde6be --- /dev/null +++ b/examples/fibonacci/meson.build @@ -0,0 +1,27 @@ +testSuite = [ 'examples', 'fibonacci' ] + +if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') + threading = executable('threading', [ 'cpp/pthreads.cpp'], dependencies: [ TaskRBuildDep ]) + + if get_option('buildTests') + test('threading', threading, args : [ '15' ], suite: testSuite, workdir: threading.path() + '.p' ) + endif +endif + +if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') + nosv = executable('nosv', [ 'cpp/nosv.cpp'], dependencies: [ TaskRBuildDep ]) + + if get_option('buildTests') + test('nosv', nosv, args : [ '15' ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' ) + endif +endif + +if get_option('buildPyTaskR') and get_option('buildTests') + test('pyTaskR', + py, + args : [ 'python/main.py'], + is_parallel : false, + env: ['PYTHONPATH=' + meson.project_build_root() + '/include/pytaskr/'], + suite: testSuite, + workdir: meson.current_source_dir()) +endif diff --git a/examples/fibonacci/python/fibonacci.py b/examples/fibonacci/python/fibonacci.py new file mode 100644 index 0000000..1ef6175 --- /dev/null +++ b/examples/fibonacci/python/fibonacci.py @@ -0,0 +1,110 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License") + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +from atomic import AtomicLong +import time +import taskr + +# Globally assigned variables +_runtime = None +_taskCounter = AtomicLong(0) + +# Fibonacci without memoization to stress the tasking runtime +def fibonacci(currentTask, x): + if x == 0: return 0 + if x == 1: return 1 + + global _taskCounter + global _runtime + + result1 = 0 + result2 = 0 + + # Creating task functions + def Fc1(task): + nonlocal result1 + result1 = fibonacci(task, x - 1) + + def Fc2(task): + nonlocal result2 + result2 = fibonacci(task, x - 2) + + fibFc1 = taskr.Function(Fc1) + fibFc2 = taskr.Function(Fc2) + + # Creating two new tasks + subTask1 = taskr.Task(_taskCounter.value, fibFc1) + _taskCounter += 1 + subTask2 = taskr.Task(_taskCounter.value, fibFc2) + _taskCounter += 1 + + # Adding dependencies with the newly created tasks + currentTask.addDependency(subTask1) + currentTask.addDependency(subTask2) + + # Adding new tasks to TaskR + _runtime.addTask(subTask1) + _runtime.addTask(subTask2) + + # Suspending current task + currentTask.suspend() + + return result1 + result2 + +def fibonacciDriver(initialValue, runtime): + # Setting global variables + global _taskCounter + global _runtime + _runtime = runtime + + # Storage for result + result = 0 + + # Creating task functions + def Fc(task): + nonlocal result + result = fibonacci(task, initialValue) + + initialFc = taskr.Function(Fc) + + # Now creating tasks and their dependency graph + initialTask = taskr.Task(_taskCounter.value, initialFc) + _taskCounter += 1 + + runtime.addTask(initialTask) + + # Initializing taskR + runtime.initialize() + + # Running taskr + startTime = time.time() + runtime.run() + runtime.await_() + endTime = time.time() + + computeTime = endTime - startTime + + print(f"Running Time: {computeTime:.5f}s") + print(f"Total Tasks: {_taskCounter.value}") + + # Finalizing taskR + runtime.finalize() + + # Dereferencing this global instance to let runtime call his Destructor + _runtime = None + + # Returning fibonacci value + return result diff --git a/examples/fibonacci/python/fibonacci_mutex.py b/examples/fibonacci/python/fibonacci_mutex.py new file mode 100644 index 0000000..024c39a --- /dev/null +++ b/examples/fibonacci/python/fibonacci_mutex.py @@ -0,0 +1,115 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License") + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + + +import time +import taskr + +# Globally assigned variables +_runtime = None +_taskCounter = 0 +_m = taskr.Mutex() + +# Fibonacci without memoization to stress the tasking runtime +def fibonacci(currentTask, x): + if x == 0: return 0 + if x == 1: return 1 + + global _taskCounter + global _runtime + + result1 = 0 + result2 = 0 + + # Creating task functions + def Fc1(task): + nonlocal result1 + result1 = fibonacci(task, x - 1) + + def Fc2(task): + nonlocal result2 + result2 = fibonacci(task, x - 2) + + fibFc1 = taskr.Function(Fc1) + fibFc2 = taskr.Function(Fc2) + + # Creating two new tasks + subTask1 = taskr.Task(_taskCounter, fibFc1) + _m.lock(currentTask) + _taskCounter += 1 + _m.unlock(currentTask) + subTask2 = taskr.Task(_taskCounter, fibFc2) + _m.lock(currentTask) + _taskCounter += 1 + _m.unlock(currentTask) + + # Adding dependencies with the newly created tasks + currentTask.addDependency(subTask1) + currentTask.addDependency(subTask2) + + # Adding new tasks to TaskR + _runtime.addTask(subTask1) + _runtime.addTask(subTask2) + + # Suspending current task + currentTask.suspend() + + return result1 + result2 + +def fibonacciDriver(initialValue, runtime): + # Setting global variables + global _taskCounter + global _runtime + _runtime = runtime + + # Storage for result + result = 0 + + # Creating task functions + def Fc(task): + nonlocal result + result = fibonacci(task, initialValue) + + initialFc = taskr.Function(Fc) + + # Now creating tasks and their dependency graph + initialTask = taskr.Task(_taskCounter, initialFc) + _taskCounter += 1 + + runtime.addTask(initialTask) + + # Initializing taskR + runtime.initialize() + + # Running taskr + startTime = time.time() + runtime.run() + runtime.await_() + endTime = time.time() + + computeTime = endTime - startTime + + print(f"Running Time: {computeTime:.5f}s") + print(f"Total Tasks: {_taskCounter}") + + # Finalizing taskR + runtime.finalize() + + # Dereferencing this global instance to let runtime call his Destructor + _runtime = None + + # Returning fibonacci value + return result diff --git a/examples/fibonacci/python/main.py b/examples/fibonacci/python/main.py new file mode 100644 index 0000000..4da0092 --- /dev/null +++ b/examples/fibonacci/python/main.py @@ -0,0 +1,41 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import sys +import taskr +# import fibonacci +import fibonacci_mutex + +def main(): + # Define the Fibonacci number to compute. + initialValue = 10 + if len(sys.argv) > 1: initialValue = int(sys.argv[1]) + + # Initialize taskr with the wanted compute manager backend and number of PUs + t = taskr.taskr(taskr.HiCRBackend.nosv) + + # Get the runtime + runtime = t.get_runtime() + + # Running Fibonacci example + # result = fibonacci.fibonacciDriver(initialValue, runtime) + result = fibonacci_mutex.fibonacciDriver(initialValue, runtime) + + # Printing result + print(f"Fib({initialValue}) = {result}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/examples/distributed/jacobi3d/.gitignore b/examples/jacobi3d/.gitignore similarity index 100% rename from examples/distributed/jacobi3d/.gitignore rename to examples/jacobi3d/.gitignore diff --git a/examples/distributed/jacobi3d/README.md b/examples/jacobi3d/README.md similarity index 100% rename from examples/distributed/jacobi3d/README.md rename to examples/jacobi3d/README.md diff --git a/examples/distributed/jacobi3d/meson.build b/examples/jacobi3d/meson.build similarity index 93% rename from examples/distributed/jacobi3d/meson.build rename to examples/jacobi3d/meson.build index d6f5e28..276796d 100644 --- a/examples/distributed/jacobi3d/meson.build +++ b/examples/jacobi3d/meson.build @@ -1,4 +1,4 @@ -testSuite = [ 'examples', 'distributed', 'jacobi3d' ] +testSuite = [ 'examples', 'jacobi3d' ] if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') threading = executable('threading', [ 'source/pthreads.cpp', 'source/grid.cpp' ], dependencies: [ TaskRBuildDep ], cpp_args: [ TaskRDistributedCppFlag ] ) diff --git a/examples/distributed/jacobi3d/mpi/Makefile b/examples/jacobi3d/mpi/Makefile similarity index 100% rename from examples/distributed/jacobi3d/mpi/Makefile rename to examples/jacobi3d/mpi/Makefile diff --git a/examples/distributed/jacobi3d/mpi/grid.cpp b/examples/jacobi3d/mpi/grid.cpp similarity index 100% rename from examples/distributed/jacobi3d/mpi/grid.cpp rename to examples/jacobi3d/mpi/grid.cpp diff --git a/examples/distributed/jacobi3d/mpi/grid.hpp b/examples/jacobi3d/mpi/grid.hpp similarity index 100% rename from examples/distributed/jacobi3d/mpi/grid.hpp rename to examples/jacobi3d/mpi/grid.hpp diff --git a/examples/distributed/jacobi3d/mpi/jacobi.cpp b/examples/jacobi3d/mpi/jacobi.cpp similarity index 100% rename from examples/distributed/jacobi3d/mpi/jacobi.cpp rename to examples/jacobi3d/mpi/jacobi.cpp diff --git a/examples/distributed/jacobi3d/source/grid.cpp b/examples/jacobi3d/source/grid.cpp similarity index 100% rename from examples/distributed/jacobi3d/source/grid.cpp rename to examples/jacobi3d/source/grid.cpp diff --git a/examples/distributed/jacobi3d/source/grid.hpp b/examples/jacobi3d/source/grid.hpp similarity index 100% rename from examples/distributed/jacobi3d/source/grid.hpp rename to examples/jacobi3d/source/grid.hpp diff --git a/examples/distributed/jacobi3d/source/nosv.cpp b/examples/jacobi3d/source/nosv.cpp similarity index 100% rename from examples/distributed/jacobi3d/source/nosv.cpp rename to examples/jacobi3d/source/nosv.cpp diff --git a/examples/distributed/jacobi3d/source/pthreads.cpp b/examples/jacobi3d/source/pthreads.cpp similarity index 100% rename from examples/distributed/jacobi3d/source/pthreads.cpp rename to examples/jacobi3d/source/pthreads.cpp diff --git a/examples/distributed/jacobi3d/source/task.hpp b/examples/jacobi3d/source/task.hpp similarity index 100% rename from examples/distributed/jacobi3d/source/task.hpp rename to examples/jacobi3d/source/task.hpp diff --git a/examples/local/abcTasks/meson.build b/examples/local/abcTasks/meson.build deleted file mode 100644 index 44c7a0f..0000000 --- a/examples/local/abcTasks/meson.build +++ /dev/null @@ -1,17 +0,0 @@ -testSuite = [ 'examples', 'local', 'abcTasks' ] - -if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') - threading = executable('threading', [ 'source/pthreads.cpp'], dependencies: [ TaskRBuildDep ]) - - if get_option('buildTests') - test('threading', threading, args : [ ], suite: testSuite, workdir: threading.path() + '.p' ) - endif -endif - -if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') - nosv = executable('nosv', [ 'source/nosv.cpp'], dependencies: [ TaskRBuildDep ]) - - if get_option('buildTests') - test('nosv', nosv, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p') - endif -endif \ No newline at end of file diff --git a/examples/local/conditionVariable/meson.build b/examples/local/conditionVariable/meson.build deleted file mode 100644 index b2037f4..0000000 --- a/examples/local/conditionVariable/meson.build +++ /dev/null @@ -1,29 +0,0 @@ -testSuite = [ 'examples', 'local', 'conditionVariable' ] - -if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') - threading_conditionVariableWait = executable('threading_conditionVariableWait', [ 'source/pthreads.cpp'], dependencies: [ TaskRBuildDep ], cpp_args: [ '-D__TEST_FUNCTION_=conditionVariableWait'] ) - threading_conditionVariableWaitFor = executable('threading_conditionVariableWaitFor', [ 'source/pthreads.cpp'], dependencies: [ TaskRBuildDep ], cpp_args: [ '-D__TEST_FUNCTION_=conditionVariableWaitFor'] ) - threading_conditionVariableWaitCondition = executable('threading_conditionVariableWaitCondition', [ 'source/pthreads.cpp'], dependencies: [ TaskRBuildDep ], cpp_args: [ '-D__TEST_FUNCTION_=conditionVariableWaitCondition'] ) - threading_conditionVariableWaitForCondition = executable('threading_conditionVariableWaitForCondition', [ 'source/pthreads.cpp'], dependencies: [ TaskRBuildDep ], cpp_args: [ '-D__TEST_FUNCTION_=conditionVariableWaitForCondition'] ) - - if get_option('buildTests') - test('threading_conditionVariableWait', threading_conditionVariableWait, args : [ ], suite: testSuite, workdir: threading_conditionVariableWait.path() + '.p' ) - test('threading_conditionVariableWaitFor', threading_conditionVariableWaitFor, args : [ ], suite: testSuite, workdir: threading_conditionVariableWaitFor.path() + '.p' ) - test('threading_conditionVariableWaitCondition', threading_conditionVariableWaitCondition, args : [ ], suite: testSuite, workdir: threading_conditionVariableWaitCondition.path() + '.p' ) - test('threading_conditionVariableWaitForCondition', threading_conditionVariableWaitForCondition, args : [ ], suite: testSuite, workdir: threading_conditionVariableWaitForCondition.path() + '.p' ) - endif -endif - -if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') - nosv_conditionVariableWait = executable('nosv_conditionVariableWait', [ 'source/nosv.cpp'], dependencies: [ TaskRBuildDep ], cpp_args: [ '-D__TEST_FUNCTION_=conditionVariableWait'] ) - nosv_conditionVariableWaitFor = executable('nosv_conditionVariableWaitFor', [ 'source/nosv.cpp'], dependencies: [ TaskRBuildDep ], cpp_args: [ '-D__TEST_FUNCTION_=conditionVariableWaitFor'] ) - nosv_conditionVariableWaitCondition = executable('nosv_conditionVariableWaitCondition', [ 'source/nosv.cpp'], dependencies: [ TaskRBuildDep ], cpp_args: [ '-D__TEST_FUNCTION_=conditionVariableWaitCondition'] ) - nosv_conditionVariableWaitForCondition = executable('nosv_conditionVariableWaitForCondition', [ 'source/nosv.cpp'], dependencies: [ TaskRBuildDep ], cpp_args: [ '-D__TEST_FUNCTION_=conditionVariableWaitForCondition'] ) - - if get_option('buildTests') - test('nosv_conditionVariableWait', nosv_conditionVariableWait, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv_conditionVariableWait.path() + '.p' ) - test('nosv_conditionVariableWaitFor', nosv_conditionVariableWaitFor, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv_conditionVariableWaitFor.path() + '.p' ) - test('nosv_conditionVariableWaitCondition', nosv_conditionVariableWaitCondition, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv_conditionVariableWaitCondition.path() + '.p' ) - test('nosv_conditionVariableWaitForCondition', nosv_conditionVariableWaitForCondition, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv_conditionVariableWaitForCondition.path() + '.p' ) - endif -endif \ No newline at end of file diff --git a/examples/local/fibonacci/meson.build b/examples/local/fibonacci/meson.build deleted file mode 100644 index 720d203..0000000 --- a/examples/local/fibonacci/meson.build +++ /dev/null @@ -1,17 +0,0 @@ -testSuite = [ 'examples', 'local', 'fibonacci' ] - -if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') - threading = executable('threading', [ 'source/pthreads.cpp'], dependencies: [ TaskRBuildDep ]) - - if get_option('buildTests') - test('threading', threading, args : [ '10' ], suite: testSuite, workdir: threading.path() + '.p' ) - endif -endif - -if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') - nosv = executable('nosv', [ 'source/nosv.cpp'], dependencies: [ TaskRBuildDep ]) - - if get_option('buildTests') - test('nosv', nosv, args : [ '10' ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' ) - endif -endif \ No newline at end of file diff --git a/examples/local/manyParallel/meson.build b/examples/local/manyParallel/meson.build deleted file mode 100644 index 0032ad6..0000000 --- a/examples/local/manyParallel/meson.build +++ /dev/null @@ -1,17 +0,0 @@ -testSuite = [ 'examples', 'local', 'manyParallel' ] - -if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') - threading = executable('threading', [ 'source/pthreads.cpp'], dependencies: [ TaskRBuildDep ] ) - - if get_option('buildTests') - test('threading', threading, args : [ '2', '100' ], suite: testSuite, workdir: threading.path() + '.p' ) - endif -endif - -if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') - nosv = executable('nosv', [ 'source/nosv.cpp'], dependencies: [ TaskRBuildDep ] ) - - if get_option('buildTests') - test('nosv', nosv, args : [ '2', '100' ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' ) - endif -endif \ No newline at end of file diff --git a/examples/local/meson.build b/examples/local/meson.build deleted file mode 100644 index f3188a4..0000000 --- a/examples/local/meson.build +++ /dev/null @@ -1,13 +0,0 @@ -subdir('abcTasks') -subdir('conditionVariable') -subdir('cholesky') -subdir('mutex') -subdir('energySaver') -subdir('resourceList') -subdir('fibonacci') -subdir('multiJob') -subdir('pendingOperation') -subdir('workerSpecific') -subdir('manyParallel') -subdir('suspend') -subdir('simple') \ No newline at end of file diff --git a/examples/local/multiJob/meson.build b/examples/local/multiJob/meson.build deleted file mode 100644 index 002e324..0000000 --- a/examples/local/multiJob/meson.build +++ /dev/null @@ -1,17 +0,0 @@ -testSuite = [ 'examples', 'local', 'multiJob' ] - -if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') - threading = executable('threading', [ 'source/pthreads.cpp', 'source/job1.cpp', 'source/job2.cpp' ], dependencies: [ TaskRBuildDep ] ) - - if get_option('buildTests') - test('threading', threading, args : [ ], suite: testSuite, workdir: threading.path() + '.p' ) - endif -endif - -if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') - nosv = executable('nosv', [ 'source/nosv.cpp', 'source/job1.cpp', 'source/job2.cpp' ], dependencies: [ TaskRBuildDep ] ) - - if get_option('buildTests') - test('nosv', nosv, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' ) - endif -endif \ No newline at end of file diff --git a/examples/local/mutex/meson.build b/examples/local/mutex/meson.build deleted file mode 100644 index 3c31bfa..0000000 --- a/examples/local/mutex/meson.build +++ /dev/null @@ -1,17 +0,0 @@ -testSuite = [ 'examples', 'local', 'mutex' ] - -if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') - threading = executable('threading', [ 'source/pthreads.cpp'], dependencies: [ TaskRBuildDep ] ) - - if get_option('buildTests') - test('threading', threading, args : [ ], suite: testSuite, workdir: threading.path() + '.p' ) - endif -endif - -if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') - nosv = executable('nosv', [ 'source/nosv.cpp'], dependencies: [ TaskRBuildDep ] ) - - if get_option('buildTests') - test('nosv', nosv, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' ) - endif -endif \ No newline at end of file diff --git a/examples/local/pendingOperation/meson.build b/examples/local/pendingOperation/meson.build deleted file mode 100644 index 11bbcfe..0000000 --- a/examples/local/pendingOperation/meson.build +++ /dev/null @@ -1,17 +0,0 @@ -testSuite = [ 'examples', 'local', 'pendingOperation' ] - -if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') - threading = executable('threading', [ 'source/pthreads.cpp'], dependencies: [ TaskRBuildDep ] ) - - if get_option('buildTests') - test('threading', threading, args : [ ], suite: testSuite, workdir: threading.path() + '.p' ) - endif -endif - -if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') - nosv = executable('nosv', [ 'source/nosv.cpp'], dependencies: [ TaskRBuildDep ] ) - - if get_option('buildTests') - test('nosv', nosv, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' ) - endif -endif \ No newline at end of file diff --git a/examples/local/simple/meson.build b/examples/local/simple/meson.build deleted file mode 100644 index fa6de31..0000000 --- a/examples/local/simple/meson.build +++ /dev/null @@ -1,17 +0,0 @@ -testSuite = [ 'examples', 'local', 'simple' ] - -if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') - threading = executable('threading', [ 'source/pthreads.cpp'], dependencies: [ TaskRBuildDep ]) - - if get_option('buildTests') - test('threading', threading, args : [ ], suite: testSuite, workdir: threading.path() + '.p' ) - endif -endif - -if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') - nosv = executable('nosv', [ 'source/nosv.cpp'], dependencies: [ TaskRBuildDep ]) - - if get_option('buildTests') - test('nosv', nosv, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' ) - endif -endif \ No newline at end of file diff --git a/examples/local/workerSpecific/meson.build b/examples/local/workerSpecific/meson.build deleted file mode 100644 index bcea67d..0000000 --- a/examples/local/workerSpecific/meson.build +++ /dev/null @@ -1,17 +0,0 @@ -testSuite = [ 'examples', 'local', 'workerSpecific' ] - -if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') - threading = executable('threading', [ 'source/pthreads.cpp'], dependencies: [ TaskRBuildDep ] ) - - if get_option('buildTests') - test('threading', threading, args : [ ], suite: testSuite, workdir: threading.path() + '.p' ) - endif -endif - -if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') - nosv = executable('nosv', [ 'source/nosv.cpp'], dependencies: [ TaskRBuildDep ] ) - - if get_option('buildTests') - test('nosv', nosv, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' ) - endif -endif \ No newline at end of file diff --git a/examples/local/manyParallel/README.rst b/examples/manyParallel/README.rst similarity index 100% rename from examples/local/manyParallel/README.rst rename to examples/manyParallel/README.rst diff --git a/examples/local/manyParallel/source/manyParallel.hpp b/examples/manyParallel/cpp/manyParallel.hpp similarity index 100% rename from examples/local/manyParallel/source/manyParallel.hpp rename to examples/manyParallel/cpp/manyParallel.hpp diff --git a/examples/local/manyParallel/source/nosv.cpp b/examples/manyParallel/cpp/nosv.cpp similarity index 100% rename from examples/local/manyParallel/source/nosv.cpp rename to examples/manyParallel/cpp/nosv.cpp diff --git a/examples/local/manyParallel/source/pthreads.cpp b/examples/manyParallel/cpp/pthreads.cpp similarity index 100% rename from examples/local/manyParallel/source/pthreads.cpp rename to examples/manyParallel/cpp/pthreads.cpp diff --git a/examples/manyParallel/meson.build b/examples/manyParallel/meson.build new file mode 100644 index 0000000..6ed7857 --- /dev/null +++ b/examples/manyParallel/meson.build @@ -0,0 +1,27 @@ +testSuite = [ 'examples', 'manyParallel' ] + +if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') + threading = executable('threading', [ 'cpp/pthreads.cpp'], dependencies: [ TaskRBuildDep ] ) + + if get_option('buildTests') + test('threading', threading, args : [ '2', '100' ], suite: testSuite, workdir: threading.path() + '.p' ) + endif +endif + +if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') + nosv = executable('nosv', [ 'cpp/nosv.cpp'], dependencies: [ TaskRBuildDep ] ) + + if get_option('buildTests') + test('nosv', nosv, args : [ '2', '100' ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' ) + endif +endif + +if get_option('buildPyTaskR') and get_option('buildTests') + test('pyTaskR', + py, + args : [ 'python/main.py' ], + is_parallel : false, + env: ['PYTHONPATH=' + meson.project_build_root() + '/include/pytaskr/'], + suite: testSuite, + workdir: meson.current_source_dir()) +endif \ No newline at end of file diff --git a/examples/manyParallel/python/main.py b/examples/manyParallel/python/main.py new file mode 100644 index 0000000..92932be --- /dev/null +++ b/examples/manyParallel/python/main.py @@ -0,0 +1,38 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import sys +import taskr +import manyParallel + +def main(): + # Getting arguments, if provided + taskCount = 2 + branchCount = 100 + if len(sys.argv) > 1: taskCount = int(sys.argv[1]) + if len(sys.argv) > 2: branchCount = int(sys.argv[2]) + + # Initialize taskr with the wanted compute manager backend and number of PUs + t = taskr.taskr(taskr.HiCRBackend.threading) + + # Get the runtime + runtime = t.get_runtime() + + # Running simple example + manyParallel.manyParallel(runtime, taskCount, branchCount) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/examples/manyParallel/python/manyParallel.py b/examples/manyParallel/python/manyParallel.py new file mode 100644 index 0000000..0b55372 --- /dev/null +++ b/examples/manyParallel/python/manyParallel.py @@ -0,0 +1,53 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License") + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import time +import taskr + +def manyParallel(runtime, branchCount, taskCount): + # Creating the execution units (functions that the tasks will run) + taskfc = taskr.Function(lambda task : None) + + # Initializing taskr + runtime.initialize() + + # Store a pointer to the previous task to generate a long chain + prevTask = None + + # Each run consists of several iterations of ABC + for b in range(branchCount): + for i in range(taskCount): + task = taskr.Task(b * taskCount + i, taskfc) + + # Creating dependencies + if i > 0: task.addDependency(prevTask) + + # Adding to taskr + runtime.addTask(task) + + # Setting as new previous task + prevTask = task + + # Running taskr for the current repetition + startTime = time.time() + runtime.run() + runtime.await_() + endTime = time.time() + computeTime = endTime - startTime + print(f"Running Time: {computeTime:0.5f}s") + + # Finalizing taskr + runtime.finalize() \ No newline at end of file diff --git a/examples/matmul/README.rst b/examples/matmul/README.rst new file mode 100644 index 0000000..ad40e64 --- /dev/null +++ b/examples/matmul/README.rst @@ -0,0 +1,8 @@ +MatMul +============ + +A simple example of pyTaskR registering a cpp-based function (in this case a Matrix-Matrix multiplication) to run in python. + +- `main.py`: The main script to initialize TaskR runtime +- `matmul.cpp`: The cpp-function to be registered and callable in python +- `matmul.py`: The Driver to load the cpp function and execute it in python. It also consists of a NumPy example for comparisons. diff --git a/examples/matmul/meson.build b/examples/matmul/meson.build new file mode 100644 index 0000000..94ec388 --- /dev/null +++ b/examples/matmul/meson.build @@ -0,0 +1,17 @@ +testSuite = [ 'examples', 'matmul' ] + +if get_option('buildPyTaskR') and get_option('buildTests') + py.extension_module('cpp_matmul', + ['python/matmul.cpp'], + install: true, + dependencies : [TaskRBuildDep, pybind11_dep], + ) + + test('pyTaskR', + py, + args : [ 'python/main.py' ], + is_parallel : false, + env: ['PYTHONPATH=' + meson.project_build_root() + '/include/pytaskr/:' + meson.project_build_root() + '/examples/matmul/'], + suite: testSuite, + workdir: meson.current_source_dir()) +endif \ No newline at end of file diff --git a/examples/matmul/python/main.py b/examples/matmul/python/main.py new file mode 100644 index 0000000..1906da7 --- /dev/null +++ b/examples/matmul/python/main.py @@ -0,0 +1,34 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import taskr +from matmul import matmul_cpp_Driver, matmul_numpy_Driver + +def main(): + # Initialize taskr with the wanted compute manager backend and number of PUs + t = taskr.taskr(taskr.HiCRBackend.nosv, 2) + + # Get the runtime + runtime = t.get_runtime() + + # Running matmul example + matmul_cpp_Driver(runtime) + + matmul_numpy_Driver(runtime) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/examples/matmul/python/matmul.cpp b/examples/matmul/python/matmul.cpp new file mode 100644 index 0000000..ccc17c6 --- /dev/null +++ b/examples/matmul/python/matmul.cpp @@ -0,0 +1,66 @@ +/* + * Copyright 2025 Huawei Technologies Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +#define mytype float + +/** + * Compute mmm + */ +void matmul(taskr::Task *) +{ + const size_t N = 1000; + + // Allocate memory + volatile mytype *A = (mytype *)calloc(1, N * N * sizeof(mytype)); + volatile mytype *B = (mytype *)malloc(N * N * sizeof(mytype)); + volatile mytype *C = (mytype *)malloc(N * N * sizeof(mytype)); + + // Filling matrices B and C + for (size_t i = 0; i < N; ++i) + { + for (size_t j = 0; j < N; ++j) + { + B[i * N + j] = 1.0 / (mytype(i + 1)); + C[i * N + j] = 1.0 / (mytype(j + 1)); + } + } + + // mmm + for (size_t i = 0; i < N; ++i) + { + for (size_t j = 0; j < N; ++j) + { + for (size_t k = 0; k < N; ++k) { A[i * N + j] += B[i * N + k] * C[k * N + j]; } + } + } + + // free memory + free((mytype *)A); + free((mytype *)B); + free((mytype *)C); +} + +PYBIND11_MODULE(cpp_matmul, m) +{ + m.doc() = "pybind11 plugin for matmul example"; + + m.def("cpp_matmul", &matmul, "cpp function to do matrix-matrix multiplication."); +} \ No newline at end of file diff --git a/examples/matmul/python/matmul.py b/examples/matmul/python/matmul.py new file mode 100644 index 0000000..daf8ebb --- /dev/null +++ b/examples/matmul/python/matmul.py @@ -0,0 +1,85 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import time +import numpy as np + +import taskr +import cpp_matmul + +NTASKS = 2 + +def matmul_cpp_Driver(runtime): + # Initializing taskr + runtime.initialize() + + taskfc = taskr.Function(cpp_matmul.cpp_matmul) + + # Adding to tasks to taskr + for i in range(NTASKS): + runtime.addTask(taskr.Task(i, taskfc)) + + # Running taskr for the current repetition + t_start = time.time() + runtime.run() + + # Waiting current repetition to end + runtime.await_() + print(f"total time: {time.time() - t_start}") + + # Finalizing taskr + runtime.finalize() + + + + + +def matmul_numpy_Driver(runtime): + # Initializing taskr + runtime.initialize() + + def matmul_numpy(task): + N = 1000 + A = np.zeros((N,N)) + B = np.empty((N,N)) + C = np.empty((N,N)) + + for i in range(N): + for j in range(N): + B[i, j] = 1.0/(i + 1) + C[i, j] = 1.0/(j + 1) + + B += task.getLabel()+1 + C += task.getLabel()+1 + + A = B @ C + + taskfc = taskr.Function(matmul_numpy) + + # Adding to tasks to taskr + for i in range(NTASKS): + runtime.addTask(taskr.Task(i, taskfc)) + + # Running taskr for the current repetition + t_start = time.time() + runtime.run() + + # Waiting current repetition to end + runtime.await_() + print(f"total time: {time.time() - t_start}") + + # Finalizing taskr + runtime.finalize() \ No newline at end of file diff --git a/examples/meson.build b/examples/meson.build index 340b0c2..cc852f8 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -1,2 +1,30 @@ -subdir('local') -subdir('distributed') +# Handling distributed engine options +if distributedEngine == 'mpi' +TaskRDistributedCppFlag = '-D_TASKR_DISTRIBUTED_ENGINE_MPI' +endif + +if distributedEngine == 'lpf' +TaskRDistributedCppFlag = '-D_TASKR_DISTRIBUTED_ENGINE_LPF' +endif + +if distributedEngine == 'none' +TaskRDistributedCppFlag = '-D_TASKR_DISTRIBUTED_ENGINE_NONE' +endif + +subdir('jacobi3d') + +# local +subdir('abcTasks') +subdir('conditionVariable') +subdir('cholesky') +subdir('mutex') +subdir('energySaver') +subdir('resourceList') +subdir('fibonacci') +subdir('multiJob') +subdir('pendingOperation') +subdir('workerSpecific') +subdir('manyParallel') +subdir('suspend') +subdir('simple') +subdir('matmul') \ No newline at end of file diff --git a/examples/local/multiJob/README.rst b/examples/multiJob/README.rst similarity index 100% rename from examples/local/multiJob/README.rst rename to examples/multiJob/README.rst diff --git a/examples/local/multiJob/source/job1.cpp b/examples/multiJob/cpp/job1.cpp similarity index 100% rename from examples/local/multiJob/source/job1.cpp rename to examples/multiJob/cpp/job1.cpp diff --git a/examples/local/multiJob/source/job2.cpp b/examples/multiJob/cpp/job2.cpp similarity index 100% rename from examples/local/multiJob/source/job2.cpp rename to examples/multiJob/cpp/job2.cpp diff --git a/examples/local/multiJob/source/jobs.hpp b/examples/multiJob/cpp/jobs.hpp similarity index 100% rename from examples/local/multiJob/source/jobs.hpp rename to examples/multiJob/cpp/jobs.hpp diff --git a/examples/local/multiJob/source/nosv.cpp b/examples/multiJob/cpp/nosv.cpp similarity index 100% rename from examples/local/multiJob/source/nosv.cpp rename to examples/multiJob/cpp/nosv.cpp diff --git a/examples/local/multiJob/source/pthreads.cpp b/examples/multiJob/cpp/pthreads.cpp similarity index 100% rename from examples/local/multiJob/source/pthreads.cpp rename to examples/multiJob/cpp/pthreads.cpp diff --git a/examples/multiJob/meson.build b/examples/multiJob/meson.build new file mode 100644 index 0000000..99f0a8d --- /dev/null +++ b/examples/multiJob/meson.build @@ -0,0 +1,27 @@ +testSuite = [ 'examples', 'multiJob' ] + +if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') + threading = executable('threading', [ 'cpp/pthreads.cpp', 'cpp/job1.cpp', 'cpp/job2.cpp' ], dependencies: [ TaskRBuildDep ] ) + + if get_option('buildTests') + test('threading', threading, args : [ ], suite: testSuite, workdir: threading.path() + '.p' ) + endif +endif + +if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') + nosv = executable('nosv', [ 'cpp/nosv.cpp', 'cpp/job1.cpp', 'cpp/job2.cpp' ], dependencies: [ TaskRBuildDep ] ) + + if get_option('buildTests') + test('nosv', nosv, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' ) + endif +endif + +if get_option('buildPyTaskR') and get_option('buildTests') + test('pyTaskR', + py, + args : [ 'python/main.py' ], + is_parallel : false, + env: ['PYTHONPATH=' + meson.project_build_root() + '/include/pytaskr/'], + suite: testSuite, + workdir: meson.current_source_dir()) +endif \ No newline at end of file diff --git a/examples/multiJob/python/job1.py b/examples/multiJob/python/job1.py new file mode 100644 index 0000000..5ffd2bb --- /dev/null +++ b/examples/multiJob/python/job1.py @@ -0,0 +1,49 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License") + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import taskr +from main import ITERATIONS +JOB_ID = 0 + +def job1(runtime): + # Creating a storage for all the tasks we will create in this example + tasks = [None] * (3 * ITERATIONS) + + # Creating the execution units (functions that the tasks will run) + taskAfc = taskr.Function(lambda task : print(f"Job 1 - Task A {task.getLabel()}")) + taskBfc = taskr.Function(lambda task : print(f"Job 1 - Task B {task.getLabel()}")) + taskCfc = taskr.Function(lambda task : print(f"Job 1 - Task C {task.getLabel()}")) + + # Now creating tasks + for i in range(ITERATIONS): + taskId = i * 3 + 1 + tasks[taskId] = taskr.Task(3 * ITERATIONS * JOB_ID + taskId, taskBfc) + + for i in range(ITERATIONS): + taskId = i * 3 + 0 + tasks[taskId] = taskr.Task(3 * ITERATIONS * JOB_ID + taskId, taskAfc) + + for i in range(ITERATIONS): + taskId = i * 3 + 2 + tasks[taskId] = taskr.Task(3 * ITERATIONS * JOB_ID + taskId, taskCfc) + + # Now creating the dependency graph + for i in range(ITERATIONS): tasks[i * 3 + 2].addDependency(tasks[i * 3 + 1]) + for i in range(ITERATIONS): tasks[i * 3 + 1].addDependency(tasks[i * 3 + 0]) + for i in range(1, ITERATIONS): tasks[i * 3 + 0].addDependency(tasks[i * 3 - 1]) + + # Adding tasks to TaskR runtime + for task in tasks: runtime.addTask(task) \ No newline at end of file diff --git a/examples/multiJob/python/job2.py b/examples/multiJob/python/job2.py new file mode 100644 index 0000000..1a0adbd --- /dev/null +++ b/examples/multiJob/python/job2.py @@ -0,0 +1,49 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import taskr +from main import ITERATIONS +JOB_ID = 1 + +def job2(runtime): + # Creating a storage for all the tasks we will create in this example + tasks = [None] * (3 * ITERATIONS) + + # Creating the execution units (functions that the tasks will run) + taskAfc = taskr.Function(lambda task : print(f"Job 1 - Task A {task.getLabel()}")) + taskBfc = taskr.Function(lambda task : print(f"Job 1 - Task B {task.getLabel()}")) + taskCfc = taskr.Function(lambda task : print(f"Job 1 - Task C {task.getLabel()}")) + + # Now creating tasks + for i in range(ITERATIONS): + taskId = i * 3 + 1 + tasks[taskId] = taskr.Task(3 * ITERATIONS * JOB_ID + taskId, taskBfc) + + for i in range(ITERATIONS): + taskId = i * 3 + 0 + tasks[taskId] = taskr.Task(3 * ITERATIONS * JOB_ID + taskId, taskAfc) + + for i in range(ITERATIONS): + taskId = i * 3 + 2 + tasks[taskId] = taskr.Task(3 * ITERATIONS * JOB_ID + taskId, taskCfc) + + # Now creating the dependency graph + for i in range(ITERATIONS): tasks[i * 3 + 2].addDependency(tasks[i * 3 + 1]) + for i in range(ITERATIONS): tasks[i * 3 + 1].addDependency(tasks[i * 3 + 0]) + for i in range(1, ITERATIONS): tasks[i * 3 + 0].addDependency(tasks[i * 3 - 1]) + + # Adding tasks to TaskR runtime + for task in tasks: runtime.addTask(task) \ No newline at end of file diff --git a/examples/multiJob/python/main.py b/examples/multiJob/python/main.py new file mode 100644 index 0000000..a653ff6 --- /dev/null +++ b/examples/multiJob/python/main.py @@ -0,0 +1,47 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" +ITERATIONS = 100 + +import taskr +import job1 +import job2 + +def main(): + + # Initialize taskr with the wanted compute manager backend and number of PUs + t = taskr.taskr(taskr.HiCRBackend.threading) + + # Get the runtime + runtime = t.get_runtime() + + # Running multiJob example + job1.job1(runtime) + job2.job2(runtime) + + # Initializing taskr + runtime.initialize() + + # Running taskr for the current repetition + runtime.run() + + # Waiting current repetition to end + runtime.await_() + + # Finalizing taskr + runtime.finalize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/examples/local/mutex/README.rst b/examples/mutex/README.rst similarity index 100% rename from examples/local/mutex/README.rst rename to examples/mutex/README.rst diff --git a/examples/local/mutex/source/mutex.hpp b/examples/mutex/cpp/mutex.hpp similarity index 100% rename from examples/local/mutex/source/mutex.hpp rename to examples/mutex/cpp/mutex.hpp diff --git a/examples/local/mutex/source/nosv.cpp b/examples/mutex/cpp/nosv.cpp similarity index 100% rename from examples/local/mutex/source/nosv.cpp rename to examples/mutex/cpp/nosv.cpp diff --git a/examples/local/mutex/source/pthreads.cpp b/examples/mutex/cpp/pthreads.cpp similarity index 100% rename from examples/local/mutex/source/pthreads.cpp rename to examples/mutex/cpp/pthreads.cpp diff --git a/examples/mutex/meson.build b/examples/mutex/meson.build new file mode 100644 index 0000000..8ca8c9f --- /dev/null +++ b/examples/mutex/meson.build @@ -0,0 +1,27 @@ +testSuite = [ 'examples', 'mutex' ] + +if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') + threading = executable('threading', [ 'cpp/pthreads.cpp'], dependencies: [ TaskRBuildDep ] ) + + if get_option('buildTests') + test('threading', threading, args : [ ], suite: testSuite, workdir: threading.path() + '.p' ) + endif +endif + +if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') + nosv = executable('nosv', [ 'cpp/nosv.cpp'], dependencies: [ TaskRBuildDep ] ) + + if get_option('buildTests') + test('nosv', nosv, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' ) + endif +endif + +if get_option('buildPyTaskR') and get_option('buildTests') + test('pyTaskR', + py, + args : [ 'python/main.py' ], + is_parallel : false, + env: ['PYTHONPATH=' + meson.project_build_root() + '/include/pytaskr/'], + suite: testSuite, + workdir: meson.current_source_dir()) +endif \ No newline at end of file diff --git a/examples/mutex/python/main.py b/examples/mutex/python/main.py new file mode 100644 index 0000000..6a7f00a --- /dev/null +++ b/examples/mutex/python/main.py @@ -0,0 +1,32 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import taskr +import mutex + +def main(): + + # Initialize taskr with the wanted compute manager backend and number of PUs + t = taskr.taskr(taskr.HiCRBackend.threading) + + # Get the runtime + runtime = t.get_runtime() + + # Running mutex example + mutex.mutex(runtime) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/examples/mutex/python/mutex.py b/examples/mutex/python/mutex.py new file mode 100644 index 0000000..f6d9539 --- /dev/null +++ b/examples/mutex/python/mutex.py @@ -0,0 +1,62 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import taskr + +_CONCURRENT_TASKS = 32 +_ITERATIONS_ = 1000 + +def mutex(runtime): + + # Contention value + value = 0 + + # Task-aware mutex + m = taskr.Mutex() + + def fc(task): + nonlocal value + + for i in range(_ITERATIONS_): + m.lock(task) + value += 1 + m.unlock(task) + + # Create the taskr Tasks + taskfc = taskr.Function(fc) + + # Creating the execution units (functions that the tasks will run) + for i in range(_CONCURRENT_TASKS): + task = taskr.Task(i, taskfc) + + # Adding to taskr + runtime.addTask(task) + + # Initializing taskr + runtime.initialize() + + # Running taskr for the current repetition + runtime.run() + + # Waiting current repetition to end + runtime.await_() + + # Finalizing taskr + runtime.finalize() + + # Value should be equal to concurrent task count + print(f"Value {value} / Expected {_CONCURRENT_TASKS * _ITERATIONS_}") + assert value == _CONCURRENT_TASKS * _ITERATIONS_ \ No newline at end of file diff --git a/examples/local/pendingOperation/README.rst b/examples/pendingOperation/README.rst similarity index 100% rename from examples/local/pendingOperation/README.rst rename to examples/pendingOperation/README.rst diff --git a/examples/local/pendingOperation/source/nosv.cpp b/examples/pendingOperation/cpp/nosv.cpp similarity index 100% rename from examples/local/pendingOperation/source/nosv.cpp rename to examples/pendingOperation/cpp/nosv.cpp diff --git a/examples/local/pendingOperation/source/pendingOperation.hpp b/examples/pendingOperation/cpp/pendingOperation.hpp similarity index 100% rename from examples/local/pendingOperation/source/pendingOperation.hpp rename to examples/pendingOperation/cpp/pendingOperation.hpp diff --git a/examples/local/pendingOperation/source/pthreads.cpp b/examples/pendingOperation/cpp/pthreads.cpp similarity index 100% rename from examples/local/pendingOperation/source/pthreads.cpp rename to examples/pendingOperation/cpp/pthreads.cpp diff --git a/examples/pendingOperation/meson.build b/examples/pendingOperation/meson.build new file mode 100644 index 0000000..f270c81 --- /dev/null +++ b/examples/pendingOperation/meson.build @@ -0,0 +1,27 @@ +testSuite = [ 'examples', 'pendingOperation' ] + +if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') + threading = executable('threading', [ 'cpp/pthreads.cpp'], dependencies: [ TaskRBuildDep ] ) + + if get_option('buildTests') + test('threading', threading, args : [ ], suite: testSuite, workdir: threading.path() + '.p' ) + endif +endif + +if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') + nosv = executable('nosv', [ 'cpp/nosv.cpp'], dependencies: [ TaskRBuildDep ] ) + + if get_option('buildTests') + test('nosv', nosv, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' ) + endif +endif + +if get_option('buildPyTaskR') and get_option('buildTests') + test('pyTaskR', + py, + args : [ 'python/main.py' ], + is_parallel : false, + env: ['PYTHONPATH=' + meson.project_build_root() + '/include/pytaskr/'], + suite: testSuite, + workdir: meson.current_source_dir()) +endif \ No newline at end of file diff --git a/examples/pendingOperation/python/main.py b/examples/pendingOperation/python/main.py new file mode 100644 index 0000000..10fd765 --- /dev/null +++ b/examples/pendingOperation/python/main.py @@ -0,0 +1,32 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import taskr +import pendingOperation + +def main(): + + # Initialize taskr with the wanted compute manager backend and number of PUs + t = taskr.taskr(taskr.HiCRBackend.nosv) + + # Get the runtime + runtime = t.get_runtime() + + # Running pendingOperation example + pendingOperation.pendingOperation(runtime) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/examples/pendingOperation/python/pendingOperation.py b/examples/pendingOperation/python/pendingOperation.py new file mode 100644 index 0000000..81208a0 --- /dev/null +++ b/examples/pendingOperation/python/pendingOperation.py @@ -0,0 +1,83 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License") + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import time +import taskr + +def heavyTask(currentTask): + # Printing starting message + print(f"Task {currentTask.getLabel()} -- Starting 1 second-long operation.") + + # Getting initial time + t0 = time.time() + + # Now registering operation + def operation(): + # Getting current time + t1 = time.time() + + # Getting difference in ms + dt = (t1 - t0)*1e3 + + # If difference higher than 1 second, the operation is finished + if dt > 1000: + return True + + # Otherwise not + return False + + # Now registering pending operation + currentTask.addPendingOperation(operation) + + # Suspending task until the operation is finished + currentTask.suspend() + + # Printing finished message + print(f"Task {currentTask.getLabel()} - operation finished") + + +def pendingOperation(runtime): + # Allowing tasks to immediately resume upon suspension -- they won't execute until their pending operation is finished + runtime.setTaskCallbackHandler(taskr.TaskCallback.onTaskSuspend, lambda task : runtime.resumeTask(task)) + + # Creating the execution units (functions that the tasks will run) + fc = lambda task : heavyTask(task) + + # Create the taskr Tasks + taskfc = taskr.Function(fc) + + # Now creating heavy many tasks task + for i in range(100): + task = taskr.Task(i, taskfc) + + # Adding to taskr + runtime.addTask(task) + + # Initializing taskr + runtime.initialize() + + # Running taskr for the current repetition + runtime.run() + + # Waiting current repetition to end + runtime.await_() + + # Finalizing taskr + runtime.finalize() + + # Overwrite the onTaskSuspend fc to be None such that runtime no longer has + # a dependency to the previous fc and runtime can call the destructor + runtime.setTaskCallbackHandler(taskr.TaskCallback.onTaskSuspend, None) \ No newline at end of file diff --git a/examples/local/resourceList/README.rst b/examples/resourceList/README.rst similarity index 100% rename from examples/local/resourceList/README.rst rename to examples/resourceList/README.rst diff --git a/examples/local/resourceList/source/nosv.cpp b/examples/resourceList/cpp/nosv.cpp similarity index 99% rename from examples/local/resourceList/source/nosv.cpp rename to examples/resourceList/cpp/nosv.cpp index d036699..67c32f9 100644 --- a/examples/local/resourceList/source/nosv.cpp +++ b/examples/resourceList/cpp/nosv.cpp @@ -24,7 +24,7 @@ #include #include -#include "source/workTask.hpp" +#include "cpp/workTask.hpp" int main(int argc, char **argv) { diff --git a/examples/local/resourceList/source/pthreads.cpp b/examples/resourceList/cpp/pthreads.cpp similarity index 99% rename from examples/local/resourceList/source/pthreads.cpp rename to examples/resourceList/cpp/pthreads.cpp index 43b6d0f..d85e5f0 100644 --- a/examples/local/resourceList/source/pthreads.cpp +++ b/examples/resourceList/cpp/pthreads.cpp @@ -21,7 +21,7 @@ #include #include #include -#include "source/workTask.hpp" +#include "cpp/workTask.hpp" int main(int argc, char **argv) { diff --git a/examples/local/resourceList/source/workTask.hpp b/examples/resourceList/cpp/workTask.hpp similarity index 100% rename from examples/local/resourceList/source/workTask.hpp rename to examples/resourceList/cpp/workTask.hpp diff --git a/examples/local/resourceList/meson.build b/examples/resourceList/meson.build similarity index 51% rename from examples/local/resourceList/meson.build rename to examples/resourceList/meson.build index 3f6986a..6d43937 100644 --- a/examples/local/resourceList/meson.build +++ b/examples/resourceList/meson.build @@ -1,7 +1,7 @@ -testSuite = [ 'examples', 'local', 'resourceList' ] +testSuite = [ 'examples', 'resourceList' ] if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') - threading = executable('threading', [ 'source/pthreads.cpp'], dependencies: [ TaskRBuildDep ]) + threading = executable('threading', [ 'cpp/pthreads.cpp'], dependencies: [ TaskRBuildDep ]) if get_option('buildTests') test('threading', threading, args : [ '4', '100', '0', '1', '2', '3' ], suite: testSuite, workdir: threading.path() + '.p' ) @@ -9,9 +9,19 @@ if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('pro endif if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') - nosv = executable('nosv', [ 'source/nosv.cpp'], dependencies: [ TaskRBuildDep ]) + nosv = executable('nosv', [ 'cpp/nosv.cpp'], dependencies: [ TaskRBuildDep ]) if get_option('buildTests') test('nosv', nosv, args : [ '4', '100', '0', '1', '2', '3' ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' ) endif +endif + +if get_option('buildPyTaskR') and get_option('buildTests') + test('pyTaskR', + py, + args : [ 'python/main.py' ], + is_parallel : false, + env: ['PYTHONPATH=' + meson.project_build_root() + '/include/pytaskr/'], + suite: testSuite, + workdir: meson.current_source_dir()) endif \ No newline at end of file diff --git a/examples/resourceList/python/main.py b/examples/resourceList/python/main.py new file mode 100644 index 0000000..bca700c --- /dev/null +++ b/examples/resourceList/python/main.py @@ -0,0 +1,74 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License") + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" +import sys +import time +import taskr +import workTask + +def main(): + # Getting work task count + workTaskCount = 4 + iterations = 100 + if len(sys.argv) > 1: workTaskCount = int(sys.argv[1]) + if len(sys.argv) > 2: iterations = int(sys.argv[2]) + + + + + # Getting the core subset from the argument list (could be from a file too) + coreSubset = {0, 1, 2, 3} + if len(sys.argv) > 3: + coreSubset = {} + for i in range(3, len(sys.argv)): + coreSubset.add(int(sys.argv[i])) + + # Sanity check + if not len(coreSubset): + sys.stderr.write("Launch error: no compute resources provided") + sys.exit(1) + + # Initialize taskr with the wanted compute manager backend and number of PUs + t = taskr.taskr(taskr.HiCRBackend.threading, coreSubset) + + # Get the runtime + runtime = t.get_runtime() + + # Creating task function + taskFunction = taskr.Function(lambda task : workTask.work(iterations)) + + # Adding multiple compute tasks + print(f"Running {workTaskCount} work tasks with {len(coreSubset)} processing units...") + for i in range(workTaskCount): + task = taskr.Task(i, taskFunction) + runtime.addTask(task) + + # Initializing taskR + runtime.initialize() + + # Running taskr only on the core subset + t0 = time.time() + runtime.run() + runtime.await_() + tf = time.time() + + dt = tf - t0 + print(f"Finished in {dt:.3} seconds.") + + # Finalizing taskR + runtime.finalize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/examples/resourceList/python/workTask.py b/examples/resourceList/python/workTask.py new file mode 100644 index 0000000..4614746 --- /dev/null +++ b/examples/resourceList/python/workTask.py @@ -0,0 +1,24 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import taskr + +def work(iterations): + value = 2.0 + for i in range(iterations): + for j in range(iterations): + value = (value + i)**0.5 + value **= 2 \ No newline at end of file diff --git a/examples/local/simple/README.rst b/examples/simple/README.rst similarity index 100% rename from examples/local/simple/README.rst rename to examples/simple/README.rst diff --git a/examples/local/simple/source/nosv.cpp b/examples/simple/cpp/nosv.cpp similarity index 98% rename from examples/local/simple/source/nosv.cpp rename to examples/simple/cpp/nosv.cpp index 8a1e72c..26c31d7 100644 --- a/examples/local/simple/source/nosv.cpp +++ b/examples/simple/cpp/nosv.cpp @@ -65,7 +65,7 @@ int main(int argc, char **argv) // Creating taskr taskr::Runtime taskr(&computeManager, &computeManager, computeResources); - // Running ABCtasks example + // Running simple example simple(&taskr); // Freeing up memory diff --git a/examples/local/simple/source/pthreads.cpp b/examples/simple/cpp/pthreads.cpp similarity index 98% rename from examples/local/simple/source/pthreads.cpp rename to examples/simple/cpp/pthreads.cpp index 72a4c66..485c9a5 100644 --- a/examples/local/simple/source/pthreads.cpp +++ b/examples/simple/cpp/pthreads.cpp @@ -57,7 +57,7 @@ int main(int argc, char **argv) // Creating taskr taskr::Runtime taskr(&boostComputeManager, &pthreadsComputeManager, computeResources); - // Running ABCtasks example + // Running simple example simple(&taskr); // Freeing up memory diff --git a/examples/local/simple/source/simple.hpp b/examples/simple/cpp/simple.hpp similarity index 100% rename from examples/local/simple/source/simple.hpp rename to examples/simple/cpp/simple.hpp diff --git a/examples/simple/meson.build b/examples/simple/meson.build new file mode 100644 index 0000000..609ffc5 --- /dev/null +++ b/examples/simple/meson.build @@ -0,0 +1,27 @@ +testSuite = [ 'examples', 'simple' ] + +if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') + threading = executable('threading', [ 'cpp/pthreads.cpp'], dependencies: [ TaskRBuildDep ]) + + if get_option('buildTests') + test('threading', threading, args : [ ], suite: testSuite, workdir: threading.path() + '.p' ) + endif +endif + +if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') + nosv = executable('nosv', [ 'cpp/nosv.cpp'], dependencies: [ TaskRBuildDep ]) + + if get_option('buildTests') + test('nosv', nosv, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' ) + endif +endif + +if get_option('buildPyTaskR') and get_option('buildTests') + test('pyTaskR', + py, + args : [ 'python/main.py' ], + is_parallel : false, + env: ['PYTHONPATH=' + meson.project_build_root() + '/include/pytaskr/'], + suite: testSuite, + workdir: meson.current_source_dir()) +endif \ No newline at end of file diff --git a/examples/simple/python/main.py b/examples/simple/python/main.py new file mode 100644 index 0000000..63efd91 --- /dev/null +++ b/examples/simple/python/main.py @@ -0,0 +1,31 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import taskr +import simple + +def main(): + # Initialize taskr with the wanted compute manager backend and number of PUs + t = taskr.taskr(taskr.HiCRBackend.nosv, 2) + + # Get the runtime + runtime = t.get_runtime() + + # Running simple example + simple.simple(runtime) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/examples/simple/python/simple.py b/examples/simple/python/simple.py new file mode 100644 index 0000000..bcf9ef9 --- /dev/null +++ b/examples/simple/python/simple.py @@ -0,0 +1,40 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import taskr + +NTASKS = 2 + +def simple(runtime): + # Initializing taskr + runtime.initialize() + + fc = lambda task : print(f"Hello, I am task {task.getLabel()}") + + taskfc = taskr.Function(fc) + + # Adding to tasks to taskr + for i in range(NTASKS): + runtime.addTask(taskr.Task(i, taskfc)) + + # Running taskr for the current repetition + runtime.run() + + # Waiting current repetition to end + runtime.await_() + + # Finalizing taskr + runtime.finalize() \ No newline at end of file diff --git a/examples/local/suspend/README.rst b/examples/suspend/README.rst similarity index 100% rename from examples/local/suspend/README.rst rename to examples/suspend/README.rst diff --git a/examples/local/suspend/source/nosv.cpp b/examples/suspend/cpp/nosv.cpp similarity index 100% rename from examples/local/suspend/source/nosv.cpp rename to examples/suspend/cpp/nosv.cpp diff --git a/examples/local/suspend/source/pthreads.cpp b/examples/suspend/cpp/pthreads.cpp similarity index 100% rename from examples/local/suspend/source/pthreads.cpp rename to examples/suspend/cpp/pthreads.cpp diff --git a/examples/local/suspend/source/suspend.hpp b/examples/suspend/cpp/suspend.hpp similarity index 100% rename from examples/local/suspend/source/suspend.hpp rename to examples/suspend/cpp/suspend.hpp diff --git a/examples/local/suspend/meson.build b/examples/suspend/meson.build similarity index 50% rename from examples/local/suspend/meson.build rename to examples/suspend/meson.build index ea2dc76..02baefa 100644 --- a/examples/local/suspend/meson.build +++ b/examples/suspend/meson.build @@ -1,7 +1,7 @@ -testSuite = [ 'examples', 'local', 'suspend' ] +testSuite = [ 'examples', 'suspend' ] if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') - threading = executable('threading', [ 'source/pthreads.cpp'], dependencies: [ TaskRBuildDep ] ) + threading = executable('threading', [ 'cpp/pthreads.cpp'], dependencies: [ TaskRBuildDep ] ) if get_option('buildTests') test('threading', threading, args : [ '2', '100' ], suite: testSuite, workdir: threading.path() + '.p' ) @@ -9,9 +9,19 @@ if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('pro endif if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') - nosv = executable('nosv', [ 'source/nosv.cpp'], dependencies: [ TaskRBuildDep ] ) + nosv = executable('nosv', [ 'cpp/nosv.cpp'], dependencies: [ TaskRBuildDep ] ) if get_option('buildTests') test('nosv', nosv, args : [ '2', '100' ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' ) endif +endif + +if get_option('buildPyTaskR') and get_option('buildTests') + test('pyTaskR', + py, + args : [ 'python/main.py' ], + is_parallel : false, + env: ['PYTHONPATH=' + meson.project_build_root() + '/include/pytaskr/'], + suite: testSuite, + workdir: meson.current_source_dir()) endif \ No newline at end of file diff --git a/examples/suspend/python/main.py b/examples/suspend/python/main.py new file mode 100644 index 0000000..aed145d --- /dev/null +++ b/examples/suspend/python/main.py @@ -0,0 +1,39 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import sys + +import taskr +import suspend + +def main(): + # Getting arguments, if provided + taskCount = 2 + branchCount = 100 + if len(sys.argv) > 1: taskCount = int(sys.argv[1]) + if len(sys.argv) > 2: branchCount = int(sys.argv[2]) + + # Initialize taskr with the wanted compute manager backend and number of PUs + t = taskr.taskr(taskr.HiCRBackend.nosv) + + # Get the runtime + runtime = t.get_runtime() + + # Running simple example + suspend.suspend(runtime, branchCount, taskCount) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/examples/suspend/python/suspend.py b/examples/suspend/python/suspend.py new file mode 100644 index 0000000..dd50854 --- /dev/null +++ b/examples/suspend/python/suspend.py @@ -0,0 +1,66 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import time + +import taskr + +NSUSPENDS = 1000 + +def suspend(runtime, branchCount, taskCount): + # Allowing tasks to immediately resume upon suspension -- they won't execute until their pending operation is finished + runtime.setTaskCallbackHandler(taskr.TaskCallback.onTaskSuspend, lambda task : runtime.resumeTask(task)) + + def fc(task): + for _ in range(NSUSPENDS): task.suspend() + + # Creating the execution units (functions that the tasks will run) + taskfc = taskr.Function(fc) + + # Initializing taskr + runtime.initialize() + + # Creating the execution units (functions that the tasks will run) + prevTask = None + for b in range(branchCount): + for i in range(taskCount): + task = taskr.Task(b * taskCount + i, taskfc) + + # Creating dependencies + if i > 0: task.addDependency(prevTask) + + # Adding to taskr + runtime.addTask(task) + + # Setting as new previous task + prevTask = task + + # Running taskr for the current repetition + startTime = time.time() + runtime.run() + runtime.await_() + + endTime = time.time() + computeTime = endTime - startTime + + print(f"Running Time: {computeTime:0.5f}s") + + # Finalizing taskr + runtime.finalize() + + # Overwrite the onTaskSuspend fc to be None such that runtime no longer has + # a dependency to the previous fc and runtime can call the destructor + runtime.setTaskCallbackHandler(taskr.TaskCallback.onTaskSuspend, None) \ No newline at end of file diff --git a/examples/local/workerSpecific/README.rst b/examples/workerSpecific/README.rst similarity index 100% rename from examples/local/workerSpecific/README.rst rename to examples/workerSpecific/README.rst diff --git a/examples/local/workerSpecific/source/nosv.cpp b/examples/workerSpecific/cpp/nosv.cpp similarity index 100% rename from examples/local/workerSpecific/source/nosv.cpp rename to examples/workerSpecific/cpp/nosv.cpp diff --git a/examples/local/workerSpecific/source/pthreads.cpp b/examples/workerSpecific/cpp/pthreads.cpp similarity index 100% rename from examples/local/workerSpecific/source/pthreads.cpp rename to examples/workerSpecific/cpp/pthreads.cpp diff --git a/examples/local/workerSpecific/source/workerSpecific.hpp b/examples/workerSpecific/cpp/workerSpecific.hpp similarity index 100% rename from examples/local/workerSpecific/source/workerSpecific.hpp rename to examples/workerSpecific/cpp/workerSpecific.hpp diff --git a/examples/workerSpecific/meson.build b/examples/workerSpecific/meson.build new file mode 100644 index 0000000..f890e61 --- /dev/null +++ b/examples/workerSpecific/meson.build @@ -0,0 +1,27 @@ +testSuite = [ 'examples', 'workerSpecific' ] + +if 'boost' in get_option('executionStateType') and 'pthreads' in get_option('processingUnitType') + threading = executable('threading', [ 'cpp/pthreads.cpp'], dependencies: [ TaskRBuildDep ] ) + + if get_option('buildTests') + test('threading', threading, args : [ ], suite: testSuite, workdir: threading.path() + '.p' ) + endif +endif + +if 'nosv' in get_option('executionStateType') and 'nosv' in get_option('processingUnitType') + nosv = executable('nosv', [ 'cpp/nosv.cpp'], dependencies: [ TaskRBuildDep ] ) + + if get_option('buildTests') + test('nosv', nosv, args : [ ], is_parallel : false, suite: testSuite, workdir: nosv.path() + '.p' ) + endif +endif + +if get_option('buildPyTaskR') and get_option('buildTests') + test('pyTaskR', + py, + args : [ 'python/main.py' ], + is_parallel : false, + env: ['PYTHONPATH=' + meson.project_build_root() + '/include/pytaskr/'], + suite: testSuite, + workdir: meson.current_source_dir()) +endif \ No newline at end of file diff --git a/examples/workerSpecific/python/main.py b/examples/workerSpecific/python/main.py new file mode 100644 index 0000000..9c53839 --- /dev/null +++ b/examples/workerSpecific/python/main.py @@ -0,0 +1,34 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import taskr +import workerSpecific + +def main(): + + # Initialize taskr with the wanted compute manager backend and number of PUs + t = taskr.taskr() + + # Get the runtime + runtime = t.get_runtime() + + num_workers = t.get_num_workers() + + # Running workerSpecific example + workerSpecific.workerSpecific(runtime, num_workers) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/examples/workerSpecific/python/workerSpecific.py b/examples/workerSpecific/python/workerSpecific.py new file mode 100644 index 0000000..6513640 --- /dev/null +++ b/examples/workerSpecific/python/workerSpecific.py @@ -0,0 +1,80 @@ +""" + Copyright 2025 Huawei Technologies Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License") + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import ctypes + +libc = ctypes.CDLL("libc.so.6") +libc.sched_getcpu.restype = ctypes.c_int + +import sys + +import taskr + +def workFc(currentTask): + taskLabel = currentTask.getLabel() + currentCPUId = libc.sched_getcpu() + + #### First launched on even cpus + + print(f"Task {taskLabel} first run running on CPU {currentCPUId}") + + # Sanity check + if int(2 * taskLabel) != currentCPUId: + sys.stderr.write(f"Task label ({taskLabel}) does not coincide with the current CPU id! ({currentCPUId})") + sys.exit(1) + + # Changing to odd cpus + currentTask.setWorkerAffinity(currentTask.getWorkerAffinity() + 1) + + # Suspending + currentTask.suspend() + + #### Now launched in odd cpus + + currentCPUId = libc.sched_getcpu() + print(f"Task {taskLabel} second run running on CPU {currentCPUId}") + + # Sanity check + if int(2 * taskLabel) + 1 != currentCPUId: + sys.stderr.write(f"Task label ({taskLabel}) + 1 does not coincide with the current CPU id! ({currentCPUId})") + sys.exit(1) + + +def workerSpecific(runtime, workerCount): + # Auto-adding task when it suspends. + runtime.setTaskCallbackHandler(taskr.TaskCallback.onTaskSuspend, lambda task : runtime.resumeTask(task)) + + # Creating the execution units (functions that the tasks will run) + workTaskfc = taskr.Function(lambda task : workFc(task)) + + # Initializing taskr + runtime.initialize() + + # Run only on even worker ids + for i in range(workerCount // 2): runtime.addTask(taskr.Task(i, workTaskfc, 2 * i)) + + # Running taskr for the current repetition + runtime.run() + + # Waiting for taskr to finish + runtime.await_() + + # Finalizing taskr + runtime.finalize() + + # Overwrite the onTaskSuspend fc to be None such that runtime no longer has + # a dependency to the previous fc and runtime can call the destructor + runtime.setTaskCallbackHandler(taskr.TaskCallback.onTaskSuspend, None) \ No newline at end of file diff --git a/extern/hicr b/extern/hicr index e31ef4e..a3408df 160000 --- a/extern/hicr +++ b/extern/hicr @@ -1 +1 @@ -Subproject commit e31ef4ec287dde6c8c88f9977d5ae5772e788955 +Subproject commit a3408df876e3f41fc72cf5bed24c587c7c4e3788 diff --git a/extern/pybind11 b/extern/pybind11 new file mode 160000 index 0000000..58c382a --- /dev/null +++ b/extern/pybind11 @@ -0,0 +1 @@ +Subproject commit 58c382a8e3d7081364d2f5c62e7f429f0412743b diff --git a/extern/tracr b/extern/tracr index 01b9e96..54387c3 160000 --- a/extern/tracr +++ b/extern/tracr @@ -1 +1 @@ -Subproject commit 01b9e96067dc17d6965bb9fc9f39cf5afe5ce16b +Subproject commit 54387c3c786095780c7a325162c5ebab3accbed4 diff --git a/include/pytaskr/README.md b/include/pytaskr/README.md new file mode 100644 index 0000000..7926e2d --- /dev/null +++ b/include/pytaskr/README.md @@ -0,0 +1,32 @@ +# pybind11 installation + +To install pybind11 go inside `extern/pybind11` and type + +``` +mkdir build +cd build +cmake .. +make check -j$(nproc) +``` + +Be sure all the tests are passing! + +Now, inside the `build` folder it will create another folder called `mock_install/share/pkgconfig` and this pkg-config file `pybind11.pc` type this: + +``` +prefix=/taskr/extern/pybind11/ +includedir=${prefix}/include + +Name: pybind11 +Description: Seamless operability between C++11 and Python +Version: 2.13.6 +Cflags: -I${includedir} +``` + +and add the PKG-CONFIG PATH in your `.bashrc` file: + +``` +export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/taskr/extern/pybind11/build/mock_install/share/pkgconfig +``` + +run `source ~/.bashrc` and now, you should be good-to-go with running `meson setup`. diff --git a/include/pytaskr/meson.build b/include/pytaskr/meson.build new file mode 100644 index 0000000..905bc9e --- /dev/null +++ b/include/pytaskr/meson.build @@ -0,0 +1,12 @@ +# pybind11 stuff with the compiler flags +# Manually compile like this: +# c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3-config --includes) -Iextern/pybind11/include example.cpp -o example$(python3-config --extension-suffix) + +py = import('python').find_installation(pure: false) +pybind11_dep = dependency('pybind11', required: true) + +py.extension_module('taskr', + ['pytaskr.cpp'], + install: true, + dependencies : [TaskRBuildDep, pybind11_dep], +) \ No newline at end of file diff --git a/include/pytaskr/pyproject.toml b/include/pytaskr/pyproject.toml new file mode 100644 index 0000000..ece15b2 --- /dev/null +++ b/include/pytaskr/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["meson-python", "pybind11"] +build-backend = "mesonpy" diff --git a/include/pytaskr/pyruntime.hpp b/include/pytaskr/pyruntime.hpp new file mode 100644 index 0000000..42b7d13 --- /dev/null +++ b/include/pytaskr/pyruntime.hpp @@ -0,0 +1,223 @@ +/* + * Copyright 2025 Huawei Technologies Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace taskr +{ + +enum backend_t +{ + /** + * HiCR's nOS-V backend with the executionStates and ProcessingUnits being nOS-V + */ + nosv, + + /** + * executionStates are Boost and ProcessingUnits are Pthreads + */ + threading +}; + +/** + * TaskR Runtime class python wrapper. It simplifies the user for constructing the TaskR Runtime + */ +class PyRuntime +{ + public: + + /** + * Constructor with num_workers being an interger value. If 0, initialize all. + */ + PyRuntime(const backend_t &backend_type = backend_t::nosv, size_t num_workers = 0) + : _backend_type(backend_type) + { + // Specify the compute Managers + if (_backend_type == backend_t::nosv) + { + // Initialize nosv + check(nosv_init()); + + // nosv task instance for the main thread + nosv_task_t mainTask; + + // Attaching the main thread + check(nosv_attach(&mainTask, NULL, NULL, NOSV_ATTACH_NONE)); + + _executionStateComputeManager = std::make_unique(); + _processingUnitComputeManager = std::make_unique(); + } + else if (_backend_type == backend_t::threading) + { + _executionStateComputeManager = std::make_unique(); + _processingUnitComputeManager = std::make_unique(); + } + else { HICR_THROW_LOGIC("'%d' is not a known HiCR backend. Try 'nosv' or 'threading'\n", _backend_type); } + + // Reserving memory for hwloc + hwloc_topology_init(&_topology); + + // Initializing HWLoc-based host (CPU) topology manager + HiCR::backend::hwloc::TopologyManager tm(&_topology); + + // Asking backend to check the available devices + const auto t = tm.queryTopology(); + + // Compute resources to use + HiCR::Device::computeResourceList_t _computeResources; + + // Getting compute resources in this device + auto cr = (*(t.getDevices().begin()))->getComputeResourceList(); + + auto itr = cr.begin(); + + // Allocate the compute resources (i.e. PUs) + if (num_workers == 0) { num_workers = cr.size(); } + else if (num_workers > cr.size()) { HICR_THROW_LOGIC("num_workers = %d is not a legal number. FYI, we can have at most %d workers.\n", num_workers, cr.size()); } + + for (size_t i = 0; i < num_workers; i++) + { + _computeResources.push_back(*itr); + itr++; + } + + _num_workers = num_workers; + + _runtime = std::make_unique(_executionStateComputeManager.get(), _processingUnitComputeManager.get(), _computeResources); + } + + /** + * Constructor with num_workers being a set of integers. The set specifies which process affinity to use (if available). + */ + PyRuntime(const backend_t &backend_type, const std::set &workersSet) + : _backend_type(backend_type) + { + // Check if the workerSet is not empty + if (workersSet.empty()) { HICR_THROW_LOGIC("Error: no compute resources provided\n"); } + + // Specify the compute Managers + if (_backend_type == backend_t::nosv) + { + // Initialize nosv + check(nosv_init()); + + // nosv task instance for the main thread + nosv_task_t mainTask; + + // Attaching the main thread + check(nosv_attach(&mainTask, NULL, NULL, NOSV_ATTACH_NONE)); + + _executionStateComputeManager = std::make_unique(); + _processingUnitComputeManager = std::make_unique(); + } + else if (_backend_type == backend_t::threading) + { + _executionStateComputeManager = std::make_unique(); + _processingUnitComputeManager = std::make_unique(); + } + else { HICR_THROW_LOGIC("'%d' is not a known HiCR backend. Try 'nosv' or 'threading'\n", _backend_type); } + + // Reserving memory for hwloc + hwloc_topology_init(&_topology); + + // Initializing HWLoc-based host (CPU) topology manager + HiCR::backend::hwloc::TopologyManager tm(&_topology); + + // Asking backend to check the available devices + const auto t = tm.queryTopology(); + + // Getting compute resource lists from devices + std::vector computeResourceLists; + for (auto d : t.getDevices()) computeResourceLists.push_back(d->getComputeResourceList()); + + // Create processing units from the detected compute resource list and giving them to taskr + HiCR::Device::computeResourceList_t _computeResources; + for (auto computeResourceList : computeResourceLists) + for (auto computeResource : computeResourceList) + { + // Interpreting compute resource as core + auto core = dynamic_pointer_cast(computeResource); + + // If the core affinity is included in the list, Add it to the list + if (workersSet.contains(core->getProcessorId())) _computeResources.push_back(computeResource); + } + + if (!_computeResources.size()) { HICR_THROW_LOGIC("Error: non-existing compute resources provided\n"); } + + // Store the number of initialized workers + _num_workers = _computeResources.size(); + + // Initialize the runtime + _runtime = std::make_unique(_executionStateComputeManager.get(), _processingUnitComputeManager.get(), _computeResources); + } + + /** + * Destructor of PyRuntime + * + * Destroying topology and shutting down nOS-V if nosv backend have been used. + */ + ~PyRuntime() + { + // Freeing up memory + hwloc_topology_destroy(_topology); + + if (_backend_type == backend_t::nosv) + { + // Detaching the main thread + check(nosv_detach(NOSV_DETACH_NONE)); + + // Shutdown nosv + check(nosv_shutdown()); + } + } + + Runtime &get_runtime() { return *_runtime; } + + const size_t get_num_workers() { return _num_workers; } + + private: + + backend_t _backend_type; + + size_t _num_workers; + + std::unique_ptr _runtime; + + std::unique_ptr _executionStateComputeManager; + + std::unique_ptr _processingUnitComputeManager; + + hwloc_topology_t _topology; + + const HiCR::Device::computeResourceList_t _computeResources; +}; + +} // namespace taskr \ No newline at end of file diff --git a/include/pytaskr/pytaskr.cpp b/include/pytaskr/pytaskr.cpp new file mode 100644 index 0000000..122e72a --- /dev/null +++ b/include/pytaskr/pytaskr.cpp @@ -0,0 +1,105 @@ +/* + * Copyright 2025 Huawei Technologies Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include // std::function +#include // std::set + +#include +#include + +namespace py = pybind11; + +namespace taskr +{ + +/** + * Pybind11 module for binding taskr stuff + */ +PYBIND11_MODULE(taskr, m) +{ + m.doc() = "pybind11 plugin for TaskR"; + + py::enum_(m, "HiCRBackend").value("nosv", backend_t::nosv).value("threading", backend_t::threading).export_values(); + + // pyTaskR's PyRuntime class + py::class_(m, "taskr") + .def(py::init(), py::arg("backend") = backend_t::nosv, py::arg("num_workers") = 0) + .def(py::init &>(), py::arg("backend") = backend_t::nosv, py::arg("workersSet")) + .def("get_runtime", &PyRuntime::get_runtime, py::return_value_policy::reference_internal) + .def("get_num_workers", &PyRuntime::get_num_workers); + + // TaskR's Runtime class + py::class_(m, "Runtime") + .def("setTaskCallbackHandler", &Runtime::setTaskCallbackHandler) + .def("setServiceWorkerCallbackHandler", &Runtime::setServiceWorkerCallbackHandler) + .def("setTaskWorkerCallbackHandler", &Runtime::setTaskWorkerCallbackHandler) + .def("initialize", &Runtime::initialize) + .def("addTask", &Runtime::addTask, py::keep_alive<1, 2>()) // keep_alive as the task should be alive until runtime's destructor + .def("resumeTask", &Runtime::resumeTask) + .def("run", &Runtime::run, py::call_guard()) + .def("await_", &Runtime::await, py::call_guard()) // Release GIL is important otherwise non-finished tasks are getting blocked + .def("finalize", &Runtime::finalize) + .def("setFinishedTask", &Runtime::setFinishedTask) + .def("addService", &Runtime::addService); + + // TaskR's Function class + py::class_(m, "Function").def(py::init()); + + // TaskR's Task class + py::class_(m, "Task") + .def(py::init(), py::arg("fc"), py::arg("workerAffinity") = -1) + .def(py::init(), py::arg("label"), py::arg("fc"), py::arg("workerAffinity") = -1) + .def("getLabel", &Task::getLabel) + .def("setLabel", &Task::setLabel) + .def("getWorkerAffinity", &Task::getWorkerAffinity) + .def("setWorkerAffinity", &Task::setWorkerAffinity) + .def("addDependency", &Task::addDependency) + .def("getDependencyCount", &Task::getDependencyCount) + .def("incrementDependencyCount", &Task::incrementDependencyCount) + .def("decrementDependencyCount", &Task::decrementDependencyCount) + .def("addOutputDependency", &Task::addOutputDependency) + .def("getOutputDependencies", &Task::getOutputDependencies) + .def("addPendingOperation", &Task::addPendingOperation) + .def("getPendingOperations", &Task::getPendingOperations) + .def("suspend", &Task::suspend, py::call_guard()); + + py::enum_(m, "TaskCallback") + .value("onTaskExecute", Task::callback_t::onTaskExecute) + .value("onTaskSuspend", Task::callback_t::onTaskSuspend) + .value("onTaskFinish", Task::callback_t::onTaskFinish) + .value("onTaskSync", Task::callback_t::onTaskSync) + .export_values(); + + // TaskR's Mutex class + py::class_(m, "Mutex").def(py::init<>()).def("lock", &Mutex::lock).def("unlock", &Mutex::unlock).def("ownsLock", &Mutex::ownsLock).def("trylock", &Mutex::trylock); + + // TaskR's ConditionVariable class + py::class_(m, "ConditionVariable") + .def(py::init<>()) + .def("wait", py::overload_cast(&ConditionVariable::wait), py::call_guard(), "cv wait") + .def("wait", py::overload_cast &>(&ConditionVariable::wait), py::call_guard(), "cv wait with condition") + .def("waitFor", + py::overload_cast &, size_t>(&ConditionVariable::waitFor), + py::call_guard(), + "cv waitFor with condition") + .def("waitFor", py::overload_cast(&ConditionVariable::waitFor), py::call_guard(), "cv waitFor") + .def("notifyOne", &ConditionVariable::notifyOne) // Not sure if I need to release the GIL here as this function also uses the intern mutex lock + .def("notifyAll", &ConditionVariable::notifyAll) // Same here + .def("getWaitingTaskCount", &ConditionVariable::getWaitingTaskCount); +} + +} // namespace taskr \ No newline at end of file diff --git a/meson.build b/meson.build index b03c312..bfd5495 100644 --- a/meson.build +++ b/meson.build @@ -74,9 +74,9 @@ TaskRBuildIncludes = include_directories([ if get_option('buildInstrumentation') -InstrumentationProject = subproject('tracr', required: true) -InstrumentationBuildDep = InstrumentationProject.get_variable('InstrumentationBuildDep') -taskrDependencies += InstrumentationBuildDep + InstrumentationProject = subproject('tracr', required: true) + InstrumentationBuildDep = InstrumentationProject.get_variable('InstrumentationBuildDep') + taskrDependencies += InstrumentationBuildDep add_project_arguments('-DENABLE_INSTRUMENTATION', language: 'cpp') @@ -92,6 +92,20 @@ TaskRBuildDep = declare_dependency( dependencies: taskrDependencies ) +####### Build PyTaskR +if get_option('buildPyTaskR') + missing = [] + foreach r : ['boost', 'pthreads', 'nosv'] + if not (r in HiCRBackends) + missing += r + endif + endforeach + + assert(missing.length() == 0, 'Missing required backends for pyTaskr: ' + ', '.join(missing)) + + subdir('include/pytaskr') +endif + ####### Build test / example targets only if TaskR is being loaded as a subproject if meson.is_subproject() == false @@ -106,4 +120,4 @@ if meson.is_subproject() == false subdir('tests') endif -endif +endif \ No newline at end of file diff --git a/meson_options.txt b/meson_options.txt index 541d34f..34aaf2b 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -28,6 +28,10 @@ option('buildInstrumentation', type : 'boolean', value : false, description: 'Indicates whether to build the instrumentation using TraCR', ) +option('buildPyTaskR', type : 'boolean', value : false, + description: 'Indicates whether to build the TaskR Python API', +) + option('compileWarningsAsErrors', type : 'boolean', value : false, description: 'Indicates whether a compilation warning should result in a fatal error. This is useful for CI testing but may result in inconveniences for normal users, hence it should be false by default' ) diff --git a/tests/meson.build b/tests/meson.build index 491c8fe..0447553 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -23,4 +23,13 @@ TaskRTestDep = declare_dependency( compile_args: TaskRTestCppFlags, dependencies: gtest_dep - ) \ No newline at end of file + ) + +#### Testing if the python interface of pytaskr is working + +if get_option('buildPyTaskR') + testSuite = ['tests', 'pyruntime'] + pyruntime = executable('pyruntime_test', [ 'pyruntime_test.cpp'], dependencies: [ TaskRBuildDep ]) + + test('pyruntime_test', pyruntime, args : [ ], suite: testSuite, workdir: pyruntime.path() + '.p' ) +endif \ No newline at end of file diff --git a/tests/pyruntime_test.cpp b/tests/pyruntime_test.cpp new file mode 100644 index 0000000..52664a7 --- /dev/null +++ b/tests/pyruntime_test.cpp @@ -0,0 +1,32 @@ +/* + * Copyright 2025 Huawei Technologies Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +int main(int argc, char **argv) +{ + // Creating taskr instance + taskr::PyRuntime pytaskr(taskr::backend_t::nosv, 0); + + // Getting the runtime + taskr::Runtime &runtime = pytaskr.get_runtime(); + + // Printing runtime + printf("I got the runtime with nOS-V backend: %p\n", &runtime); + + return 0; +}