diff --git a/CMakeLists.txt b/CMakeLists.txt index 53a327e..5408e81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,6 +125,7 @@ CheckPartestInstall(${BUILD_TESTS} partest_includepath partest_libpath) add_subdirectory(base_c) add_subdirectory(base_cpp) add_subdirectory(mtapi_c) +add_subdirectory(tasks_cpp) add_subdirectory(mtapi_cpp) add_subdirectory(containers_cpp) add_subdirectory(algorithms_cpp) diff --git a/README.md b/README.md index f3c8f35..1698458 100644 --- a/README.md +++ b/README.md @@ -21,10 +21,10 @@ processor cores. It builds on MTAPI, a standardized programming interface for leveraging task parallelism in embedded systems containing symmetric or asymmetric multicore processors. A core feature of MTAPI is low-overhead scheduling of fine-grained tasks among the available cores during runtime. -Unlike existing libraries, EMB² supports task priorities, which allows the -creation of soft real-time systems. Additionally, the scheduling strategy can -be optimized for non-functional requirements such as minimal latency and -fairness. +Unlike existing libraries, EMB² supports task priorities and affinities, which +allows the creation of soft real-time systems. Additionally, the scheduling +strategy can be optimized for non-functional requirements such as minimal +latency and fairness. Besides the task scheduler, EMB² provides basic parallel algorithms, concurrent data structures, and skeletons for implementing stream processing applications diff --git a/algorithms_cpp/CMakeLists.txt b/algorithms_cpp/CMakeLists.txt index bf9f799..5378bd3 100644 --- a/algorithms_cpp/CMakeLists.txt +++ b/algorithms_cpp/CMakeLists.txt @@ -17,18 +17,18 @@ include_directories(${EMBB_ALGORITHMS_CPP_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include ${CMAKE_CURRENT_BINARY_DIR}/../base_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_c/include - ${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_cpp/include - ${CMAKE_CURRENT_BINARY_DIR}/../mtapi_cpp/include) + ${CMAKE_CURRENT_SOURCE_DIR}/../tasks_cpp/include + ${CMAKE_CURRENT_BINARY_DIR}/../tasks_cpp/include) add_library(embb_algorithms_cpp ${EMBB_ALGORITHMS_CPP_SOURCES} ${EMBB_ALGORITHMS_CPP_HEADERS}) -target_link_libraries(embb_algorithms_cpp embb_mtapi_cpp) +target_link_libraries(embb_algorithms_cpp embb_tasks_cpp) if (BUILD_TESTS STREQUAL ON) include_directories(${CMAKE_CURRENT_BINARY_DIR}/../partest/include) add_executable (embb_algorithms_cpp_test ${EMBB_ALGORITHMS_CPP_TEST_SOURCES}) target_link_libraries(embb_algorithms_cpp_test embb_algorithms_cpp - embb_mtapi_cpp embb_mtapi_c partest embb_base_cpp + embb_tasks_cpp embb_mtapi_c partest embb_base_cpp embb_base_c ${compiler_libs}) CopyBin(BIN embb_algorithms_cpp_test DEST ${local_install_dir}) endif() diff --git a/algorithms_cpp/include/embb/algorithms/count.h b/algorithms_cpp/include/embb/algorithms/count.h index 90dae22..73f5b31 100644 --- a/algorithms_cpp/include/embb/algorithms/count.h +++ b/algorithms_cpp/include/embb/algorithms/count.h @@ -27,7 +27,7 @@ #ifndef EMBB_ALGORITHMS_COUNT_H_ #define EMBB_ALGORITHMS_COUNT_H_ -#include +#include #include namespace embb { @@ -132,7 +132,7 @@ typename std::iterator_traits::difference_type Count( RAI first, RAI last, const ValueType& value, - const embb::mtapi::ExecutionPolicy& policy, + const embb::tasks::ExecutionPolicy& policy, size_t block_size ); @@ -145,7 +145,7 @@ typename std::iterator_traits::difference_type Count( RAI last, const ValueType& value ) { - return Count(first, last, value, embb::mtapi::ExecutionPolicy(), 0); + return Count(first, last, value, embb::tasks::ExecutionPolicy(), 0); } /** @@ -156,7 +156,7 @@ typename std::iterator_traits::difference_type Count( RAI first, RAI last, const ValueType& value, - const embb::mtapi::ExecutionPolicy& policy + const embb::tasks::ExecutionPolicy& policy ) { return Count(first, last, value, policy, 0); } @@ -169,7 +169,7 @@ typename std::iterator_traits::difference_type CountIf( RAI first, RAI last, ComparisonFunction comparison, - const embb::mtapi::ExecutionPolicy& policy, + const embb::tasks::ExecutionPolicy& policy, size_t block_size ); @@ -182,7 +182,7 @@ typename std::iterator_traits::difference_type CountIf( RAI last, ComparisonFunction comparison ) { - return CountIf(first, last, comparison, embb::mtapi::ExecutionPolicy(), 0); + return CountIf(first, last, comparison, embb::tasks::ExecutionPolicy(), 0); } /** @@ -193,7 +193,7 @@ typename std::iterator_traits::difference_type CountIf( RAI first, RAI last, ComparisonFunction comparison, - const embb::mtapi::ExecutionPolicy& policy + const embb::tasks::ExecutionPolicy& policy ) { return CountIf(first, last, comparison, policy, 0); } diff --git a/algorithms_cpp/include/embb/algorithms/for_each.h b/algorithms_cpp/include/embb/algorithms/for_each.h index 7812949..23af854 100644 --- a/algorithms_cpp/include/embb/algorithms/for_each.h +++ b/algorithms_cpp/include/embb/algorithms/for_each.h @@ -27,7 +27,7 @@ #ifndef EMBB_ALGORITHMS_FOR_EACH_H_ #define EMBB_ALGORITHMS_FOR_EACH_H_ -#include +#include namespace embb { namespace algorithms { @@ -88,7 +88,7 @@ void ForEach( RAI first, RAI last, Function unary, - const embb::mtapi::ExecutionPolicy& policy, + const embb::tasks::ExecutionPolicy& policy, size_t block_size ); @@ -101,7 +101,7 @@ void ForEach( RAI last, Function unary ) { - ForEach(first, last, unary, embb::mtapi::ExecutionPolicy(), 0); + ForEach(first, last, unary, embb::tasks::ExecutionPolicy(), 0); } /** @@ -112,7 +112,7 @@ void ForEach( RAI first, RAI last, Function unary, - const embb::mtapi::ExecutionPolicy& policy + const embb::tasks::ExecutionPolicy& policy ) { ForEach(first, last, unary, policy, 0); } diff --git a/algorithms_cpp/include/embb/algorithms/internal/count-inl.h b/algorithms_cpp/include/embb/algorithms/internal/count-inl.h index 51aa34a..140fe51 100644 --- a/algorithms_cpp/include/embb/algorithms/internal/count-inl.h +++ b/algorithms_cpp/include/embb/algorithms/internal/count-inl.h @@ -83,7 +83,7 @@ class FunctionComparisonFunction{ template typename std::iterator_traits::difference_type Count(RAI first, RAI last, const ValueType& value, - const embb::mtapi::ExecutionPolicy& policy, size_t block_size) { + const embb::tasks::ExecutionPolicy& policy, size_t block_size) { typedef typename std::iterator_traits::difference_type Difference; return Reduce(first, last, Difference(0), std::plus(), internal::ValueComparisonFunction(value), policy, @@ -93,7 +93,7 @@ typename std::iterator_traits::difference_type template typename std::iterator_traits::difference_type CountIf(RAI first, RAI last, ComparisonFunction comparison, - const embb::mtapi::ExecutionPolicy& policy, size_t block_size) { + const embb::tasks::ExecutionPolicy& policy, size_t block_size) { typedef typename std::iterator_traits::difference_type Difference; return Reduce(first, last, Difference(0), std::plus(), internal::FunctionComparisonFunction diff --git a/algorithms_cpp/include/embb/algorithms/internal/for_each-inl.h b/algorithms_cpp/include/embb/algorithms/internal/for_each-inl.h index 8d9e034..fb5dcd3 100644 --- a/algorithms_cpp/include/embb/algorithms/internal/for_each-inl.h +++ b/algorithms_cpp/include/embb/algorithms/internal/for_each-inl.h @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include @@ -46,13 +46,13 @@ class ForEachFunctor { * Constructs a for-each functor with arguments. */ ForEachFunctor(size_t chunk_first, size_t chunk_last, Function unary, - const embb::mtapi::ExecutionPolicy& policy, + const embb::tasks::ExecutionPolicy& policy, const BlockSizePartitioner& partitioner) : chunk_first_(chunk_first), chunk_last_(chunk_last), unary_(unary), policy_(policy), partitioner_(partitioner) { } - void Action(mtapi::TaskContext&) { + void Action(embb::tasks::TaskContext&) { if (chunk_first_ == chunk_last_) { // Leaf case, recursed to single chunk. Do work on chunk: ChunkDescriptor chunk = partitioner_[chunk_first_]; @@ -71,12 +71,12 @@ class ForEachFunctor { self_t functor_r(chunk_split_index + 1, chunk_last_, unary_, policy_, partitioner_); - mtapi::Task task_l = mtapi::Node::GetInstance().Spawn( - mtapi::Action( + embb::tasks::Task task_l = embb::tasks::Node::GetInstance().Spawn( + embb::tasks::Action( base::MakeFunction(functor_l, &self_t::Action), policy_)); - mtapi::Task task_r = mtapi::Node::GetInstance().Spawn( - mtapi::Action( + embb::tasks::Task task_r = embb::tasks::Node::GetInstance().Spawn( + embb::tasks::Action( base::MakeFunction(functor_r, &self_t::Action), policy_)); task_l.Wait(MTAPI_INFINITE); @@ -91,7 +91,7 @@ class ForEachFunctor { size_t chunk_first_; size_t chunk_last_; Function unary_; - const embb::mtapi::ExecutionPolicy& policy_; + const embb::tasks::ExecutionPolicy& policy_; const BlockSizePartitioner& partitioner_; /** @@ -102,7 +102,7 @@ class ForEachFunctor { template void ForEachRecursive(RAI first, RAI last, Function unary, - const embb::mtapi::ExecutionPolicy& policy, size_t block_size) { + const embb::tasks::ExecutionPolicy& policy, size_t block_size) { typedef typename std::iterator_traits::difference_type difference_type; difference_type distance = std::distance(first, last); if (distance == 0) { @@ -114,7 +114,7 @@ void ForEachRecursive(RAI first, RAI last, Function unary, if (num_cores == 0) { EMBB_THROW(embb::base::ErrorException, "No cores in execution policy"); } - mtapi::Node& node = mtapi::Node::GetInstance(); + embb::tasks::Node& node = embb::tasks::Node::GetInstance(); // Determine actually used block size if (block_size == 0) { block_size = (static_cast(distance) / num_cores); @@ -132,7 +132,7 @@ void ForEachRecursive(RAI first, RAI last, Function unary, ForEachFunctor functor(0, partitioner.Size() - 1, unary, policy, partitioner); - mtapi::Task task = node.Spawn(mtapi::Action( + embb::tasks::Task task = node.Spawn(embb::tasks::Action( base::MakeFunction(functor, &ForEachFunctor::Action), policy)); @@ -141,7 +141,7 @@ void ForEachRecursive(RAI first, RAI last, Function unary, template void ForEachIteratorCheck(RAI first, RAI last, Function unary, - const embb::mtapi::ExecutionPolicy& policy, size_t block_size, + const embb::tasks::ExecutionPolicy& policy, size_t block_size, std::random_access_iterator_tag) { return ForEachRecursive(first, last, unary, policy, block_size); } @@ -150,7 +150,7 @@ void ForEachIteratorCheck(RAI first, RAI last, Function unary, template void ForEach(RAI first, const RAI last, Function unary, - const embb::mtapi::ExecutionPolicy& policy, size_t block_size) { + const embb::tasks::ExecutionPolicy& policy, size_t block_size) { typename std::iterator_traits::iterator_category category; internal::ForEachIteratorCheck(first, last, unary, policy, block_size, category); diff --git a/algorithms_cpp/include/embb/algorithms/internal/merge_sort-inl.h b/algorithms_cpp/include/embb/algorithms/internal/merge_sort-inl.h index a56d582..7cd2448 100644 --- a/algorithms_cpp/include/embb/algorithms/internal/merge_sort-inl.h +++ b/algorithms_cpp/include/embb/algorithms/internal/merge_sort-inl.h @@ -32,7 +32,7 @@ #include #include -#include +#include #include namespace embb { @@ -50,7 +50,7 @@ class MergeSortFunctor { MergeSortFunctor(size_t chunk_first, size_t chunk_last, RAITemp temporary_first, ComparisonFunction comparison, - const embb::mtapi::ExecutionPolicy& policy, + const embb::tasks::ExecutionPolicy& policy, const BlockSizePartitioner& partitioner, const RAI& global_first, int depth) : chunk_first_(chunk_first), chunk_last_(chunk_last), @@ -59,7 +59,7 @@ class MergeSortFunctor { global_first_(global_first), depth_(depth) { } - void Action(mtapi::TaskContext&) { + void Action(embb::tasks::TaskContext&) { size_t chunk_split_index = (chunk_first_ + chunk_last_) / 2; if (chunk_first_ == chunk_last_) { // Leaf case: recurse into a single chunk's elements: @@ -77,13 +77,13 @@ class MergeSortFunctor { temp_first_, comparison_, policy_, partitioner_, global_first_, depth_ + 1); - mtapi::Node& node = mtapi::Node::GetInstance(); - mtapi::Task task_l = node.Spawn( - mtapi::Action( + embb::tasks::Node& node = embb::tasks::Node::GetInstance(); + embb::tasks::Task task_l = node.Spawn( + embb::tasks::Action( base::MakeFunction(functor_l, &self_t::Action), policy_)); - mtapi::Task task_r = node.Spawn( - mtapi::Action( + embb::tasks::Task task_r = node.Spawn( + embb::tasks::Action( base::MakeFunction(functor_r, &self_t::Action), policy_)); task_l.Wait(MTAPI_INFINITE); @@ -177,7 +177,7 @@ class MergeSortFunctor { size_t chunk_last_; RAITemp temp_first_; ComparisonFunction comparison_; - const embb::mtapi::ExecutionPolicy& policy_; + const embb::tasks::ExecutionPolicy& policy_; const BlockSizePartitioner& partitioner_; const RAI& global_first_; int depth_; @@ -219,7 +219,7 @@ void MergeSortIteratorCheck( RAI last, RAITemp temporary_first, ComparisonFunction comparison, - const embb::mtapi::ExecutionPolicy& policy, + const embb::tasks::ExecutionPolicy& policy, size_t block_size, std::random_access_iterator_tag ) { @@ -257,8 +257,8 @@ void MergeSortIteratorCheck( partitioner, first, 0); - mtapi::Task task = embb::mtapi::Node::GetInstance().Spawn( - mtapi::Action( + embb::tasks::Task task = embb::tasks::Node::GetInstance().Spawn( + embb::tasks::Action( base::MakeFunction(functor, &functor_t::Action), policy)); @@ -269,7 +269,7 @@ void MergeSortIteratorCheck( template void MergeSort(RAI first, RAI last, RAITemp temporary_first, - ComparisonFunction comparison, const embb::mtapi::ExecutionPolicy& policy, + ComparisonFunction comparison, const embb::tasks::ExecutionPolicy& policy, size_t block_size) { typedef typename std::iterator_traits::iterator_category category; internal::MergeSortIteratorCheck(first, last, temporary_first, comparison, diff --git a/algorithms_cpp/include/embb/algorithms/internal/partition-inl.h b/algorithms_cpp/include/embb/algorithms/internal/partition-inl.h index 434af54..48cdb9f 100644 --- a/algorithms_cpp/include/embb/algorithms/internal/partition-inl.h +++ b/algorithms_cpp/include/embb/algorithms/internal/partition-inl.h @@ -93,7 +93,7 @@ ChunkPartitioner::ChunkPartitioner(ForwardIterator first, size = amountChunks; } else { // if no concrete chunk size was given, use number of cores... - mtapi::Node& node = mtapi::Node::GetInstance(); + embb::tasks::Node& node = embb::tasks::Node::GetInstance(); size = node.GetWorkerThreadCount(); } diff --git a/algorithms_cpp/include/embb/algorithms/internal/partition.h b/algorithms_cpp/include/embb/algorithms/internal/partition.h index 403cb65..7e7548e 100644 --- a/algorithms_cpp/include/embb/algorithms/internal/partition.h +++ b/algorithms_cpp/include/embb/algorithms/internal/partition.h @@ -27,7 +27,7 @@ #ifndef EMBB_ALGORITHMS_INTERNAL_PARTITION_H_ #define EMBB_ALGORITHMS_INTERNAL_PARTITION_H_ -#include +#include namespace embb { namespace algorithms { diff --git a/algorithms_cpp/include/embb/algorithms/internal/quick_sort-inl.h b/algorithms_cpp/include/embb/algorithms/internal/quick_sort-inl.h index 1b4bb2f..79a1241 100644 --- a/algorithms_cpp/include/embb/algorithms/internal/quick_sort-inl.h +++ b/algorithms_cpp/include/embb/algorithms/internal/quick_sort-inl.h @@ -33,7 +33,7 @@ #include #include -#include +#include #include namespace embb { @@ -48,7 +48,7 @@ class QuickSortFunctor { * Constructs a functor. */ QuickSortFunctor(RAI first, RAI last, ComparisonFunction comparison, - const embb::mtapi::ExecutionPolicy& policy, size_t block_size) + const embb::tasks::ExecutionPolicy& policy, size_t block_size) : first_(first), last_(last), comparison_(comparison), policy_(policy), block_size_(block_size) { } @@ -56,7 +56,7 @@ class QuickSortFunctor { /** * MTAPI action function and starting point of the parallel quick sort. */ - void Action(mtapi::TaskContext&) { + void Action(embb::tasks::TaskContext&) { Difference distance = last_ - first_; if (distance <= 1) { return; @@ -68,15 +68,15 @@ class QuickSortFunctor { SerialQuickSort(first_, mid); SerialQuickSort(mid, last_); } else { - mtapi::Node& node = mtapi::Node::GetInstance(); + embb::tasks::Node& node = embb::tasks::Node::GetInstance(); QuickSortFunctor functor_l(first_, mid, comparison_, policy_, block_size_); - mtapi::Task task_l = node.Spawn(mtapi::Action(base::MakeFunction( - functor_l, &QuickSortFunctor::Action))); + embb::tasks::Task task_l = node.Spawn(embb::tasks::Action( + base::MakeFunction(functor_l, &QuickSortFunctor::Action))); QuickSortFunctor functor_r(mid, last_, comparison_, policy_, block_size_); - mtapi::Task task_r = node.Spawn(mtapi::Action(base::MakeFunction( - functor_r, &QuickSortFunctor::Action))); + embb::tasks::Task task_r = node.Spawn(embb::tasks::Action( + base::MakeFunction(functor_r, &QuickSortFunctor::Action))); task_l.Wait(MTAPI_INFINITE); task_r.Wait(MTAPI_INFINITE); } @@ -87,7 +87,7 @@ class QuickSortFunctor { RAI first_; RAI last_; ComparisonFunction comparison_; - const embb::mtapi::ExecutionPolicy& policy_; + const embb::tasks::ExecutionPolicy& policy_; size_t block_size_; typedef typename std::iterator_traits::difference_type Difference; @@ -189,10 +189,10 @@ class QuickSortFunctor { template void QuickSortIteratorCheck(RAI first, RAI last, ComparisonFunction comparison, - const embb::mtapi::ExecutionPolicy& policy, + const embb::tasks::ExecutionPolicy& policy, size_t block_size, std::random_access_iterator_tag) { - embb::mtapi::Node& node = embb::mtapi::Node::GetInstance(); + embb::tasks::Node& node = embb::tasks::Node::GetInstance(); typedef typename std::iterator_traits::difference_type difference_type; difference_type distance = std::distance(first, last); if (distance == 0) { @@ -215,7 +215,7 @@ void QuickSortIteratorCheck(RAI first, RAI last, } QuickSortFunctor functor( first, last, comparison, policy, block_size); - mtapi::Task task = node.Spawn(mtapi::Action(base::MakeFunction( + embb::tasks::Task task = node.Spawn(embb::tasks::Action(base::MakeFunction( functor, &QuickSortFunctor::Action))); task.Wait(MTAPI_INFINITE); } @@ -224,7 +224,7 @@ void QuickSortIteratorCheck(RAI first, RAI last, template void QuickSort(RAI first, RAI last, ComparisonFunction comparison, - const embb::mtapi::ExecutionPolicy& policy, size_t block_size) { + const embb::tasks::ExecutionPolicy& policy, size_t block_size) { typedef typename std::iterator_traits::iterator_category category; internal::QuickSortIteratorCheck(first, last, comparison, policy, block_size, category()); diff --git a/algorithms_cpp/include/embb/algorithms/internal/reduce-inl.h b/algorithms_cpp/include/embb/algorithms/internal/reduce-inl.h index 86892a2..bc15801 100644 --- a/algorithms_cpp/include/embb/algorithms/internal/reduce-inl.h +++ b/algorithms_cpp/include/embb/algorithms/internal/reduce-inl.h @@ -27,7 +27,7 @@ #ifndef EMBB_ALGORITHMS_INTERNAL_REDUCE_INL_H_ #define EMBB_ALGORITHMS_INTERNAL_REDUCE_INL_H_ -#include +#include #include #include @@ -46,7 +46,7 @@ class ReduceFunctor { ReturnType neutral, ReductionFunction reduction, TransformationFunction transformation, - const embb::mtapi::ExecutionPolicy& policy, + const embb::tasks::ExecutionPolicy& policy, const BlockSizePartitioner& partitioner, ReturnType& result) : chunk_first_(chunk_first), chunk_last_(chunk_last), neutral_(neutral), @@ -54,7 +54,7 @@ class ReduceFunctor { partitioner_(partitioner), result_(result) { } - void Action(mtapi::TaskContext&) { + void Action(embb::tasks::TaskContext&) { if (chunk_first_ == chunk_last_) { // Leaf case, recursed to single chunk. Do work on chunk: ChunkDescriptor chunk = partitioner_[chunk_first_]; @@ -81,13 +81,13 @@ class ReduceFunctor { neutral_, reduction_, transformation_, policy_, partitioner_, result_r); - mtapi::Task task_l = mtapi::Node::GetInstance().Spawn( - mtapi::Action( + embb::tasks::Task task_l = embb::tasks::Node::GetInstance().Spawn( + embb::tasks::Action( base::MakeFunction( functor_l, &self_t::Action), policy_)); - mtapi::Task task_r = mtapi::Node::GetInstance().Spawn( - mtapi::Action( + embb::tasks::Task task_r = embb::tasks::Node::GetInstance().Spawn( + embb::tasks::Action( base::MakeFunction( functor_r, &self_t::Action), policy_)); @@ -108,7 +108,7 @@ class ReduceFunctor { ReturnType neutral_; ReductionFunction reduction_; TransformationFunction transformation_; - const embb::mtapi::ExecutionPolicy& policy_; + const embb::tasks::ExecutionPolicy& policy_; const BlockSizePartitioner& partitioner_; ReturnType& result_; @@ -124,7 +124,7 @@ template::difference_type difference_type; difference_type distance = std::distance(first, last); @@ -137,7 +137,7 @@ ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral, if (num_cores == 0) { EMBB_THROW(embb::base::ErrorException, "No cores in execution policy"); } - mtapi::Node& node = mtapi::Node::GetInstance(); + embb::tasks::Node& node = embb::tasks::Node::GetInstance(); // Determine actually used block size if (block_size == 0) { block_size = (static_cast(distance) / num_cores); @@ -162,8 +162,8 @@ ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral, policy, partitioner, result); - mtapi::Task task = node.Spawn( - mtapi::Action(base::MakeFunction( + embb::tasks::Task task = node.Spawn( + embb::tasks::Action(base::MakeFunction( functor, &Functor::Action), policy)); task.Wait(MTAPI_INFINITE); return result; @@ -174,7 +174,7 @@ template::iterator_category category; return internal::ReduceIteratorCheck(first, last, reduction, transformation, diff --git a/algorithms_cpp/include/embb/algorithms/internal/scan-inl.h b/algorithms_cpp/include/embb/algorithms/internal/scan-inl.h index a3b6c99..cbf748e 100644 --- a/algorithms_cpp/include/embb/algorithms/internal/scan-inl.h +++ b/algorithms_cpp/include/embb/algorithms/internal/scan-inl.h @@ -29,8 +29,8 @@ #include #include -#include -#include +#include +#include #include namespace embb { @@ -44,7 +44,7 @@ class ScanFunctor { ScanFunctor(size_t chunk_first, size_t chunk_last, RAIOut output_iterator, ReturnType neutral, ScanFunction scan, TransformationFunction transformation, - const embb::mtapi::ExecutionPolicy& policy, + const embb::tasks::ExecutionPolicy& policy, const BlockSizePartitioner& partitioner, ReturnType* tree_values, size_t node_id, bool going_down) @@ -55,7 +55,7 @@ class ScanFunctor { node_id_(node_id), parent_value_(neutral), is_first_pass_(going_down) { } - void Action(mtapi::TaskContext&) { + void Action(embb::tasks::TaskContext&) { if (chunk_first_ == chunk_last_) { ChunkDescriptor chunk = partitioner_[chunk_first_]; RAIIn iter_in = chunk.GetFirst(); @@ -104,13 +104,13 @@ class ScanFunctor { functor_r.parent_value_ = functor_l.GetTreeValue() + parent_value_; } // Spawn tasks to recurse: - mtapi::Node& node = mtapi::Node::GetInstance(); - mtapi::Task task_l = node.Spawn( - mtapi::Action( + embb::tasks::Node& node = embb::tasks::Node::GetInstance(); + embb::tasks::Task task_l = node.Spawn( + embb::tasks::Action( base::MakeFunction(functor_l, &ScanFunctor::Action), policy_)); - mtapi::Task task_r = node.Spawn( - mtapi::Action( + embb::tasks::Task task_r = node.Spawn( + embb::tasks::Action( base::MakeFunction(functor_r, &ScanFunctor::Action), policy_)); // Wait for tasks to complete: @@ -131,7 +131,7 @@ class ScanFunctor { private: static const int LEFT = 1; static const int RIGHT = 2; - const embb::mtapi::ExecutionPolicy& policy_; + const embb::tasks::ExecutionPolicy& policy_; size_t chunk_first_; size_t chunk_last_; RAIOut output_iterator_; @@ -168,7 +168,7 @@ typename ScanFunction, typename TransformationFunction> void ScanIteratorCheck(RAIIn first, RAIIn last, RAIOut output_iterator, ReturnType neutral, ScanFunction scan, TransformationFunction transformation, - const embb::mtapi::ExecutionPolicy& policy, + const embb::tasks::ExecutionPolicy& policy, size_t block_size, std::random_access_iterator_tag) { typedef typename std::iterator_traits::difference_type difference_type; @@ -199,15 +199,14 @@ void ScanIteratorCheck(RAIIn first, RAIIn last, RAIOut output_iterator, // it creates the tree. typedef ScanFunctor Functor; - mtapi::Node& node = mtapi::Node::GetInstance(); + embb::tasks::Node& node = embb::tasks::Node::GetInstance(); BlockSizePartitioner partitioner_down(first, last, block_size); Functor functor_down(0, partitioner_down.Size() - 1, output_iterator, neutral, scan, transformation, policy, partitioner_down, values, 0, true); - mtapi::Task task_down = node.Spawn(mtapi::Action(base::MakeFunction( - functor_down, &Functor::Action), - policy)); + embb::tasks::Task task_down = node.Spawn(embb::tasks::Action( + base::MakeFunction(functor_down, &Functor::Action), policy)); task_down.Wait(MTAPI_INFINITE); // Second pass. Gives to each leaf the part of the prefix missing @@ -215,9 +214,8 @@ void ScanIteratorCheck(RAIIn first, RAIIn last, RAIOut output_iterator, Functor functor_up(0, partitioner_up.Size() - 1, output_iterator, neutral, scan, transformation, policy, partitioner_up, values, 0, false); - mtapi::Task task_up = node.Spawn(mtapi::Action(base::MakeFunction( - functor_up, &Functor::Action), - policy)); + embb::tasks::Task task_up = node.Spawn(embb::tasks::Action( + base::MakeFunction(functor_up, &Functor::Action), policy)); task_up.Wait(MTAPI_INFINITE); } @@ -227,7 +225,7 @@ template void Scan(RAIIn first, RAIIn last, RAIOut output_iterator, ReturnType neutral, ScanFunction scan, TransformationFunction transformation, - const embb::mtapi::ExecutionPolicy& policy, size_t block_size) { + const embb::tasks::ExecutionPolicy& policy, size_t block_size) { typedef typename std::iterator_traits::iterator_category category; internal::ScanIteratorCheck(first, last, output_iterator, neutral, scan, transformation, policy, block_size, category()); diff --git a/algorithms_cpp/include/embb/algorithms/invoke.h b/algorithms_cpp/include/embb/algorithms/invoke.h index 1484d5a..10dd818 100644 --- a/algorithms_cpp/include/embb/algorithms/invoke.h +++ b/algorithms_cpp/include/embb/algorithms/invoke.h @@ -28,7 +28,7 @@ #define EMBB_ALGORITHMS_INVOKE_H_ #include -#include +#include namespace embb { namespace algorithms { @@ -89,15 +89,16 @@ template class TaskWrapper { public: /** - * Wraps the function into an mtapi::Action and spawns an mtapi::Task. + * Wraps the function into an embb::tasks::Action and spawns an + * embb::tasks::Task. */ explicit TaskWrapper( Function function, - const embb::mtapi::ExecutionPolicy& policy) + const embb::tasks::ExecutionPolicy& policy) : function_(function), task_() { - mtapi::Action action(embb::base::MakeFunction(*this, &TaskWrapper::Run), - policy); - task_ = mtapi::Node::GetInstance().Spawn(action); + embb::tasks::Action action(embb::base::MakeFunction( + *this, &TaskWrapper::Run), policy); + task_ = embb::tasks::Node::GetInstance().Spawn(action); } /** @@ -109,9 +110,9 @@ class TaskWrapper { private: Function function_; - mtapi::Task task_; + embb::tasks::Task task_; - void Run(embb::mtapi::TaskContext&) { + void Run(embb::tasks::TaskContext&) { function_(); } }; @@ -120,7 +121,7 @@ class TaskWrapper { template void Invoke( Function1 func1, - const embb::mtapi::ExecutionPolicy& policy) { + const embb::tasks::ExecutionPolicy& policy) { internal::TaskWrapper wrap1(func1, policy); } @@ -128,7 +129,7 @@ template void Invoke( Function1 func1, Function2 func2, - const embb::mtapi::ExecutionPolicy& policy) { + const embb::tasks::ExecutionPolicy& policy) { internal::TaskWrapper wrap1(func1, policy); internal::TaskWrapper wrap2(func2, policy); } @@ -138,7 +139,7 @@ void Invoke( Function1 func1, Function2 func2, Function3 func3, - const embb::mtapi::ExecutionPolicy& policy) { + const embb::tasks::ExecutionPolicy& policy) { internal::TaskWrapper wrap1(func1, policy); internal::TaskWrapper wrap2(func2, policy); internal::TaskWrapper wrap3(func3, policy); @@ -151,7 +152,7 @@ template wrap1(func1, policy); internal::TaskWrapper wrap2(func2, policy); internal::TaskWrapper wrap3(func3, policy); @@ -166,7 +167,7 @@ template wrap1(func1, policy); internal::TaskWrapper wrap2(func2, policy); internal::TaskWrapper wrap3(func3, policy); @@ -183,7 +184,7 @@ template wrap1(func1, policy); internal::TaskWrapper wrap2(func2, policy); internal::TaskWrapper wrap3(func3, policy); @@ -203,7 +204,7 @@ template wrap1(func1, policy); internal::TaskWrapper wrap2(func2, policy); internal::TaskWrapper wrap3(func3, policy); @@ -225,7 +226,7 @@ template wrap1(func1, policy); internal::TaskWrapper wrap2(func2, policy); internal::TaskWrapper wrap3(func3, policy); @@ -249,7 +250,7 @@ template wrap1(func1, policy); internal::TaskWrapper wrap2(func2, policy); internal::TaskWrapper wrap3(func3, policy); @@ -276,7 +277,7 @@ template wrap1(func1, policy); internal::TaskWrapper wrap2(func2, policy); internal::TaskWrapper wrap3(func3, policy); @@ -292,21 +293,21 @@ template void Invoke( Function1 func1) { - Invoke(func1, embb::mtapi::ExecutionPolicy()); + Invoke(func1, embb::tasks::ExecutionPolicy()); } template void Invoke( Function1 func1, Function2 func2) { - Invoke(func1, func2, embb::mtapi::ExecutionPolicy()); + Invoke(func1, func2, embb::tasks::ExecutionPolicy()); } template void Invoke( Function1 func1, Function2 func2, Function3 func3) { - Invoke(func1, func2, func3, embb::mtapi::ExecutionPolicy()); + Invoke(func1, func2, func3, embb::tasks::ExecutionPolicy()); } template -#include +#include #include namespace embb { @@ -149,7 +149,7 @@ void MergeSort( RAI last, RAITemp temporary_first, ComparisonFunction comparison, - const embb::mtapi::ExecutionPolicy& policy, + const embb::tasks::ExecutionPolicy& policy, size_t block_size ); @@ -161,7 +161,7 @@ void MergeSortAllocate( RAI first, RAI last, ComparisonFunction comparison, - const embb::mtapi::ExecutionPolicy& policy, + const embb::tasks::ExecutionPolicy& policy, size_t block_size ) { typedef base::Allocation Alloc; @@ -200,7 +200,7 @@ void MergeSortAllocate( ) { MergeSortAllocate(first, last, std::less::value_type>(), - embb::mtapi::ExecutionPolicy(), 0); + embb::tasks::ExecutionPolicy(), 0); } /** @@ -212,7 +212,7 @@ void MergeSortAllocate( RAI last, ComparisonFunction comparison ) { - MergeSortAllocate(first, last, comparison, embb::mtapi::ExecutionPolicy(), 0); + MergeSortAllocate(first, last, comparison, embb::tasks::ExecutionPolicy(), 0); } /** @@ -223,7 +223,7 @@ void MergeSortAllocate( RAI first, RAI last, ComparisonFunction comparison, - const embb::mtapi::ExecutionPolicy& policy + const embb::tasks::ExecutionPolicy& policy ) { MergeSortAllocate(first, last, comparison, policy, 0); } @@ -239,7 +239,7 @@ void MergeSort( ) { MergeSort(first, last, temporary_first, std::less::value_type>(), - embb::mtapi::ExecutionPolicy(), 0); + embb::tasks::ExecutionPolicy(), 0); } /** @@ -253,7 +253,7 @@ void MergeSort( ComparisonFunction comparison ) { MergeSort(first, last, temporary_first, comparison, - embb::mtapi::ExecutionPolicy(), 0); + embb::tasks::ExecutionPolicy(), 0); } /** @@ -265,7 +265,7 @@ void MergeSort( RAI last, RAITemp temporary_first, ComparisonFunction comparison, - const embb::mtapi::ExecutionPolicy& policy + const embb::tasks::ExecutionPolicy& policy ) { MergeSort(first, last, temporary_first, comparison, policy, 0); } diff --git a/algorithms_cpp/include/embb/algorithms/quick_sort.h b/algorithms_cpp/include/embb/algorithms/quick_sort.h index cf25020..80181d5 100644 --- a/algorithms_cpp/include/embb/algorithms/quick_sort.h +++ b/algorithms_cpp/include/embb/algorithms/quick_sort.h @@ -28,7 +28,7 @@ #define EMBB_ALGORITHMS_QUICK_SORT_H_ #include -#include +#include namespace embb { namespace algorithms { @@ -72,7 +72,7 @@ void QuickSort( \c a appears before an element \c b in the sorted range if comparison(a, b) == true. The default value uses the less-than relation. */ - const embb::mtapi::ExecutionPolicy& policy = embb::mtapi::ExecutionPolicy(), + const embb::tasks::ExecutionPolicy& policy = embb::tasks::ExecutionPolicy(), /**< [IN] embb::mtapi::ExecutionPolicy for the quick sort algorithm */ size_t block_size = 0 /**< [IN] Lower bound for partitioning the range of elements into blocks that @@ -95,7 +95,7 @@ void QuickSort( RAI first, RAI last, ComparisonFunction comparison, - const embb::mtapi::ExecutionPolicy& policy, + const embb::tasks::ExecutionPolicy& policy, size_t block_size ); @@ -109,7 +109,7 @@ void QuickSort( ) { QuickSort(first, last, std::less::value_type>(), - embb::mtapi::ExecutionPolicy(), 0); + embb::tasks::ExecutionPolicy(), 0); } /** @@ -121,7 +121,7 @@ void QuickSort( RAI last, ComparisonFunction comparison ) { - QuickSort(first, last, comparison, embb::mtapi::ExecutionPolicy(), 0); + QuickSort(first, last, comparison, embb::tasks::ExecutionPolicy(), 0); } /** @@ -132,7 +132,7 @@ void QuickSort( RAI first, RAI last, ComparisonFunction comparison, - const embb::mtapi::ExecutionPolicy& policy + const embb::tasks::ExecutionPolicy& policy ) { QuickSort(first, last, comparison, policy, 0); } diff --git a/algorithms_cpp/include/embb/algorithms/reduce.h b/algorithms_cpp/include/embb/algorithms/reduce.h index 9058ee9..463e1b8 100644 --- a/algorithms_cpp/include/embb/algorithms/reduce.h +++ b/algorithms_cpp/include/embb/algorithms/reduce.h @@ -27,7 +27,7 @@ #ifndef EMBB_ALGORITHMS_REDUCE_H_ #define EMBB_ALGORITHMS_REDUCE_H_ -#include +#include #include namespace embb { @@ -113,7 +113,7 @@ ReturnType Reduce( ReturnType neutral, ReductionFunction reduction, TransformationFunction transformation, - const embb::mtapi::ExecutionPolicy& policy, + const embb::tasks::ExecutionPolicy& policy, size_t block_size ); @@ -128,7 +128,7 @@ ReturnType Reduce( ReductionFunction reduction ) { return Reduce(first, last, neutral, reduction, Identity(), - embb::mtapi::ExecutionPolicy(), 0); + embb::tasks::ExecutionPolicy(), 0); } /** @@ -144,7 +144,7 @@ ReturnType Reduce( TransformationFunction transformation ) { return Reduce(first, last, neutral, reduction, transformation, - embb::mtapi::ExecutionPolicy(), 0); + embb::tasks::ExecutionPolicy(), 0); } /** @@ -158,7 +158,7 @@ ReturnType Reduce( ReturnType neutral, ReductionFunction reduction, TransformationFunction transformation, - const embb::mtapi::ExecutionPolicy& policy + const embb::tasks::ExecutionPolicy& policy ) { return Reduce(first, last, neutral, reduction, transformation, policy, 0); } diff --git a/algorithms_cpp/include/embb/algorithms/scan.h b/algorithms_cpp/include/embb/algorithms/scan.h index 5d019cb..8a32e91 100644 --- a/algorithms_cpp/include/embb/algorithms/scan.h +++ b/algorithms_cpp/include/embb/algorithms/scan.h @@ -27,7 +27,7 @@ #ifndef EMBB_ALGORITHMS_SCAN_H_ #define EMBB_ALGORITHMS_SCAN_H_ -#include +#include #include namespace embb { @@ -121,7 +121,7 @@ void Scan( ReturnType neutral, ScanFunction scan, TransformationFunction transformation, - const embb::mtapi::ExecutionPolicy& policy, + const embb::tasks::ExecutionPolicy& policy, size_t block_size ); @@ -138,7 +138,7 @@ void Scan( ScanFunction scan ) { Scan(first, last, output_iterator, neutral, scan, Identity(), - embb::mtapi::ExecutionPolicy(), 0); + embb::tasks::ExecutionPolicy(), 0); } /** @@ -155,7 +155,7 @@ void Scan( TransformationFunction transformation ) { Scan(first, last, output_iterator, neutral, scan, transformation, - embb::mtapi::ExecutionPolicy(), 0); + embb::tasks::ExecutionPolicy(), 0); } /** @@ -170,7 +170,7 @@ void Scan( ReturnType neutral, ScanFunction scan, TransformationFunction transformation, - const embb::mtapi::ExecutionPolicy& policy + const embb::tasks::ExecutionPolicy& policy ) { Scan(first, last, output_iterator, neutral, scan, transformation, policy, 0); } diff --git a/algorithms_cpp/test/count_test.cc b/algorithms_cpp/test/count_test.cc index fdc5993..0ab2571 100644 --- a/algorithms_cpp/test/count_test.cc +++ b/algorithms_cpp/test/count_test.cc @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include #include @@ -122,7 +122,7 @@ void CountTest::TestBlockSizes() { void CountTest::TestPolicy() { using embb::algorithms::Count; - using embb::mtapi::ExecutionPolicy; + using embb::tasks::ExecutionPolicy; int a[] = { 10, 20, 30, 30, 20, 10, 10, 20, 20, 20 }; std::vector vector(a, a + (sizeof a / sizeof a[0])); PT_EXPECT_EQ(Count(vector.begin(), vector.end(), 10, ExecutionPolicy()), 3); @@ -134,7 +134,7 @@ void CountTest::TestPolicy() { void CountTest::StressTest() { using embb::algorithms::Count; - size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() *10; + size_t count = embb::tasks::Node::GetInstance().GetCoreCount() * 10; std::vector large_vector(count); for (size_t i = 0; i < count; i++) { large_vector[i] = static_cast(0); diff --git a/algorithms_cpp/test/for_each_test.cc b/algorithms_cpp/test/for_each_test.cc index 3ca3081..df46122 100644 --- a/algorithms_cpp/test/for_each_test.cc +++ b/algorithms_cpp/test/for_each_test.cc @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include #include @@ -166,7 +166,7 @@ void ForEachTest::TestRanges() { void ForEachTest::TestBlockSizes() { using embb::algorithms::ForEach; - using embb::mtapi::ExecutionPolicy; + using embb::tasks::ExecutionPolicy; size_t count = 4; std::vector init(count); std::vector vector(count); @@ -186,7 +186,7 @@ void ForEachTest::TestBlockSizes() { void ForEachTest::TestPolicy() { using embb::algorithms::ForEach; - using embb::mtapi::ExecutionPolicy; + using embb::tasks::ExecutionPolicy; size_t count = 4; std::vector init(count); std::vector vector(count); @@ -240,8 +240,8 @@ void ForEachTest::TestPolicy() { void ForEachTest::StressTest() { using embb::algorithms::ForEach; - using embb::mtapi::ExecutionPolicy; - size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() *10; + using embb::tasks::ExecutionPolicy; + size_t count = embb::tasks::Node::GetInstance().GetCoreCount() * 10; std::vector large_vector(count); for (size_t i = 0; i < count; i++) { large_vector[i] = static_cast((i + 2) % 1000); diff --git a/algorithms_cpp/test/main.cc b/algorithms_cpp/test/main.cc index 4b5bf5e..1da1475 100644 --- a/algorithms_cpp/test/main.cc +++ b/algorithms_cpp/test/main.cc @@ -25,7 +25,7 @@ */ #include -#include +#include #include #include @@ -66,7 +66,7 @@ int compute1_() { } PT_MAIN("Algorithms") { - embb::mtapi::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID); + embb::tasks::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID); PT_RUN(PartitionerTest); PT_RUN(ForEachTest); @@ -78,7 +78,7 @@ PT_MAIN("Algorithms") { PT_RUN(MergeSortTest); PT_RUN(InvokeTest); - embb::mtapi::Node::Finalize(); + embb::tasks::Node::Finalize(); PT_EXPECT(embb_get_bytes_allocated() == 0); diff --git a/algorithms_cpp/test/merge_sort_test.cc b/algorithms_cpp/test/merge_sort_test.cc index d7b1170..c3fd3ee 100644 --- a/algorithms_cpp/test/merge_sort_test.cc +++ b/algorithms_cpp/test/merge_sort_test.cc @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include #include @@ -50,7 +50,7 @@ MergeSortTest::MergeSortTest() { void MergeSortTest::TestDataStructures() { using embb::algorithms::MergeSortAllocate; - using embb::mtapi::ExecutionPolicy; + using embb::tasks::ExecutionPolicy; int array[kCountSize]; std::vector vector(kCountSize); std::deque deque(kCountSize); @@ -75,7 +75,7 @@ void MergeSortTest::TestDataStructures() { void MergeSortTest::TestFunctionPointers() { using embb::algorithms::MergeSortAllocate; - using embb::mtapi::ExecutionPolicy; + using embb::tasks::ExecutionPolicy; std::vector vector(kCountSize); for (size_t i = kCountSize - 1; i > 0; i--) { @@ -158,7 +158,7 @@ void MergeSortTest::TestRanges() { void MergeSortTest::TestBlockSizes() { using embb::algorithms::MergeSortAllocate; - using embb::mtapi::ExecutionPolicy; + using embb::tasks::ExecutionPolicy; size_t count = 4; std::vector init(count); std::vector vector(count); @@ -181,7 +181,7 @@ void MergeSortTest::TestBlockSizes() { void MergeSortTest::TestPolicy() { using embb::algorithms::MergeSortAllocate; - using embb::mtapi::ExecutionPolicy; + using embb::tasks::ExecutionPolicy; size_t count = 4; std::vector init(count); std::vector vector(count); @@ -242,7 +242,7 @@ void MergeSortTest::TestPolicy() { void MergeSortTest::StressTest() { using embb::algorithms::MergeSortAllocate; - size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() * 10; + size_t count = embb::tasks::Node::GetInstance().GetCoreCount() * 10; std::vector large_vector(count); std::vector vector_copy(count); for (size_t i = count - 1; i > 0; i--) { diff --git a/algorithms_cpp/test/quick_sort_test.cc b/algorithms_cpp/test/quick_sort_test.cc index 863b278..151b658 100644 --- a/algorithms_cpp/test/quick_sort_test.cc +++ b/algorithms_cpp/test/quick_sort_test.cc @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include #include @@ -54,7 +54,7 @@ QuickSortTest::QuickSortTest() { void QuickSortTest::TestDataStructures() { using embb::algorithms::QuickSort; - using embb::mtapi::ExecutionPolicy; + using embb::tasks::ExecutionPolicy; int array[kCountSize]; std::vector vector(kCountSize); @@ -163,7 +163,7 @@ void QuickSortTest::TestRanges() { void QuickSortTest::TestBlockSizes() { using embb::algorithms::QuickSort; - using embb::mtapi::ExecutionPolicy; + using embb::tasks::ExecutionPolicy; size_t count = 4; std::vector init(count); @@ -187,7 +187,7 @@ void QuickSortTest::TestBlockSizes() { void QuickSortTest::TestPolicy() { using embb::algorithms::QuickSort; - using embb::mtapi::ExecutionPolicy; + using embb::tasks::ExecutionPolicy; size_t count = 4; std::vector init(count); std::vector vector(count); @@ -248,7 +248,7 @@ void QuickSortTest::TestPolicy() { void QuickSortTest::StressTest() { using embb::algorithms::QuickSort; - size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() *10; + size_t count = embb::tasks::Node::GetInstance().GetCoreCount() * 10; std::vector large_vector(count); std::vector vector_copy(count); for (size_t i = 0; i < count; i++) { diff --git a/algorithms_cpp/test/reduce_test.cc b/algorithms_cpp/test/reduce_test.cc index c8ab5ae..63d31be 100644 --- a/algorithms_cpp/test/reduce_test.cc +++ b/algorithms_cpp/test/reduce_test.cc @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include #include @@ -163,7 +163,7 @@ void ReduceTest::TestBlockSizes() { void ReduceTest::TestPolicy() { using embb::algorithms::Reduce; - using embb::mtapi::ExecutionPolicy; + using embb::tasks::ExecutionPolicy; using embb::algorithms::Identity; size_t count = 4; int sum = 0; @@ -210,9 +210,9 @@ void ReduceTest::TestPolicy() { void ReduceTest::StressTest() { using embb::algorithms::Reduce; - using embb::mtapi::ExecutionPolicy; + using embb::tasks::ExecutionPolicy; using embb::algorithms::Identity; - size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() *10; + size_t count = embb::tasks::Node::GetInstance().GetCoreCount() * 10; std::vector large_vector(count); mtapi_int32_t expected = 0; for (size_t i = 0; i < count; i++) { diff --git a/algorithms_cpp/test/scan_test.cc b/algorithms_cpp/test/scan_test.cc index e902a81..61f85f5 100644 --- a/algorithms_cpp/test/scan_test.cc +++ b/algorithms_cpp/test/scan_test.cc @@ -228,7 +228,7 @@ void ScanTest::TestRanges() { void ScanTest::TestBlockSizes() { using embb::algorithms::Scan; - using embb::mtapi::ExecutionPolicy; + using embb::tasks::ExecutionPolicy; using embb::algorithms::Identity; size_t count = 4; std::vector init(count); @@ -253,7 +253,7 @@ void ScanTest::TestBlockSizes() { void ScanTest::TestPolicy() { using embb::algorithms::Scan; - using embb::mtapi::ExecutionPolicy; + using embb::tasks::ExecutionPolicy; using embb::algorithms::Identity; size_t count = 4; std::vector init(count); @@ -324,8 +324,8 @@ void ScanTest::TestPolicy() { void ScanTest::StressTest() { using embb::algorithms::Scan; using embb::algorithms::Identity; - using embb::mtapi::ExecutionPolicy; - size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() *10; + using embb::tasks::ExecutionPolicy; + size_t count = embb::tasks::Node::GetInstance().GetCoreCount() *10; std::vector large_vector(count); std::vector large_vector_output(count); for (size_t i = 0; i < count; i++) { diff --git a/algorithms_cpp/test/zip_iterator_test.cc b/algorithms_cpp/test/zip_iterator_test.cc index 52c1f59..d345206 100644 --- a/algorithms_cpp/test/zip_iterator_test.cc +++ b/algorithms_cpp/test/zip_iterator_test.cc @@ -136,7 +136,7 @@ void ZipIteratorTest::TestZipScan() { Scan(embb::algorithms::Zip(vectorA.begin(), vectorB.begin()), embb::algorithms::Zip(vectorA.end(), vectorB.end()), vectorOut.begin(), 0, std::plus(), DotProductFunctor(), - embb::mtapi::ExecutionPolicy(), 0); + embb::tasks::ExecutionPolicy(), 0); long sum = 0; for (size_t i = 0; i < kCountSize; i++) { diff --git a/base_cpp/include/embb/base/core_set.h b/base_cpp/include/embb/base/core_set.h index 74c1360..9682c0d 100644 --- a/base_cpp/include/embb/base/core_set.h +++ b/base_cpp/include/embb/base/core_set.h @@ -184,6 +184,13 @@ class CoreSet { /** [IN] Core set on right-hand side of union operation */ ); + /** + * Provides access to internal representation to use it with C API. + * + * \return A reference to the internal embb_core_set_t structure. + */ + embb_core_set_t const & GetInternal() const { return rep_; } + private: /** * Internal representation of core set. diff --git a/base_cpp/include/embb/base/duration.h b/base_cpp/include/embb/base/duration.h index 5c6d2e8..4dbc4e4 100644 --- a/base_cpp/include/embb/base/duration.h +++ b/base_cpp/include/embb/base/duration.h @@ -46,6 +46,9 @@ namespace base { * Represents a relative time duration for a given tick type. * * \notthreadsafe + * \note The typedefs DurationSeconds, DurationMilliseconds, + * DurationMicroseconds, and DurationNanoseconds provide directly usable + * duration types. * \tparam Tick Possible tick types are Seconds, Milliseconds, Microseconds, * Nanoseconds * \ingroup CPP_BASE_TIMEDURATION @@ -271,6 +274,8 @@ Duration operator+( return Duration(lhs.Count() + rhs.Count()); } +namespace internal { + /** * Base class for ticks. */ @@ -517,6 +522,33 @@ class Nanoseconds : public Tick { static unsigned long long Max(); }; +} // namespace internal + +/** + * Duration with seconds tick. + * + * \ingroup CPP_BASE_TIMEDURATION + */ +typedef Duration DurationSeconds; +/** + * Duration with milliseconds tick. + * + * \ingroup CPP_BASE_TIMEDURATION + */ +typedef Duration DurationMilliseconds; +/** + * Duration with microseconds tick. + * + * \ingroup CPP_BASE_TIMEDURATION + */ +typedef Duration DurationMicroseconds; +/** + * Duration with nanoseconds tick. + * + * \ingroup CPP_BASE_TIMEDURATION + */ +typedef Duration DurationNanoseconds; + } // namespace base } // namespace embb diff --git a/base_cpp/src/duration.cc b/base_cpp/src/duration.cc index 38ed5d1..efc493f 100644 --- a/base_cpp/src/duration.cc +++ b/base_cpp/src/duration.cc @@ -35,7 +35,7 @@ namespace embb { namespace base { -void Tick::CheckExceptions(int status, const char* msg) { +void internal::Tick::CheckExceptions(int status, const char* msg) { switch (status) { case EMBB_SUCCESS: return; case EMBB_OVERFLOW: EMBB_THROW(OverflowException, msg); @@ -44,16 +44,18 @@ void Tick::CheckExceptions(int status, const char* msg) { } } -int Seconds::Set(embb_duration_t& duration, unsigned long long ticks) { +int internal::Seconds::Set(embb_duration_t& duration, + unsigned long long ticks) { return embb_duration_set_seconds(&duration, ticks); } -void Seconds::SetAndCheck(embb_duration_t& duration, unsigned long long ticks) { +void internal::Seconds::SetAndCheck(embb_duration_t& duration, + unsigned long long ticks) { int status = Set(duration, ticks); CheckExceptions(status, "Setting duration from seconds"); } -unsigned long long Seconds::Get(const embb_duration_t& duration) { +unsigned long long internal::Seconds::Get(const embb_duration_t& duration) { unsigned long long ticks = 0; int status = embb_duration_as_seconds(&duration, &ticks); assert(status == EMBB_SUCCESS); @@ -61,25 +63,27 @@ unsigned long long Seconds::Get(const embb_duration_t& duration) { return ticks; } -unsigned long long Seconds::Min() { +unsigned long long internal::Seconds::Min() { return 1; } -unsigned long long Seconds::Max() { +unsigned long long internal::Seconds::Max() { return EMBB_DURATION_MAX_SECONDS; } -int Milliseconds::Set(embb_duration_t& duration, unsigned long long ticks) { +int internal::Milliseconds::Set(embb_duration_t& duration, + unsigned long long ticks) { return embb_duration_set_milliseconds(&duration, ticks); } -void Milliseconds::SetAndCheck( +void internal::Milliseconds::SetAndCheck( embb_duration_t& duration, unsigned long long ticks) { int status = Set(duration, ticks); CheckExceptions(status, "Setting duration from milliseconds"); } -unsigned long long Milliseconds::Get(const embb_duration_t& duration) { +unsigned long long internal::Milliseconds::Get( + const embb_duration_t& duration) { unsigned long long ticks = 0; int status = embb_duration_as_milliseconds(&duration, &ticks); assert(status == EMBB_SUCCESS); @@ -87,7 +91,7 @@ unsigned long long Milliseconds::Get(const embb_duration_t& duration) { return ticks; } -unsigned long long Milliseconds::Min() { +unsigned long long internal::Milliseconds::Min() { #if EMBB_DURATION_MIN_NANOSECONDS > 1000000 assert(EMBB_DURATION_MIN_NANOSECONDS % 1000000 == 0); return EMBB_DURATION_MIN_NANOSECONDS / 1000000; @@ -95,7 +99,7 @@ unsigned long long Milliseconds::Min() { return 1; } -unsigned long long Milliseconds::Max() { +unsigned long long internal::Milliseconds::Max() { #if EMBB_DURATION_MAX_SECONDS < ULLONG_MAX / 1000 return ULLONG_MAX; #else @@ -103,17 +107,19 @@ unsigned long long Milliseconds::Max() { #endif } -int Microseconds::Set(embb_duration_t& duration, unsigned long long ticks) { +int internal::Microseconds::Set(embb_duration_t& duration, + unsigned long long ticks) { return embb_duration_set_microseconds(&duration, ticks); } -void Microseconds::SetAndCheck( +void internal::Microseconds::SetAndCheck( embb_duration_t& duration, unsigned long long ticks) { int status = Set(duration, ticks); CheckExceptions(status, "Setting duration from microseconds"); } -unsigned long long Microseconds::Get(const embb_duration_t& duration) { +unsigned long long internal::Microseconds::Get( + const embb_duration_t& duration) { unsigned long long ticks = 0; int status = embb_duration_as_microseconds(&duration, &ticks); @@ -123,7 +129,7 @@ unsigned long long Microseconds::Get(const embb_duration_t& duration) { return ticks; } -unsigned long long Microseconds::Min() { +unsigned long long internal::Microseconds::Min() { #if EMBB_DURATION_MIN_NANOSECONDS > 1000 assert(EMBB_DURATION_MIN_NANOSECONDS % 1000 == 0); return EMBB_DURATION_MIN_NANOSECONDS / 1000; @@ -131,7 +137,7 @@ unsigned long long Microseconds::Min() { return 1; } -unsigned long long Microseconds::Max() { +unsigned long long internal::Microseconds::Max() { #if EMBB_DURATION_MAX_SECONDS < ULLONG_MAX / 1000000 return ULLONG_MAX; #else @@ -139,17 +145,18 @@ unsigned long long Microseconds::Max() { #endif } -int Nanoseconds::Set(embb_duration_t& duration, unsigned long long ticks) { +int internal::Nanoseconds::Set(embb_duration_t& duration, + unsigned long long ticks) { return embb_duration_set_nanoseconds(&duration, ticks); } -void Nanoseconds::SetAndCheck( +void internal::Nanoseconds::SetAndCheck( embb_duration_t& duration, unsigned long long ticks) { int status = Set(duration, ticks); CheckExceptions(status, "Setting duration from microseconds"); } -unsigned long long Nanoseconds::Get(const embb_duration_t& duration) { +unsigned long long internal::Nanoseconds::Get(const embb_duration_t& duration) { unsigned long long ticks = 0; int status = embb_duration_as_nanoseconds(&duration, &ticks); assert(status == EMBB_SUCCESS); @@ -157,11 +164,11 @@ unsigned long long Nanoseconds::Get(const embb_duration_t& duration) { return ticks; } -unsigned long long Nanoseconds::Min() { +unsigned long long internal::Nanoseconds::Min() { return EMBB_DURATION_MIN_NANOSECONDS; } -unsigned long long Nanoseconds::Max() { +unsigned long long internal::Nanoseconds::Max() { #if EMBB_DURATION_MAX_SECONDS < ULLONG_MAX / 1000000000 return ULLONG_MAX; #else diff --git a/base_cpp/test/condition_var_test.cc b/base_cpp/test/condition_var_test.cc index fd7a3e6..a023cf0 100644 --- a/base_cpp/test/condition_var_test.cc +++ b/base_cpp/test/condition_var_test.cc @@ -63,15 +63,15 @@ void ConditionVarTest::TestTimedWaitTimeouts() { PT_EXPECT_EQ(success, false); // Wait for a future timepoint - success = cond.WaitUntil(lock, Time(Duration(1))); + success = cond.WaitUntil(lock, Time(DurationMilliseconds(1))); PT_EXPECT_EQ(success, false); // Wait for a zero duration - success = cond.WaitFor(lock, Duration()); + success = cond.WaitFor(lock, DurationMilliseconds()); PT_EXPECT_EQ(success, false); // Wait for some duration - success = cond.WaitFor(lock, Duration(1)); + success = cond.WaitFor(lock, DurationMilliseconds(1)); PT_EXPECT_EQ(success, false); } @@ -96,14 +96,14 @@ void ConditionVarTest::TestNotify() { cond_notify_.NotifyOne(); - cond_wait_.WaitUntil(lock_wait, Time(Duration(1))); + cond_wait_.WaitUntil(lock_wait, Time(DurationMilliseconds(1))); while (embb_counter_get(&counter_) == 0) {} // If hangs here signal has not succeeded PT_ASSERT_EQ_MSG(embb_counter_get(&counter_), static_cast(1), "Only 1 thread notified"); cond_notify_.NotifyAll(); - cond_wait_.WaitUntil(lock_wait, Time(Duration(2))); + cond_wait_.WaitUntil(lock_wait, Time(DurationMilliseconds(2))); while (embb_counter_get(&counter_) != static_cast(num_threads_-1)) diff --git a/base_cpp/test/duration_test.cc b/base_cpp/test/duration_test.cc index c7da972..fb70d22 100644 --- a/base_cpp/test/duration_test.cc +++ b/base_cpp/test/duration_test.cc @@ -31,10 +31,13 @@ namespace base { namespace test { DurationTest::DurationTest() { - CreateUnit("Seconds").Add(&DurationTest::Test, this); - CreateUnit("Milliseconds").Add(&DurationTest::Test, this); - CreateUnit("Microseconds").Add(&DurationTest::Test, this); - CreateUnit("Nanoseconds").Add(&DurationTest::Test, this); + CreateUnit("Seconds").Add(&DurationTest::Test, this); + CreateUnit("Milliseconds").Add(&DurationTest::Test, + this); + CreateUnit("Microseconds").Add(&DurationTest::Test, + this); + CreateUnit("Nanoseconds").Add(&DurationTest::Test, + this); } } // namespace test diff --git a/dataflow_cpp/CMakeLists.txt b/dataflow_cpp/CMakeLists.txt index 0ad76a0..657d4bd 100644 --- a/dataflow_cpp/CMakeLists.txt +++ b/dataflow_cpp/CMakeLists.txt @@ -17,16 +17,16 @@ include_directories(${EMBB_DATAFLOW_CPP_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include ${CMAKE_CURRENT_BINARY_DIR}/../base_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_c/include - ${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_cpp/include - ${CMAKE_CURRENT_BINARY_DIR}/../mtapi_cpp/include) + ${CMAKE_CURRENT_SOURCE_DIR}/../tasks_cpp/include + ${CMAKE_CURRENT_BINARY_DIR}/../tasks_cpp/include) add_library (embb_dataflow_cpp ${EMBB_DATAFLOW_CPP_SOURCES} ${EMBB_DATAFLOW_CPP_HEADERS}) -target_link_libraries(embb_dataflow_cpp embb_mtapi_cpp embb_base_cpp embb_mtapi_c embb_base_c) +target_link_libraries(embb_dataflow_cpp embb_tasks_cpp embb_base_cpp embb_mtapi_c embb_base_c) if (BUILD_TESTS STREQUAL ON) include_directories(${CMAKE_CURRENT_BINARY_DIR}/../partest/include) add_executable (embb_dataflow_cpp_test ${EMBB_DATAFLOW_CPP_TEST_SOURCES}) - target_link_libraries(embb_dataflow_cpp_test embb_mtapi_cpp embb_mtapi_c partest + target_link_libraries(embb_dataflow_cpp_test embb_dataflow_cpp embb_tasks_cpp embb_mtapi_c partest embb_base_cpp embb_base_c ${compiler_libs}) CopyBin(BIN embb_dataflow_cpp_test DEST ${local_install_dir}) endif() diff --git a/dataflow_cpp/include/embb/dataflow/internal/action.h b/dataflow_cpp/include/embb/dataflow/internal/action.h index d2d766b..2b85680 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/action.h +++ b/dataflow_cpp/include/embb/dataflow/internal/action.h @@ -29,7 +29,7 @@ #include -#include +#include #include @@ -48,7 +48,7 @@ class Action { pending_ = 0; } - void RunMTAPI(embb::mtapi::TaskContext & /*context*/) { + void RunMTAPI(embb::tasks::TaskContext & /*context*/) { pending_ = 1; node_->Run(clock_); pending_ = 0; diff --git a/dataflow_cpp/include/embb/dataflow/internal/inputs.h b/dataflow_cpp/include/embb/dataflow/internal/inputs.h index afcb011..4f4430a 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/inputs.h +++ b/dataflow_cpp/include/embb/dataflow/internal/inputs.h @@ -27,6 +27,7 @@ #ifndef EMBB_DATAFLOW_INTERNAL_INPUTS_H_ #define EMBB_DATAFLOW_INTERNAL_INPUTS_H_ +#include #include #include diff --git a/dataflow_cpp/include/embb/dataflow/internal/node.h b/dataflow_cpp/include/embb/dataflow/internal/node.h index daf80b3..122750e 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/node.h +++ b/dataflow_cpp/include/embb/dataflow/internal/node.h @@ -28,7 +28,7 @@ #define EMBB_DATAFLOW_INTERNAL_NODE_H_ #include - +#include #include namespace embb { @@ -50,6 +50,9 @@ class Node { protected: Scheduler * sched_; + static int next_process_id_; + + static int GetNextProcessID() { return next_process_id_++; } }; } // namespace internal diff --git a/dataflow_cpp/include/embb/dataflow/internal/process.h b/dataflow_cpp/include/embb/dataflow/internal/process.h index 1765db0..581f162 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/process.h +++ b/dataflow_cpp/include/embb/dataflow/internal/process.h @@ -56,6 +56,13 @@ class Process< Slices, Serial, Inputs, explicit Process(FunctionType function) : executor_(function) { next_clock_ = 0; + queued_clock_ = 0; + bool ordered = Serial; + if (ordered) { + queue_id_ = GetNextProcessID(); + } else { + queue_id_ = 0; + } inputs_.SetListener(this); } @@ -95,21 +102,39 @@ class Process< Slices, Serial, Inputs, } virtual void OnClock(int clock) { - if (!inputs_.AreAtClock(clock)) + if (!inputs_.AreAtClock(clock)) { EMBB_THROW(embb::base::ErrorException, "Some inputs are not at expected clock.") + } bool ordered = Serial; if (ordered) { - lock_.Lock(); - for (int ii = next_clock_; ii < next_clock_ + Slices; ii++) { - if (!inputs_.AreAtClock(ii)) { - break; + bool retry = true; + while (retry) { + int clk = next_clock_; + int clk_end = clk + Slices; + int clk_res = clk; + for (int ii = clk; ii < clk_end; ii++) { + if (!inputs_.AreAtClock(ii)) { + break; + } + clk_res++; + } + if (clk_res > clk) { + if (next_clock_.CompareAndSwap(clk, clk_res)) { + while (queued_clock_.Load() < clk) continue; + for (int ii = clk; ii < clk_res; ii++) { + const int idx = ii % Slices; + action_[idx] = Action(this, ii); + sched_->Enqueue(queue_id_, action_[idx]); + } + queued_clock_.Store(clk_res); + retry = false; + } + } else { + retry = false; } - next_clock_ = ii + 1; - Run(ii); } - lock_.Unlock(); } else { const int idx = clock % Slices; action_[idx] = Action(this, clock); @@ -121,9 +146,10 @@ class Process< Slices, Serial, Inputs, InputsType inputs_; OutputsType outputs_; ExecutorType executor_; - int next_clock_; Action action_[Slices]; - SpinLock lock_; + embb::base::Atomic next_clock_; + embb::base::Atomic queued_clock_; + int queue_id_; }; } // namespace internal diff --git a/dataflow_cpp/include/embb/dataflow/internal/scheduler.h b/dataflow_cpp/include/embb/dataflow/internal/scheduler.h index 811c7dd..5770217 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/scheduler.h +++ b/dataflow_cpp/include/embb/dataflow/internal/scheduler.h @@ -38,6 +38,7 @@ class Scheduler { Scheduler() {} virtual ~Scheduler() {} virtual void Spawn(Action & action) = 0; + virtual void Enqueue(int process_id, Action & action) = 0; virtual void WaitForSlice(int slice) = 0; }; diff --git a/dataflow_cpp/include/embb/dataflow/internal/scheduler_mtapi.h b/dataflow_cpp/include/embb/dataflow/internal/scheduler_mtapi.h index 7e72812..8f1271e 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/scheduler_mtapi.h +++ b/dataflow_cpp/include/embb/dataflow/internal/scheduler_mtapi.h @@ -29,7 +29,7 @@ #include #include -#include +#include #include namespace embb { @@ -40,29 +40,51 @@ template class SchedulerMTAPI : public Scheduler { public: SchedulerMTAPI() { - embb::mtapi::Node & node = embb::mtapi::Node::GetInstance(); + embb::tasks::Node & node = embb::tasks::Node::GetInstance(); for (int ii = 0; ii < Slices; ii++) { - embb::mtapi::Group & group = node.CreateGroup(); + embb::tasks::Group & group = node.CreateGroup(); group_[ii] = &group; } + + queue_count_ = static_cast(node.GetWorkerThreadCount()); + queue_ = reinterpret_cast( + embb::base::Allocation::Allocate( + sizeof(embb::tasks::Queue*)*queue_count_)); + + for (int ii = 0; ii < queue_count_; ii++) { + embb::tasks::Queue & queue = node.CreateQueue(0, true); + queue_[ii] = &queue; + } } virtual ~SchedulerMTAPI() { - embb::mtapi::Node & node = embb::mtapi::Node::GetInstance(); + embb::tasks::Node & node = embb::tasks::Node::GetInstance(); for (int ii = 0; ii < Slices; ii++) { group_[ii]->WaitAll(MTAPI_INFINITE); node.DestroyGroup(*group_[ii]); } + for (int ii = 0; ii < queue_count_; ii++) { + node.DestroyQueue(*queue_[ii]); + } + embb::base::Allocation::Free(queue_); } virtual void Spawn(Action & action) { const int idx = action.GetClock() % Slices; group_[idx]->Spawn(embb::base::MakeFunction(action, &Action::RunMTAPI)); } + virtual void Enqueue(int process_id, Action & action) { + const int idx = action.GetClock() % Slices; + const int queue_id = process_id % queue_count_; + queue_[queue_id]->Spawn(group_[idx], + embb::base::MakeFunction(action, &Action::RunMTAPI)); + } virtual void WaitForSlice(int slice) { group_[slice]->WaitAll(MTAPI_INFINITE); } private: - embb::mtapi::Group * group_[Slices]; + embb::tasks::Group * group_[Slices]; + embb::tasks::Queue ** queue_; + int queue_count_; }; } // namespace internal diff --git a/dataflow_cpp/include/embb/dataflow/internal/scheduler_sequential.h b/dataflow_cpp/include/embb/dataflow/internal/scheduler_sequential.h index a553548..919a3a3 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/scheduler_sequential.h +++ b/dataflow_cpp/include/embb/dataflow/internal/scheduler_sequential.h @@ -41,6 +41,9 @@ class SchedulerSequential : public Scheduler { virtual void Spawn(Action & action) { action.RunSequential(); } + virtual void Enqueue(int, Action & action) { + action.RunSequential(); + } virtual void WaitForSlice(int /*slice*/) {} }; diff --git a/dataflow_cpp/include/embb/dataflow/internal/signal.h b/dataflow_cpp/include/embb/dataflow/internal/signal.h index 951e75a..dde39cc 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/signal.h +++ b/dataflow_cpp/include/embb/dataflow/internal/signal.h @@ -27,7 +27,7 @@ #ifndef EMBB_DATAFLOW_INTERNAL_SIGNAL_H_ #define EMBB_DATAFLOW_INTERNAL_SIGNAL_H_ -#include +#include namespace embb { namespace dataflow { @@ -42,27 +42,23 @@ class Signal { Signal(Signal const & other) : blank_(other.blank_), value_(other.value_), clock_(other.clock_) {} void operator = (Signal const & rhs) { - lock_.Lock(); blank_ = rhs.blank_; value_ = rhs.value_; clock_ = rhs.clock_; - lock_.Unlock(); + embb_atomic_memory_barrier(); } int GetClock() const { return clock_; } bool IsBlank() const { return blank_; } Type const & GetValue() const { return value_; } void Clear() { - lock_.Lock(); blank_ = true; clock_ = -1; - lock_.Unlock(); } private: bool blank_; Type value_; int clock_; - SpinLock lock_; }; } // namespace internal diff --git a/dataflow_cpp/include/embb/dataflow/internal/sink.h b/dataflow_cpp/include/embb/dataflow/internal/sink.h index 7066995..b0b4063 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/sink.h +++ b/dataflow_cpp/include/embb/dataflow/internal/sink.h @@ -52,6 +52,8 @@ class Sink< Slices, Inputs > explicit Sink(FunctionType function) : executor_(function) { next_clock_ = 0; + queued_clock_ = 0; + queue_id_ = GetNextProcessID(); inputs_.SetListener(this); } @@ -80,32 +82,47 @@ class Sink< Slices, Inputs > } virtual void OnClock(int clock) { - TrySpawn(clock); + if (!inputs_.AreAtClock(clock)) { + EMBB_THROW(embb::base::ErrorException, + "Some inputs are not at expected clock.") + } + + bool retry = true; + while (retry) { + int clk = next_clock_; + int clk_end = clk + Slices; + int clk_res = clk; + for (int ii = clk; ii < clk_end; ii++) { + if (!inputs_.AreAtClock(ii)) { + break; + } + clk_res++; + } + if (clk_res > clk) { + if (next_clock_.CompareAndSwap(clk, clk_res)) { + while (queued_clock_.Load() < clk) continue; + for (int ii = clk; ii < clk_res; ii++) { + const int idx = ii % Slices; + action_[idx] = Action(this, ii); + sched_->Enqueue(queue_id_, action_[idx]); + } + queued_clock_.Store(clk_res); + retry = false; + } + } else { + retry = false; + } + } } private: InputsType inputs_; ExecutorType executor_; - int next_clock_; Action action_[Slices]; ClockListener * listener_; - SpinLock lock_; - - void TrySpawn(int clock) { - if (!inputs_.AreAtClock(clock)) - EMBB_THROW(embb::base::ErrorException, - "Some inputs are not at expected clock.") - - lock_.Lock(); - for (int ii = next_clock_; ii < next_clock_ + Slices; ii++) { - if (!inputs_.AreAtClock(ii)) { - break; - } - next_clock_ = ii + 1; - Run(ii); - } - lock_.Unlock(); - } + embb::base::Atomic next_clock_; + embb::base::Atomic queued_clock_; + int queue_id_; }; } // namespace internal diff --git a/dataflow_cpp/include/embb/dataflow/internal/source.h b/dataflow_cpp/include/embb/dataflow/internal/source.h index 48f5772..232a50e 100644 --- a/dataflow_cpp/include/embb/dataflow/internal/source.h +++ b/dataflow_cpp/include/embb/dataflow/internal/source.h @@ -27,13 +27,9 @@ #ifndef EMBB_DATAFLOW_INTERNAL_SOURCE_H_ #define EMBB_DATAFLOW_INTERNAL_SOURCE_H_ -#include -#include - #include #include #include -#include namespace embb { namespace dataflow { @@ -53,7 +49,6 @@ class Source< Slices, Outputs > explicit Source(FunctionType function) : executor_(function), not_done_(true) { - next_clock_ = 0; } virtual bool HasOutputs() const { @@ -62,7 +57,6 @@ class Source< Slices, Outputs > virtual void Run(int clock) { not_done_ = executor_.Execute(clock, outputs_); - next_clock_++; } virtual bool Start(int clock) { @@ -89,9 +83,7 @@ class Source< Slices, Outputs > private: OutputsType outputs_; ExecutorType executor_; - Action action_[Slices]; volatile bool not_done_; - embb::base::Atomic next_clock_; }; } // namespace internal diff --git a/dataflow_cpp/src/dummy.cc b/dataflow_cpp/src/node.cc similarity index 96% rename from dataflow_cpp/src/dummy.cc rename to dataflow_cpp/src/node.cc index e95756a..55b91c7 100644 --- a/dataflow_cpp/src/dummy.cc +++ b/dataflow_cpp/src/node.cc @@ -24,3 +24,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include + +int embb::dataflow::internal::Node::next_process_id_ = 0; diff --git a/dataflow_cpp/test/dataflow_cpp_test_simple.cc b/dataflow_cpp/test/dataflow_cpp_test_simple.cc index 3fe9272..c63a57e 100644 --- a/dataflow_cpp/test/dataflow_cpp_test_simple.cc +++ b/dataflow_cpp/test/dataflow_cpp_test_simple.cc @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include @@ -60,7 +60,7 @@ bool sourceFunc(int & out) { source_array[source_counter] = out; source_counter++; - return source_counter < 12; + return source_counter < TEST_COUNT; } embb::base::Atomic pred_counter; @@ -143,7 +143,7 @@ SimpleTest::SimpleTest() { } void SimpleTest::TestBasic() { - embb::mtapi::Node::Initialize(1, 1); + embb::tasks::Node::Initialize(1, 1); for (int ii = 0; ii < 10000; ii++) { ArraySink asink; @@ -203,7 +203,7 @@ void SimpleTest::TestBasic() { PT_EXPECT(asink.Check()); } - embb::mtapi::Node::Finalize(); + embb::tasks::Node::Finalize(); PT_EXPECT(embb_get_bytes_allocated() == 0); } diff --git a/doc/examples/CMakeLists.txt b/doc/examples/CMakeLists.txt index 9393c95..7d4e4c9 100644 --- a/doc/examples/CMakeLists.txt +++ b/doc/examples/CMakeLists.txt @@ -11,7 +11,8 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/../../base_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_c/include ${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_cpp/include - ${CMAKE_CURRENT_BINARY_DIR}/../../mtapi_cpp/include + ${CMAKE_CURRENT_SOURCE_DIR}/../../tasks_cpp/include + ${CMAKE_CURRENT_BINARY_DIR}/../../tasks_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../../containers_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../../algorithms_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../../dataflow_cpp/include @@ -22,6 +23,6 @@ if(CMAKE_COMPILER_IS_GNUCXX) endif() add_executable(examples ${EXAMPLES_SOURCES}) -target_link_libraries(examples embb_dataflow_cpp embb_algorithms_cpp embb_mtapi_cpp +target_link_libraries(examples embb_dataflow_cpp embb_algorithms_cpp embb_tasks_cpp embb_mtapi_cpp embb_mtapi_c embb_base_cpp embb_base_c embb_containers_cpp ${compiler_libs}) CopyBin(BIN examples DEST ${local_install_dir}) diff --git a/doc/examples/main.cc b/doc/examples/main.cc index 08b2df6..f231db0 100644 --- a/doc/examples/main.cc +++ b/doc/examples/main.cc @@ -25,9 +25,11 @@ */ #include +#include void RunMTAPI_C(); void RunMTAPI_CPP(); +void RunTasks(); void RunDataflowLinear(); void RunDataflowNonLinear(); void RunSTLForEach(); @@ -45,6 +47,8 @@ void RunQueueExamples(); * Runs all examples and tests their correctness. */ int main() { + embb_thread_set_max_count(1024); + std::cout << "Running examples ..." << std::endl; std::cout << "RunMTAPI_C() ..." << std::endl; @@ -55,6 +59,10 @@ int main() { RunMTAPI_CPP(); std::cout << "RunMTAPI_CPP() ... done" << std::endl; + std::cout << "RunTasks() ..." << std::endl; + RunTasks(); + std::cout << "RunTasks() ... done" << std::endl; + std::cout << "RunDataflowLinear() ..." << std::endl; RunDataflowLinear(); std::cout << "RunDataflowLinear() ... done" << std::endl; diff --git a/doc/examples/mtapi/mtapi_c_domain_node_id-snippet.h b/doc/examples/mtapi/mtapi_c_domain_node_id-snippet.h index 9af8d70..b1850d0 100644 --- a/doc/examples/mtapi/mtapi_c_domain_node_id-snippet.h +++ b/doc/examples/mtapi/mtapi_c_domain_node_id-snippet.h @@ -2,4 +2,4 @@ #define THIS_NODE_ID 1 #define FIBONACCI_JOB 1 -mtapi_job_hndl_t fibonacciJob; +static mtapi_job_hndl_t fibonacciJob; diff --git a/doc/examples/mtapi/mtapi_cpp-fragmented.cc b/doc/examples/mtapi/mtapi_cpp-fragmented.cc index 700d758..d211fd9 100644 --- a/doc/examples/mtapi/mtapi_cpp-fragmented.cc +++ b/doc/examples/mtapi/mtapi_cpp-fragmented.cc @@ -29,9 +29,12 @@ #include #include "mtapi/mtapi_check_status-snippet.h" +#include "mtapi/mtapi_cpp_domain_node_id-snippet.h" static -#include "mtapi/mtapi_cpp_action_signature-snippet.h" +#include "mtapi/mtapi_c_action_signature-snippet.h" +#include "mtapi/mtapi_c_validate_arguments-snippet.h" +#include "mtapi/mtapi_c_validate_result_buffer-snippet.h" /* get the node instance */ #include "mtapi/mtapi_cpp_get_node-snippet.h" /* calculate */ @@ -39,26 +42,26 @@ static /* first recursive call spawned as task (x = fib(n - 1);) */ #include "mtapi/mtapi_cpp_calc_task-snippet.h" /* second recursive call can be called directly (y = fib(n - 2);) */ -#include "mtapi/mtapi_cpp_calc_direct-snippet.h" +#include "mtapi/mtapi_c_calc_direct-snippet.h" /* wait for completion */ #include "mtapi/mtapi_cpp_wait_task-snippet.h" - /* add the two preceeding numbers */ + /* add the two preceding numbers */ #include "mtapi/mtapi_write_back-snippet.h" static int fibonacci(int n) { - /* get the node instance, the node is initialized automatically */ - embb::mtapi::Node& node = embb::mtapi::Node::GetInstance(); +#include "mtapi/mtapi_cpp_initialize-snippet.h" +#include "mtapi/mtapi_cpp_register_action-snippet.h" +#include "mtapi/mtapi_cpp_get_node-snippet.h" /* start calculation */ #include "mtapi/mtapi_cpp_start_task-snippet.h" /* wait for task completion */ mtapi_status_t status = task.Wait(MTAPI_INFINITE); MTAPI_CHECK_STATUS(status); - +#include "mtapi/mtapi_cpp_finalize-snippet.h" return result; } void RunMTAPI_CPP() { - int result = fibonacci(6); - std::cout << "result: " << result << std::endl; +#include "mtapi/mtapi_cpp_main-snippet.h" } diff --git a/doc/examples/mtapi/mtapi_cpp_calc_task-snippet.h b/doc/examples/mtapi/mtapi_cpp_calc_task-snippet.h index 4362f38..aad4e1e 100644 --- a/doc/examples/mtapi/mtapi_cpp_calc_task-snippet.h +++ b/doc/examples/mtapi/mtapi_cpp_calc_task-snippet.h @@ -1,10 +1,3 @@ int a = n - 1; int x; - embb::mtapi::Task task = node.Spawn( - embb::base::Bind( - embb::base::MakeFunction(fibonacciActionFunction), - a, /* argument */ - &x, /* result */ - embb::base::Placeholder::_1 - ) - ); + embb::mtapi::Task task = node.Start(fibonacciJob, &a, &x); diff --git a/doc/examples/mtapi/mtapi_cpp_domain_node_id-snippet.h b/doc/examples/mtapi/mtapi_cpp_domain_node_id-snippet.h new file mode 100644 index 0000000..747609d --- /dev/null +++ b/doc/examples/mtapi/mtapi_cpp_domain_node_id-snippet.h @@ -0,0 +1,5 @@ +#define THIS_DOMAIN_ID 1 +#define THIS_NODE_ID 1 + +#define FIBONACCI_JOB 1 +static embb::mtapi::Job fibonacciJob; diff --git a/doc/examples/mtapi/mtapi_cpp_finalize-snippet.h b/doc/examples/mtapi/mtapi_cpp_finalize-snippet.h new file mode 100644 index 0000000..5061b36 --- /dev/null +++ b/doc/examples/mtapi/mtapi_cpp_finalize-snippet.h @@ -0,0 +1,2 @@ + /* finalize the node */ + embb::mtapi::Node::Finalize(); diff --git a/doc/examples/mtapi/mtapi_cpp_initialize-snippet.h b/doc/examples/mtapi/mtapi_cpp_initialize-snippet.h new file mode 100644 index 0000000..859b55a --- /dev/null +++ b/doc/examples/mtapi/mtapi_cpp_initialize-snippet.h @@ -0,0 +1,2 @@ + /* initialize the node with default attributes */ + embb::mtapi::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID); diff --git a/doc/examples/mtapi/mtapi_cpp_main-snippet.h b/doc/examples/mtapi/mtapi_cpp_main-snippet.h new file mode 100644 index 0000000..582850a --- /dev/null +++ b/doc/examples/mtapi/mtapi_cpp_main-snippet.h @@ -0,0 +1,6 @@ + EMBB_TRY { + int result = fibonacci(6); + std::cout << "result: " << result << std::endl; + } EMBB_CATCH(embb::mtapi::StatusException &) { + std::cout << "MTAPI error occured." << std::endl; + } diff --git a/doc/examples/mtapi/mtapi_cpp_register_action-snippet.h b/doc/examples/mtapi/mtapi_cpp_register_action-snippet.h new file mode 100644 index 0000000..beeea5a --- /dev/null +++ b/doc/examples/mtapi/mtapi_cpp_register_action-snippet.h @@ -0,0 +1,9 @@ + /* create action */ + embb::mtapi::Action fibonacciAction( + FIBONACCI_JOB, /* action ID, defined by the + application */ + (fibonacciActionFunction) /* action function */ + ); + + /* get job */ + fibonacciJob = embb::mtapi::Job(FIBONACCI_JOB, THIS_DOMAIN_ID); diff --git a/doc/examples/mtapi/mtapi_cpp_start_task-snippet.h b/doc/examples/mtapi/mtapi_cpp_start_task-snippet.h index 7dddbb3..cf1f908 100644 --- a/doc/examples/mtapi/mtapi_cpp_start_task-snippet.h +++ b/doc/examples/mtapi/mtapi_cpp_start_task-snippet.h @@ -1,9 +1,2 @@ int result; - embb::mtapi::Task task = node.Spawn( - embb::base::Bind( - embb::base::MakeFunction(fibonacciActionFunction), - n, - &result, - embb::base::Placeholder::_1 - ) - ); + embb::mtapi::Task task = node.Start(fibonacciJob, &n, &result); diff --git a/doc/examples/mtapi/mtapi_cpp_wait_task-snippet.h b/doc/examples/mtapi/mtapi_cpp_wait_task-snippet.h index 21637fd..9f1f9d7 100644 --- a/doc/examples/mtapi/mtapi_cpp_wait_task-snippet.h +++ b/doc/examples/mtapi/mtapi_cpp_wait_task-snippet.h @@ -1,2 +1,5 @@ mtapi_status_t status = task.Wait(MTAPI_INFINITE); - MTAPI_CHECK_STATUS(status); + if (status != MTAPI_SUCCESS) { + printf("task failed with error: %d\n\n", status); + exit(status); + } diff --git a/doc/examples/tasks/tasks_cpp-fragmented.cc b/doc/examples/tasks/tasks_cpp-fragmented.cc new file mode 100644 index 0000000..4e13885 --- /dev/null +++ b/doc/examples/tasks/tasks_cpp-fragmented.cc @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include + +#include "mtapi/mtapi_check_status-snippet.h" + +static +#include "tasks/tasks_cpp_action_signature-snippet.h" + /* get the node instance */ +#include "tasks/tasks_cpp_get_node-snippet.h" + /* calculate */ +#include "mtapi/mtapi_terminating_condition-snippet.h" + /* first recursive call spawned as task (x = fib(n - 1);) */ +#include "tasks/tasks_cpp_calc_task-snippet.h" + /* second recursive call can be called directly (y = fib(n - 2);) */ +#include "tasks/tasks_cpp_calc_direct-snippet.h" + /* wait for completion */ +#include "tasks/tasks_cpp_wait_task-snippet.h" + /* add the two preceeding numbers */ +#include "mtapi/mtapi_write_back-snippet.h" + +static +int fibonacci(int n) { + /* get the node instance, the node is initialized automatically */ + embb::tasks::Node& node = embb::tasks::Node::GetInstance(); + /* start calculation */ +#include "tasks/tasks_cpp_start_task-snippet.h" + /* wait for task completion */ + mtapi_status_t status = task.Wait(MTAPI_INFINITE); + MTAPI_CHECK_STATUS(status); + + return result; +} + +void RunTasks() { + int result = fibonacci(6); + std::cout << "result: " << result << std::endl; +} diff --git a/doc/examples/mtapi/mtapi_cpp_action_signature-snippet.h b/doc/examples/tasks/tasks_cpp_action_signature-snippet.h similarity index 80% rename from doc/examples/mtapi/mtapi_cpp_action_signature-snippet.h rename to doc/examples/tasks/tasks_cpp_action_signature-snippet.h index f15cd7f..24aa989 100644 --- a/doc/examples/mtapi/mtapi_cpp_action_signature-snippet.h +++ b/doc/examples/tasks/tasks_cpp_action_signature-snippet.h @@ -1,5 +1,5 @@ void fibonacciActionFunction( int n, int* result, - embb::mtapi::TaskContext & task_context + embb::tasks::TaskContext & task_context ) { diff --git a/doc/examples/mtapi/mtapi_cpp_calc_direct-snippet.h b/doc/examples/tasks/tasks_cpp_calc_direct-snippet.h similarity index 100% rename from doc/examples/mtapi/mtapi_cpp_calc_direct-snippet.h rename to doc/examples/tasks/tasks_cpp_calc_direct-snippet.h diff --git a/doc/examples/tasks/tasks_cpp_calc_task-snippet.h b/doc/examples/tasks/tasks_cpp_calc_task-snippet.h new file mode 100644 index 0000000..cfe5664 --- /dev/null +++ b/doc/examples/tasks/tasks_cpp_calc_task-snippet.h @@ -0,0 +1,10 @@ + int a = n - 1; + int x; + embb::tasks::Task task = node.Spawn( + embb::base::Bind( + embb::base::MakeFunction(fibonacciActionFunction), + a, /* argument */ + &x, /* result */ + embb::base::Placeholder::_1 + ) + ); diff --git a/doc/examples/tasks/tasks_cpp_get_node-snippet.h b/doc/examples/tasks/tasks_cpp_get_node-snippet.h new file mode 100644 index 0000000..f644ec5 --- /dev/null +++ b/doc/examples/tasks/tasks_cpp_get_node-snippet.h @@ -0,0 +1 @@ + embb::tasks::Node& node = embb::tasks::Node::GetInstance(); diff --git a/doc/examples/tasks/tasks_cpp_start_task-snippet.h b/doc/examples/tasks/tasks_cpp_start_task-snippet.h new file mode 100644 index 0000000..507e634 --- /dev/null +++ b/doc/examples/tasks/tasks_cpp_start_task-snippet.h @@ -0,0 +1,9 @@ + int result; + embb::tasks::Task task = node.Spawn( + embb::base::Bind( + embb::base::MakeFunction(fibonacciActionFunction), + n, + &result, + embb::base::Placeholder::_1 + ) + ); diff --git a/doc/examples/tasks/tasks_cpp_wait_task-snippet.h b/doc/examples/tasks/tasks_cpp_wait_task-snippet.h new file mode 100644 index 0000000..21637fd --- /dev/null +++ b/doc/examples/tasks/tasks_cpp_wait_task-snippet.h @@ -0,0 +1,2 @@ + mtapi_status_t status = task.Wait(MTAPI_INFINITE); + MTAPI_CHECK_STATUS(status); diff --git a/doc/reference/Doxyfile.in b/doc/reference/Doxyfile.in index f1948b5..45b37c5 100644 --- a/doc/reference/Doxyfile.in +++ b/doc/reference/Doxyfile.in @@ -148,6 +148,7 @@ INPUT = "@CMAKE_SOURCE_DIR@/doc/reference/embb.dox" \ "@CMAKE_SOURCE_DIR@/containers_cpp/include" \ "@CMAKE_SOURCE_DIR@/dataflow_cpp/include" \ "@CMAKE_SOURCE_DIR@/algorithms_cpp/include" \ + "@CMAKE_SOURCE_DIR@/tasks_cpp/include" \ "@CMAKE_SOURCE_DIR@/mtapi_cpp/include" \ "@CMAKE_SOURCE_DIR@/base_cpp/include" \ "@CMAKE_SOURCE_DIR@/mtapi_c/include" \ diff --git a/doc/reference/embb.dox b/doc/reference/embb.dox index 60ab98d..73402be 100644 --- a/doc/reference/embb.dox +++ b/doc/reference/embb.dox @@ -20,10 +20,10 @@ programming interface for leveraging task parallelism in embedded systems containing symmetric or asymmetric multicore processors. A core feature of MTAPI is low-overhead scheduling of fine-grained tasks among the available cores during runtime. Unlike existing libraries, -EMB2 supports task priorities, which allows the creation of -soft real-time systems. Additionally, the scheduling strategy can be -optimized for non-functional requirements such as minimal latency and -fairness. +EMB2 supports task priorities and affinities, which allows +the creation of soft real-time systems. Additionally, the scheduling +strategy can be optimized for non-functional requirements such as minimal +latency and fairness. Besides the task scheduler, EMB2 provides basic parallel algorithms, concurrent data structures, and skeletons for implementing diff --git a/doc/tutorial/content/mtapi.tex b/doc/tutorial/content/mtapi.tex index e0cb5a3..956e93a 100644 --- a/doc/tutorial/content/mtapi.tex +++ b/doc/tutorial/content/mtapi.tex @@ -152,27 +152,21 @@ After everything is done, the action is deleted (\lstinline|mtapi_action_delete( \section{C++ Interface} \label{sec:mtapi_cpp_interface} -\embb provides C++ wrappers for the MTAPI C interface. Using the example from the previous section, the signature of the action function for the C++ interface looks like this: +\embb provides C++ wrappers for the MTAPI C interface. The signature of the action function for the C++ interface is the same as in the C interface: % -\\\inputlisting{../examples/mtapi/mtapi_cpp_action_signature-snippet.h} -% -First, the node instance needs to be obtained. If the node is not initialized yet, this function will do it. -% -\\\inputlisting{../examples/mtapi/mtapi_cpp_get_node-snippet.h} +\\\inputlisting{../examples/mtapi/mtapi_c_action_signature-snippet.h} % -\emph{\textbf{Note:} Automatic initialization allows for easy usage of the \emph{Algorithms} and \emph{Dataflow} building blocks. For performance measurements however, explicit initialization by calling \lstinline|embb::mtapi::Node::Initialize| is imperative since the measurements will otherwise include the initialization time of MTAPI.} - -Checking the arguments and the result buffer is not necessary, since everything is safely typed. However, the terminating condition of the recursion still needs to be checked: +Checking argument and result buffer sizes is the same as in the C example. Also, the terminating condition of the recursion still needs to be checked: % \\\inputlisting{../examples/mtapi/mtapi_terminating_condition-snippet.h} % -After that, the first part of the computation is launched as an MTAPI task using \lstinline|embb::mtapi::Node::Spawn()| (registering an action function with a job is done automatically): +After that, the first part of the computation is launched as an MTAPI task using \lstinline|embb::mtapi::Node::Start()| (the action function is registered with the job \lstinline|FIBONACCI_JOB| in the \lstinline|fibonacci()| function and the resulting handle is stored in the global variable \lstinline|embb::mtapi::Job fibonacciJob|): % \\\inputlisting{../examples/mtapi/mtapi_cpp_calc_task-snippet.h} % The second part can be executed directly: % -\\\inputlisting{../examples/mtapi/mtapi_cpp_calc_direct-snippet.h} +\\\inputlisting{../examples/mtapi/mtapi_c_calc_direct-snippet.h} % Then, completion of the MTAPI task has to be waited for using \lstinline|embb::mtapi::Task::Wait()|: % @@ -182,15 +176,29 @@ Finally, the two parts can be added and written into the result buffer: % \\\inputlisting{../examples/mtapi/mtapi_write_back-snippet.h} % +Note that there is no need to do error checking everywhere, since errors are reported as exceptions. In this example there is only a single try/catch block in the main function: +% +\\\inputlisting{../examples/mtapi/mtapi_cpp_main-snippet.h} +% -The \lstinline|fibonacci()| function also gets simpler compared to the C version. The MTAPI runtime is initialized automatically, only the node instance has to be fetched: +The \lstinline|fibonacci()| function is about the same as in the C version. The MTAPI runtime needs to be initialized first: +% +\\\inputlisting{../examples/mtapi/mtapi_cpp_initialize-snippet.h} +% +Then the node instance can to be fetched: % \\\inputlisting{../examples/mtapi/mtapi_cpp_get_node-snippet.h} % -The root task can be started using \lstinline|embb::mtapi::Node::Spawn()| directly, registering with a job is done automatically: +After that, the action function needs to be associated to a job. By instancing an \lstinline|embb::mtap::Action| object, the action function is registered with the job \lstinline|FIBONACCI_JOB|. The job is stored in the global variable \lstinline|embb::mtapi::Job fibonacciJob| so that it can be accessed by the action function later on: +% +\\\inputlisting{../examples/mtapi/mtapi_cpp_register_action-snippet.h} +% +Not that the action is registered and the job is initialized, the root task can be started: % \\\inputlisting{../examples/mtapi/mtapi_cpp_start_task-snippet.h} % -Again, the started task has to be waited for (using \lstinline|embb::mtapi::Task::Wait()|) before the result can be returned. The runtime is shut down automatically in an \lstinline|atexit()| handler. +Again, the started task has to be waited for (using \lstinline|embb::mtapi::Task::Wait()|) before the result can be returned. -\emph{\textbf{Note:} If the node was initialized explicitly by calling \lstinline|embb::mtapi::Node::Initialize|, the runtime must also be shut down explicitly by calling \lstinline|embb::mtapi::Node::Finalize|.} +The registered action will be unregistered when it goes out of scope. +The runtime needs to be shut down by calling: +\\\inputlisting{../examples/mtapi/mtapi_cpp_finalize-snippet.h} diff --git a/doc/tutorial/content/tasks.tex b/doc/tutorial/content/tasks.tex new file mode 100644 index 0000000..45770bc --- /dev/null +++ b/doc/tutorial/content/tasks.tex @@ -0,0 +1,45 @@ +\chapter{Tasks} +\label{cha:tasks} + +\embb provides a simple task management wrapper for the MTAPI interface. Using the example from the previous section, the signature of the action function for the tasks interface looks like this: +% +\\\inputlisting{../examples/tasks/tasks_cpp_action_signature-snippet.h} +% +First, the node instance needs to be obtained. If the node is not initialized yet, this function will do it. +% +\\\inputlisting{../examples/tasks/tasks_cpp_get_node-snippet.h} +% +\emph{\textbf{Note:} Automatic initialization allows for easy usage of the \emph{Algorithms} and \emph{Dataflow} building blocks. For performance measurements however, explicit initialization by calling \lstinline|embb::tasks::Node::Initialize| is imperative since the measurements will otherwise include the initialization time of MTAPI.} + +Checking the arguments and the result buffer is not necessary, since everything is safely typed. However, the terminating condition of the recursion still needs to be checked: +% +\\\inputlisting{../examples/mtapi/mtapi_terminating_condition-snippet.h} +% +After that, the first part of the computation is launched as an MTAPI task using \lstinline|embb::tasks::Node::Spawn()| (registering an action function with a job is done automatically): +% +\\\inputlisting{../examples/tasks/tasks_cpp_calc_task-snippet.h} +% +The second part can be executed directly: +% +\\\inputlisting{../examples/tasks/tasks_cpp_calc_direct-snippet.h} +% +Then, completion of the MTAPI task has to be waited for using \lstinline|embb::tasks::Task::Wait()|: +% +\\\inputlisting{../examples/tasks/tasks_cpp_wait_task-snippet.h} +% +Finally, the two parts can be added and written into the result buffer: +% +\\\inputlisting{../examples/mtapi/mtapi_write_back-snippet.h} +% + +The \lstinline|fibonacci()| function also gets simpler compared to the C version. The MTAPI runtime is initialized automatically, only the node instance has to be fetched: +% +\\\inputlisting{../examples/tasks/tasks_cpp_get_node-snippet.h} +% +The root task can be started using \lstinline|embb::tasks::Node::Spawn()| directly, registering with a job is done automatically: +% +\\\inputlisting{../examples/tasks/tasks_cpp_start_task-snippet.h} +% +Again, the started task has to be waited for (using \lstinline|embb::tasks::Task::Wait()|) before the result can be returned. The runtime is shut down automatically in an \lstinline|atexit()| handler. + +\emph{\textbf{Note:} If the node was initialized explicitly by calling \lstinline|embb::tasks::Node::Initialize|, the runtime must also be shut down explicitly by calling \lstinline|embb::tasks::Node::Finalize|.} diff --git a/doc/tutorial/tutorial.tex b/doc/tutorial/tutorial.tex index 6a7c920..4e969e1 100644 --- a/doc/tutorial/tutorial.tex +++ b/doc/tutorial/tutorial.tex @@ -114,6 +114,7 @@ % \input{content/preface} \input{content/introduction} \input{content/mtapi} +\input{content/tasks} \input{content/algorithms} \input{content/dataflow} \input{content/containers} diff --git a/mtapi_c/src/embb_mtapi_scheduler_t.c b/mtapi_c/src/embb_mtapi_scheduler_t.c index 29a2a65..28cc5ce 100644 --- a/mtapi_c/src/embb_mtapi_scheduler_t.c +++ b/mtapi_c/src/embb_mtapi_scheduler_t.c @@ -304,13 +304,16 @@ int embb_mtapi_scheduler_worker(void * arg) { switch (task->state) { case MTAPI_TASK_SCHEDULED: + /* multi-instance task, another instance might be running */ + case MTAPI_TASK_RUNNING: /* there was work, execute it */ embb_mtapi_task_context_initialize_with_thread_context_and_task( &task_context, thread_context, task); - embb_mtapi_task_execute(task, &task_context); - /* tell queue that a task is done */ - if (MTAPI_NULL != local_queue) { - embb_mtapi_queue_task_finished(local_queue); + if (embb_mtapi_task_execute(task, &task_context)) { + /* tell queue that a task is done */ + if (MTAPI_NULL != local_queue) { + embb_mtapi_queue_task_finished(local_queue); + } } counter = 0; break; @@ -318,25 +321,27 @@ int embb_mtapi_scheduler_worker(void * arg) { case MTAPI_TASK_RETAINED: /* put task into queue again for later execution */ embb_mtapi_scheduler_schedule_task( - node->scheduler, task); + node->scheduler, task, 0); /* yield, as there may be only retained tasks in the queue */ embb_thread_yield(); /* task is not done, so do not notify queue */ break; case MTAPI_TASK_CANCELLED: - /* set return value to cancelled */ + /* set return value to canceled */ task->error_code = MTAPI_ERR_ACTION_CANCELLED; - /* tell queue that a task is done */ - if (MTAPI_NULL != local_queue) { - embb_mtapi_queue_task_finished(local_queue); + if (embb_atomic_fetch_and_add_unsigned_int( + &task->instances_todo, (unsigned int)-1) == 0) { + /* tell queue that a task is done */ + if (MTAPI_NULL != local_queue) { + embb_mtapi_queue_task_finished(local_queue); + } } break; case MTAPI_TASK_COMPLETED: case MTAPI_TASK_DELETED: case MTAPI_TASK_WAITING: - case MTAPI_TASK_RUNNING: case MTAPI_TASK_CREATED: case MTAPI_TASK_PRENATAL: case MTAPI_TASK_ERROR: @@ -351,12 +356,14 @@ int embb_mtapi_scheduler_worker(void * arg) { counter++; } else { /* no work, go to sleep */ + embb_atomic_store_int(&thread_context->is_sleeping, 1); embb_mutex_lock(&thread_context->work_available_mutex); embb_condition_wait_for( &thread_context->work_available, &thread_context->work_available_mutex, &sleep_duration); embb_mutex_unlock(&thread_context->work_available_mutex); + embb_atomic_store_int(&thread_context->is_sleeping, 0); } } @@ -526,10 +533,11 @@ mtapi_boolean_t embb_mtapi_scheduler_process_tasks( mtapi_boolean_t embb_mtapi_scheduler_schedule_task( embb_mtapi_scheduler_t * that, - embb_mtapi_task_t * task) { + embb_mtapi_task_t * task, + mtapi_uint_t instance) { embb_mtapi_scheduler_t * scheduler = that; /* distribute round robin */ - mtapi_uint_t ii = task->handle.id % scheduler->worker_count; + mtapi_uint_t ii = (task->handle.id + instance) % scheduler->worker_count; mtapi_boolean_t pushed = MTAPI_FALSE; embb_mtapi_node_t* node = embb_mtapi_node_get_instance(); @@ -586,8 +594,8 @@ mtapi_boolean_t embb_mtapi_scheduler_schedule_task( } if (pushed) { - /* signal all threads */ - for (ii = 0; ii < scheduler->worker_count; ii++) { + /* signal the worker thread a task was pushed to */ + if (embb_atomic_load_int(&scheduler->worker_contexts[ii].is_sleeping)) { embb_condition_notify_one( &scheduler->worker_contexts[ii].work_available); } diff --git a/mtapi_c/src/embb_mtapi_scheduler_t.h b/mtapi_c/src/embb_mtapi_scheduler_t.h index 07ff116..9b340d2 100644 --- a/mtapi_c/src/embb_mtapi_scheduler_t.h +++ b/mtapi_c/src/embb_mtapi_scheduler_t.h @@ -198,7 +198,8 @@ mtapi_boolean_t embb_mtapi_scheduler_process_tasks( */ mtapi_boolean_t embb_mtapi_scheduler_schedule_task( embb_mtapi_scheduler_t * that, - embb_mtapi_task_t * task); + embb_mtapi_task_t * task, + mtapi_uint_t instance); #ifdef __cplusplus diff --git a/mtapi_c/src/embb_mtapi_task_context_t.c b/mtapi_c/src/embb_mtapi_task_context_t.c index 92be087..a74088a 100644 --- a/mtapi_c/src/embb_mtapi_task_context_t.c +++ b/mtapi_c/src/embb_mtapi_task_context_t.c @@ -51,8 +51,8 @@ void embb_mtapi_task_context_initialize_with_thread_context_and_task( that->task = task; that->thread_context = thread_context; that->num_instances = task->attributes.num_instances; - that->instance_num = embb_atomic_fetch_and_add_unsigned_int( - &task->current_instance, 1); + that->instance_num = + embb_atomic_fetch_and_add_unsigned_int(&task->current_instance, 1); } void embb_mtapi_task_context_finalize(embb_mtapi_task_context_t* that) { diff --git a/mtapi_c/src/embb_mtapi_task_t.c b/mtapi_c/src/embb_mtapi_task_t.c index b26bcd1..7f0c27f 100644 --- a/mtapi_c/src/embb_mtapi_task_t.c +++ b/mtapi_c/src/embb_mtapi_task_t.c @@ -95,9 +95,11 @@ void embb_mtapi_task_finalize(embb_mtapi_task_t* that) { embb_mtapi_spinlock_finalize(&that->state_lock); } -void embb_mtapi_task_execute( +mtapi_boolean_t embb_mtapi_task_execute( embb_mtapi_task_t* that, embb_mtapi_task_context_t * context) { + unsigned int todo = that->attributes.num_instances; + assert(MTAPI_NULL != that); assert(MTAPI_NULL != context); @@ -110,17 +112,25 @@ void embb_mtapi_task_execute( embb_mtapi_action_t* local_action = embb_mtapi_action_pool_get_storage_for_handle( context->thread_context->node->action_pool, that->action); - local_action->action_function( - that->arguments, - that->arguments_size, - that->result_buffer, - that->result_size, - local_action->node_local_data, - local_action->node_local_data_size, - context); + /* only continue if there was no error so far */ + if (context->task->error_code == MTAPI_SUCCESS) { + local_action->action_function( + that->arguments, + that->arguments_size, + that->result_buffer, + that->result_size, + local_action->node_local_data, + local_action->node_local_data_size, + context); + } embb_atomic_memory_barrier(); - /* task has completed successfully */ - embb_mtapi_task_set_state(that, MTAPI_TASK_COMPLETED); + todo = embb_atomic_fetch_and_add_unsigned_int( + &that->instances_todo, (unsigned int)-1); + + if (todo == 1) { + /* task has completed successfully */ + embb_mtapi_task_set_state(that, MTAPI_TASK_COMPLETED); + } embb_atomic_fetch_and_add_int(&local_action->num_tasks, -1); } else { /* action was deleted, task did not complete */ @@ -128,13 +138,18 @@ void embb_mtapi_task_execute( embb_mtapi_task_set_state(that, MTAPI_TASK_ERROR); } - /* is task associated with a group? */ - if (embb_mtapi_group_pool_is_handle_valid( - context->thread_context->node->group_pool, that->group)) { - embb_mtapi_group_t* local_group = - embb_mtapi_group_pool_get_storage_for_handle( - context->thread_context->node->group_pool, that->group); - embb_mtapi_task_queue_push(&local_group->queue, that); + if (todo == 1) { + /* is task associated with a group? */ + if (embb_mtapi_group_pool_is_handle_valid( + context->thread_context->node->group_pool, that->group)) { + embb_mtapi_group_t* local_group = + embb_mtapi_group_pool_get_storage_for_handle( + context->thread_context->node->group_pool, that->group); + embb_mtapi_task_queue_push(&local_group->queue, that); + } + return MTAPI_TRUE; + } else { + return MTAPI_FALSE; } } @@ -189,6 +204,9 @@ static mtapi_task_hndl_t embb_mtapi_task_start( mtapi_taskattr_init(&task->attributes, &local_status); } + embb_atomic_store_unsigned_int( + &task->instances_todo, task->attributes.num_instances); + if (embb_mtapi_group_pool_is_handle_valid(node->group_pool, group)) { embb_mtapi_group_t* local_group = embb_mtapi_group_pool_get_storage_for_handle( @@ -233,8 +251,12 @@ static mtapi_task_hndl_t embb_mtapi_task_start( embb_mtapi_task_set_state(task, MTAPI_TASK_SCHEDULED); - was_scheduled = - embb_mtapi_scheduler_schedule_task(scheduler, task); + was_scheduled = MTAPI_TRUE; + + for (mtapi_uint_t kk = 0; kk < task->attributes.num_instances; kk++) { + was_scheduled = was_scheduled & + embb_mtapi_scheduler_schedule_task(scheduler, task, kk); + } if (was_scheduled) { /* if task is detached, do not return a handle, it will be deleted diff --git a/mtapi_c/src/embb_mtapi_task_t.h b/mtapi_c/src/embb_mtapi_task_t.h index 77617b3..f5dadc5 100644 --- a/mtapi_c/src/embb_mtapi_task_t.h +++ b/mtapi_c/src/embb_mtapi_task_t.h @@ -68,6 +68,7 @@ struct embb_mtapi_task_struct { embb_mtapi_spinlock_t state_lock; volatile mtapi_task_state_t state; embb_atomic_unsigned_int current_instance; + embb_atomic_unsigned_int instances_todo; mtapi_status_t error_code; }; @@ -106,7 +107,7 @@ void embb_mtapi_task_finalize(embb_mtapi_task_t* that); * detached. * \memberof embb_mtapi_task_struct */ -void embb_mtapi_task_execute( +mtapi_boolean_t embb_mtapi_task_execute( embb_mtapi_task_t* that, embb_mtapi_task_context_t * context); diff --git a/mtapi_c/src/embb_mtapi_thread_context_t.c b/mtapi_c/src/embb_mtapi_thread_context_t.c index ea5d4d1..2a7bdc4 100644 --- a/mtapi_c/src/embb_mtapi_thread_context_t.c +++ b/mtapi_c/src/embb_mtapi_thread_context_t.c @@ -70,6 +70,7 @@ void embb_mtapi_thread_context_initialize_with_node_worker_and_core( embb_mutex_init(&that->work_available_mutex, EMBB_MUTEX_PLAIN); embb_condition_init(&that->work_available); + embb_atomic_store_int(&that->is_sleeping, 0); } mtapi_boolean_t embb_mtapi_thread_context_start( diff --git a/mtapi_c/src/embb_mtapi_thread_context_t.h b/mtapi_c/src/embb_mtapi_thread_context_t.h index 0ed2dd3..a207886 100644 --- a/mtapi_c/src/embb_mtapi_thread_context_t.h +++ b/mtapi_c/src/embb_mtapi_thread_context_t.h @@ -56,6 +56,7 @@ struct embb_mtapi_thread_context_struct { embb_condition_t work_available; embb_thread_t thread; embb_tss_t tss_id; + embb_atomic_int is_sleeping; embb_mtapi_node_t* node; embb_mtapi_task_queue_t** queue; diff --git a/mtapi_c/test/embb_mtapi_test_task.cc b/mtapi_c/test/embb_mtapi_test_task.cc index 4b01445..bde956f 100644 --- a/mtapi_c/test/embb_mtapi_test_task.cc +++ b/mtapi_c/test/embb_mtapi_test_task.cc @@ -33,6 +33,7 @@ #include #define JOB_TEST_TASK 42 +#define JOB_TEST_MULTIINSTANCE_TASK 43 #define TASK_TEST_ID 23 static void testTaskAction( @@ -44,7 +45,9 @@ static void testTaskAction( mtapi_size_t /*node_local_data_size*/, mtapi_task_context_t* task_context) { int ii; - mtapi_uint_t core_num = mtapi_context_corenum_get(task_context, MTAPI_NULL); + mtapi_status_t status; + mtapi_uint_t core_num = mtapi_context_corenum_get(task_context, &status); + MTAPI_CHECK_STATUS(status); srand(core_num); for (ii = 1000; ii < rand()%1000000; ii ++) { } @@ -53,6 +56,41 @@ static void testTaskAction( EMBB_UNUSED(args); } +void testMultiInstanceTaskAction( + const void* args, + mtapi_size_t arg_size, + void* result_buffer, + mtapi_size_t result_buffer_size, + const void* node_local_data, + mtapi_size_t node_local_data_size, + mtapi_task_context_t* task_context) { + EMBB_UNUSED(args); + EMBB_UNUSED(arg_size); + + EMBB_UNUSED(node_local_data); + EMBB_UNUSED(node_local_data_size); + + mtapi_status_t status; + mtapi_uint_t this_instance, num_instances; + mtapi_uint_t* result; + num_instances = mtapi_context_numinst_get(task_context, &status); + this_instance = mtapi_context_instnum_get(task_context, &status); + + /* check result buffer size... */ + if (result_buffer_size == sizeof(int) * num_instances) { + /* ... and cast the result buffer */ + result = reinterpret_cast(result_buffer); + } else { + mtapi_context_status_set(task_context, MTAPI_ERR_RESULT_SIZE, &status); + MTAPI_CHECK_STATUS(status); + return; + } + + /* dummy for calculating result */ + result[this_instance] = this_instance; +} + + static void testDoSomethingElse() { } @@ -151,7 +189,7 @@ void TaskTest::TestBasic() { for (ii = 0; ii < 100; ii++) { status = MTAPI_ERR_UNKNOWN; - mtapi_task_wait(task[ii], 100, &status); + mtapi_task_wait(task[ii], 100000, &status); MTAPI_CHECK_STATUS(status); } @@ -160,10 +198,66 @@ void TaskTest::TestBasic() { MTAPI_CHECK_STATUS(status); status = MTAPI_ERR_UNKNOWN; + mtapi_action_hndl_t multiinstance_action = mtapi_action_create( + JOB_TEST_MULTIINSTANCE_TASK, + testMultiInstanceTaskAction, + MTAPI_NULL, + 0, + &action_attr, + &status); + MTAPI_CHECK_STATUS(status); + + status = MTAPI_ERR_UNKNOWN; + mtapi_job_hndl_t multiinstance_job = mtapi_job_get( + JOB_TEST_MULTIINSTANCE_TASK, THIS_DOMAIN_ID, &status); + MTAPI_CHECK_STATUS(status); + + mtapi_task_attributes_t task_attr; + + status = MTAPI_ERR_UNKNOWN; + mtapi_taskattr_init(&task_attr, &status); + MTAPI_CHECK_STATUS(status); + + const int kTaskInstances = 5; + + status = MTAPI_ERR_UNKNOWN; + mtapi_taskattr_set(&task_attr, MTAPI_TASK_INSTANCES, + MTAPI_ATTRIBUTE_VALUE(kTaskInstances), MTAPI_ATTRIBUTE_POINTER_AS_VALUE, + &status); + MTAPI_CHECK_STATUS(status); + + mtapi_uint_t result[kTaskInstances]; + for (mtapi_uint_t ii = 0; ii < kTaskInstances; ii++) { + result[ii] = kTaskInstances + 1; + } + + status = MTAPI_ERR_UNKNOWN; + mtapi_task_hndl_t multiinstance_task = + mtapi_task_start(MTAPI_TASK_ID_NONE, multiinstance_job, + MTAPI_NULL, 0, + &result[0], sizeof(mtapi_uint_t) * kTaskInstances, + &task_attr, + MTAPI_GROUP_NONE, + &status); + MTAPI_CHECK_STATUS(status); + + status = MTAPI_ERR_UNKNOWN; + mtapi_task_wait(multiinstance_task, MTAPI_INFINITE, &status); + MTAPI_CHECK_STATUS(status); + + for (mtapi_uint_t ii = 0; ii < kTaskInstances; ii++) { + PT_EXPECT_EQ(result[ii], ii); + } + + status = MTAPI_ERR_UNKNOWN; + mtapi_action_delete(multiinstance_action, 10, &status); + MTAPI_CHECK_STATUS(status); + + status = MTAPI_ERR_UNKNOWN; mtapi_finalize(&status); MTAPI_CHECK_STATUS(status); - PT_EXPECT(embb_get_bytes_allocated() == 0); + PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u); embb_mtapi_log_info("...done\n\n"); } diff --git a/mtapi_c/test/main.cc b/mtapi_c/test/main.cc index 6d8b6c2..2c91b7e 100644 --- a/mtapi_c/test/main.cc +++ b/mtapi_c/test/main.cc @@ -25,6 +25,7 @@ */ #include +#include #include @@ -38,10 +39,11 @@ PT_MAIN("MTAPI C") { embb_log_set_log_level(EMBB_LOG_LEVEL_NONE); + embb_thread_set_max_count(1024); + PT_RUN(TaskTest); PT_RUN(ErrorTest); PT_RUN(InitFinalizeTest); - PT_RUN(TaskTest); PT_RUN(GroupTest); PT_RUN(QueueTest); } diff --git a/mtapi_cpp/CMakeLists.txt b/mtapi_cpp/CMakeLists.txt index 19a6353..3652d63 100644 --- a/mtapi_cpp/CMakeLists.txt +++ b/mtapi_cpp/CMakeLists.txt @@ -13,8 +13,6 @@ else() endif() message(" (set with command line option -DUSE_AUTOMATIC_INITIALIZATION=ON/OFF)") -configure_file("include/embb/mtapi/internal/cmake_config.h.in" - "include/embb/mtapi/internal/cmake_config.h") # Execute the GroupSources macro include(${CMAKE_SOURCE_DIR}/CMakeCommon/GroupSourcesMSVC.cmake) @@ -24,7 +22,6 @@ GroupSourcesMSVC(test) set (EMBB_MTAPI_CPP_INCLUDE_DIRS "include" "src" "test") include_directories(${EMBB_MTAPI_CPP_INCLUDE_DIRS} - ${CMAKE_CURRENT_BINARY_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/../base_c/include ${CMAKE_CURRENT_BINARY_DIR}/../base_c/include ${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include @@ -44,6 +41,4 @@ endif() install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION include FILES_MATCHING PATTERN "*.h") -install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/ - DESTINATION include FILES_MATCHING PATTERN "*.h") install(TARGETS embb_mtapi_cpp DESTINATION lib) diff --git a/mtapi_cpp/include/embb/mtapi/action.h b/mtapi_cpp/include/embb/mtapi/action.h index 68e9776..50f8d75 100644 --- a/mtapi_cpp/include/embb/mtapi/action.h +++ b/mtapi_cpp/include/embb/mtapi/action.h @@ -27,80 +27,113 @@ #ifndef EMBB_MTAPI_ACTION_H_ #define EMBB_MTAPI_ACTION_H_ -#include -#include -#include +#include +#include +#include namespace embb { namespace mtapi { /** - * A function to be spawned as a Task. - * - * \ingroup CPP_MTAPI - */ + * Holds the actual worker function used to execute a Task. + * + * \ingroup CPP_MTAPI + */ class Action { public: /** - * Constructs an empty Action. - */ - Action() - : function_() - , execution_policy_() { - // empty + * Constructs an Action. + */ + Action( + mtapi_job_id_t job_id, /**< Job ID the Action belongs to */ + mtapi_action_function_t func, /**< The action function */ + const void * node_local_data, /**< Node local data available to all + Tasks using this Action */ + mtapi_size_t node_local_data_size, /**< Size of node local data */ + ActionAttributes const & attributes + /**< Attributes of the Action */ + ) { + Create(job_id, func, node_local_data, node_local_data_size, + &attributes.GetInternal()); } /** - * Constructs an Action from a function object. - * - * \tparam Function Function object - */ - template + * Constructs an Action. + */ Action( - Function func /**< [in] Function object */ - ) - : function_(func) - , execution_policy_() { - // empty + mtapi_job_id_t job_id, /**< Job ID the Action belongs to */ + mtapi_action_function_t func, /**< The action function */ + const void * node_local_data, /**< Node local data available to all + Tasks using this Action */ + mtapi_size_t node_local_data_size /**< Size of node local data */ + ) { + Create(job_id, func, node_local_data, node_local_data_size, + MTAPI_DEFAULT_ACTION_ATTRIBUTES); } /** - * Constructs an Action from a function object and an Affinity. - * - * \tparam Function Function object - */ - template + * Constructs an Action. + */ Action( - Function func, /**< [in] Function object */ - ExecutionPolicy execution_policy /**< [in] Execution policy */ - ) - : function_(func) - , execution_policy_(execution_policy) { - // empty + mtapi_job_id_t job_id, /**< Job ID the Action belongs to */ + mtapi_action_function_t func, /**< The action function */ + ActionAttributes const & attributes + /**< Attributes of the Action */ + ) { + Create(job_id, func, MTAPI_NULL, 0, &attributes.GetInternal()); } /** - * Executes the Action in a given TaskContext. - */ - void operator() ( - TaskContext & context /**< [in, out] Context the operator - is executed in */ + * Constructs an Action. + */ + Action( + mtapi_job_id_t job_id, /**< Job ID the Action belongs to */ + mtapi_action_function_t func /**< The action function */ ) { - function_(context); + Create(job_id, func, MTAPI_NULL, 0, MTAPI_DEFAULT_ACTION_ATTRIBUTES); } /** - * Returns the ExecutionPolicy specified during creation. - * \return The ExecutionPolicy of the Action - * \waitfree - */ - ExecutionPolicy GetExecutionPolicy() const { - return execution_policy_; + * Destroys an Action. + */ + ~Action() { + mtapi_action_delete(handle_, MTAPI_INFINITE, MTAPI_NULL); + } + + /** + * Returns the internal representation of this object. + * Allows for interoperability with the C interface. + * + * \returns The internal mtapi_action_hndl_t. + * \waitfree + */ + mtapi_action_hndl_t GetInternal() const { + return handle_; } private: - embb::base::Function function_; - ExecutionPolicy execution_policy_; + // no default constructor + Action(); + + // not copyable + Action(Action const & other); + void operator=(Action const & other); + + void Create( + mtapi_job_id_t job_id, + mtapi_action_function_t func, + const void * node_local_data, + mtapi_size_t node_local_data_size, + mtapi_action_attributes_t const * attributes + ) { + mtapi_status_t status; + handle_ = mtapi_action_create(job_id, func, + node_local_data, node_local_data_size, + attributes, &status); + internal::CheckStatus(status); + } + + mtapi_action_hndl_t handle_; }; } // namespace mtapi diff --git a/mtapi_cpp/include/embb/mtapi/action_attributes.h b/mtapi_cpp/include/embb/mtapi/action_attributes.h new file mode 100644 index 0000000..70f798b --- /dev/null +++ b/mtapi_cpp/include/embb/mtapi/action_attributes.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_MTAPI_ACTION_ATTRIBUTES_H_ +#define EMBB_MTAPI_ACTION_ATTRIBUTES_H_ + +#include +#include +#include + +namespace embb { +namespace mtapi { + +/** + * Contains attributes of an Action. + * + * \ingroup CPP_MTAPI + */ +class ActionAttributes { + public: + /** + * Constructs an ActionAttributes object. + */ + ActionAttributes() { + mtapi_status_t status; + mtapi_actionattr_init(&attributes_, &status); + internal::CheckStatus(status); + } + + /** + * Sets the global property of an Action. + * This determines whether the object will be visible across nodes. + * + * \returns Reference to this object. + */ + ActionAttributes & SetGlobal( + bool state /**< The state to set */ + ) { + mtapi_status_t status; + mtapi_boolean_t st = state ? MTAPI_TRUE : MTAPI_FALSE; + mtapi_actionattr_set(&attributes_, MTAPI_ACTION_GLOBAL, + &st, sizeof(st), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Sets the affinity of an Action. + * + * \returns Reference to this object. + */ + ActionAttributes & SetAffinity( + Affinity const & affinity /**< The Affinity to set. */ + ) { + mtapi_status_t status; + mtapi_affinity_t af = affinity.GetInternal(); + mtapi_actionattr_set(&attributes_, MTAPI_ACTION_AFFINITY, + &af, sizeof(af), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Sets the domain shared property of an Action. + * This determines whether the object will be visible across domains. + * + * \returns Reference to this object. + */ + ActionAttributes & SetDomainShared( + bool state /**< The state to set */ + ) { + mtapi_status_t status; + mtapi_boolean_t st = state ? MTAPI_TRUE : MTAPI_FALSE; + mtapi_actionattr_set(&attributes_, MTAPI_ACTION_DOMAIN_SHARED, + &st, sizeof(st), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Returns the internal representation of this object. + * Allows for interoperability with the C interface. + * + * \returns A reference to the internal mtapi_action_attributes_t structure. + * \waitfree + */ + mtapi_action_attributes_t const & GetInternal() const { + return attributes_; + } + + private: + mtapi_action_attributes_t attributes_; +}; + +} // namespace mtapi +} // namespace embb + +#endif // EMBB_MTAPI_ACTION_ATTRIBUTES_H_ diff --git a/mtapi_cpp/include/embb/mtapi/affinity.h b/mtapi_cpp/include/embb/mtapi/affinity.h new file mode 100644 index 0000000..c2e0cfe --- /dev/null +++ b/mtapi_cpp/include/embb/mtapi/affinity.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_MTAPI_AFFINITY_H_ +#define EMBB_MTAPI_AFFINITY_H_ + +#include +#include + +namespace embb { +namespace mtapi { + +/** + * Describes the affinity of an Action or Task to a worker thread of a Node. + * + * \ingroup CPP_MTAPI + */ +class Affinity { + public: + /** + * Constructs an Affinity object. + */ + Affinity() { + Init(true); + } + + /** + * Copies an Affinity object. + */ + Affinity( + Affinity const & other /**< The Affinity to copy from */ + ) + : affinity_(other.affinity_) { + // empty + } + + /** + * Copies an Affinity object. + */ + void operator=( + Affinity const & other /**< The Affinity to copy from */ + ) { + affinity_ = other.affinity_; + } + + /** + * Constructs an Affinity object with the given initial affinity. + * If \c initial_affinity is \c true the Affinity will map to all worker + * threads, otherwise it will map to no worker threads. + */ + Affinity( + bool initial_affinity /**< The initial affinity to set. */ + ) { + Init(initial_affinity); + } + + /** + * Initializes an Affinity object with the given initial affinity. + * If \c initial_affinity is \c true the Affinity will map to all worker + * threads, otherwise it will map to no worker threads. + * + * \notthreadsafe + */ + void Init( + bool initial_affinity /**< The initial affinity to set. */ + ) { + mtapi_status_t status; + mtapi_boolean_t ia = initial_affinity ? MTAPI_TRUE : MTAPI_FALSE; + mtapi_affinity_init(&affinity_, ia, &status); + internal::CheckStatus(status); + } + + /** + * Sets affinity to the given worker. + * + * \notthreadsafe + */ + void Set( + mtapi_uint_t worker, /**< The worker to set affinity to. */ + bool state /**< The state of the affinity. */ + ) { + mtapi_status_t status; + mtapi_boolean_t st = state ? MTAPI_TRUE : MTAPI_FALSE; + mtapi_affinity_set(&affinity_, worker, st, &status); + internal::CheckStatus(status); + } + + /** + * Gets affinity to the given worker. + * + * \returns \c true, if the Affinity maps to the worker, \c false otherwise. + * \waitfree + */ + bool Get( + mtapi_uint_t worker /**< The worker to get affinity of. */ + ) { + mtapi_status_t status; + mtapi_boolean_t state = + mtapi_affinity_get(&affinity_, worker, &status); + internal::CheckStatus(status); + return (state != MTAPI_FALSE) ? true : false; + } + + /** + * Returns the internal representation of this object. + * Allows for interoperability with the C interface. + * + * \returns The internal mtapi_affinity_t. + * \waitfree + */ + mtapi_affinity_t GetInternal() const { + return affinity_; + } + + private: + mtapi_affinity_t affinity_; +}; + +} // namespace mtapi +} // namespace embb + +#endif // EMBB_MTAPI_AFFINITY_H_ diff --git a/mtapi_cpp/include/embb/mtapi/group.h b/mtapi_cpp/include/embb/mtapi/group.h index b3c4906..8fefc53 100644 --- a/mtapi_cpp/include/embb/mtapi/group.h +++ b/mtapi_cpp/include/embb/mtapi/group.h @@ -28,8 +28,10 @@ #define EMBB_MTAPI_GROUP_H_ #include -#include +#include #include +#include +#include namespace embb { @@ -42,81 +44,270 @@ class Allocation; namespace mtapi { /** - * Represents a facility to wait for multiple related - * \link Task Tasks\endlink. - * - * \ingroup CPP_MTAPI - */ + * Represents a facility to wait for multiple related + * \link Task Tasks\endlink. + * + * \ingroup CPP_MTAPI + */ class Group { public: /** - * Runs an Action within the Group. - * \return A Task identifying the Action to run - * \throws ErrorException if the Task object could not be constructed. - * \threadsafe - */ - Task Spawn( - Action action /**< [in] The Action to run */ - ); - - /** - * Runs an Action within the Group. The \c id is returned by WaitAny(). - * \return A Task identifying the Action to run - * \throws ErrorException if the Task object could not be constructed. - * \threadsafe - */ - Task Spawn( - mtapi_task_id_t id, /**< [in] The id to return by - WaitAny() */ - Action action /**< [in] The Action to run */ - ); - - /** - * Waits for any Task in the Group to finish for \c timeout milliseconds. - * \return The status of the Task that finished execution - * \threadsafe - */ - mtapi_status_t WaitAny( - mtapi_timeout_t timeout /**< [in] Timeout duration in - milliseconds */ - ); + * Constructs a Group object with default attributes. + * Requires an initialized Node. + */ + Group() { + Create(MTAPI_GROUP_ID_NONE, MTAPI_DEFAULT_GROUP_ATTRIBUTES); + } + + /** + * Constructs a Group object using the given Attributes. + * Requires an initialized Node. + */ + Group( + GroupAttributes const & attr /**< The GroupAttributes to use. */ + ) { + Create(MTAPI_GROUP_ID_NONE, &attr.GetInternal()); + } + + /** + * Constructs a Group object with default attributes and the given ID. + * Requires an initialized Node. + */ + Group( + mtapi_group_id_t id /**< A user defined ID of the Group. */ + ) { + Create(id, MTAPI_DEFAULT_GROUP_ATTRIBUTES); + } /** - * Waits for any Task in the Group to finish for \c timeout milliseconds and - * retrieves the id given in Spawn(). - * \return The status of the Task that finished execution, \c MTAPI_TIMEOUT - * or \c MTAPI_ERR_* - * \threadsafe - */ + * Constructs a Group object with given attributes and ID. + * Requires an initialized Node. + */ + Group( + mtapi_group_id_t id, /**< A user defined ID of the Group. */ + GroupAttributes const & attr /**< The GroupAttributes to use. */ + ) { + Create(id, &attr.GetInternal()); + } + + /** + * Destroys a Group object. + */ + ~Group() { + // delete the group, ignore status + mtapi_group_delete(handle_, MTAPI_NULL); + } + + /** + * Starts a new Task in this Group. + * + * \returns The handle to the started Task. + * \threadsafe + */ + template + Task Start( + mtapi_task_id_t task_id, /**< A user defined ID of the Task. */ + Job const & job, /**< The Job to execute. */ + const ARGS * arguments, /**< Pointer to the arguments. */ + RES * results, /**< Pointer to the results. */ + TaskAttributes const & attributes /**< Attributes of the Task */ + ) { + return Start(task_id, + job.GetInternal(), + arguments, internal::SizeOfType(), + results, internal::SizeOfType(), + &attributes.GetInternal()); + } + + /** + * Starts a new Task in this Group. + * + * \returns The handle to the started Task. + * \threadsafe + */ + template + Task Start( + mtapi_task_id_t task_id, /**< A user defined ID of the Task. */ + Job const & job, /**< The Job to execute. */ + const ARGS * arguments, /**< Pointer to the arguments. */ + RES * results /**< Pointer to the results. */ + ) { + return Start(task_id, + job.GetInternal(), + arguments, internal::SizeOfType(), + results, internal::SizeOfType(), + MTAPI_DEFAULT_TASK_ATTRIBUTES); + } + + /** + * Starts a new Task in this Group. + * + * \returns The handle to the started Task. + * \threadsafe + */ + template + Task Start( + Job const & job, /**< The Job to execute. */ + const ARGS * arguments, /**< Pointer to the arguments. */ + RES * results, /**< Pointer to the results. */ + TaskAttributes const & attributes /**< Attributes of the Task */ + ) { + return Start(MTAPI_TASK_ID_NONE, + job.GetInternal(), + arguments, internal::SizeOfType(), + results, internal::SizeOfType(), + &attributes.GetInternal()); + } + + /** + * Starts a new Task in this Group. + * + * \returns The handle to the started Task. + * \threadsafe + */ + template + Task Start( + Job const & job, /**< The Job to execute. */ + const ARGS * arguments, /**< Pointer to the arguments. */ + RES * results /**< Pointer to the results. */ + ) { + return Start(MTAPI_TASK_ID_NONE, + job.GetInternal(), + arguments, internal::SizeOfType(), + results, internal::SizeOfType(), + MTAPI_DEFAULT_TASK_ATTRIBUTES); + } + + /** + * Waits for any Task in the Group to finish for \c timeout milliseconds and + * retrieves the result buffer given in Start(). + * \return The status of the Task that finished execution, \c MTAPI_TIMEOUT + * or \c MTAPI_ERR_* + * \threadsafe + */ mtapi_status_t WaitAny( mtapi_timeout_t timeout, /**< [in] Timeout duration in milliseconds */ - mtapi_task_id_t & id /**< [out] The id given to Spawn() */ - ); + void ** result /**< [out] The result buffer given in + Node::Start, Group::Start or + Queue::Enqueue */ + ) { + mtapi_status_t status; + mtapi_group_wait_any(handle_, result, timeout, &status); + needs_delete_ = status != MTAPI_GROUP_COMPLETED; + return status; + } /** - * Waits for all Task in the Group to finish for \c timeout milliseconds. - * \return \c MTAPI_SUCCESS, \c MTAPI_TIMEOUT, \c MTAPI_ERR_* or the status - * of any failed Task - * \threadsafe - */ + * Waits for any Task in the Group to finish and + * retrieves the result buffer given in Start(). + * \return The status of the Task that finished execution or \c MTAPI_ERR_* + * \threadsafe + */ + mtapi_status_t WaitAny( + void ** result /**< [out] The result buffer given in + Node::Start, Group::Start or + Queue::Enqueue */ + ) { + return WaitAny(MTAPI_INFINITE, result); + } + + /** + * Waits for any Task in the Group to finish for \c timeout milliseconds. + * \return The status of the Task that finished execution + * \threadsafe + */ + mtapi_status_t WaitAny( + mtapi_timeout_t timeout /**< [in] Timeout duration in + milliseconds */ + ) { + return WaitAny(timeout, MTAPI_NULL); + } + + /** + * Waits for any Task in the Group to finish. + * \return The status of the Task that finished execution + * \threadsafe + */ + mtapi_status_t WaitAny() { + return WaitAny(MTAPI_INFINITE, MTAPI_NULL); + } + + /** + * Waits for all Task in the Group to finish for \c timeout milliseconds. + * \return \c MTAPI_SUCCESS, \c MTAPI_TIMEOUT, \c MTAPI_ERR_* or the status + * of any failed Task + * \threadsafe + */ mtapi_status_t WaitAll( mtapi_timeout_t timeout /**< [in] Timeout duration in milliseconds */ - ); + ) { + mtapi_status_t status; + mtapi_group_wait_all(handle_, timeout, &status); + needs_delete_ = status != MTAPI_SUCCESS; + return status; + } + + /** + * Waits for all Task in the Group to finish. + * \return \c MTAPI_SUCCESS, \c MTAPI_TIMEOUT, \c MTAPI_ERR_* or the status + * of any failed Task + * \threadsafe + */ + mtapi_status_t WaitAll() { + return WaitAll(MTAPI_INFINITE); + } + + /** + * Returns the internal representation of this object. + * Allows for interoperability with the C interface. + * + * \returns The internal mtapi_group_hndl_t. + * \waitfree + */ + mtapi_group_hndl_t GetInternal() const { + return handle_; + } friend class embb::base::Allocation; - friend class Node; - friend class Queue; private: - Group(Group const & group); - Group(); - ~Group(); + // not copyable + Group(Group const & other); + void operator=(Group const & other); + + void Create( + mtapi_group_id_t group_id, + mtapi_group_attributes_t const * attributes + ) { + needs_delete_ = false; + mtapi_status_t status; + handle_ = mtapi_group_create(group_id, attributes, &status); + internal::CheckStatus(status); + needs_delete_ = true; + } - void Create(); + Task Start( + mtapi_task_id_t task_id, + mtapi_job_hndl_t job, + const void * arguments, + mtapi_size_t arguments_size, + void * results, + mtapi_size_t results_size, + mtapi_task_attributes_t const * attributes + ) { + mtapi_status_t status; + mtapi_task_hndl_t task_hndl = + mtapi_task_start(task_id, job, arguments, arguments_size, + results, results_size, attributes, handle_, + &status); + internal::CheckStatus(status); + return Task(task_hndl); + } mtapi_group_hndl_t handle_; + bool needs_delete_; }; } // namespace mtapi diff --git a/mtapi_cpp/include/embb/mtapi/group_attributes.h b/mtapi_cpp/include/embb/mtapi/group_attributes.h new file mode 100644 index 0000000..3f254f2 --- /dev/null +++ b/mtapi_cpp/include/embb/mtapi/group_attributes.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_MTAPI_GROUP_ATTRIBUTES_H_ +#define EMBB_MTAPI_GROUP_ATTRIBUTES_H_ + +#include +#include + +namespace embb { +namespace mtapi { + +/** + * Contains attributes of a Group. + * + * \ingroup CPP_MTAPI + */ +class GroupAttributes { + public: + /** + * Constructs a GroupAttributes object. + */ + GroupAttributes() { + mtapi_status_t status; + mtapi_groupattr_init(&attributes_, &status); + internal::CheckStatus(status); + } + + /** + * Returns the internal representation of this object. + * Allows for interoperability with the C interface. + * + * \returns A reference to the internal mtapi_group_attributes_t structure. + * \waitfree + */ + mtapi_group_attributes_t const & GetInternal() const { + return attributes_; + } + + private: + mtapi_group_attributes_t attributes_; +}; + +} // namespace mtapi +} // namespace embb + +#endif // EMBB_MTAPI_GROUP_ATTRIBUTES_H_ diff --git a/mtapi_cpp/include/embb/mtapi/internal/check_status.h b/mtapi_cpp/include/embb/mtapi/internal/check_status.h new file mode 100644 index 0000000..5176a4d --- /dev/null +++ b/mtapi_cpp/include/embb/mtapi/internal/check_status.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_MTAPI_INTERNAL_CHECK_STATUS_H_ +#define EMBB_MTAPI_INTERNAL_CHECK_STATUS_H_ + +#include + +namespace embb { +namespace mtapi { +namespace internal { + +void CheckStatus(mtapi_status_t status); + +template +inline mtapi_size_t SizeOfType() { + return sizeof(T); +} + +template <> +inline mtapi_size_t SizeOfType() { + return 0u; +} + +} // namespace internal +} // namespace mtapi +} // namespace embb + +#endif // EMBB_MTAPI_INTERNAL_CHECK_STATUS_H_ diff --git a/mtapi_cpp/include/embb/mtapi/job.h b/mtapi_cpp/include/embb/mtapi/job.h new file mode 100644 index 0000000..50eeec9 --- /dev/null +++ b/mtapi_cpp/include/embb/mtapi/job.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_MTAPI_JOB_H_ +#define EMBB_MTAPI_JOB_H_ + +#include +#include + +namespace embb { +namespace mtapi { + +/** + * Represents a collection of Actions. + * + * \ingroup CPP_MTAPI + */ +class Job { + public: + /** + * Constructs a Job. + * The Job object will be invalid. + */ + Job() { + handle_.id = 0; + handle_.tag = 0; + } + + /** + * Constructs a Job with the given \c job_id and \c domain_id. + * Requires an initialized Node. + */ + Job( + mtapi_job_id_t job_id, /**< Job ID to use. */ + mtapi_domain_t domain_id /**< Domain ID to use. */ + ) { + mtapi_status_t status; + handle_ = mtapi_job_get(job_id, domain_id, &status); + internal::CheckStatus(status); + } + + /** + * Copies a Job object. + */ + Job( + Job const & other /**< The Job to copy from */ + ) : handle_(other.handle_) { + // empty + } + + /** + * Copies a Job object. + */ + void operator=( + Job const & other /**< The Job to copy from */ + ) { + handle_ = other.handle_; + } + + /** + * Returns the internal representation of this object. + * Allows for interoperability with the C interface. + * + * \returns The internal mtapi_job_hndl_t. + * \waitfree + */ + mtapi_job_hndl_t GetInternal() const { + return handle_; + } + + private: + mtapi_job_hndl_t handle_; +}; + +} // namespace mtapi +} // namespace embb + +#endif // EMBB_MTAPI_JOB_H_ diff --git a/mtapi_cpp/include/embb/mtapi/mtapi.h b/mtapi_cpp/include/embb/mtapi/mtapi.h index 4c83834..8ceb6e9 100644 --- a/mtapi_cpp/include/embb/mtapi/mtapi.h +++ b/mtapi_cpp/include/embb/mtapi/mtapi.h @@ -35,21 +35,12 @@ * \ingroup CPP */ -#include - -#define MTAPI_CPP_TASK_JOB 1 -#if MTAPI_CPP_AUTOMATIC_INITIALIZE -#define MTAPI_CPP_AUTOMATIC_DOMAIN_ID 1 -#define MTAPI_CPP_AUTOMATIC_NODE_ID 1 -#endif - -#include +#include #include -#include #include -#include #include #include -#include +#include +#include #endif // EMBB_MTAPI_MTAPI_H_ diff --git a/mtapi_cpp/include/embb/mtapi/node.h b/mtapi_cpp/include/embb/mtapi/node.h index a7c5d99..071cfff 100644 --- a/mtapi_cpp/include/embb/mtapi/node.h +++ b/mtapi_cpp/include/embb/mtapi/node.h @@ -27,14 +27,13 @@ #ifndef EMBB_MTAPI_NODE_H_ #define EMBB_MTAPI_NODE_H_ -#include -#include +#include #include -#include +#include +#include #include -#include -#include -#include +#include +#include namespace embb { @@ -47,182 +46,251 @@ class Allocation; namespace mtapi { /** - * A singleton representing the MTAPI runtime. - * - * \ingroup CPP_MTAPI - */ + * A singleton representing the MTAPI runtime. + * + * \ingroup CPP_MTAPI + */ class Node { public: /** - * Initializes the runtime singleton using default values: - * - all available cores will be used - * - maximum number of tasks is 1024 - * - maximum number of groups is 128 - * - maximum number of queues is 16 - * - maximum queue capacity is 1024 - * - maximum number of priorities is 4. - * - * \notthreadsafe - * \throws ErrorException if the singleton was already initialized or the - * Node could not be initialized. - * \memory Allocates about 200kb of memory. - */ + * Initializes the runtime singleton using default values: + * - all available cores will be used + * - maximum number of tasks is 1024 + * - maximum number of groups is 128 + * - maximum number of queues is 16 + * - maximum queue capacity is 1024 + * - maximum number of priorities is 4. + * + * \notthreadsafe + * \throws ErrorException if the singleton was already initialized or the + * Node could not be initialized. + * \memory Allocates about 200kb of memory. + */ static void Initialize( mtapi_domain_t domain_id, /**< [in] The domain id to use */ mtapi_node_t node_id /**< [in] The node id to use */ - ); + ) { + if (IsInitialized()) { + EMBB_THROW(StatusException, + "MTAPI: node was already initialized."); + } else { + NodeAttributes attributes; // default attributes + node_instance_ = embb::base::Allocation::New( + domain_id, node_id, attributes); + } + } /** - * Initializes the runtime singleton. - * \notthreadsafe - * \throws ErrorException if the singleton was already initialized or the - * Node could not be initialized. - * \memory Allocates some memory depending on the values given. - */ + * Initializes the runtime singleton. + * \notthreadsafe + * \throws ErrorException if the singleton was already initialized or the + * Node could not be initialized. + * \memory Allocates some memory depending on the values given. + */ static void Initialize( mtapi_domain_t domain_id, /**< [in] The domain id to use */ mtapi_node_t node_id, /**< [in] The node id to use */ - embb::base::CoreSet const & core_set, - /**< [in] A set of cores MTAPI should - use for its worker threads */ - mtapi_uint_t max_tasks, /**< [in] Maximum number of concurrent - \link Task Tasks \endlink */ - mtapi_uint_t max_groups, /**< [in] Maximum number of concurrent - \link Group Groups \endlink */ - mtapi_uint_t max_queues, /**< [in] Maximum number of concurrent - \link Queue Queues \endlink */ - mtapi_uint_t queue_limit, /**< [in] Maximum Queue capacity */ - mtapi_uint_t max_priorities /**< [in] Maximum number of priorities, - priorities will be between 0 and - max_priorities-1 */ - ); + NodeAttributes const & attributes /**< [in] Attributes to use */ + ) { + if (IsInitialized()) { + EMBB_THROW(StatusException, + "MTAPI: node was already initialized."); + } else { + node_instance_ = embb::base::Allocation::New( + domain_id, node_id, attributes); + } + } /** - * Checks if runtime is initialized. - * \return \c true if the Node singleton is already initialized, false - * otherwise - * \waitfree - */ - static bool IsInitialized(); + * Checks if runtime is initialized. + * \return \c true if the Node singleton is already initialized, false + * otherwise + * \waitfree + */ + static bool IsInitialized() { + return NULL != node_instance_; + } /** - * Gets the instance of the runtime system. - * \return Reference to the Node singleton - * \threadsafe - */ - static Node & GetInstance(); + * Gets the instance of the runtime system. + * \return Reference to the Node singleton + * \threadsafe + */ + static Node & GetInstance() { + if (IsInitialized()) { + return *node_instance_; + } else { + EMBB_THROW(StatusException, + "MTAPI: node is not initialized."); + } + } /** - * Shuts the runtime system down. - * \throws ErrorException if the singleton is not initialized. - * \notthreadsafe - */ - static void Finalize(); + * Shuts the runtime system down. + * \throws ErrorException if the singleton is not initialized. + * \notthreadsafe + */ + static void Finalize() { + if (IsInitialized()) { + embb::base::Allocation::Delete(node_instance_); + node_instance_ = NULL; + } else { + EMBB_THROW(StatusException, + "MTAPI: node is not initialized."); + } + } /** - * Returns the number of available cores. - * \return The number of available cores - * \waitfree - */ + * Returns the number of available cores. + * \return The number of available cores + * \waitfree + */ mtapi_uint_t GetCoreCount() const { return core_count_; } /** - * Returns the number of worker threads. - * \return The number of worker threads. - * \waitfree - */ + * Returns the number of worker threads. + * \return The number of worker threads. + * \waitfree + */ mtapi_uint_t GetWorkerThreadCount() const { return worker_thread_count_; } /** - * Creates a Group to launch \link Task Tasks \endlink in. - * \return A reference to the created Group - * \throws ErrorException if the Group object could not be constructed. - * \threadsafe - * \memory Allocates some memory depending on the configuration of the - * runtime. - */ - Group & CreateGroup(); - - /** - * Destroys a Group. \link Task Tasks \endlink running in the Group will - * finish execution. - * \threadsafe - */ - void DestroyGroup( - Group & group /**< [in,out] The Group to destroy */ - ); - - /** - * Creates a Queue for stream processing. The queue might execute its - * \link Task Tasks \endlink either in order or unordered. - * \return A reference to the new Queue - * \throws ErrorException if the Queue object could not be constructed. - * \threadsafe - * \memory Allocates some memory depending on the configuration of the - * runtime. - */ - Queue & CreateQueue( - mtapi_uint_t priority, /**< [in] Priority of the Queue */ - bool ordered /**< [in] \c true if the Queue should be - ordered, otherwise \c false */ - ); + * Starts a new Task. + * + * \returns The handle to the started Task. + * \threadsafe + */ + template + Task Start( + mtapi_task_id_t task_id, /**< A user defined ID of the Task. */ + Job const & job, /**< The Job to execute. */ + const ARGS * arguments, /**< Pointer to the arguments. */ + RES * results, /**< Pointer to the results. */ + TaskAttributes const & attributes /**< Attributes of the Task */ + ) { + return Start(task_id, + job.GetInternal(), + arguments, internal::SizeOfType(), + results, internal::SizeOfType(), + &attributes.GetInternal()); + } /** - * Destroys a Queue. Running \link Task Tasks \endlink will be canceled. - * \threadsafe - */ - void DestroyQueue( - Queue & queue /**< [in,out] The Queue to destroy */ - ); + * Starts a new Task. + * + * \returns The handle to the started Task. + * \threadsafe + */ + template + Task Start( + mtapi_task_id_t task_id, /**< A user defined ID of the Task. */ + Job const & job, /**< The Job to execute. */ + const ARGS * arguments, /**< Pointer to the arguments. */ + RES * results /**< Pointer to the results. */ + ) { + return Start(task_id, + job.GetInternal(), + arguments, internal::SizeOfType(), + results, internal::SizeOfType(), + MTAPI_DEFAULT_TASK_ATTRIBUTES); + } /** - * Runs an Action. - * \return A Task identifying the Action to run - * \throws ErrorException if the Task object could not be constructed. - * \threadsafe - */ - Task Spawn( - Action action /**< [in] The Action to execute */ - ); + * Starts a new Task. + * + * \returns The handle to the started Task. + * \threadsafe + */ + template + Task Start( + Job const & job, /**< The Job to execute. */ + const ARGS * arguments, /**< Pointer to the arguments. */ + RES * results, /**< Pointer to the results. */ + TaskAttributes const & attributes /**< Attributes of the Task */ + ) { + return Start(MTAPI_TASK_ID_NONE, + job.GetInternal(), + arguments, internal::SizeOfType(), + results, internal::SizeOfType(), + &attributes.GetInternal()); + } /** - * Creates a Continuation. - * \return A Continuation chain - * \threadsafe - */ - Continuation First( - Action action /**< [in] The first Action of the - Continuation chain */ - ); + * Starts a new Task. + * + * \returns The handle to the started Task. + * \threadsafe + */ + template + Task Start( + Job const & job, /**< The Job to execute. */ + const ARGS * arguments, /**< Pointer to the arguments. */ + RES * results /**< Pointer to the results. */ + ) { + return Start(MTAPI_TASK_ID_NONE, + job.GetInternal(), + arguments, internal::SizeOfType(), + results, internal::SizeOfType(), + MTAPI_DEFAULT_TASK_ATTRIBUTES); + } friend class embb::base::Allocation; private: + // not copyable Node(Node const & node); + Node const & operator=(Node const & other); + Node( mtapi_domain_t domain_id, mtapi_node_t node_id, - mtapi_node_attributes_t * attr); - ~Node(); - - static void action_func( - const void* args, - mtapi_size_t args_size, - void* result_buffer, - mtapi_size_t result_buffer_size, - const void* node_local_data, - mtapi_size_t node_local_data_size, - mtapi_task_context_t * context); + NodeAttributes const & attr) { + mtapi_status_t status; + mtapi_info_t info; + mtapi_initialize(domain_id, node_id, &attr.GetInternal(), &info, &status); + needs_finalize_ = status == MTAPI_SUCCESS; + internal::CheckStatus(status); + + core_count_ = info.hardware_concurrency; + worker_thread_count_ = embb_core_set_count( + &attr.GetInternal().core_affinity); + } + + ~Node() { + if (needs_finalize_) { + mtapi_status_t status; + mtapi_finalize(&status); + internal::CheckStatus(status); + } + } + + Task Start( + mtapi_task_id_t task_id, + mtapi_job_hndl_t job, + const void * arguments, + mtapi_size_t arguments_size, + void * results, + mtapi_size_t results_size, + mtapi_task_attributes_t const * attributes + ) { + mtapi_status_t status; + mtapi_task_hndl_t task_hndl = + mtapi_task_start(task_id, job, arguments, arguments_size, + results, results_size, attributes, MTAPI_GROUP_NONE, + &status); + internal::CheckStatus(status); + return Task(task_hndl); + } + + static embb::mtapi::Node * node_instance_; mtapi_uint_t core_count_; mtapi_uint_t worker_thread_count_; - mtapi_action_hndl_t action_handle_; - std::list queues_; - std::list groups_; + bool needs_finalize_; }; } // namespace mtapi diff --git a/mtapi_cpp/include/embb/mtapi/node_attributes.h b/mtapi_cpp/include/embb/mtapi/node_attributes.h new file mode 100644 index 0000000..1dc104e --- /dev/null +++ b/mtapi_cpp/include/embb/mtapi/node_attributes.h @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_MTAPI_NODE_ATTRIBUTES_H_ +#define EMBB_MTAPI_NODE_ATTRIBUTES_H_ + +#include +#include +#include + +namespace embb { +namespace mtapi { + +/** + * Contains attributes of a Node. + * + * \ingroup CPP_MTAPI + */ +class NodeAttributes { + public: + /** + * Constructs a NodeAttributes object. + */ + NodeAttributes() { + mtapi_status_t status; + mtapi_nodeattr_init(&attributes_, &status); + internal::CheckStatus(status); + } + + /** + * Copies a NodeAttributes object. + */ + NodeAttributes( + NodeAttributes const & other /**< The NodeAttributes to copy. */ + ) + : attributes_(other.attributes_) { + // empty + } + + /** + * Copies a NodeAttributes object. + */ + void operator=( + NodeAttributes const & other /**< The NodeAttributes to copy. */ + ) { + attributes_ = other.attributes_; + } + + /** + * Sets the core affinity of the Node. This also determines the number of + * worker threads. + * + * \returns Reference to this object. + * \notthreadsafe + */ + NodeAttributes & SetCoreAffinity( + embb::base::CoreSet const & cores /**< The cores to use. */ + ) { + mtapi_status_t status; + mtapi_nodeattr_set(&attributes_, MTAPI_NODE_CORE_AFFINITY, + &cores.GetInternal(), sizeof(embb_core_set_t), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Sets the maximum number of concurrently active tasks. + * + * \returns Reference to this object. + * \notthreadsafe + */ + NodeAttributes & SetMaxTasks( + mtapi_uint_t value /**< The value to set. */ + ) { + mtapi_status_t status; + mtapi_nodeattr_set(&attributes_, MTAPI_NODE_MAX_TASKS, + &value, sizeof(value), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Sets the maximum number of actions. + * + * \returns Reference to this object. + * \notthreadsafe + */ + NodeAttributes & SetMaxActions( + mtapi_uint_t value /**< The value to set. */ + ) { + mtapi_status_t status; + mtapi_nodeattr_set(&attributes_, MTAPI_NODE_MAX_ACTIONS, + &value, sizeof(value), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Sets the maximum number of groups. + * + * \returns Reference to this object. + * \notthreadsafe + */ + NodeAttributes & SetMaxGroups( + mtapi_uint_t value /**< The value to set. */ + ) { + mtapi_status_t status; + mtapi_nodeattr_set(&attributes_, MTAPI_NODE_MAX_GROUPS, + &value, sizeof(value), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Sets the maximum number of queues. + * + * \returns Reference to this object. + * \notthreadsafe + */ + NodeAttributes & SetMaxQueues( + mtapi_uint_t value /**< The value to set. */ + ) { + mtapi_status_t status; + mtapi_nodeattr_set(&attributes_, MTAPI_NODE_MAX_QUEUES, + &value, sizeof(value), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Sets the default limit (capacity) of all queues. + * + * \returns Reference to this object. + * \notthreadsafe + */ + NodeAttributes & SetQueueLimit( + mtapi_uint_t value /**< The value to set. */ + ) { + mtapi_status_t status; + mtapi_nodeattr_set(&attributes_, MTAPI_NODE_QUEUE_LIMIT, + &value, sizeof(value), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Sets the maximum number of available jobs. + * + * \returns Reference to this object. + * \notthreadsafe + */ + NodeAttributes & SetMaxJobs( + mtapi_uint_t value /**< The value to set. */ + ) { + mtapi_status_t status; + mtapi_nodeattr_set(&attributes_, MTAPI_NODE_MAX_JOBS, + &value, sizeof(value), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Sets the maximum number of actions per job. + * + * \returns Reference to this object. + * \notthreadsafe + */ + NodeAttributes & SetMaxActionsPerJob( + mtapi_uint_t value /**< The value to set. */ + ) { + mtapi_status_t status; + mtapi_nodeattr_set(&attributes_, MTAPI_NODE_MAX_ACTIONS_PER_JOB, + &value, sizeof(value), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Sets the maximum number of available priorities. The priority values + * will range from 0 to \c value - 1 with 0 being the highest priority. + * + * \returns Reference to this object. + * \notthreadsafe + */ + NodeAttributes & SetMaxPriorities( + mtapi_uint_t value /**< The value to set. */ + ) { + mtapi_status_t status; + mtapi_nodeattr_set(&attributes_, MTAPI_NODE_MAX_PRIORITIES, + &value, sizeof(value), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Returns the internal representation of this object. + * Allows for interoperability with the C interface. + * + * \returns A reference to the internal mtapi_node_attributes_t structure. + * \waitfree + */ + mtapi_node_attributes_t const & GetInternal() const { + return attributes_; + } + + private: + mtapi_node_attributes_t attributes_; +}; + +} // namespace mtapi +} // namespace embb + +#endif // EMBB_MTAPI_NODE_ATTRIBUTES_H_ diff --git a/mtapi_cpp/include/embb/mtapi/queue.h b/mtapi_cpp/include/embb/mtapi/queue.h index 4671359..43e957b 100644 --- a/mtapi_cpp/include/embb/mtapi/queue.h +++ b/mtapi_cpp/include/embb/mtapi/queue.h @@ -28,9 +28,11 @@ #define EMBB_MTAPI_QUEUE_H_ #include -#include +#include #include #include +#include +#include namespace embb { @@ -43,69 +45,270 @@ class Allocation; namespace mtapi { /** - * Allows for stream processing, either ordered or unordered. - * - * \ingroup CPP_MTAPI - */ + * Allows for stream processing, either ordered or unordered. + * + * \ingroup CPP_MTAPI + */ class Queue { public: /** - * Enables the Queue. \link Task Tasks \endlink enqueued while the Queue was - * disabled are executed. - * \waitfree - */ - void Enable(); + * Constructs a Queue with the given Job and default attributes. + * Requires an initialized Node. + */ + Queue( + Job const & job /**< The Job to use for the Queue. */ + ) { + Create(MTAPI_QUEUE_ID_NONE, job, MTAPI_DEFAULT_QUEUE_ATTRIBUTES); + } + + /** + * Constructs a Queue with the given Job and QueueAttributes. + * Requires an initialized Node. + */ + Queue( + Job const & job, /**< The Job to use for the Queue. */ + QueueAttributes const & attr /**< The attributes to use. */ + ) { + Create(MTAPI_QUEUE_ID_NONE, job, &attr.GetInternal()); + } /** - * Disables the Queue. Running \link Task Tasks \endlink are canceled. - * \waitfree - */ - void Disable(); + * Destroys a Queue object. + */ + ~Queue() { + mtapi_queue_delete(handle_, MTAPI_INFINITE, MTAPI_NULL); + } /** - * Runs an Action. - * \return A Task identifying the Action to run - * \throws ErrorException if the Task object could not be constructed. - * \threadsafe - */ - Task Spawn( - Action action /**< [in] The Action to run */ - ); + * Enables the Queue. \link Task Tasks \endlink enqueued while the Queue was + * disabled are executed. + * \waitfree + */ + void Enable() { + mtapi_status_t status; + mtapi_queue_enable(handle_, &status); + internal::CheckStatus(status); + } /** - * Runs an Action in the specified Group - * \return A Task identifying the Action to run - * \throws ErrorException if the Task object could not be constructed. - * \threadsafe - */ - Task Spawn( - Group const * group, /**< [in] The Group to run the Action - in */ - Action action /**< [in] The Action to run */ - ); + * Disables the Queue. Running \link Task Tasks \endlink are canceled. The + * Queue waits for the Tasks to finish for \c timout milliseconds. + * \waitfree + */ + void Disable( + mtapi_timeout_t timeout /**< The timeout in milliseconds. */ + ) { + mtapi_status_t status; + mtapi_queue_disable(handle_, timeout, &status); + internal::CheckStatus(status); + } /** - * Runs an Action in the specified Group. The \c id is returned by - * Group::WaitAny(). - * \return A Task identifying the Action to run - * \throws ErrorException if the Task object could not be constructed. - * \threadsafe - */ - Task Spawn( - mtapi_task_id_t id, /**< [in] The id to return in - Group::WaitAny() */ - Group const * group, /**< [in] The Group to run the Action - in */ - Action action /**< [in] The Action to run */ - ); + * Disables the Queue. Running \link Task Tasks \endlink are canceled. The + * Queue waits for the Tasks to finish. + * \waitfree + */ + void Disable() { + Disable(MTAPI_INFINITE); + } + + /** + * Enqueues a new Task. + * + * \returns The handle to the enqueued Task. + * \threadsafe + */ + template + Task Enqueue( + mtapi_task_id_t task_id, /**< A user defined ID of the Task. */ + const ARGS * arguments, /**< Pointer to the arguments. */ + RES * results, /**< Pointer to the results. */ + TaskAttributes const & attributes, /**< Attributes of the Task */ + Group const & group /**< The Group to start the Task in */ + ) { + return Enqueue(task_id, + arguments, internal::SizeOfType(), + results, internal::SizeOfType(), + &attributes.GetInternal(), group.GetInternal()); + } + + /** + * Enqueues a new Task. + * + * \returns The handle to the enqueued Task. + * \threadsafe + */ + template + Task Enqueue( + mtapi_task_id_t task_id, /**< A user defined ID of the Task. */ + const ARGS * arguments, /**< Pointer to the arguments. */ + RES * results, /**< Pointer to the results. */ + Group const & group /**< The Group to start the Task in */ + ) { + return Enqueue(task_id, + arguments, internal::SizeOfType(), + results, internal::SizeOfType(), + MTAPI_DEFAULT_TASK_ATTRIBUTES, group.GetInternal()); + } + + /** + * Enqueues a new Task. + * + * \returns The handle to the enqueued Task. + * \threadsafe + */ + template + Task Enqueue( + mtapi_task_id_t task_id, /**< A user defined ID of the Task. */ + const ARGS * arguments, /**< Pointer to the arguments. */ + RES * results, /**< Pointer to the results. */ + TaskAttributes const & attributes /**< Attributes of the Task */ + ) { + return Enqueue(task_id, + arguments, internal::SizeOfType(), + results, internal::SizeOfType(), + &attributes.GetInternal(), MTAPI_GROUP_NONE); + } + + /** + * Enqueues a new Task. + * + * \returns The handle to the enqueued Task. + * \threadsafe + */ + template + Task Enqueue( + mtapi_task_id_t task_id, /**< A user defined ID of the Task. */ + const ARGS * arguments, /**< Pointer to the arguments. */ + RES * results /**< Pointer to the results. */ + ) { + return Enqueue(task_id, + arguments, internal::SizeOfType(), + results, internal::SizeOfType(), + MTAPI_DEFAULT_TASK_ATTRIBUTES, MTAPI_GROUP_NONE); + } + + /** + * Enqueues a new Task. + * + * \returns The handle to the enqueued Task. + * \threadsafe + */ + template + Task Enqueue( + const ARGS * arguments, /**< Pointer to the arguments. */ + RES * results, /**< Pointer to the results. */ + TaskAttributes const & attributes, /**< Attributes of the Task */ + Group const & group /**< The Group to start the Task in */ + ) { + return Enqueue(MTAPI_TASK_ID_NONE, + arguments, internal::SizeOfType(), + results, internal::SizeOfType(), + &attributes.GetInternal(), group.GetInternal()); + } + + /** + * Enqueues a new Task. + * + * \returns The handle to the enqueued Task. + * \threadsafe + */ + template + Task Enqueue( + const ARGS * arguments, /**< Pointer to the arguments. */ + RES * results, /**< Pointer to the results. */ + Group const & group /**< The Group to start the Task in */ + ) { + return Enqueue(MTAPI_TASK_ID_NONE, + arguments, internal::SizeOfType(), + results, internal::SizeOfType(), + MTAPI_DEFAULT_TASK_ATTRIBUTES, group.GetInternal()); + } + + /** + * Enqueues a new Task. + * + * \returns The handle to the enqueued Task. + * \threadsafe + */ + template + Task Enqueue( + const ARGS * arguments, /**< Pointer to the arguments. */ + RES * results, /**< Pointer to the results. */ + TaskAttributes const & attributes /**< Attributes of the Task */ + ) { + return Enqueue(MTAPI_TASK_ID_NONE, + arguments, internal::SizeOfType(), + results, internal::SizeOfType(), + &attributes.GetInternal(), MTAPI_GROUP_NONE); + } + + /** + * Enqueues a new Task. + * + * \returns The handle to the enqueued Task. + * \threadsafe + */ + template + Task Enqueue( + const ARGS * arguments, /**< Pointer to the arguments. */ + RES * results /**< Pointer to the results. */ + ) { + return Enqueue(MTAPI_TASK_ID_NONE, + arguments, internal::SizeOfType(), + results, internal::SizeOfType(), + MTAPI_DEFAULT_TASK_ATTRIBUTES, MTAPI_GROUP_NONE); + } + + /** + * Returns the internal representation of this object. + * Allows for interoperability with the C interface. + * + * \returns The internal mtapi_queue_hndl_t. + * \waitfree + */ + mtapi_queue_hndl_t GetInternal() const { + return handle_; + } friend class embb::base::Allocation; - friend class Node; private: - Queue(Queue const & taskqueue); - Queue(mtapi_uint_t priority, bool ordered); - ~Queue(); + // no default constructor + Queue(); + + // not copyable + Queue(Queue const & other); + void operator=(Queue const & other); + + void Create( + mtapi_queue_id_t queue_id, + Job const & job, + mtapi_queue_attributes_t const * attributes + ) { + mtapi_status_t status; + handle_ = mtapi_queue_create(queue_id, job.GetInternal(), + attributes, &status); + internal::CheckStatus(status); + } + + Task Enqueue( + mtapi_task_id_t task_id, + const void * arguments, + mtapi_size_t arguments_size, + void * results, + mtapi_size_t results_size, + mtapi_task_attributes_t const * attributes, + mtapi_group_hndl_t group + ) { + mtapi_status_t status; + mtapi_task_hndl_t task_hndl = + mtapi_task_enqueue(task_id, handle_, arguments, arguments_size, + results, results_size, attributes, group, + &status); + internal::CheckStatus(status); + return Task(task_hndl); + } mtapi_queue_hndl_t handle_; }; diff --git a/mtapi_cpp/include/embb/mtapi/queue_attributes.h b/mtapi_cpp/include/embb/mtapi/queue_attributes.h new file mode 100644 index 0000000..e5050b0 --- /dev/null +++ b/mtapi_cpp/include/embb/mtapi/queue_attributes.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_MTAPI_QUEUE_ATTRIBUTES_H_ +#define EMBB_MTAPI_QUEUE_ATTRIBUTES_H_ + +#include +#include + +namespace embb { +namespace mtapi { + +/** + * Contains attributes of a Queue. + * + * \ingroup CPP_MTAPI + */ +class QueueAttributes { + public: + /** + * Constructs a QueueAttributes object. + */ + QueueAttributes() { + mtapi_status_t status; + mtapi_queueattr_init(&attributes_, &status); + internal::CheckStatus(status); + } + + /** + * Sets the global property of a Queue. + * This determines whether the object will be visible across nodes. + * + * \returns Reference to this object. + * \notthreadsafe + */ + QueueAttributes & SetGlobal( + bool state /**< The state to set. */ + ) { + mtapi_status_t status; + mtapi_boolean_t st = state ? MTAPI_TRUE : MTAPI_FALSE; + mtapi_queueattr_set(&attributes_, MTAPI_QUEUE_GLOBAL, + &st, sizeof(st), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Sets the ordered property of a Queue. + * If set to \c true, tasks enqueued will be executed in order. + * + * \returns Reference to this object. + * \notthreadsafe + */ + QueueAttributes & SetOrdered( + bool state /**< The state to set. */ + ) { + mtapi_status_t status; + mtapi_boolean_t st = state ? MTAPI_TRUE : MTAPI_FALSE; + mtapi_queueattr_set(&attributes_, MTAPI_QUEUE_ORDERED, + &st, sizeof(st), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Sets the retain property of a Queue. + * If set to \c true, tasks will be retained while a queue is disabled. + * Otherwise the will be canceled. + * + * \returns Reference to this object. + * \notthreadsafe + */ + QueueAttributes & SetRetain( + bool state /**< The state to set. */ + ) { + mtapi_status_t status; + mtapi_boolean_t st = state ? MTAPI_TRUE : MTAPI_FALSE; + mtapi_queueattr_set(&attributes_, MTAPI_QUEUE_RETAIN, + &st, sizeof(st), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Sets the domain shared property of a Queue. + * This determines whether the object will be visible across domains. + * + * \returns Reference to this object. + * \notthreadsafe + */ + QueueAttributes & SetDomainShared( + bool state /**< The state to set. */ + ) { + mtapi_status_t status; + mtapi_boolean_t st = state ? MTAPI_TRUE : MTAPI_FALSE; + mtapi_queueattr_set(&attributes_, MTAPI_QUEUE_DOMAIN_SHARED, + &st, sizeof(st), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Sets the priority of a Queue. + * The priority influences the order in which tasks are chosen for execution. + * + * \returns Reference to this object. + * \notthreadsafe + */ + QueueAttributes & SetPriority( + mtapi_uint_t priority /**< The priority to set. */ + ) { + mtapi_status_t status; + mtapi_queueattr_set(&attributes_, MTAPI_QUEUE_PRIORITY, + &priority, sizeof(priority), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Sets the limit (capacity) of a Queue. + * + * \returns Reference to this object. + * \notthreadsafe + */ + QueueAttributes & SetLimit( + mtapi_uint_t limit /**< The limit to set. */ + ) { + mtapi_status_t status; + mtapi_queueattr_set(&attributes_, MTAPI_QUEUE_LIMIT, + &limit, sizeof(limit), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Returns the internal representation of this object. + * Allows for interoperability with the C interface. + * + * \returns A reference to the internal mtapi_queue_attributes_t structure. + * \waitfree + */ + mtapi_queue_attributes_t const & GetInternal() const { + return attributes_; + } + + private: + mtapi_queue_attributes_t attributes_; +}; + +} // namespace mtapi +} // namespace embb + +#endif // EMBB_MTAPI_QUEUE_ATTRIBUTES_H_ diff --git a/mtapi_cpp/include/embb/mtapi/status_exception.h b/mtapi_cpp/include/embb/mtapi/status_exception.h new file mode 100644 index 0000000..a69c78a --- /dev/null +++ b/mtapi_cpp/include/embb/mtapi/status_exception.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_MTAPI_STATUS_EXCEPTION_H_ +#define EMBB_MTAPI_STATUS_EXCEPTION_H_ + +#include + +namespace embb { +namespace mtapi { + +/** + * Represents an MTAPI error state and is thrown by almost all mtapi_cpp + * methods. + * + * \ingroup CPP_MTAPI + */ +class StatusException : public embb::base::Exception { + public: + /** + * Constructs a StatusException. + */ + explicit StatusException( + const char* message /**< The message to use. */ + ) + : embb::base::Exception(message) { + // empty + } + + /** + * Returns the code of the exception. + * \waitfree + */ + virtual int Code() const { return EMBB_ERROR; } +}; + +} // namespace mtapi +} // namespace embb + +#endif // EMBB_MTAPI_STATUS_EXCEPTION_H_ diff --git a/mtapi_cpp/include/embb/mtapi/task.h b/mtapi_cpp/include/embb/mtapi/task.h index a98e09a..40f3aaf 100644 --- a/mtapi_cpp/include/embb/mtapi/task.h +++ b/mtapi_cpp/include/embb/mtapi/task.h @@ -28,85 +28,109 @@ #define EMBB_MTAPI_TASK_H_ #include -#include +#include namespace embb { namespace mtapi { /** - * A Task represents a running Action. - * - * \ingroup CPP_MTAPI - */ + * A Task represents a running Action of a specific Job. + * + * \ingroup CPP_MTAPI + */ class Task { public: /** - * Constructs an empty Task - */ - Task(); + * Constructs an invalid Task. + */ + Task() { + handle_.id = 0; + handle_.tag = 0; + } /** - * Copies a Task - */ + * Copies a Task. + */ Task( - Task const & task /**< The task to copy. */ - ); + Task const & other /**< The task to copy. */ + ) : handle_(other.handle_) { + // emtpy + } + + /** + * Copies a Task. + */ + void operator=( + Task const & other /**< The task to copy. */ + ) { + handle_ = other.handle_; + } /** - * Destroys a Task - */ - ~Task(); + * Destroys a Task. + */ + ~Task() { + // empty + } /** - * Waits for Task to finish for \c timeout milliseconds. - * \return The status of the finished Task, \c MTAPI_TIMEOUT or - * \c MTAPI_ERR_* - * \threadsafe - */ + * Waits for Task to finish for \c timeout milliseconds. + * \return The status of the finished Task, \c MTAPI_TIMEOUT or + * \c MTAPI_ERR_* + * \threadsafe + */ mtapi_status_t Wait( mtapi_timeout_t timeout /**< [in] Timeout duration in milliseconds */ - ); + ) { + mtapi_status_t status; + mtapi_task_wait(handle_, timeout, &status); + return status; + } /** - * Signals the Task to cancel computation. - * \waitfree - */ - void Cancel(); - - friend class Group; - friend class Queue; - friend class Node; - - private: - Task( - Action action); - - Task( - Action action, - mtapi_group_hndl_t group); + * Waits for Task to finish. + * \return The status of the finished Task or \c MTAPI_ERR_* + * \threadsafe + */ + mtapi_status_t Wait() { + mtapi_status_t status; + mtapi_task_wait(handle_, MTAPI_INFINITE, &status); + return status; + } - Task( - mtapi_task_id_t id, - Action action, - mtapi_group_hndl_t group); - - Task( - Action action, - mtapi_queue_hndl_t queue); + /** + * Signals the Task to cancel computation. + * \waitfree + */ + void Cancel() { + mtapi_status_t status; + mtapi_task_cancel(handle_, &status); + internal::CheckStatus(status); + } - Task( - Action action, - mtapi_queue_hndl_t queue, - mtapi_group_hndl_t group); + /** + * Returns the internal representation of this object. + * Allows for interoperability with the C interface. + * + * \returns The internal mtapi_task_hndl_t. + * \waitfree + */ + mtapi_task_hndl_t GetInternal() const { + return handle_; + } - Task( - mtapi_task_id_t id, - Action action, - mtapi_queue_hndl_t queue, - mtapi_group_hndl_t group); + private: + explicit Task(mtapi_task_hndl_t handle) + : handle_(handle) { + // empty + } mtapi_task_hndl_t handle_; + + friend class Node; + friend class Group; + friend class Queue; }; } // namespace mtapi diff --git a/mtapi_cpp/include/embb/mtapi/task_attributes.h b/mtapi_cpp/include/embb/mtapi/task_attributes.h new file mode 100644 index 0000000..e743279 --- /dev/null +++ b/mtapi_cpp/include/embb/mtapi/task_attributes.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_MTAPI_TASK_ATTRIBUTES_H_ +#define EMBB_MTAPI_TASK_ATTRIBUTES_H_ + +#include +#include + +namespace embb { +namespace mtapi { + +/** + * Contains attributes of a Task. + * + * \ingroup CPP_MTAPI + */ +class TaskAttributes { + public: + /** + * Constructs a TaskAttributes object. + */ + TaskAttributes() { + mtapi_status_t status; + mtapi_taskattr_init(&attributes_, &status); + internal::CheckStatus(status); + } + + /** + * Sets the detached property of a Task. + * If set to \c true, the started Task will have no handle and cannot be + * waited for. + * + * \returns Reference to this object. + * \notthreadsafe + */ + TaskAttributes & SetDetached( + bool state /**< The state to set. */ + ) { + mtapi_status_t status; + mtapi_boolean_t st = state ? MTAPI_TRUE : MTAPI_FALSE; + mtapi_taskattr_set(&attributes_, MTAPI_TASK_DETACHED, + &st, sizeof(st), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Sets the priority of a Task. + * The priority influences the order in which tasks are chosen for execution. + * + * \returns Reference to this object. + * \notthreadsafe + */ + TaskAttributes & SetPriority( + mtapi_uint_t priority /**< The priority to set. */ + ) { + mtapi_status_t status; + mtapi_taskattr_set(&attributes_, MTAPI_TASK_PRIORITY, + &priority, sizeof(priority), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Sets the number of instances in a Task. + * The Task will be launched \c instances times. In the action function, + * the number of instances and the current instance can be queried from + * the TaskContext. + * + * \returns Reference to this object. + * \notthreadsafe + */ + TaskAttributes & SetInstances( + mtapi_uint_t instances /**< Number of instances to set. */ + ) { + mtapi_status_t status; + mtapi_taskattr_set(&attributes_, MTAPI_TASK_INSTANCES, + &instances, sizeof(instances), &status); + internal::CheckStatus(status); + return *this; + } + + /** + * Returns the internal representation of this object. + * Allows for interoperability with the C interface. + * + * \returns A reference to the internal mtapi_task_attributes_t structure. + * \waitfree + */ + mtapi_task_attributes_t const & GetInternal() const { + return attributes_; + } + + private: + mtapi_task_attributes_t attributes_; +}; + +} // namespace mtapi +} // namespace embb + +#endif // EMBB_MTAPI_TASK_ATTRIBUTES_H_ diff --git a/mtapi_cpp/include/embb/mtapi/task_context.h b/mtapi_cpp/include/embb/mtapi/task_context.h new file mode 100644 index 0000000..73df784 --- /dev/null +++ b/mtapi_cpp/include/embb/mtapi/task_context.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_MTAPI_TASK_CONTEXT_H_ +#define EMBB_MTAPI_TASK_CONTEXT_H_ + +#include +#include + +namespace embb { +namespace mtapi { + +/** + * Provides information about the status of the currently running Task. + * + * \ingroup CPP_MTAPI + */ +class TaskContext { + public: + /** + * Constructs a TaskContext from the given C representation. + */ + explicit TaskContext( + mtapi_task_context_t * task_context + /**< The C task context to wrap. */ + ) + : context_(task_context) { + // empty + } + + /** + * Queries whether the Task running in the TaskContext should finish. + * \return \c true if the Task should finish, otherwise \c false + * \notthreadsafe + */ + bool ShouldCancel() { + return MTAPI_TASK_CANCELLED == GetTaskState(); + } + + /** + * Queries the current Task state. + * \return The current Task state. + * \notthreadsafe + */ + mtapi_task_state_t GetTaskState() { + mtapi_status_t status; + mtapi_task_state_t result = + mtapi_context_taskstate_get(context_, &status); + internal::CheckStatus(status); + return result; + } + + /** + * Queries the index of the worker thread the Task is running on. + * \return The worker thread index the Task is running on + * \notthreadsafe + */ + mtapi_uint_t GetCurrentWorkerNumber() { + mtapi_status_t status; + mtapi_uint_t result = mtapi_context_corenum_get(context_, &status); + internal::CheckStatus(status); + return result; + } + + /** + * Queries the current instance of the currently executing Task. + * \return The current instance number + * \notthreadsafe + */ + mtapi_uint_t GetInstanceNumber() { + mtapi_status_t status; + mtapi_uint_t result = mtapi_context_instnum_get(context_, &status); + internal::CheckStatus(status); + return result; + } + + /** + * Queries the number of instances of the currently executing Task. + * \return The number of instances + * \notthreadsafe + */ + mtapi_uint_t GetNumberOfInstances() { + mtapi_status_t status; + mtapi_uint_t result = mtapi_context_numinst_get(context_, &status); + internal::CheckStatus(status); + return result; + } + + /** + * Sets the return status of the running Task. This will be returned by + * Task::Wait() and is set to \c MTAPI_SUCCESS by default. + * \notthreadsafe + */ + void SetStatus( + mtapi_status_t error_code /**< [in] The status to return by + Task::Wait(), Group::WaitAny(), + Group::WaitAll() */ + ) { + mtapi_status_t status; + mtapi_context_status_set(context_, error_code, &status); + internal::CheckStatus(status); + } + + /** + * Returns the internal representation of this object. + * Allows for interoperability with the C interface. + * + * \returns A pointer to a mtapi_task_context_t. + * \notthreadsafe + */ + mtapi_task_context_t * GetInternal() const { + return context_; + } + + private: + // no default constructor + TaskContext(); + + mtapi_task_context_t * context_; +}; + +} // namespace mtapi +} // namespace embb + +#endif // EMBB_MTAPI_TASK_CONTEXT_H_ diff --git a/mtapi_cpp/src/check_status.cc b/mtapi_cpp/src/check_status.cc new file mode 100644 index 0000000..7af10ae --- /dev/null +++ b/mtapi_cpp/src/check_status.cc @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +namespace embb { +namespace mtapi { +namespace internal { + +void CheckStatus(mtapi_status_t status) { + if (MTAPI_SUCCESS != status) { + switch (status) { + case MTAPI_SUCCESS: + case MTAPI_TIMEOUT: + case MTAPI_GROUP_COMPLETED: + // these are no errors + break; + + case MTAPI_ERR_NODE_INITIALIZED: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: node already initialized."); + break; + case MTAPI_ERR_NODE_NOTINIT: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: node not initialized."); + break; + case MTAPI_ERR_PARAMETER: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: invalid parameter."); + break; + case MTAPI_ERR_CORE_NUM: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: invalid worker number."); + break; + case MTAPI_ERR_RUNTIME_LOADBALANCING_NOTSUPPORTED: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: load balancing not supported."); + break; + case MTAPI_ERR_RUNTIME_REMOTETASKS_NOTSUPPORTED: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: remote tasks not supported."); + break; + case MTAPI_ERR_ARG_NOT_IMPLEMENTED: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: argument not implemented."); + break; + case MTAPI_ERR_FUNC_NOT_IMPLEMENTED: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: function not implemented."); + break; + case MTAPI_ERR_WAIT_PENDING: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: wait pending."); + break; + case MTAPI_ERR_ARG_SIZE: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: argument size mismatch."); + break; + case MTAPI_ERR_RESULT_SIZE: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: result buffer size mismatch."); + break; + case MTAPI_ERR_BUFFER_SIZE: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: buffer size mismatch."); + break; + case MTAPI_ERR_GROUP_LIMIT: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: group limit exceeded."); + break; + case MTAPI_ERR_GROUP_INVALID: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: group invalid."); + break; + case MTAPI_ERR_QUEUE_LIMIT: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: queue limit exceeded."); + break; + case MTAPI_ERR_QUEUE_DISABLED: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: queue disabled."); + break; + case MTAPI_ERR_QUEUE_DELETED: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: queue deleted."); + break; + case MTAPI_ERR_QUEUE_INVALID: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: queue invalid."); + break; + case MTAPI_ERR_JOB_INVALID: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: job invalid."); + break; + case MTAPI_ERR_TASK_LIMIT: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: task limit exceeded."); + break; + case MTAPI_ERR_TASK_INVALID: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: task invalid."); + break; + case MTAPI_ERR_CONTEXT_OUTOFCONTEXT: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: task context used outside of worker thread."); + break; + case MTAPI_ERR_CONTEXT_INVALID: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: task context invalid."); + break; + case MTAPI_ERR_ACTION_DISABLED: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: action disabled."); + break; + case MTAPI_ERR_ACTION_DELETED: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: action deleted."); + break; + case MTAPI_ERR_ACTION_CANCELLED: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: action canceled."); + break; + case MTAPI_ERR_ACTION_FAILED: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: action failed."); + break; + case MTAPI_ERR_ACTION_LIMIT: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: action limit exceeded."); + break; + case MTAPI_ERR_ACTION_EXISTS: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: action already exists."); + break; + case MTAPI_ERR_ACTION_INVALID: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: action invalid."); + break; + case MTAPI_ERR_DOMAIN_INVALID: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: domain invalid."); + break; + case MTAPI_ERR_NODE_INVALID: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: node invalid."); + break; + case MTAPI_ERR_NODE_INITFAILED: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: node initialization failed."); + break; + case MTAPI_ERR_ATTR_SIZE: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: attribute size mismatch."); + break; + case MTAPI_ERR_ATTR_NUM: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: invalid attribute."); + break; + case MTAPI_ERR_ATTR_READONLY: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: attribute is read only."); + break; + + case MTAPI_ERR_ACTION_NUM_INVALID: + case MTAPI_ERR_UNKNOWN: + default: + EMBB_THROW(embb::mtapi::StatusException, + "MTAPI: unknown error."); + break; + } + } +} + +} // namespace internal +} // namespace mtapi +} // namespace embb diff --git a/mtapi_cpp/src/node.cc b/mtapi_cpp/src/node.cc index 0ffe21a..80e9406 100644 --- a/mtapi_cpp/src/node.cc +++ b/mtapi_cpp/src/node.cc @@ -24,251 +24,12 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include -#include -#include -#include - -#include -#include -#include -#if MTAPI_CPP_AUTOMATIC_INITIALIZE -#include -#endif - -namespace { - -static embb::mtapi::Node * node_instance = NULL; -#if MTAPI_CPP_AUTOMATIC_INITIALIZE -static embb::base::Mutex init_mutex; -#endif - -} +#include namespace embb { namespace mtapi { -void Node::action_func( - const void* args, - mtapi_size_t /*args_size*/, - void* /*result_buffer*/, - mtapi_size_t /*result_buffer_size*/, - const void* /*node_local_data*/, - mtapi_size_t /*node_local_data_size*/, - mtapi_task_context_t * context) { - mtapi::Action * action = - reinterpret_cast(const_cast(args)); - mtapi::TaskContext task_context(context); - (*action)(task_context); - embb::base::Allocation::Delete(action); -} - -Node::Node( - mtapi_domain_t domain_id, - mtapi_node_t node_id, - mtapi_node_attributes_t * attr) { - mtapi_status_t status; - mtapi_info_t info; - mtapi_initialize(domain_id, node_id, attr, &info, &status); - if (MTAPI_SUCCESS != status) { - EMBB_THROW(embb::base::ErrorException, - "mtapi::Node could not initialize mtapi"); - } - core_count_ = info.hardware_concurrency; - worker_thread_count_ = embb_core_set_count(&attr->core_affinity); - action_handle_ = mtapi_action_create(MTAPI_CPP_TASK_JOB, action_func, - MTAPI_NULL, 0, MTAPI_NULL, &status); - if (MTAPI_SUCCESS != status) { - EMBB_THROW(embb::base::ErrorException, - "mtapi::Node could not create an action"); - } -} - -Node::~Node() { - for (std::list::iterator ii = queues_.begin(); - ii != queues_.end(); - ++ii) { - embb::base::Allocation::Delete(*ii); - } - queues_.clear(); - - for (std::list::iterator ii = groups_.begin(); - ii != groups_.end(); - ++ii) { - embb::base::Allocation::Delete(*ii); - } - groups_.clear(); - - mtapi_status_t status; - mtapi_action_delete(action_handle_, MTAPI_INFINITE, &status); - assert(MTAPI_SUCCESS == status); - mtapi_finalize(&status); - assert(MTAPI_SUCCESS == status); -} - -void Node::Initialize( - mtapi_domain_t domain_id, - mtapi_node_t node_id) { - if (IsInitialized()) { - EMBB_THROW(embb::base::ErrorException, - "mtapi::Node was already initialized"); - } else { - mtapi_status_t status; - mtapi_node_attributes_t attr; - mtapi_uint_t tmp; - mtapi_nodeattr_init(&attr, &status); - assert(MTAPI_SUCCESS == status); - tmp = 4; - mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_ACTIONS, - &tmp, sizeof(tmp), &status); - assert(MTAPI_SUCCESS == status); - tmp = 4; - mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_JOBS, - &tmp, sizeof(tmp), &status); - assert(MTAPI_SUCCESS == status); - tmp = 1; - mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_ACTIONS_PER_JOB, - &tmp, sizeof(tmp), &status); - assert(MTAPI_SUCCESS == status); - node_instance = embb::base::Allocation::New( - domain_id, node_id, &attr); - } -} - -void Node::Initialize( - mtapi_domain_t domain_id, - mtapi_node_t node_id, - embb::base::CoreSet const & core_set, - mtapi_uint_t max_tasks, - mtapi_uint_t max_groups, - mtapi_uint_t max_queues, - mtapi_uint_t queue_limit, - mtapi_uint_t max_priorities) { - if (IsInitialized()) { - EMBB_THROW(embb::base::ErrorException, - "mtapi::Node was already initialized"); - } else { - mtapi_status_t status; - mtapi_node_attributes_t attr; - mtapi_uint_t tmp; - mtapi_nodeattr_init(&attr, &status); - assert(MTAPI_SUCCESS == status); - embb_core_set_t cs; - embb_core_set_init(&cs, 0); - for (unsigned int ii = 0; embb_core_set_count(&cs) < core_set.Count(); - ii++) { - if (core_set.IsContained(ii)) { - embb_core_set_add(&cs, ii); - } - } - mtapi_nodeattr_set(&attr, MTAPI_NODE_CORE_AFFINITY, - &cs, sizeof(cs), &status); - assert(MTAPI_SUCCESS == status); - mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_TASKS, - &max_tasks, sizeof(max_tasks), &status); - assert(MTAPI_SUCCESS == status); - tmp = 4; - mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_ACTIONS, - &tmp, sizeof(tmp), &status); - assert(MTAPI_SUCCESS == status); - mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_GROUPS, - &max_groups, sizeof(max_groups), &status); - assert(MTAPI_SUCCESS == status); - mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_QUEUES, - &max_queues, sizeof(max_queues), &status); - assert(MTAPI_SUCCESS == status); - mtapi_nodeattr_set(&attr, MTAPI_NODE_QUEUE_LIMIT, - &queue_limit, sizeof(queue_limit), &status); - assert(MTAPI_SUCCESS == status); - tmp = 4; - mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_JOBS, - &tmp, sizeof(tmp), &status); - assert(MTAPI_SUCCESS == status); - tmp = 1; - mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_ACTIONS_PER_JOB, - &tmp, sizeof(tmp), &status); - assert(MTAPI_SUCCESS == status); - mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_PRIORITIES, - &max_priorities, sizeof(max_priorities), &status); - assert(MTAPI_SUCCESS == status); - node_instance = embb::base::Allocation::New( - domain_id, node_id, &attr); - } -} - -bool Node::IsInitialized() { - return NULL != node_instance; -} - -Node & Node::GetInstance() { -#if MTAPI_CPP_AUTOMATIC_INITIALIZE - if (!IsInitialized()) { - init_mutex.Lock(); - if (!IsInitialized()) { - Node::Initialize( - MTAPI_CPP_AUTOMATIC_DOMAIN_ID, MTAPI_CPP_AUTOMATIC_NODE_ID); - atexit(Node::Finalize); - } - init_mutex.Unlock(); - } - return *node_instance; -#else - if (IsInitialized()) { - return *node_instance; - } else { - EMBB_THROW(embb::base::ErrorException, - "mtapi::Node is not initialized"); - } -#endif -} - -void Node::Finalize() { - if (IsInitialized()) { - embb::base::Allocation::Delete(node_instance); - node_instance = NULL; - } else { - EMBB_THROW(embb::base::ErrorException, - "mtapi::Node is not initialized"); - } -} - -Group & Node::CreateGroup() { - Group * group = embb::base::Allocation::New(); - groups_.push_back(group); - return *group; -} - -void Node::DestroyGroup(Group & group) { - std::list::iterator ii = - std::find(groups_.begin(), groups_.end(), &group); - if (ii != groups_.end()) { - embb::base::Allocation::Delete(*ii); - groups_.erase(ii); - } -} - -Queue & Node::CreateQueue(mtapi_uint_t priority, bool ordered) { - Queue * queue = embb::base::Allocation::New(priority, ordered); - queues_.push_back(queue); - return *queue; -} - -void Node::DestroyQueue(Queue & queue) { - std::list::iterator ii = - std::find(queues_.begin(), queues_.end(), &queue); - if (ii != queues_.end()) { - embb::base::Allocation::Delete(*ii); - queues_.erase(ii); - } -} - -Task Node::Spawn(Action action) { - return Task(action); -} - -Continuation Node::First(Action action) { - return Continuation(action); -} +embb::mtapi::Node * embb::mtapi::Node::node_instance_ = NULL; } // namespace mtapi } // namespace embb diff --git a/mtapi_cpp/test/main.cc b/mtapi_cpp/test/main.cc index f5aa24a..4cd6b97 100644 --- a/mtapi_cpp/test/main.cc +++ b/mtapi_cpp/test/main.cc @@ -26,7 +26,7 @@ #include -#include +#include #include #include @@ -34,6 +34,8 @@ PT_MAIN("MTAPI C++") { + embb_thread_set_max_count(1024); + PT_RUN(TaskTest); PT_RUN(GroupTest); PT_RUN(QueueTest); diff --git a/mtapi_cpp/test/mtapi_cpp_test_group.cc b/mtapi_cpp/test/mtapi_cpp_test_group.cc index 6645dd5..610d58d 100644 --- a/mtapi_cpp/test/mtapi_cpp_test_group.cc +++ b/mtapi_cpp/test/mtapi_cpp_test_group.cc @@ -24,65 +24,90 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include - #include #include #include +#define JOB_TEST_GROUP 5 +#define TASK_COUNT 4 + struct result_example_struct { - mtapi_uint_t value1; - mtapi_uint_t value2; + int value1; + int value2; }; typedef struct result_example_struct result_example_t; -static void testGroupAction(embb::mtapi::TaskContext & /*context*/) { - //std::cout << "testGroupAction on core " << - // context.GetCurrentCoreNumber() << std::endl; +static void testGroupAction( + const void* args, + mtapi_size_t /*args_size*/, + void* results, + mtapi_size_t /*results_size*/, + const void* /*node_local_data*/, + mtapi_size_t /*node_local_data_size*/, + mtapi_task_context_t * /*context*/) { + result_example_t const * in = static_cast(args); + result_example_t * out = static_cast(results); + out->value2 = in->value1; } static void testDoSomethingElse() { } GroupTest::GroupTest() { - CreateUnit("mtapi group test").Add(&GroupTest::TestBasic, this); + CreateUnit("mtapi_cpp group test").Add(&GroupTest::TestBasic, this); } void GroupTest::TestBasic() { - //std::cout << "running testGroup..." << std::endl; - embb::mtapi::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID); - embb::mtapi::Node & node = embb::mtapi::Node::GetInstance(); - embb::mtapi::Group & group = node.CreateGroup(); - embb::mtapi::Task task; + embb::mtapi::Job job(JOB_TEST_GROUP, THIS_DOMAIN_ID); + embb::mtapi::Action action(JOB_TEST_GROUP, testGroupAction); - //std::cout << "wait all..." << std::endl; + { + embb::mtapi::Group group; - for (int ii = 0; ii < 4; ii++) { - task = group.Spawn(testGroupAction); - } - testDoSomethingElse(); - group.WaitAll(MTAPI_INFINITE); + result_example_t buffer[TASK_COUNT]; + for (int ii = 0; ii < TASK_COUNT; ii++) { + buffer[ii].value1 = ii; + buffer[ii].value2 = -1; + group.Start(job, &buffer[ii], &buffer[ii]); + } - //std::cout << "wait any..." << std::endl; + testDoSomethingElse(); - for (int ii = 0; ii < 4; ii++) { - task = group.Spawn(mtapi_task_id_t(ii + 1), testGroupAction); - } - testDoSomethingElse(); - mtapi_status_t status; - mtapi_task_id_t result; - while (MTAPI_SUCCESS == (status = group.WaitAny(MTAPI_INFINITE, result))) { - //std::cout << "got a result from task " << result << std::endl; + group.WaitAll(); + + for (int ii = 0; ii < TASK_COUNT; ii++) { + PT_EXPECT_EQ(buffer[ii].value1, ii); + PT_EXPECT_EQ(buffer[ii].value2, ii); + } } - node.DestroyGroup(group); + { + embb::mtapi::Group group; + + result_example_t buffer[TASK_COUNT]; + for (int ii = 0; ii < 4; ii++) { + buffer[ii].value1 = ii; + buffer[ii].value2 = -1; + group.Start(job, &buffer[ii], &buffer[ii]); + } + + testDoSomethingElse(); + + mtapi_status_t status; + result_example_t* result; + while (MTAPI_SUCCESS == + (status = group.WaitAny(reinterpret_cast(&result)))) { + PT_EXPECT(result != MTAPI_NULL); + PT_EXPECT_EQ(result->value1, result->value2); + } + PT_EXPECT_EQ(status, MTAPI_GROUP_COMPLETED); + } embb::mtapi::Node::Finalize(); - PT_EXPECT(embb_get_bytes_allocated() == 0); - //std::cout << "...done" << std::endl << std::endl; + PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u); } diff --git a/mtapi_cpp/test/mtapi_cpp_test_queue.cc b/mtapi_cpp/test/mtapi_cpp_test_queue.cc index b8f7145..91a8884 100644 --- a/mtapi_cpp/test/mtapi_cpp_test_queue.cc +++ b/mtapi_cpp/test/mtapi_cpp_test_queue.cc @@ -24,47 +24,55 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include - #include #include #include -#define JOB_TEST_TASK 42 -#define TASK_TEST_ID 23 -#define QUEUE_TEST_ID 17 - -static void testQueueAction(embb::mtapi::TaskContext & /*context*/) { - //std::cout << "testQueueAction on core " << - // context.GetCurrentCoreNumber() << std::endl; +#define JOB_TEST_QUEUE 42 + +static void testQueueAction( + const void* /*args*/, + mtapi_size_t /*args_size*/, + void* results, + mtapi_size_t /*results_size*/, + const void* /*node_local_data*/, + mtapi_size_t /*node_local_data_size*/, + mtapi_task_context_t * context) { + embb::mtapi::TaskContext ctx(context); + int * out = reinterpret_cast(results); + *out = 1; + ctx.SetStatus(MTAPI_ERR_ACTION_CANCELLED); } static void testDoSomethingElse() { } QueueTest::QueueTest() { - CreateUnit("mtapi queue test").Add(&QueueTest::TestBasic, this); + CreateUnit("mtapi_cpp queue test").Add(&QueueTest::TestBasic, this); } void QueueTest::TestBasic() { - //std::cout << "running testQueue..." << std::endl; - embb::mtapi::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID); - embb::mtapi::Node & node = embb::mtapi::Node::GetInstance(); - embb::mtapi::Queue & queue = node.CreateQueue(0, false); + embb::mtapi::Job job(JOB_TEST_QUEUE, THIS_DOMAIN_ID); + embb::mtapi::Action action(JOB_TEST_QUEUE, testQueueAction, + MTAPI_NULL, 0); - embb::mtapi::Task task = queue.Spawn(testQueueAction); + { + embb::mtapi::Queue queue(job); - testDoSomethingElse(); + int result = 0; + embb::mtapi::Task task = queue.Enqueue(MTAPI_NULL, &result); - task.Wait(MTAPI_INFINITE); + testDoSomethingElse(); - node.DestroyQueue(queue); + mtapi_status_t status = task.Wait(); + PT_EXPECT_EQ(status, MTAPI_ERR_ACTION_CANCELLED); + PT_EXPECT_EQ(result, 1); + } embb::mtapi::Node::Finalize(); - PT_EXPECT(embb_get_bytes_allocated() == 0); - //std::cout << "...done" << std::endl << std::endl; + PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u); } diff --git a/mtapi_cpp/test/mtapi_cpp_test_task.cc b/mtapi_cpp/test/mtapi_cpp_test_task.cc index 88242b3..b21ddf7 100644 --- a/mtapi_cpp/test/mtapi_cpp_test_task.cc +++ b/mtapi_cpp/test/mtapi_cpp_test_task.cc @@ -34,33 +34,32 @@ #include #define JOB_TEST_TASK 42 -#define TASK_TEST_ID 23 +#define JOB_TEST_ERROR 17 static void testTaskAction( - char const * msg, - std::string * output, - embb::mtapi::TaskContext & /*context*/) { - //std::cout << "testTaskAction " << msg << " on core " << - // context.GetCurrentCoreNumber() << std::endl; - *output = msg; + const void* args, + mtapi_size_t /*args_size*/, + void* results, + mtapi_size_t /*results_size*/, + const void* /*node_local_data*/, + mtapi_size_t /*node_local_data_size*/, + mtapi_task_context_t * context) { + embb::mtapi::TaskContext ctx(context); + const char * msg = static_cast(args); + std::string* out = static_cast(results); + *out = msg; } -static void testRecursiveTaskAction( - int * value, - embb::mtapi::TaskContext & /*context*/) { - embb::mtapi::Node & node = embb::mtapi::Node::GetInstance(); - *value = *value + 1; - if (*value < 1000) { - embb::mtapi::Task task = node.Spawn( - embb::base::Bind( - testRecursiveTaskAction, value, embb::base::Placeholder::_1)); - task.Wait(MTAPI_INFINITE); - } - PT_EXPECT(*value == 1000); -} - -static void testErrorTaskAction(embb::mtapi::TaskContext & context) { - context.SetStatus(MTAPI_ERR_ACTION_FAILED); +static void testErrorAction( + const void* /*args*/, + mtapi_size_t /*args_size*/, + void* /*results*/, + mtapi_size_t /*results_size*/, + const void* /*node_local_data*/, + mtapi_size_t /*node_local_data_size*/, + mtapi_task_context_t * context) { + embb::mtapi::TaskContext ctx(context); + ctx.SetStatus(MTAPI_ERR_ACTION_FAILED); } static void testDoSomethingElse() { @@ -71,66 +70,58 @@ TaskTest::TaskTest() { } void TaskTest::TestBasic() { - //std::cout << "running testTask..." << std::endl; - embb::mtapi::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID); embb::mtapi::Node & node = embb::mtapi::Node::GetInstance(); - embb::mtapi::ExecutionPolicy policy(false); - PT_EXPECT_EQ(policy.GetAffinity(), 0u); - PT_EXPECT_EQ(policy.GetPriority(), 0u); - policy.AddWorker(0u); - PT_EXPECT_EQ(policy.GetAffinity(), 1u); - policy.AddWorker(1u); - PT_EXPECT_EQ(policy.GetAffinity(), 3u); - policy.RemoveWorker(0u); - PT_EXPECT_EQ(policy.GetAffinity(), 2u); - PT_EXPECT_EQ(policy.IsSetWorker(0), false); - PT_EXPECT_EQ(policy.IsSetWorker(1), true); - - std::string test; - embb::mtapi::Task task = node.Spawn( - embb::base::Bind( - testTaskAction, "simple", &test, embb::base::Placeholder::_1)); - testDoSomethingElse(); - task.Wait(MTAPI_INFINITE); - PT_EXPECT(test == "simple"); - //std::cout << "result: " << test.c_str() << std::endl; - - std::string test1, test2, test3; - task = node.First( - embb::base::Bind( - testTaskAction, "first", &test1, embb::base::Placeholder::_1)). - Then(embb::base::Bind( - testTaskAction, "second", &test2, embb::base::Placeholder::_1)). - Then(embb::base::Bind( - testTaskAction, "third", &test3, embb::base::Placeholder::_1)). - Spawn(); - testDoSomethingElse(); - task.Wait(MTAPI_INFINITE); - PT_EXPECT(test1 == "first"); - PT_EXPECT(test2 == "second"); - PT_EXPECT(test3 == "third"); - //std::cout << "result1: " << test1.c_str() << std::endl; - //std::cout << "result2: " << test2.c_str() << std::endl; - //std::cout << "result3: " << test3.c_str() << std::endl; - - int value = 0; - task = node.Spawn( - embb::base::Bind( - testRecursiveTaskAction, &value, embb::base::Placeholder::_1)); - task.Wait(MTAPI_INFINITE); - PT_EXPECT(value == 1000); - - mtapi_status_t status; - task = node.Spawn(testErrorTaskAction); - testDoSomethingElse(); - status = task.Wait(MTAPI_INFINITE); - PT_EXPECT(MTAPI_ERR_ACTION_FAILED == status); + { + embb::mtapi::NodeAttributes attr; + attr + .SetMaxActions(1024) + .SetMaxActionsPerJob(2) + .SetMaxPriorities(4); + } + + { + embb::mtapi::Affinity affinity(false); + PT_EXPECT_EQ(affinity.GetInternal(), 0u); + affinity.Set(0u, true); + PT_EXPECT_EQ(affinity.GetInternal(), 1u); + affinity.Set(1u, true); + PT_EXPECT_EQ(affinity.GetInternal(), 3u); + affinity.Set(0u, false); + PT_EXPECT_EQ(affinity.GetInternal(), 2u); + PT_EXPECT_EQ(affinity.Get(0), false); + PT_EXPECT_EQ(affinity.Get(1), true); + } + + { + embb::mtapi::Job job_task(JOB_TEST_TASK, THIS_DOMAIN_ID); + + embb::mtapi::Action action_task(JOB_TEST_TASK, testTaskAction); + + std::string test; + embb::mtapi::Task task = node.Start(job_task, "simple", &test); + testDoSomethingElse(); + mtapi_status_t status = task.Wait(); + PT_EXPECT_EQ(status, MTAPI_SUCCESS); + PT_EXPECT(test == "simple"); + } + + { + embb::mtapi::Job job_error(JOB_TEST_ERROR, THIS_DOMAIN_ID); + + embb::mtapi::Action action_error(JOB_TEST_ERROR, testErrorAction, + embb::mtapi::ActionAttributes()); + + std::string test; + embb::mtapi::Task task = node.Start(job_error, "simple", &test); + testDoSomethingElse(); + mtapi_status_t status = task.Wait(); + PT_EXPECT_EQ(status, MTAPI_ERR_ACTION_FAILED); + } embb::mtapi::Node::Finalize(); - PT_EXPECT(embb_get_bytes_allocated() == 0); - //std::cout << "...done" << std::endl << std::endl; + PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u); } diff --git a/scripts/run_cpplint.sh b/scripts/run_cpplint.sh index 1aabd8a..68a618e 100755 --- a/scripts/run_cpplint.sh +++ b/scripts/run_cpplint.sh @@ -79,7 +79,7 @@ retval=0 ##Excluded files RAND_FILES=( embb_mtapi_test_group.cc embb_mtapi_test_queue.cc embb_mtapi_test_task.cc queue_test-inl.h ) -for project in base_c mtapi_c base_cpp mtapi_cpp algorithms_cpp containers_cpp dataflow_cpp +for project in base_c mtapi_c base_cpp mtapi_cpp tasks_cpp algorithms_cpp containers_cpp dataflow_cpp do echo "-> Doing project: $project" dir=$d/$project diff --git a/scripts/run_tests_cygwin.sh b/scripts/run_tests_cygwin.sh index 0746c2c..43ae62d 100755 --- a/scripts/run_tests_cygwin.sh +++ b/scripts/run_tests_cygwin.sh @@ -37,7 +37,7 @@ done DIR=`dirname "$SCRIPT_LOCATION"` TESTS="embb_base_c_test embb_base_cpp_test embb_mtapi_c_test \ - embb_mtapi_cpp_test embb_algorithms_cpp_test \ + embb_mtapi_cpp_test embb_tasks_cpp_test embb_algorithms_cpp_test \ embb_containers_cpp_test embb_dataflow_cpp_test" for TEST in $TESTS; do diff --git a/scripts/run_tests_unix.sh b/scripts/run_tests_unix.sh index cfd8a2d..a39ede6 100755 --- a/scripts/run_tests_unix.sh +++ b/scripts/run_tests_unix.sh @@ -37,7 +37,7 @@ done DIR=`dirname "$SCRIPT_LOCATION"` TESTS="embb_base_c_test embb_base_cpp_test embb_mtapi_c_test \ - embb_mtapi_cpp_test embb_algorithms_cpp_test \ + embb_mtapi_cpp_test embb_tasks_cpp_test embb_algorithms_cpp_test \ embb_containers_cpp_test embb_dataflow_cpp_test" for TEST in $TESTS; do diff --git a/scripts/run_tests_windows.bat b/scripts/run_tests_windows.bat index 69dffb1..1621f08 100644 --- a/scripts/run_tests_windows.bat +++ b/scripts/run_tests_windows.bat @@ -40,6 +40,9 @@ echo. "%DIR:~0,-1%\embb_mtapi_cpp_test.exe" if not !ERRORLEVEL! ==0 set /a NUM_ERRORS=!NUM_ERRORS!+1 echo. +"%DIR:~0,-1%\embb_tasks_cpp_test.exe" +if not !ERRORLEVEL! ==0 set /a NUM_ERRORS=!NUM_ERRORS!+1 +echo. "%DIR:~0,-1%\embb_algorithms_cpp_test.exe" if not !ERRORLEVEL! ==0 set /a NUM_ERRORS=!NUM_ERRORS!+1 echo. diff --git a/tasks_cpp/CMakeLists.txt b/tasks_cpp/CMakeLists.txt new file mode 100644 index 0000000..31effbf --- /dev/null +++ b/tasks_cpp/CMakeLists.txt @@ -0,0 +1,49 @@ +project (project_tasks_cpp) + +file(GLOB_RECURSE EMBB_TASKS_CPP_SOURCES "src/*.cc" "src/*.h") +file(GLOB_RECURSE EMBB_TASKS_CPP_HEADERS "include/*.h") +file(GLOB_RECURSE EMBB_TASKS_CPP_TEST_SOURCES "test/*.cc" "test/*.h") + +if (USE_AUTOMATIC_INITIALIZATION STREQUAL ON) + message("-- Automatic initialization enabled (default)") + set(TASKS_CPP_AUTOMATIC_INITIALIZE 1) +else() + set(TASKS_CPP_AUTOMATIC_INITIALIZE 0) + message("-- Automatic initialization disabled") +endif() +message(" (set with command line option -DUSE_AUTOMATIC_INITIALIZATION=ON/OFF)") + +configure_file("include/embb/tasks/internal/cmake_config.h.in" + "include/embb/tasks/internal/cmake_config.h") + +# Execute the GroupSources macro +include(${CMAKE_SOURCE_DIR}/CMakeCommon/GroupSourcesMSVC.cmake) +GroupSourcesMSVC(include) +GroupSourcesMSVC(src) +GroupSourcesMSVC(test) + +set (EMBB_TASKS_CPP_INCLUDE_DIRS "include" "src" "test") +include_directories(${EMBB_TASKS_CPP_INCLUDE_DIRS} + ${CMAKE_CURRENT_BINARY_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/../base_c/include + ${CMAKE_CURRENT_BINARY_DIR}/../base_c/include + ${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include + ${CMAKE_CURRENT_BINARY_DIR}/../base_cpp/include + ${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_c/include) + +add_library (embb_tasks_cpp ${EMBB_TASKS_CPP_SOURCES} ${EMBB_TASKS_CPP_HEADERS}) +target_link_libraries(embb_tasks_cpp embb_mtapi_c) + +if (BUILD_TESTS STREQUAL ON) + include_directories(${CMAKE_CURRENT_BINARY_DIR}/../partest/include) + add_executable (embb_tasks_cpp_test ${EMBB_TASKS_CPP_TEST_SOURCES}) + target_link_libraries(embb_tasks_cpp_test embb_tasks_cpp embb_mtapi_c partest + embb_base_cpp embb_base_c ${compiler_libs}) + CopyBin(BIN embb_tasks_cpp_test DEST ${local_install_dir}) +endif() + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ + DESTINATION include FILES_MATCHING PATTERN "*.h") +install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/ + DESTINATION include FILES_MATCHING PATTERN "*.h") +install(TARGETS embb_tasks_cpp DESTINATION lib) diff --git a/tasks_cpp/include/embb/tasks/action.h b/tasks_cpp/include/embb/tasks/action.h new file mode 100644 index 0000000..34c22db --- /dev/null +++ b/tasks_cpp/include/embb/tasks/action.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_TASKS_ACTION_H_ +#define EMBB_TASKS_ACTION_H_ + +#include +#include +#include + +namespace embb { +namespace tasks { + +/** + * A function to be spawned as a Task. + * + * \ingroup CPP_TASKS + */ +class Action { + public: + /** + * Constructs an empty Action. + */ + Action() + : function_() + , execution_policy_() { + // empty + } + + /** + * Constructs an Action from a function object. + * + * \tparam Function Function object + */ + template + Action( + Function func /**< [in] Function object */ + ) + : function_(func) + , execution_policy_() { + // empty + } + + /** + * Constructs an Action from a function object and an Affinity. + * + * \tparam Function Function object + */ + template + Action( + Function func, /**< [in] Function object */ + ExecutionPolicy execution_policy /**< [in] Execution policy */ + ) + : function_(func) + , execution_policy_(execution_policy) { + // empty + } + + /** + * Executes the Action in a given TaskContext. + */ + void operator() ( + TaskContext & context /**< [in, out] Context the operator + is executed in */ + ) { + function_(context); + } + + /** + * Returns the ExecutionPolicy specified during creation. + * \return The ExecutionPolicy of the Action + * \waitfree + */ + ExecutionPolicy GetExecutionPolicy() const { + return execution_policy_; + } + + private: + embb::base::Function function_; + ExecutionPolicy execution_policy_; +}; + +} // namespace tasks +} // namespace embb + +#endif // EMBB_TASKS_ACTION_H_ diff --git a/mtapi_cpp/include/embb/mtapi/continuation.h b/tasks_cpp/include/embb/tasks/continuation.h similarity index 86% rename from mtapi_cpp/include/embb/mtapi/continuation.h rename to tasks_cpp/include/embb/tasks/continuation.h index 29789a2..666df75 100644 --- a/mtapi_cpp/include/embb/mtapi/continuation.h +++ b/tasks_cpp/include/embb/tasks/continuation.h @@ -24,66 +24,66 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef EMBB_MTAPI_CONTINUATION_H_ -#define EMBB_MTAPI_CONTINUATION_H_ +#ifndef EMBB_TASKS_CONTINUATION_H_ +#define EMBB_TASKS_CONTINUATION_H_ #include -#include -#include -#include +#include +#include +#include namespace embb { -namespace mtapi { +namespace tasks { /** - * Helper struct for Continuation. - * - * \ingroup CPP_MTAPI - */ + * Helper struct for Continuation. + * + * \ingroup CPP_TASKS + */ struct ContinuationStage; /** - * A Continuation encapsulates a chain of \link Action Actions \endlink to be - * executed consecutively. - * - * \ingroup CPP_MTAPI - */ + * A Continuation encapsulates a chain of \link Action Actions \endlink to be + * executed consecutively. + * + * \ingroup CPP_TASKS + */ class Continuation { public: /** - * Copy constructor. - */ + * Copies a Continuation. + */ Continuation( Continuation const & cont /**< [in] The Continuation to copy. */ ); /** - * Destructor. - */ + * Destroys a Continuation. + */ ~Continuation(); /** - * Appends an Action to the Continuation chain. - * \returns A reference to this Continuation chain. - * \notthreadsafe - */ + * Appends an Action to the Continuation chain. + * \returns A reference to this Continuation chain. + * \notthreadsafe + */ Continuation & Then( Action action /**< [in] The Action to append to the continuation */ ); /** - * Runs the Continuation chain. - * \returns The Task representing the Continuation chain. - * \notthreadsafe - */ + * Runs the Continuation chain. + * \returns The Task representing the Continuation chain. + * \notthreadsafe + */ Task Spawn(); /** - * Runs the Continuation chain with the specified execution_policy. - * \returns The Task representing the Continuation chain. - * \notthreadsafe - */ + * Runs the Continuation chain with the specified execution_policy. + * \returns The Task representing the Continuation chain. + * \notthreadsafe + */ Task Spawn( ExecutionPolicy execution_policy /**< [in] The execution policy to use */ ); @@ -99,7 +99,7 @@ class Continuation { ContinuationStage * last_; }; -} // namespace mtapi +} // namespace tasks } // namespace embb -#endif // EMBB_MTAPI_CONTINUATION_H_ +#endif // EMBB_TASKS_CONTINUATION_H_ diff --git a/mtapi_cpp/include/embb/mtapi/execution_policy.h b/tasks_cpp/include/embb/tasks/execution_policy.h similarity index 96% rename from mtapi_cpp/include/embb/mtapi/execution_policy.h rename to tasks_cpp/include/embb/tasks/execution_policy.h index 85727f3..8a9a019 100644 --- a/mtapi_cpp/include/embb/mtapi/execution_policy.h +++ b/tasks_cpp/include/embb/tasks/execution_policy.h @@ -24,13 +24,14 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef EMBB_MTAPI_EXECUTION_POLICY_H_ -#define EMBB_MTAPI_EXECUTION_POLICY_H_ +#ifndef EMBB_TASKS_EXECUTION_POLICY_H_ +#define EMBB_TASKS_EXECUTION_POLICY_H_ #include namespace embb { -namespace mtapi { +namespace tasks { + /** * Describes the execution policy of a parallel algorithm. * The execution policy comprises @@ -41,7 +42,7 @@ namespace mtapi { * max_priorities - 1 as given during initialization using Node::Initialize(). * The default value of max_priorities is 4. * - * \ingroup CPP_MTAPI + * \ingroup CPP_TASKS */ class ExecutionPolicy{ public: @@ -145,7 +146,8 @@ class ExecutionPolicy{ */ mtapi_uint_t priority_; }; -} // namespace mtapi + +} // namespace tasks } // namespace embb -#endif // EMBB_MTAPI_EXECUTION_POLICY_H_ +#endif // EMBB_TASKS_EXECUTION_POLICY_H_ diff --git a/tasks_cpp/include/embb/tasks/group.h b/tasks_cpp/include/embb/tasks/group.h new file mode 100644 index 0000000..039fe1d --- /dev/null +++ b/tasks_cpp/include/embb/tasks/group.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_TASKS_GROUP_H_ +#define EMBB_TASKS_GROUP_H_ + +#include +#include +#include + +namespace embb { + +namespace base { + +class Allocation; + +} // namespace base + +namespace tasks { + +/** + * Represents a facility to wait for multiple related + * \link Task Tasks\endlink. + * + * \ingroup CPP_TASKS + */ +class Group { + public: + /** + * Runs an Action within the Group. + * \return A Task identifying the Action to run + * \throws ErrorException if the Task object could not be constructed. + * \threadsafe + */ + Task Spawn( + Action action /**< [in] The Action to run */ + ); + + /** + * Runs an Action within the Group. The \c id is returned by WaitAny(). + * \return A Task identifying the Action to run + * \throws ErrorException if the Task object could not be constructed. + * \threadsafe + */ + Task Spawn( + mtapi_task_id_t id, /**< [in] The id to return by + WaitAny() */ + Action action /**< [in] The Action to run */ + ); + + /** + * Waits for any Task in the Group to finish for \c timeout milliseconds. + * \return The status of the Task that finished execution + * \threadsafe + */ + mtapi_status_t WaitAny( + mtapi_timeout_t timeout /**< [in] Timeout duration in + milliseconds */ + ); + + /** + * Waits for any Task in the Group to finish for \c timeout milliseconds and + * retrieves the id given in Spawn(). + * \return The status of the Task that finished execution, \c MTAPI_TIMEOUT + * or \c MTAPI_ERR_* + * \threadsafe + */ + mtapi_status_t WaitAny( + mtapi_timeout_t timeout, /**< [in] Timeout duration in + milliseconds */ + mtapi_task_id_t & id /**< [out] The id given to Spawn() */ + ); + + /** + * Waits for all Task in the Group to finish for \c timeout milliseconds. + * \return \c MTAPI_SUCCESS, \c MTAPI_TIMEOUT, \c MTAPI_ERR_* or the status + * of any failed Task + * \threadsafe + */ + mtapi_status_t WaitAll( + mtapi_timeout_t timeout /**< [in] Timeout duration in + milliseconds */ + ); + + friend class embb::base::Allocation; + friend class Node; + friend class Queue; + + private: + Group(Group const & group); + Group(); + ~Group(); + + void Create(); + + mtapi_group_hndl_t handle_; +}; + +} // namespace tasks +} // namespace embb + +#endif // EMBB_TASKS_GROUP_H_ diff --git a/mtapi_cpp/include/embb/mtapi/internal/cmake_config.h.in b/tasks_cpp/include/embb/tasks/internal/cmake_config.h.in similarity index 83% rename from mtapi_cpp/include/embb/mtapi/internal/cmake_config.h.in rename to tasks_cpp/include/embb/tasks/internal/cmake_config.h.in index 32af64c..400139a 100644 --- a/mtapi_cpp/include/embb/mtapi/internal/cmake_config.h.in +++ b/tasks_cpp/include/embb/tasks/internal/cmake_config.h.in @@ -24,18 +24,18 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef EMBB_MTAPI_INTERNAL_CMAKE_CONFIG_H_ -#define EMBB_MTAPI_INTERNAL_CMAKE_CONFIG_H_ +#ifndef EMBB_TASKS_INTERNAL_CMAKE_CONFIG_H_ +#define EMBB_TASKS_INTERNAL_CMAKE_CONFIG_H_ /* This file is used as input for CMake. CMake creates a file cmake_config.h in - its current build directory under the path builddir/embb/mtapi/internal/. From + its current build directory under the path builddir/embb/tasks/internal/. From there, the cmake_config.h can be included as usual using - #include + #include */ /** * Is used to enable automatic initialization of the MTAPI node */ -#define MTAPI_CPP_AUTOMATIC_INITIALIZE ${MTAPI_CPP_AUTOMATIC_INITIALIZE} +#define TASKS_CPP_AUTOMATIC_INITIALIZE ${TASKS_CPP_AUTOMATIC_INITIALIZE} -#endif // EMBB_MTAPI_INTERNAL_CMAKE_CONFIG_H_ +#endif // EMBB_TASKS_INTERNAL_CMAKE_CONFIG_H_ diff --git a/tasks_cpp/include/embb/tasks/node.h b/tasks_cpp/include/embb/tasks/node.h new file mode 100644 index 0000000..094b34d --- /dev/null +++ b/tasks_cpp/include/embb/tasks/node.h @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_TASKS_NODE_H_ +#define EMBB_TASKS_NODE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace embb { + +namespace base { + +class Allocation; + +} // namespace base + +namespace tasks { + +/** + * A singleton representing the MTAPI runtime. + * + * \ingroup CPP_TASKS + */ +class Node { + public: + /** + * Initializes the runtime singleton using default values: + * - all available cores will be used + * - maximum number of tasks is 1024 + * - maximum number of groups is 128 + * - maximum number of queues is 16 + * - maximum queue capacity is 1024 + * - maximum number of priorities is 4. + * + * \notthreadsafe + * \throws ErrorException if the singleton was already initialized or the + * Node could not be initialized. + * \memory Allocates about 200kb of memory. + */ + static void Initialize( + mtapi_domain_t domain_id, /**< [in] The domain id to use */ + mtapi_node_t node_id /**< [in] The node id to use */ + ); + + /** + * Initializes the runtime singleton. + * \notthreadsafe + * \throws ErrorException if the singleton was already initialized or the + * Node could not be initialized. + * \memory Allocates some memory depending on the values given. + */ + static void Initialize( + mtapi_domain_t domain_id, /**< [in] The domain id to use */ + mtapi_node_t node_id, /**< [in] The node id to use */ + embb::base::CoreSet const & core_set, + /**< [in] A set of cores MTAPI should + use for its worker threads */ + mtapi_uint_t max_tasks, /**< [in] Maximum number of concurrent + \link Task Tasks \endlink */ + mtapi_uint_t max_groups, /**< [in] Maximum number of concurrent + \link Group Groups \endlink */ + mtapi_uint_t max_queues, /**< [in] Maximum number of concurrent + \link Queue Queues \endlink */ + mtapi_uint_t queue_limit, /**< [in] Maximum Queue capacity */ + mtapi_uint_t max_priorities /**< [in] Maximum number of priorities, + priorities will be between 0 and + max_priorities-1 */ + ); + + /** + * Checks if runtime is initialized. + * \return \c true if the Node singleton is already initialized, false + * otherwise + * \waitfree + */ + static bool IsInitialized(); + + /** + * Gets the instance of the runtime system. + * \return Reference to the Node singleton + * \threadsafe + */ + static Node & GetInstance(); + + /** + * Shuts the runtime system down. + * \throws ErrorException if the singleton is not initialized. + * \notthreadsafe + */ + static void Finalize(); + + /** + * Returns the number of available cores. + * \return The number of available cores + * \waitfree + */ + mtapi_uint_t GetCoreCount() const { + return core_count_; + } + + /** + * Returns the number of worker threads. + * \return The number of worker threads. + * \waitfree + */ + mtapi_uint_t GetWorkerThreadCount() const { + return worker_thread_count_; + } + + /** + * Creates a Group to launch \link Task Tasks \endlink in. + * \return A reference to the created Group + * \throws ErrorException if the Group object could not be constructed. + * \threadsafe + * \memory Allocates some memory depending on the configuration of the + * runtime. + */ + Group & CreateGroup(); + + /** + * Destroys a Group. \link Task Tasks \endlink running in the Group will + * finish execution. + * \threadsafe + */ + void DestroyGroup( + Group & group /**< [in,out] The Group to destroy */ + ); + + /** + * Creates a Queue for stream processing. The queue might execute its + * \link Task Tasks \endlink either in order or unordered. + * \return A reference to the new Queue + * \throws ErrorException if the Queue object could not be constructed. + * \threadsafe + * \memory Allocates some memory depending on the configuration of the + * runtime. + */ + Queue & CreateQueue( + mtapi_uint_t priority, /**< [in] Priority of the Queue */ + bool ordered /**< [in] \c true if the Queue should be + ordered, otherwise \c false */ + ); + + /** + * Destroys a Queue. Running \link Task Tasks \endlink will be canceled. + * \threadsafe + */ + void DestroyQueue( + Queue & queue /**< [in,out] The Queue to destroy */ + ); + + /** + * Runs an Action. + * \return A Task identifying the Action to run + * \throws ErrorException if the Task object could not be constructed. + * \threadsafe + */ + Task Spawn( + Action action /**< [in] The Action to execute */ + ); + + /** + * Creates a Continuation. + * \return A Continuation chain + * \threadsafe + */ + Continuation First( + Action action /**< [in] The first Action of the + Continuation chain */ + ); + + friend class embb::base::Allocation; + + private: + Node(Node const & node); + Node( + mtapi_domain_t domain_id, + mtapi_node_t node_id, + mtapi_node_attributes_t * attr); + ~Node(); + + static void action_func( + const void* args, + mtapi_size_t args_size, + void* result_buffer, + mtapi_size_t result_buffer_size, + const void* node_local_data, + mtapi_size_t node_local_data_size, + mtapi_task_context_t * context); + + mtapi_uint_t core_count_; + mtapi_uint_t worker_thread_count_; + mtapi_action_hndl_t action_handle_; + std::list queues_; + std::list groups_; +}; + +} // namespace tasks +} // namespace embb + +#endif // EMBB_TASKS_NODE_H_ diff --git a/tasks_cpp/include/embb/tasks/queue.h b/tasks_cpp/include/embb/tasks/queue.h new file mode 100644 index 0000000..df9f303 --- /dev/null +++ b/tasks_cpp/include/embb/tasks/queue.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_TASKS_QUEUE_H_ +#define EMBB_TASKS_QUEUE_H_ + +#include +#include +#include +#include + +namespace embb { + +namespace base { + +class Allocation; + +} // namespace base + +namespace tasks { + +/** + * Allows for stream processing, either ordered or unordered. + * + * \ingroup CPP_TASKS + */ +class Queue { + public: + /** + * Enables the Queue. \link Task Tasks \endlink enqueued while the Queue was + * disabled are executed. + * \waitfree + */ + void Enable(); + + /** + * Disables the Queue. Running \link Task Tasks \endlink are canceled. + * \waitfree + */ + void Disable(); + + /** + * Runs an Action. + * \return A Task identifying the Action to run + * \throws ErrorException if the Task object could not be constructed. + * \threadsafe + */ + Task Spawn( + Action action /**< [in] The Action to run */ + ); + + /** + * Runs an Action in the specified Group + * \return A Task identifying the Action to run + * \throws ErrorException if the Task object could not be constructed. + * \threadsafe + */ + Task Spawn( + Group const * group, /**< [in] The Group to run the Action + in */ + Action action /**< [in] The Action to run */ + ); + + /** + * Runs an Action in the specified Group. The \c id is returned by + * Group::WaitAny(). + * \return A Task identifying the Action to run + * \throws ErrorException if the Task object could not be constructed. + * \threadsafe + */ + Task Spawn( + mtapi_task_id_t id, /**< [in] The id to return in + Group::WaitAny() */ + Group const * group, /**< [in] The Group to run the Action + in */ + Action action /**< [in] The Action to run */ + ); + + friend class embb::base::Allocation; + friend class Node; + + private: + Queue(Queue const & taskqueue); + Queue(mtapi_uint_t priority, bool ordered); + ~Queue(); + + mtapi_queue_hndl_t handle_; +}; + +} // namespace tasks +} // namespace embb + +#endif // EMBB_TASKS_QUEUE_H_ diff --git a/tasks_cpp/include/embb/tasks/task.h b/tasks_cpp/include/embb/tasks/task.h new file mode 100644 index 0000000..fd86b40 --- /dev/null +++ b/tasks_cpp/include/embb/tasks/task.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_TASKS_TASK_H_ +#define EMBB_TASKS_TASK_H_ + +#include +#include + +namespace embb { +namespace tasks { + +/** + * A Task represents a running Action. + * + * \ingroup CPP_TASKS + */ +class Task { + public: + /** + * Constructs an empty Task + */ + Task(); + + /** + * Copies a Task + */ + Task( + Task const & task /**< The task to copy. */ + ); + + /** + * Destroys a Task + */ + ~Task(); + + /** + * Waits for Task to finish for \c timeout milliseconds. + * \return The status of the finished Task, \c MTAPI_TIMEOUT or + * \c MTAPI_ERR_* + * \threadsafe + */ + mtapi_status_t Wait( + mtapi_timeout_t timeout /**< [in] Timeout duration in + milliseconds */ + ); + + /** + * Signals the Task to cancel computation. + * \waitfree + */ + void Cancel(); + + friend class Group; + friend class Queue; + friend class Node; + + private: + Task( + Action action); + + Task( + Action action, + mtapi_group_hndl_t group); + + Task( + mtapi_task_id_t id, + Action action, + mtapi_group_hndl_t group); + + Task( + Action action, + mtapi_queue_hndl_t queue); + + Task( + Action action, + mtapi_queue_hndl_t queue, + mtapi_group_hndl_t group); + + Task( + mtapi_task_id_t id, + Action action, + mtapi_queue_hndl_t queue, + mtapi_group_hndl_t group); + + mtapi_task_hndl_t handle_; +}; + +} // namespace tasks +} // namespace embb + +#endif // EMBB_TASKS_TASK_H_ diff --git a/mtapi_cpp/include/embb/mtapi/taskcontext.h b/tasks_cpp/include/embb/tasks/task_context.h similarity index 91% rename from mtapi_cpp/include/embb/mtapi/taskcontext.h rename to tasks_cpp/include/embb/tasks/task_context.h index 955991d..ecb416e 100644 --- a/mtapi_cpp/include/embb/mtapi/taskcontext.h +++ b/tasks_cpp/include/embb/tasks/task_context.h @@ -24,18 +24,18 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef EMBB_MTAPI_TASKCONTEXT_H_ -#define EMBB_MTAPI_TASKCONTEXT_H_ +#ifndef EMBB_TASKS_TASK_CONTEXT_H_ +#define EMBB_TASKS_TASK_CONTEXT_H_ #include namespace embb { -namespace mtapi { +namespace tasks { /** * Provides information about the status of the currently running Task. * - * \ingroup CPP_MTAPI + * \ingroup CPP_TASKS */ class TaskContext { public: @@ -72,7 +72,7 @@ class TaskContext { mtapi_task_context_t * context_; }; -} // namespace mtapi +} // namespace tasks } // namespace embb -#endif // EMBB_MTAPI_TASKCONTEXT_H_ +#endif // EMBB_TASKS_TASK_CONTEXT_H_ diff --git a/tasks_cpp/include/embb/tasks/tasks.h b/tasks_cpp/include/embb/tasks/tasks.h new file mode 100644 index 0000000..11e8d12 --- /dev/null +++ b/tasks_cpp/include/embb/tasks/tasks.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_TASKS_TASKS_H_ +#define EMBB_TASKS_TASKS_H_ + +/** + * \defgroup CPP_TASKS Tasks + * Simple task management based on MTAPI. + * \ingroup CPP + */ + +#include + +#define TASKS_CPP_JOB 1 +#if TASKS_CPP_AUTOMATIC_INITIALIZE +#define TASKS_CPP_AUTOMATIC_DOMAIN_ID 1 +#define TASKS_CPP_AUTOMATIC_NODE_ID 1 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // EMBB_TASKS_TASKS_H_ diff --git a/mtapi_cpp/src/continuation.cc b/tasks_cpp/src/continuation.cc similarity index 91% rename from mtapi_cpp/src/continuation.cc rename to tasks_cpp/src/continuation.cc index 40bbc30..35b9d65 100644 --- a/mtapi_cpp/src/continuation.cc +++ b/tasks_cpp/src/continuation.cc @@ -28,12 +28,12 @@ #include #include -#include +#include #include namespace embb { -namespace mtapi { +namespace tasks { Continuation::Continuation(Action action) { first_ = last_ = embb::base::Allocation::New(); @@ -50,10 +50,10 @@ Continuation::~Continuation() { } void Continuation::ExecuteContinuation(TaskContext &) { - mtapi::ContinuationStage * stage = first_; - mtapi::Node & node = mtapi::Node::GetInstance(); + ContinuationStage * stage = first_; + Node & node = Node::GetInstance(); while (NULL != stage) { - mtapi::Task task = node.Spawn(stage->action); + Task task = node.Spawn(stage->action); task.Wait(MTAPI_INFINITE); stage = stage->next; } @@ -61,7 +61,7 @@ void Continuation::ExecuteContinuation(TaskContext &) { // delete stages stage = first_; while (NULL != stage) { - mtapi::ContinuationStage * next = stage->next; + ContinuationStage * next = stage->next; embb::base::Allocation::Delete(stage); stage = next; } @@ -90,5 +90,5 @@ Task Continuation::Spawn(ExecutionPolicy execution_policy) { ExecutionPolicy(execution_policy))); } -} // namespace mtapi +} // namespace tasks } // namespace embb diff --git a/mtapi_cpp/src/continuationstage.h b/tasks_cpp/src/continuationstage.h similarity index 81% rename from mtapi_cpp/src/continuationstage.h rename to tasks_cpp/src/continuationstage.h index 1f37607..9c1f5b0 100644 --- a/mtapi_cpp/src/continuationstage.h +++ b/tasks_cpp/src/continuationstage.h @@ -24,20 +24,20 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MTAPI_CPP_SRC_CONTINUATIONSTAGE_H_ -#define MTAPI_CPP_SRC_CONTINUATIONSTAGE_H_ +#ifndef TASKS_CPP_SRC_CONTINUATIONSTAGE_H_ +#define TASKS_CPP_SRC_CONTINUATIONSTAGE_H_ -#include +#include namespace embb { -namespace mtapi { +namespace tasks { struct ContinuationStage { - mtapi::Action action; + Action action; ContinuationStage * next; }; -} // namespace mtapi +} // namespace tasks } // namespace embb -#endif // MTAPI_CPP_SRC_CONTINUATIONSTAGE_H_ +#endif // TASKS_CPP_SRC_CONTINUATIONSTAGE_H_ diff --git a/mtapi_cpp/src/execution_policy.cc b/tasks_cpp/src/execution_policy.cc similarity index 96% rename from mtapi_cpp/src/execution_policy.cc rename to tasks_cpp/src/execution_policy.cc index 157d0ac..bb25954 100644 --- a/mtapi_cpp/src/execution_policy.cc +++ b/tasks_cpp/src/execution_policy.cc @@ -24,14 +24,14 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include -#include +#include +#include #include #include #include namespace embb { -namespace mtapi { +namespace tasks { ExecutionPolicy::ExecutionPolicy() : priority_(DefaultPriority) { @@ -120,5 +120,5 @@ mtapi_uint_t ExecutionPolicy::GetPriority() const { const mtapi_uint_t ExecutionPolicy::DefaultPriority = 0; -} // namespace mtapi +} // namespace tasks } // namespace embb diff --git a/mtapi_cpp/src/group.cc b/tasks_cpp/src/group.cc similarity index 96% rename from mtapi_cpp/src/group.cc rename to tasks_cpp/src/group.cc index 20dc0b2..709290f 100644 --- a/mtapi_cpp/src/group.cc +++ b/tasks_cpp/src/group.cc @@ -28,10 +28,10 @@ #include #include -#include +#include namespace embb { -namespace mtapi { +namespace tasks { Group::Group() { Create(); @@ -92,5 +92,5 @@ mtapi_status_t Group::WaitAll(mtapi_timeout_t timeout) { return status; } -} // namespace mtapi +} // namespace tasks } // namespace embb diff --git a/tasks_cpp/src/node.cc b/tasks_cpp/src/node.cc new file mode 100644 index 0000000..362252c --- /dev/null +++ b/tasks_cpp/src/node.cc @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#if TASKS_CPP_AUTOMATIC_INITIALIZE +#include +#endif + +namespace { + +static embb::tasks::Node * node_instance = NULL; +#if TASKS_CPP_AUTOMATIC_INITIALIZE +static embb::base::Mutex init_mutex; +#endif + +} + +namespace embb { +namespace tasks { + +void Node::action_func( + const void* args, + mtapi_size_t /*args_size*/, + void* /*result_buffer*/, + mtapi_size_t /*result_buffer_size*/, + const void* /*node_local_data*/, + mtapi_size_t /*node_local_data_size*/, + mtapi_task_context_t * context) { + Action * action = + reinterpret_cast(const_cast(args)); + TaskContext task_context(context); + (*action)(task_context); + embb::base::Allocation::Delete(action); +} + +Node::Node( + mtapi_domain_t domain_id, + mtapi_node_t node_id, + mtapi_node_attributes_t * attr) { + mtapi_status_t status; + mtapi_info_t info; + mtapi_initialize(domain_id, node_id, attr, &info, &status); + if (MTAPI_SUCCESS != status) { + EMBB_THROW(embb::base::ErrorException, + "mtapi::Node could not initialize mtapi"); + } + core_count_ = info.hardware_concurrency; + worker_thread_count_ = embb_core_set_count(&attr->core_affinity); + action_handle_ = mtapi_action_create(TASKS_CPP_JOB, action_func, + MTAPI_NULL, 0, MTAPI_NULL, &status); + if (MTAPI_SUCCESS != status) { + EMBB_THROW(embb::base::ErrorException, + "mtapi::Node could not create an action"); + } +} + +Node::~Node() { + for (std::list::iterator ii = queues_.begin(); + ii != queues_.end(); + ++ii) { + embb::base::Allocation::Delete(*ii); + } + queues_.clear(); + + for (std::list::iterator ii = groups_.begin(); + ii != groups_.end(); + ++ii) { + embb::base::Allocation::Delete(*ii); + } + groups_.clear(); + + mtapi_status_t status; + mtapi_action_delete(action_handle_, MTAPI_INFINITE, &status); + assert(MTAPI_SUCCESS == status); + mtapi_finalize(&status); + assert(MTAPI_SUCCESS == status); +} + +void Node::Initialize( + mtapi_domain_t domain_id, + mtapi_node_t node_id) { + if (IsInitialized()) { + EMBB_THROW(embb::base::ErrorException, + "mtapi::Node was already initialized"); + } else { + mtapi_status_t status; + mtapi_node_attributes_t attr; + mtapi_uint_t tmp; + mtapi_nodeattr_init(&attr, &status); + assert(MTAPI_SUCCESS == status); + tmp = 4; + mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_ACTIONS, + &tmp, sizeof(tmp), &status); + assert(MTAPI_SUCCESS == status); + tmp = 4; + mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_JOBS, + &tmp, sizeof(tmp), &status); + assert(MTAPI_SUCCESS == status); + tmp = 1; + mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_ACTIONS_PER_JOB, + &tmp, sizeof(tmp), &status); + assert(MTAPI_SUCCESS == status); + node_instance = embb::base::Allocation::New( + domain_id, node_id, &attr); + } +} + +void Node::Initialize( + mtapi_domain_t domain_id, + mtapi_node_t node_id, + embb::base::CoreSet const & core_set, + mtapi_uint_t max_tasks, + mtapi_uint_t max_groups, + mtapi_uint_t max_queues, + mtapi_uint_t queue_limit, + mtapi_uint_t max_priorities) { + if (IsInitialized()) { + EMBB_THROW(embb::base::ErrorException, + "mtapi::Node was already initialized"); + } else { + mtapi_status_t status; + mtapi_node_attributes_t attr; + mtapi_uint_t tmp; + mtapi_nodeattr_init(&attr, &status); + assert(MTAPI_SUCCESS == status); + embb_core_set_t cs; + embb_core_set_init(&cs, 0); + for (unsigned int ii = 0; embb_core_set_count(&cs) < core_set.Count(); + ii++) { + if (core_set.IsContained(ii)) { + embb_core_set_add(&cs, ii); + } + } + mtapi_nodeattr_set(&attr, MTAPI_NODE_CORE_AFFINITY, + &cs, sizeof(cs), &status); + assert(MTAPI_SUCCESS == status); + mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_TASKS, + &max_tasks, sizeof(max_tasks), &status); + assert(MTAPI_SUCCESS == status); + tmp = 4; + mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_ACTIONS, + &tmp, sizeof(tmp), &status); + assert(MTAPI_SUCCESS == status); + mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_GROUPS, + &max_groups, sizeof(max_groups), &status); + assert(MTAPI_SUCCESS == status); + mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_QUEUES, + &max_queues, sizeof(max_queues), &status); + assert(MTAPI_SUCCESS == status); + mtapi_nodeattr_set(&attr, MTAPI_NODE_QUEUE_LIMIT, + &queue_limit, sizeof(queue_limit), &status); + assert(MTAPI_SUCCESS == status); + tmp = 4; + mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_JOBS, + &tmp, sizeof(tmp), &status); + assert(MTAPI_SUCCESS == status); + tmp = 1; + mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_ACTIONS_PER_JOB, + &tmp, sizeof(tmp), &status); + assert(MTAPI_SUCCESS == status); + mtapi_nodeattr_set(&attr, MTAPI_NODE_MAX_PRIORITIES, + &max_priorities, sizeof(max_priorities), &status); + assert(MTAPI_SUCCESS == status); + node_instance = embb::base::Allocation::New( + domain_id, node_id, &attr); + } +} + +bool Node::IsInitialized() { + return NULL != node_instance; +} + +Node & Node::GetInstance() { +#if TASKS_CPP_AUTOMATIC_INITIALIZE + if (!IsInitialized()) { + init_mutex.Lock(); + if (!IsInitialized()) { + Node::Initialize( + TASKS_CPP_AUTOMATIC_DOMAIN_ID, TASKS_CPP_AUTOMATIC_NODE_ID); + atexit(Node::Finalize); + } + init_mutex.Unlock(); + } + return *node_instance; +#else + if (IsInitialized()) { + return *node_instance; + } else { + EMBB_THROW(embb::base::ErrorException, + "embb::tasks::Node is not initialized"); + } +#endif +} + +void Node::Finalize() { + if (IsInitialized()) { + embb::base::Allocation::Delete(node_instance); + node_instance = NULL; + } else { + EMBB_THROW(embb::base::ErrorException, + "embb::tasks::Node is not initialized"); + } +} + +Group & Node::CreateGroup() { + Group * group = embb::base::Allocation::New(); + groups_.push_back(group); + return *group; +} + +void Node::DestroyGroup(Group & group) { + std::list::iterator ii = + std::find(groups_.begin(), groups_.end(), &group); + if (ii != groups_.end()) { + embb::base::Allocation::Delete(*ii); + groups_.erase(ii); + } +} + +Queue & Node::CreateQueue(mtapi_uint_t priority, bool ordered) { + Queue * queue = embb::base::Allocation::New(priority, ordered); + queues_.push_back(queue); + return *queue; +} + +void Node::DestroyQueue(Queue & queue) { + std::list::iterator ii = + std::find(queues_.begin(), queues_.end(), &queue); + if (ii != queues_.end()) { + embb::base::Allocation::Delete(*ii); + queues_.erase(ii); + } +} + +Task Node::Spawn(Action action) { + return Task(action); +} + +Continuation Node::First(Action action) { + return Continuation(action); +} + +} // namespace tasks +} // namespace embb diff --git a/mtapi_cpp/src/queue.cc b/tasks_cpp/src/queue.cc similarity index 95% rename from mtapi_cpp/src/queue.cc rename to tasks_cpp/src/queue.cc index a6e8371..04e94b8 100644 --- a/mtapi_cpp/src/queue.cc +++ b/tasks_cpp/src/queue.cc @@ -27,10 +27,10 @@ #include #include -#include +#include namespace embb { -namespace mtapi { +namespace tasks { Queue::Queue(mtapi_uint_t priority, bool ordered) { mtapi_status_t status; @@ -51,7 +51,7 @@ Queue::Queue(mtapi_uint_t priority, bool ordered) { assert(MTAPI_SUCCESS == status); mtapi_domain_t domain_id = mtapi_domain_id_get(&status); assert(MTAPI_SUCCESS == status); - mtapi_job_hndl_t job = mtapi_job_get(MTAPI_CPP_TASK_JOB, domain_id, &status); + mtapi_job_hndl_t job = mtapi_job_get(TASKS_CPP_JOB, domain_id, &status); assert(MTAPI_SUCCESS == status); handle_ = mtapi_queue_create(MTAPI_QUEUE_ID_NONE, job, &attr, &status); if (MTAPI_SUCCESS != status) { @@ -86,5 +86,5 @@ Task Queue::Spawn(Group const * group, Action action) { return Task(action, handle_, group->handle_); } -} // namespace mtapi +} // namespace tasks } // namespace embb diff --git a/mtapi_cpp/src/task.cc b/tasks_cpp/src/task.cc similarity index 95% rename from mtapi_cpp/src/task.cc rename to tasks_cpp/src/task.cc index 5239a3c..eaba40d 100644 --- a/mtapi_cpp/src/task.cc +++ b/tasks_cpp/src/task.cc @@ -29,10 +29,10 @@ #include #include -#include +#include namespace embb { -namespace mtapi { +namespace tasks { Task::Task() { handle_.id = 0; @@ -59,7 +59,7 @@ Task::Task( assert(MTAPI_SUCCESS == status); mtapi_domain_t domain_id = mtapi_domain_id_get(&status); assert(MTAPI_SUCCESS == status); - mtapi_job_hndl_t job = mtapi_job_get(MTAPI_CPP_TASK_JOB, domain_id, &status); + mtapi_job_hndl_t job = mtapi_job_get(TASKS_CPP_JOB, domain_id, &status); assert(MTAPI_SUCCESS == status); Action* holder = embb::base::Allocation::New(action); handle_ = mtapi_task_start(MTAPI_TASK_ID_NONE, job, @@ -86,7 +86,7 @@ Task::Task( assert(MTAPI_SUCCESS == status); mtapi_domain_t domain_id = mtapi_domain_id_get(&status); assert(MTAPI_SUCCESS == status); - mtapi_job_hndl_t job = mtapi_job_get(MTAPI_CPP_TASK_JOB, domain_id, &status); + mtapi_job_hndl_t job = mtapi_job_get(TASKS_CPP_JOB, domain_id, &status); assert(MTAPI_SUCCESS == status); Action* holder = embb::base::Allocation::New(action); handle_ = mtapi_task_start(MTAPI_TASK_ID_NONE, job, @@ -114,7 +114,7 @@ Task::Task( assert(MTAPI_SUCCESS == status); mtapi_domain_t domain_id = mtapi_domain_id_get(&status); assert(MTAPI_SUCCESS == status); - mtapi_job_hndl_t job = mtapi_job_get(MTAPI_CPP_TASK_JOB, domain_id, &status); + mtapi_job_hndl_t job = mtapi_job_get(TASKS_CPP_JOB, domain_id, &status); assert(MTAPI_SUCCESS == status); Action* holder = embb::base::Allocation::New(action); void * idptr = MTAPI_NULL; @@ -216,5 +216,5 @@ void Task::Cancel() { assert(MTAPI_SUCCESS == status); } -} // namespace mtapi +} // namespace tasks } // namespace embb diff --git a/mtapi_cpp/src/taskcontext.cc b/tasks_cpp/src/task_context.cc similarity index 94% rename from mtapi_cpp/src/taskcontext.cc rename to tasks_cpp/src/task_context.cc index 71e28b3..bba9312 100644 --- a/mtapi_cpp/src/taskcontext.cc +++ b/tasks_cpp/src/task_context.cc @@ -26,10 +26,10 @@ #include -#include +#include namespace embb { -namespace mtapi { +namespace tasks { TaskContext::TaskContext(mtapi_task_context_t * task_context) : context_(task_context) { @@ -57,5 +57,5 @@ void TaskContext::SetStatus(mtapi_status_t error_code) { assert(MTAPI_SUCCESS == status); } -} // namespace mtapi +} // namespace tasks } // namespace embb diff --git a/tasks_cpp/test/main.cc b/tasks_cpp/test/main.cc new file mode 100644 index 0000000..f46b112 --- /dev/null +++ b/tasks_cpp/test/main.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include + +#include +#include +#include + + +PT_MAIN("TASKS") { + PT_RUN(TaskTest); + PT_RUN(GroupTest); + PT_RUN(QueueTest); +} diff --git a/tasks_cpp/test/tasks_cpp_test_config.h b/tasks_cpp/test/tasks_cpp_test_config.h new file mode 100644 index 0000000..b7244c3 --- /dev/null +++ b/tasks_cpp/test/tasks_cpp_test_config.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TASKS_CPP_TEST_TASKS_CPP_TEST_CONFIG_H_ +#define TASKS_CPP_TEST_TASKS_CPP_TEST_CONFIG_H_ + +#include +#include + +#define THIS_DOMAIN_ID 1 +#define THIS_NODE_ID 1 + +#endif // TASKS_CPP_TEST_TASKS_CPP_TEST_CONFIG_H_ diff --git a/tasks_cpp/test/tasks_cpp_test_group.cc b/tasks_cpp/test/tasks_cpp_test_group.cc new file mode 100644 index 0000000..2e12fae --- /dev/null +++ b/tasks_cpp/test/tasks_cpp_test_group.cc @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include + +#include + +struct result_example_struct { + mtapi_uint_t value1; + mtapi_uint_t value2; +}; + +typedef struct result_example_struct result_example_t; + +static void testGroupAction(embb::tasks::TaskContext & /*context*/) { + // emtpy +} + +static void testDoSomethingElse() { +} + +GroupTest::GroupTest() { + CreateUnit("tasks_cpp group test").Add(&GroupTest::TestBasic, this); +} + +void GroupTest::TestBasic() { + embb::tasks::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID); + + embb::tasks::Node & node = embb::tasks::Node::GetInstance(); + embb::tasks::Group & group = node.CreateGroup(); + embb::tasks::Task task; + + for (int ii = 0; ii < 4; ii++) { + task = group.Spawn(testGroupAction); + } + testDoSomethingElse(); + group.WaitAll(MTAPI_INFINITE); + + for (int ii = 0; ii < 4; ii++) { + task = group.Spawn(mtapi_task_id_t(ii + 1), testGroupAction); + } + testDoSomethingElse(); + mtapi_status_t status; + mtapi_task_id_t result; + while (MTAPI_SUCCESS == (status = group.WaitAny(MTAPI_INFINITE, result))) { + // empty + } + + node.DestroyGroup(group); + + embb::tasks::Node::Finalize(); + + PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u); +} diff --git a/tasks_cpp/test/tasks_cpp_test_group.h b/tasks_cpp/test/tasks_cpp_test_group.h new file mode 100644 index 0000000..cc6c4fe --- /dev/null +++ b/tasks_cpp/test/tasks_cpp_test_group.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TASKS_CPP_TEST_TASKS_CPP_TEST_GROUP_H_ +#define TASKS_CPP_TEST_TASKS_CPP_TEST_GROUP_H_ + +#include + +class GroupTest : public partest::TestCase { + public: + GroupTest(); + + private: + void TestBasic(); +}; + +#endif // TASKS_CPP_TEST_TASKS_CPP_TEST_GROUP_H_ diff --git a/tasks_cpp/test/tasks_cpp_test_queue.cc b/tasks_cpp/test/tasks_cpp_test_queue.cc new file mode 100644 index 0000000..17514ca --- /dev/null +++ b/tasks_cpp/test/tasks_cpp_test_queue.cc @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include + +#include + +#define JOB_TEST_TASK 42 +#define TASK_TEST_ID 23 +#define QUEUE_TEST_ID 17 + +static void testQueueAction(embb::tasks::TaskContext & /*context*/) { + // empty +} + +static void testDoSomethingElse() { +} + +QueueTest::QueueTest() { + CreateUnit("tasks_cpp queue test").Add(&QueueTest::TestBasic, this); +} + +void QueueTest::TestBasic() { + embb::tasks::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID); + + embb::tasks::Node & node = embb::tasks::Node::GetInstance(); + embb::tasks::Queue & queue = node.CreateQueue(0, false); + + embb::tasks::Task task = queue.Spawn(testQueueAction); + + testDoSomethingElse(); + + task.Wait(MTAPI_INFINITE); + + node.DestroyQueue(queue); + + embb::tasks::Node::Finalize(); + + PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u); +} diff --git a/tasks_cpp/test/tasks_cpp_test_queue.h b/tasks_cpp/test/tasks_cpp_test_queue.h new file mode 100644 index 0000000..88770ca --- /dev/null +++ b/tasks_cpp/test/tasks_cpp_test_queue.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TASKS_CPP_TEST_TASKS_CPP_TEST_QUEUE_H_ +#define TASKS_CPP_TEST_TASKS_CPP_TEST_QUEUE_H_ + +#include + +class QueueTest : public partest::TestCase { + public: + QueueTest(); + + private: + void TestBasic(); +}; + +#endif // TASKS_CPP_TEST_TASKS_CPP_TEST_QUEUE_H_ diff --git a/tasks_cpp/test/tasks_cpp_test_task.cc b/tasks_cpp/test/tasks_cpp_test_task.cc new file mode 100644 index 0000000..103098d --- /dev/null +++ b/tasks_cpp/test/tasks_cpp_test_task.cc @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include +#include + +#include + +#define JOB_TEST_TASK 42 +#define TASK_TEST_ID 23 + +static void testTaskAction( + char const * msg, + std::string * output, + embb::tasks::TaskContext & /*context*/) { + *output = msg; +} + +static void testRecursiveTaskAction( + int * value, + embb::tasks::TaskContext & /*context*/) { + embb::tasks::Node & node = embb::tasks::Node::GetInstance(); + *value = *value + 1; + if (*value < 1000) { + embb::tasks::Task task = node.Spawn( + embb::base::Bind( + testRecursiveTaskAction, value, embb::base::Placeholder::_1)); + task.Wait(MTAPI_INFINITE); + } + PT_EXPECT(*value == 1000); +} + +static void testErrorTaskAction(embb::tasks::TaskContext & context) { + context.SetStatus(MTAPI_ERR_ACTION_FAILED); +} + +static void testDoSomethingElse() { +} + +TaskTest::TaskTest() { + CreateUnit("tasks_cpp task test").Add(&TaskTest::TestBasic, this); +} + +void TaskTest::TestBasic() { + embb::tasks::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID); + + embb::tasks::Node & node = embb::tasks::Node::GetInstance(); + + embb::tasks::ExecutionPolicy policy(false); + PT_EXPECT_EQ(policy.GetAffinity(), 0u); + PT_EXPECT_EQ(policy.GetPriority(), 0u); + policy.AddWorker(0u); + PT_EXPECT_EQ(policy.GetAffinity(), 1u); + policy.AddWorker(1u); + PT_EXPECT_EQ(policy.GetAffinity(), 3u); + policy.RemoveWorker(0u); + PT_EXPECT_EQ(policy.GetAffinity(), 2u); + PT_EXPECT_EQ(policy.IsSetWorker(0), false); + PT_EXPECT_EQ(policy.IsSetWorker(1), true); + + std::string test; + embb::tasks::Task task = node.Spawn( + embb::base::Bind( + testTaskAction, "simple", &test, embb::base::Placeholder::_1)); + testDoSomethingElse(); + task.Wait(MTAPI_INFINITE); + PT_EXPECT(test == "simple"); + + std::string test1, test2, test3; + task = node.First( + embb::base::Bind( + testTaskAction, "first", &test1, embb::base::Placeholder::_1)). + Then(embb::base::Bind( + testTaskAction, "second", &test2, embb::base::Placeholder::_1)). + Then(embb::base::Bind( + testTaskAction, "third", &test3, embb::base::Placeholder::_1)). + Spawn(); + testDoSomethingElse(); + task.Wait(MTAPI_INFINITE); + PT_EXPECT(test1 == "first"); + PT_EXPECT(test2 == "second"); + PT_EXPECT(test3 == "third"); + + int value = 0; + task = node.Spawn( + embb::base::Bind( + testRecursiveTaskAction, &value, embb::base::Placeholder::_1)); + task.Wait(MTAPI_INFINITE); + PT_EXPECT(value == 1000); + + mtapi_status_t status; + task = node.Spawn(testErrorTaskAction); + testDoSomethingElse(); + status = task.Wait(MTAPI_INFINITE); + PT_EXPECT(MTAPI_ERR_ACTION_FAILED == status); + + embb::tasks::Node::Finalize(); + + PT_EXPECT(embb_get_bytes_allocated() == 0); +} diff --git a/tasks_cpp/test/tasks_cpp_test_task.h b/tasks_cpp/test/tasks_cpp_test_task.h new file mode 100644 index 0000000..cbffac1 --- /dev/null +++ b/tasks_cpp/test/tasks_cpp_test_task.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TASKS_CPP_TEST_TASKS_CPP_TEST_TASK_H_ +#define TASKS_CPP_TEST_TASKS_CPP_TEST_TASK_H_ + +#include + +class TaskTest : public partest::TestCase { + public: + TaskTest(); + + private: + void TestBasic(); +}; + +#endif // TASKS_CPP_TEST_TASKS_CPP_TEST_TASK_H_