Commit a425b12e by Tobias Fuchs

Merge branch 'development' into embb327_llx_scx

parents bc8d07e3 f0c441e4
...@@ -125,6 +125,7 @@ CheckPartestInstall(${BUILD_TESTS} partest_includepath partest_libpath) ...@@ -125,6 +125,7 @@ CheckPartestInstall(${BUILD_TESTS} partest_includepath partest_libpath)
add_subdirectory(base_c) add_subdirectory(base_c)
add_subdirectory(base_cpp) add_subdirectory(base_cpp)
add_subdirectory(mtapi_c) add_subdirectory(mtapi_c)
add_subdirectory(tasks_cpp)
add_subdirectory(mtapi_cpp) add_subdirectory(mtapi_cpp)
add_subdirectory(containers_cpp) add_subdirectory(containers_cpp)
add_subdirectory(algorithms_cpp) add_subdirectory(algorithms_cpp)
......
...@@ -21,10 +21,10 @@ processor cores. It builds on MTAPI, a standardized programming interface for ...@@ -21,10 +21,10 @@ processor cores. It builds on MTAPI, a standardized programming interface for
leveraging task parallelism in embedded systems containing symmetric or leveraging task parallelism in embedded systems containing symmetric or
asymmetric multicore processors. A core feature of MTAPI is low-overhead asymmetric multicore processors. A core feature of MTAPI is low-overhead
scheduling of fine-grained tasks among the available cores during runtime. scheduling of fine-grained tasks among the available cores during runtime.
Unlike existing libraries, EMB² supports task priorities, which allows the Unlike existing libraries, EMB² supports task priorities and affinities, which
creation of soft real-time systems. Additionally, the scheduling strategy can allows the creation of soft real-time systems. Additionally, the scheduling
be optimized for non-functional requirements such as minimal latency and strategy can be optimized for non-functional requirements such as minimal
fairness. latency and fairness.
Besides the task scheduler, EMB² provides basic parallel algorithms, concurrent Besides the task scheduler, EMB² provides basic parallel algorithms, concurrent
data structures, and skeletons for implementing stream processing applications data structures, and skeletons for implementing stream processing applications
......
...@@ -17,18 +17,18 @@ include_directories(${EMBB_ALGORITHMS_CPP_INCLUDE_DIRS} ...@@ -17,18 +17,18 @@ include_directories(${EMBB_ALGORITHMS_CPP_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../base_cpp/include ${CMAKE_CURRENT_BINARY_DIR}/../base_cpp/include
${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_c/include ${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_c/include
${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../tasks_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../mtapi_cpp/include) ${CMAKE_CURRENT_BINARY_DIR}/../tasks_cpp/include)
add_library(embb_algorithms_cpp ${EMBB_ALGORITHMS_CPP_SOURCES} add_library(embb_algorithms_cpp ${EMBB_ALGORITHMS_CPP_SOURCES}
${EMBB_ALGORITHMS_CPP_HEADERS}) ${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) if (BUILD_TESTS STREQUAL ON)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/../partest/include) include_directories(${CMAKE_CURRENT_BINARY_DIR}/../partest/include)
add_executable (embb_algorithms_cpp_test ${EMBB_ALGORITHMS_CPP_TEST_SOURCES}) add_executable (embb_algorithms_cpp_test ${EMBB_ALGORITHMS_CPP_TEST_SOURCES})
target_link_libraries(embb_algorithms_cpp_test embb_algorithms_cpp 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}) embb_base_c ${compiler_libs})
CopyBin(BIN embb_algorithms_cpp_test DEST ${local_install_dir}) CopyBin(BIN embb_algorithms_cpp_test DEST ${local_install_dir})
endif() endif()
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#ifndef EMBB_ALGORITHMS_COUNT_H_ #ifndef EMBB_ALGORITHMS_COUNT_H_
#define EMBB_ALGORITHMS_COUNT_H_ #define EMBB_ALGORITHMS_COUNT_H_
#include <embb/mtapi/execution_policy.h> #include <embb/tasks/execution_policy.h>
#include <iterator> #include <iterator>
namespace embb { namespace embb {
...@@ -132,7 +132,7 @@ typename std::iterator_traits<RAI>::difference_type Count( ...@@ -132,7 +132,7 @@ typename std::iterator_traits<RAI>::difference_type Count(
RAI first, RAI first,
RAI last, RAI last,
const ValueType& value, const ValueType& value,
const embb::mtapi::ExecutionPolicy& policy, const embb::tasks::ExecutionPolicy& policy,
size_t block_size size_t block_size
); );
...@@ -145,7 +145,7 @@ typename std::iterator_traits<RAI>::difference_type Count( ...@@ -145,7 +145,7 @@ typename std::iterator_traits<RAI>::difference_type Count(
RAI last, RAI last,
const ValueType& value 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<RAI>::difference_type Count( ...@@ -156,7 +156,7 @@ typename std::iterator_traits<RAI>::difference_type Count(
RAI first, RAI first,
RAI last, RAI last,
const ValueType& value, const ValueType& value,
const embb::mtapi::ExecutionPolicy& policy const embb::tasks::ExecutionPolicy& policy
) { ) {
return Count(first, last, value, policy, 0); return Count(first, last, value, policy, 0);
} }
...@@ -169,7 +169,7 @@ typename std::iterator_traits<RAI>::difference_type CountIf( ...@@ -169,7 +169,7 @@ typename std::iterator_traits<RAI>::difference_type CountIf(
RAI first, RAI first,
RAI last, RAI last,
ComparisonFunction comparison, ComparisonFunction comparison,
const embb::mtapi::ExecutionPolicy& policy, const embb::tasks::ExecutionPolicy& policy,
size_t block_size size_t block_size
); );
...@@ -182,7 +182,7 @@ typename std::iterator_traits<RAI>::difference_type CountIf( ...@@ -182,7 +182,7 @@ typename std::iterator_traits<RAI>::difference_type CountIf(
RAI last, RAI last,
ComparisonFunction comparison 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<RAI>::difference_type CountIf( ...@@ -193,7 +193,7 @@ typename std::iterator_traits<RAI>::difference_type CountIf(
RAI first, RAI first,
RAI last, RAI last,
ComparisonFunction comparison, ComparisonFunction comparison,
const embb::mtapi::ExecutionPolicy& policy const embb::tasks::ExecutionPolicy& policy
) { ) {
return CountIf(first, last, comparison, policy, 0); return CountIf(first, last, comparison, policy, 0);
} }
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#ifndef EMBB_ALGORITHMS_FOR_EACH_H_ #ifndef EMBB_ALGORITHMS_FOR_EACH_H_
#define EMBB_ALGORITHMS_FOR_EACH_H_ #define EMBB_ALGORITHMS_FOR_EACH_H_
#include <embb/mtapi/execution_policy.h> #include <embb/tasks/execution_policy.h>
namespace embb { namespace embb {
namespace algorithms { namespace algorithms {
...@@ -88,7 +88,7 @@ void ForEach( ...@@ -88,7 +88,7 @@ void ForEach(
RAI first, RAI first,
RAI last, RAI last,
Function unary, Function unary,
const embb::mtapi::ExecutionPolicy& policy, const embb::tasks::ExecutionPolicy& policy,
size_t block_size size_t block_size
); );
...@@ -101,7 +101,7 @@ void ForEach( ...@@ -101,7 +101,7 @@ void ForEach(
RAI last, RAI last,
Function unary Function unary
) { ) {
ForEach(first, last, unary, embb::mtapi::ExecutionPolicy(), 0); ForEach(first, last, unary, embb::tasks::ExecutionPolicy(), 0);
} }
/** /**
...@@ -112,7 +112,7 @@ void ForEach( ...@@ -112,7 +112,7 @@ void ForEach(
RAI first, RAI first,
RAI last, RAI last,
Function unary, Function unary,
const embb::mtapi::ExecutionPolicy& policy const embb::tasks::ExecutionPolicy& policy
) { ) {
ForEach(first, last, unary, policy, 0); ForEach(first, last, unary, policy, 0);
} }
......
...@@ -83,7 +83,7 @@ class FunctionComparisonFunction{ ...@@ -83,7 +83,7 @@ class FunctionComparisonFunction{
template<typename RAI, typename ValueType> template<typename RAI, typename ValueType>
typename std::iterator_traits<RAI>::difference_type typename std::iterator_traits<RAI>::difference_type
Count(RAI first, RAI last, const ValueType& value, 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<RAI>::difference_type Difference; typedef typename std::iterator_traits<RAI>::difference_type Difference;
return Reduce(first, last, Difference(0), std::plus<Difference>(), return Reduce(first, last, Difference(0), std::plus<Difference>(),
internal::ValueComparisonFunction<ValueType>(value), policy, internal::ValueComparisonFunction<ValueType>(value), policy,
...@@ -93,7 +93,7 @@ typename std::iterator_traits<RAI>::difference_type ...@@ -93,7 +93,7 @@ typename std::iterator_traits<RAI>::difference_type
template<typename RAI, typename ComparisonFunction> template<typename RAI, typename ComparisonFunction>
typename std::iterator_traits<RAI>::difference_type typename std::iterator_traits<RAI>::difference_type
CountIf(RAI first, RAI last, ComparisonFunction comparison, 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<RAI>::difference_type Difference; typedef typename std::iterator_traits<RAI>::difference_type Difference;
return Reduce(first, last, Difference(0), std::plus<Difference>(), return Reduce(first, last, Difference(0), std::plus<Difference>(),
internal::FunctionComparisonFunction<ComparisonFunction> internal::FunctionComparisonFunction<ComparisonFunction>
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include <cassert> #include <cassert>
#include <embb/base/exceptions.h> #include <embb/base/exceptions.h>
#include <embb/mtapi/mtapi.h> #include <embb/tasks/tasks.h>
#include <embb/algorithms/internal/partition.h> #include <embb/algorithms/internal/partition.h>
#include <embb/algorithms/zip_iterator.h> #include <embb/algorithms/zip_iterator.h>
...@@ -46,13 +46,13 @@ class ForEachFunctor { ...@@ -46,13 +46,13 @@ class ForEachFunctor {
* Constructs a for-each functor with arguments. * Constructs a for-each functor with arguments.
*/ */
ForEachFunctor(size_t chunk_first, size_t chunk_last, Function unary, ForEachFunctor(size_t chunk_first, size_t chunk_last, Function unary,
const embb::mtapi::ExecutionPolicy& policy, const embb::tasks::ExecutionPolicy& policy,
const BlockSizePartitioner<RAI>& partitioner) const BlockSizePartitioner<RAI>& partitioner)
: chunk_first_(chunk_first), chunk_last_(chunk_last), : chunk_first_(chunk_first), chunk_last_(chunk_last),
unary_(unary), policy_(policy), partitioner_(partitioner) { unary_(unary), policy_(policy), partitioner_(partitioner) {
} }
void Action(mtapi::TaskContext&) { void Action(embb::tasks::TaskContext&) {
if (chunk_first_ == chunk_last_) { if (chunk_first_ == chunk_last_) {
// Leaf case, recursed to single chunk. Do work on chunk: // Leaf case, recursed to single chunk. Do work on chunk:
ChunkDescriptor<RAI> chunk = partitioner_[chunk_first_]; ChunkDescriptor<RAI> chunk = partitioner_[chunk_first_];
...@@ -71,12 +71,12 @@ class ForEachFunctor { ...@@ -71,12 +71,12 @@ class ForEachFunctor {
self_t functor_r(chunk_split_index + 1, self_t functor_r(chunk_split_index + 1,
chunk_last_, chunk_last_,
unary_, policy_, partitioner_); unary_, policy_, partitioner_);
mtapi::Task task_l = mtapi::Node::GetInstance().Spawn( embb::tasks::Task task_l = embb::tasks::Node::GetInstance().Spawn(
mtapi::Action( embb::tasks::Action(
base::MakeFunction(functor_l, &self_t::Action), base::MakeFunction(functor_l, &self_t::Action),
policy_)); policy_));
mtapi::Task task_r = mtapi::Node::GetInstance().Spawn( embb::tasks::Task task_r = embb::tasks::Node::GetInstance().Spawn(
mtapi::Action( embb::tasks::Action(
base::MakeFunction(functor_r, &self_t::Action), base::MakeFunction(functor_r, &self_t::Action),
policy_)); policy_));
task_l.Wait(MTAPI_INFINITE); task_l.Wait(MTAPI_INFINITE);
...@@ -91,7 +91,7 @@ class ForEachFunctor { ...@@ -91,7 +91,7 @@ class ForEachFunctor {
size_t chunk_first_; size_t chunk_first_;
size_t chunk_last_; size_t chunk_last_;
Function unary_; Function unary_;
const embb::mtapi::ExecutionPolicy& policy_; const embb::tasks::ExecutionPolicy& policy_;
const BlockSizePartitioner<RAI>& partitioner_; const BlockSizePartitioner<RAI>& partitioner_;
/** /**
...@@ -102,7 +102,7 @@ class ForEachFunctor { ...@@ -102,7 +102,7 @@ class ForEachFunctor {
template<typename RAI, typename Function> template<typename RAI, typename Function>
void ForEachRecursive(RAI first, RAI last, Function unary, 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<RAI>::difference_type difference_type; typedef typename std::iterator_traits<RAI>::difference_type difference_type;
difference_type distance = std::distance(first, last); difference_type distance = std::distance(first, last);
if (distance == 0) { if (distance == 0) {
...@@ -114,7 +114,7 @@ void ForEachRecursive(RAI first, RAI last, Function unary, ...@@ -114,7 +114,7 @@ void ForEachRecursive(RAI first, RAI last, Function unary,
if (num_cores == 0) { if (num_cores == 0) {
EMBB_THROW(embb::base::ErrorException, "No cores in execution policy"); 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 // Determine actually used block size
if (block_size == 0) { if (block_size == 0) {
block_size = (static_cast<size_t>(distance) / num_cores); block_size = (static_cast<size_t>(distance) / num_cores);
...@@ -132,7 +132,7 @@ void ForEachRecursive(RAI first, RAI last, Function unary, ...@@ -132,7 +132,7 @@ void ForEachRecursive(RAI first, RAI last, Function unary,
ForEachFunctor<RAI, Function> functor(0, ForEachFunctor<RAI, Function> functor(0,
partitioner.Size() - 1, partitioner.Size() - 1,
unary, policy, partitioner); unary, policy, partitioner);
mtapi::Task task = node.Spawn(mtapi::Action( embb::tasks::Task task = node.Spawn(embb::tasks::Action(
base::MakeFunction(functor, base::MakeFunction(functor,
&ForEachFunctor<RAI, Function>::Action), &ForEachFunctor<RAI, Function>::Action),
policy)); policy));
...@@ -141,7 +141,7 @@ void ForEachRecursive(RAI first, RAI last, Function unary, ...@@ -141,7 +141,7 @@ void ForEachRecursive(RAI first, RAI last, Function unary,
template<typename RAI, typename Function> template<typename RAI, typename Function>
void ForEachIteratorCheck(RAI first, RAI last, Function unary, 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) { std::random_access_iterator_tag) {
return ForEachRecursive(first, last, unary, policy, block_size); return ForEachRecursive(first, last, unary, policy, block_size);
} }
...@@ -150,7 +150,7 @@ void ForEachIteratorCheck(RAI first, RAI last, Function unary, ...@@ -150,7 +150,7 @@ void ForEachIteratorCheck(RAI first, RAI last, Function unary,
template<typename RAI, typename Function> template<typename RAI, typename Function>
void ForEach(RAI first, const RAI last, Function unary, 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<RAI>::iterator_category category; typename std::iterator_traits<RAI>::iterator_category category;
internal::ForEachIteratorCheck(first, last, unary, policy, block_size, internal::ForEachIteratorCheck(first, last, unary, policy, block_size,
category); category);
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
#include <functional> #include <functional>
#include <embb/base/exceptions.h> #include <embb/base/exceptions.h>
#include <embb/mtapi/mtapi.h> #include <embb/tasks/tasks.h>
#include <embb/algorithms/internal/partition.h> #include <embb/algorithms/internal/partition.h>
namespace embb { namespace embb {
...@@ -50,7 +50,7 @@ class MergeSortFunctor { ...@@ -50,7 +50,7 @@ class MergeSortFunctor {
MergeSortFunctor(size_t chunk_first, size_t chunk_last, MergeSortFunctor(size_t chunk_first, size_t chunk_last,
RAITemp temporary_first, ComparisonFunction comparison, RAITemp temporary_first, ComparisonFunction comparison,
const embb::mtapi::ExecutionPolicy& policy, const embb::tasks::ExecutionPolicy& policy,
const BlockSizePartitioner<RAI>& partitioner, const BlockSizePartitioner<RAI>& partitioner,
const RAI& global_first, int depth) const RAI& global_first, int depth)
: chunk_first_(chunk_first), chunk_last_(chunk_last), : chunk_first_(chunk_first), chunk_last_(chunk_last),
...@@ -59,7 +59,7 @@ class MergeSortFunctor { ...@@ -59,7 +59,7 @@ class MergeSortFunctor {
global_first_(global_first), depth_(depth) { 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; size_t chunk_split_index = (chunk_first_ + chunk_last_) / 2;
if (chunk_first_ == chunk_last_) { if (chunk_first_ == chunk_last_) {
// Leaf case: recurse into a single chunk's elements: // Leaf case: recurse into a single chunk's elements:
...@@ -77,13 +77,13 @@ class MergeSortFunctor { ...@@ -77,13 +77,13 @@ class MergeSortFunctor {
temp_first_, temp_first_,
comparison_, policy_, partitioner_, comparison_, policy_, partitioner_,
global_first_, depth_ + 1); global_first_, depth_ + 1);
mtapi::Node& node = mtapi::Node::GetInstance(); embb::tasks::Node& node = embb::tasks::Node::GetInstance();
mtapi::Task task_l = node.Spawn( embb::tasks::Task task_l = node.Spawn(
mtapi::Action( embb::tasks::Action(
base::MakeFunction(functor_l, &self_t::Action), base::MakeFunction(functor_l, &self_t::Action),
policy_)); policy_));
mtapi::Task task_r = node.Spawn( embb::tasks::Task task_r = node.Spawn(
mtapi::Action( embb::tasks::Action(
base::MakeFunction(functor_r, &self_t::Action), base::MakeFunction(functor_r, &self_t::Action),
policy_)); policy_));
task_l.Wait(MTAPI_INFINITE); task_l.Wait(MTAPI_INFINITE);
...@@ -177,7 +177,7 @@ class MergeSortFunctor { ...@@ -177,7 +177,7 @@ class MergeSortFunctor {
size_t chunk_last_; size_t chunk_last_;
RAITemp temp_first_; RAITemp temp_first_;
ComparisonFunction comparison_; ComparisonFunction comparison_;
const embb::mtapi::ExecutionPolicy& policy_; const embb::tasks::ExecutionPolicy& policy_;
const BlockSizePartitioner<RAI>& partitioner_; const BlockSizePartitioner<RAI>& partitioner_;
const RAI& global_first_; const RAI& global_first_;
int depth_; int depth_;
...@@ -219,7 +219,7 @@ void MergeSortIteratorCheck( ...@@ -219,7 +219,7 @@ void MergeSortIteratorCheck(
RAI last, RAI last,
RAITemp temporary_first, RAITemp temporary_first,
ComparisonFunction comparison, ComparisonFunction comparison,
const embb::mtapi::ExecutionPolicy& policy, const embb::tasks::ExecutionPolicy& policy,
size_t block_size, size_t block_size,
std::random_access_iterator_tag std::random_access_iterator_tag
) { ) {
...@@ -257,8 +257,8 @@ void MergeSortIteratorCheck( ...@@ -257,8 +257,8 @@ void MergeSortIteratorCheck(
partitioner, partitioner,
first, first,
0); 0);
mtapi::Task task = embb::mtapi::Node::GetInstance().Spawn( embb::tasks::Task task = embb::tasks::Node::GetInstance().Spawn(
mtapi::Action( embb::tasks::Action(
base::MakeFunction(functor, &functor_t::Action), base::MakeFunction(functor, &functor_t::Action),
policy)); policy));
...@@ -269,7 +269,7 @@ void MergeSortIteratorCheck( ...@@ -269,7 +269,7 @@ void MergeSortIteratorCheck(
template<typename RAI, typename RAITemp, typename ComparisonFunction> template<typename RAI, typename RAITemp, typename ComparisonFunction>
void MergeSort(RAI first, RAI last, RAITemp temporary_first, 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) { size_t block_size) {
typedef typename std::iterator_traits<RAI>::iterator_category category; typedef typename std::iterator_traits<RAI>::iterator_category category;
internal::MergeSortIteratorCheck(first, last, temporary_first, comparison, internal::MergeSortIteratorCheck(first, last, temporary_first, comparison,
......
...@@ -93,7 +93,7 @@ ChunkPartitioner<ForwardIterator>::ChunkPartitioner(ForwardIterator first, ...@@ -93,7 +93,7 @@ ChunkPartitioner<ForwardIterator>::ChunkPartitioner(ForwardIterator first,
size = amountChunks; size = amountChunks;
} else { } else {
// if no concrete chunk size was given, use number of cores... // 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(); size = node.GetWorkerThreadCount();
} }
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#ifndef EMBB_ALGORITHMS_INTERNAL_PARTITION_H_ #ifndef EMBB_ALGORITHMS_INTERNAL_PARTITION_H_
#define EMBB_ALGORITHMS_INTERNAL_PARTITION_H_ #define EMBB_ALGORITHMS_INTERNAL_PARTITION_H_
#include <embb/mtapi/mtapi.h> #include <embb/tasks/tasks.h>
namespace embb { namespace embb {
namespace algorithms { namespace algorithms {
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#include <functional> #include <functional>
#include <embb/base/exceptions.h> #include <embb/base/exceptions.h>
#include <embb/mtapi/mtapi.h> #include <embb/tasks/tasks.h>
#include <embb/algorithms/internal/partition.h> #include <embb/algorithms/internal/partition.h>
namespace embb { namespace embb {
...@@ -48,7 +48,7 @@ class QuickSortFunctor { ...@@ -48,7 +48,7 @@ class QuickSortFunctor {
* Constructs a functor. * Constructs a functor.
*/ */
QuickSortFunctor(RAI first, RAI last, ComparisonFunction comparison, 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), : first_(first), last_(last), comparison_(comparison), policy_(policy),
block_size_(block_size) { block_size_(block_size) {
} }
...@@ -56,7 +56,7 @@ class QuickSortFunctor { ...@@ -56,7 +56,7 @@ class QuickSortFunctor {
/** /**
* MTAPI action function and starting point of the parallel quick sort. * MTAPI action function and starting point of the parallel quick sort.
*/ */
void Action(mtapi::TaskContext&) { void Action(embb::tasks::TaskContext&) {
Difference distance = last_ - first_; Difference distance = last_ - first_;
if (distance <= 1) { if (distance <= 1) {
return; return;
...@@ -68,15 +68,15 @@ class QuickSortFunctor { ...@@ -68,15 +68,15 @@ class QuickSortFunctor {
SerialQuickSort(first_, mid); SerialQuickSort(first_, mid);
SerialQuickSort(mid, last_); SerialQuickSort(mid, last_);
} else { } else {
mtapi::Node& node = mtapi::Node::GetInstance(); embb::tasks::Node& node = embb::tasks::Node::GetInstance();
QuickSortFunctor functor_l(first_, mid, comparison_, policy_, QuickSortFunctor functor_l(first_, mid, comparison_, policy_,
block_size_); block_size_);
mtapi::Task task_l = node.Spawn(mtapi::Action(base::MakeFunction( embb::tasks::Task task_l = node.Spawn(embb::tasks::Action(
functor_l, &QuickSortFunctor::Action))); base::MakeFunction(functor_l, &QuickSortFunctor::Action)));
QuickSortFunctor functor_r(mid, last_, comparison_, policy_, QuickSortFunctor functor_r(mid, last_, comparison_, policy_,
block_size_); block_size_);
mtapi::Task task_r = node.Spawn(mtapi::Action(base::MakeFunction( embb::tasks::Task task_r = node.Spawn(embb::tasks::Action(
functor_r, &QuickSortFunctor::Action))); base::MakeFunction(functor_r, &QuickSortFunctor::Action)));
task_l.Wait(MTAPI_INFINITE); task_l.Wait(MTAPI_INFINITE);
task_r.Wait(MTAPI_INFINITE); task_r.Wait(MTAPI_INFINITE);
} }
...@@ -87,7 +87,7 @@ class QuickSortFunctor { ...@@ -87,7 +87,7 @@ class QuickSortFunctor {
RAI first_; RAI first_;
RAI last_; RAI last_;
ComparisonFunction comparison_; ComparisonFunction comparison_;
const embb::mtapi::ExecutionPolicy& policy_; const embb::tasks::ExecutionPolicy& policy_;
size_t block_size_; size_t block_size_;
typedef typename std::iterator_traits<RAI>::difference_type Difference; typedef typename std::iterator_traits<RAI>::difference_type Difference;
...@@ -189,10 +189,10 @@ class QuickSortFunctor { ...@@ -189,10 +189,10 @@ class QuickSortFunctor {
template <typename RAI, typename ComparisonFunction> template <typename RAI, typename ComparisonFunction>
void QuickSortIteratorCheck(RAI first, RAI last, void QuickSortIteratorCheck(RAI first, RAI last,
ComparisonFunction comparison, ComparisonFunction comparison,
const embb::mtapi::ExecutionPolicy& policy, const embb::tasks::ExecutionPolicy& policy,
size_t block_size, size_t block_size,
std::random_access_iterator_tag) { 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<RAI>::difference_type difference_type; typedef typename std::iterator_traits<RAI>::difference_type difference_type;
difference_type distance = std::distance(first, last); difference_type distance = std::distance(first, last);
if (distance == 0) { if (distance == 0) {
...@@ -215,7 +215,7 @@ void QuickSortIteratorCheck(RAI first, RAI last, ...@@ -215,7 +215,7 @@ void QuickSortIteratorCheck(RAI first, RAI last,
} }
QuickSortFunctor<RAI, ComparisonFunction> functor( QuickSortFunctor<RAI, ComparisonFunction> functor(
first, last, comparison, policy, block_size); 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<RAI, ComparisonFunction>::Action))); functor, &QuickSortFunctor<RAI, ComparisonFunction>::Action)));
task.Wait(MTAPI_INFINITE); task.Wait(MTAPI_INFINITE);
} }
...@@ -224,7 +224,7 @@ void QuickSortIteratorCheck(RAI first, RAI last, ...@@ -224,7 +224,7 @@ void QuickSortIteratorCheck(RAI first, RAI last,
template <typename RAI, typename ComparisonFunction> template <typename RAI, typename ComparisonFunction>
void QuickSort(RAI first, RAI last, ComparisonFunction comparison, 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<RAI>::iterator_category category; typedef typename std::iterator_traits<RAI>::iterator_category category;
internal::QuickSortIteratorCheck(first, last, comparison, internal::QuickSortIteratorCheck(first, last, comparison,
policy, block_size, category()); policy, block_size, category());
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#ifndef EMBB_ALGORITHMS_INTERNAL_REDUCE_INL_H_ #ifndef EMBB_ALGORITHMS_INTERNAL_REDUCE_INL_H_
#define EMBB_ALGORITHMS_INTERNAL_REDUCE_INL_H_ #define EMBB_ALGORITHMS_INTERNAL_REDUCE_INL_H_
#include <embb/mtapi/mtapi.h> #include <embb/tasks/tasks.h>
#include <embb/algorithms/internal/partition.h> #include <embb/algorithms/internal/partition.h>
#include <functional> #include <functional>
...@@ -46,7 +46,7 @@ class ReduceFunctor { ...@@ -46,7 +46,7 @@ class ReduceFunctor {
ReturnType neutral, ReturnType neutral,
ReductionFunction reduction, ReductionFunction reduction,
TransformationFunction transformation, TransformationFunction transformation,
const embb::mtapi::ExecutionPolicy& policy, const embb::tasks::ExecutionPolicy& policy,
const BlockSizePartitioner<RAI>& partitioner, const BlockSizePartitioner<RAI>& partitioner,
ReturnType& result) ReturnType& result)
: chunk_first_(chunk_first), chunk_last_(chunk_last), neutral_(neutral), : chunk_first_(chunk_first), chunk_last_(chunk_last), neutral_(neutral),
...@@ -54,7 +54,7 @@ class ReduceFunctor { ...@@ -54,7 +54,7 @@ class ReduceFunctor {
partitioner_(partitioner), result_(result) { partitioner_(partitioner), result_(result) {
} }
void Action(mtapi::TaskContext&) { void Action(embb::tasks::TaskContext&) {
if (chunk_first_ == chunk_last_) { if (chunk_first_ == chunk_last_) {
// Leaf case, recursed to single chunk. Do work on chunk: // Leaf case, recursed to single chunk. Do work on chunk:
ChunkDescriptor<RAI> chunk = partitioner_[chunk_first_]; ChunkDescriptor<RAI> chunk = partitioner_[chunk_first_];
...@@ -81,13 +81,13 @@ class ReduceFunctor { ...@@ -81,13 +81,13 @@ class ReduceFunctor {
neutral_, reduction_, transformation_, policy_, neutral_, reduction_, transformation_, policy_,
partitioner_, partitioner_,
result_r); result_r);
mtapi::Task task_l = mtapi::Node::GetInstance().Spawn( embb::tasks::Task task_l = embb::tasks::Node::GetInstance().Spawn(
mtapi::Action( embb::tasks::Action(
base::MakeFunction( base::MakeFunction(
functor_l, &self_t::Action), functor_l, &self_t::Action),
policy_)); policy_));
mtapi::Task task_r = mtapi::Node::GetInstance().Spawn( embb::tasks::Task task_r = embb::tasks::Node::GetInstance().Spawn(
mtapi::Action( embb::tasks::Action(
base::MakeFunction( base::MakeFunction(
functor_r, &self_t::Action), functor_r, &self_t::Action),
policy_)); policy_));
...@@ -108,7 +108,7 @@ class ReduceFunctor { ...@@ -108,7 +108,7 @@ class ReduceFunctor {
ReturnType neutral_; ReturnType neutral_;
ReductionFunction reduction_; ReductionFunction reduction_;
TransformationFunction transformation_; TransformationFunction transformation_;
const embb::mtapi::ExecutionPolicy& policy_; const embb::tasks::ExecutionPolicy& policy_;
const BlockSizePartitioner<RAI>& partitioner_; const BlockSizePartitioner<RAI>& partitioner_;
ReturnType& result_; ReturnType& result_;
...@@ -124,7 +124,7 @@ template<typename RAI, typename ReturnType, typename ReductionFunction, ...@@ -124,7 +124,7 @@ template<typename RAI, typename ReturnType, typename ReductionFunction,
ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral, ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral,
ReductionFunction reduction, ReductionFunction reduction,
TransformationFunction transformation, TransformationFunction transformation,
const embb::mtapi::ExecutionPolicy& policy, const embb::tasks::ExecutionPolicy& policy,
size_t block_size) { size_t block_size) {
typedef typename std::iterator_traits<RAI>::difference_type difference_type; typedef typename std::iterator_traits<RAI>::difference_type difference_type;
difference_type distance = std::distance(first, last); difference_type distance = std::distance(first, last);
...@@ -137,7 +137,7 @@ ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral, ...@@ -137,7 +137,7 @@ ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral,
if (num_cores == 0) { if (num_cores == 0) {
EMBB_THROW(embb::base::ErrorException, "No cores in execution policy"); 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 // Determine actually used block size
if (block_size == 0) { if (block_size == 0) {
block_size = (static_cast<size_t>(distance) / num_cores); block_size = (static_cast<size_t>(distance) / num_cores);
...@@ -162,8 +162,8 @@ ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral, ...@@ -162,8 +162,8 @@ ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral,
policy, policy,
partitioner, partitioner,
result); result);
mtapi::Task task = node.Spawn( embb::tasks::Task task = node.Spawn(
mtapi::Action(base::MakeFunction( embb::tasks::Action(base::MakeFunction(
functor, &Functor::Action), policy)); functor, &Functor::Action), policy));
task.Wait(MTAPI_INFINITE); task.Wait(MTAPI_INFINITE);
return result; return result;
...@@ -174,7 +174,7 @@ template<typename RAI, typename TransformationFunction, ...@@ -174,7 +174,7 @@ template<typename RAI, typename TransformationFunction,
ReturnType ReduceIteratorCheck(RAI first, RAI last, ReductionFunction reduction, ReturnType ReduceIteratorCheck(RAI first, RAI last, ReductionFunction reduction,
TransformationFunction transformation, TransformationFunction transformation,
ReturnType neutral, ReturnType neutral,
const embb::mtapi::ExecutionPolicy& policy, const embb::tasks::ExecutionPolicy& policy,
size_t block_size, size_t block_size,
std::random_access_iterator_tag) { std::random_access_iterator_tag) {
return ReduceRecursive(first, last, neutral, reduction, transformation, return ReduceRecursive(first, last, neutral, reduction, transformation,
...@@ -188,7 +188,7 @@ template<typename RAI, typename ReturnType, typename ReductionFunction, ...@@ -188,7 +188,7 @@ template<typename RAI, typename ReturnType, typename ReductionFunction,
ReturnType Reduce(RAI first, RAI last, ReturnType neutral, ReturnType Reduce(RAI first, RAI last, ReturnType neutral,
ReductionFunction reduction, ReductionFunction reduction,
TransformationFunction transformation, TransformationFunction transformation,
const embb::mtapi::ExecutionPolicy& policy, const embb::tasks::ExecutionPolicy& policy,
size_t block_size) { size_t block_size) {
typename std::iterator_traits<RAI>::iterator_category category; typename std::iterator_traits<RAI>::iterator_category category;
return internal::ReduceIteratorCheck(first, last, reduction, transformation, return internal::ReduceIteratorCheck(first, last, reduction, transformation,
......
...@@ -29,8 +29,8 @@ ...@@ -29,8 +29,8 @@
#include <cassert> #include <cassert>
#include <embb/base/exceptions.h> #include <embb/base/exceptions.h>
#include <embb/mtapi/mtapi.h> #include <embb/tasks/tasks.h>
#include <embb/mtapi/execution_policy.h> #include <embb/tasks/execution_policy.h>
#include <embb/algorithms/internal/partition.h> #include <embb/algorithms/internal/partition.h>
namespace embb { namespace embb {
...@@ -44,7 +44,7 @@ class ScanFunctor { ...@@ -44,7 +44,7 @@ class ScanFunctor {
ScanFunctor(size_t chunk_first, size_t chunk_last, RAIOut output_iterator, ScanFunctor(size_t chunk_first, size_t chunk_last, RAIOut output_iterator,
ReturnType neutral, ScanFunction scan, ReturnType neutral, ScanFunction scan,
TransformationFunction transformation, TransformationFunction transformation,
const embb::mtapi::ExecutionPolicy& policy, const embb::tasks::ExecutionPolicy& policy,
const BlockSizePartitioner<RAIIn>& partitioner, const BlockSizePartitioner<RAIIn>& partitioner,
ReturnType* tree_values, size_t node_id, ReturnType* tree_values, size_t node_id,
bool going_down) bool going_down)
...@@ -55,7 +55,7 @@ class ScanFunctor { ...@@ -55,7 +55,7 @@ class ScanFunctor {
node_id_(node_id), parent_value_(neutral), is_first_pass_(going_down) { 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_) { if (chunk_first_ == chunk_last_) {
ChunkDescriptor<RAIIn> chunk = partitioner_[chunk_first_]; ChunkDescriptor<RAIIn> chunk = partitioner_[chunk_first_];
RAIIn iter_in = chunk.GetFirst(); RAIIn iter_in = chunk.GetFirst();
...@@ -104,13 +104,13 @@ class ScanFunctor { ...@@ -104,13 +104,13 @@ class ScanFunctor {
functor_r.parent_value_ = functor_l.GetTreeValue() + parent_value_; functor_r.parent_value_ = functor_l.GetTreeValue() + parent_value_;
} }
// Spawn tasks to recurse: // Spawn tasks to recurse:
mtapi::Node& node = mtapi::Node::GetInstance(); embb::tasks::Node& node = embb::tasks::Node::GetInstance();
mtapi::Task task_l = node.Spawn( embb::tasks::Task task_l = node.Spawn(
mtapi::Action( embb::tasks::Action(
base::MakeFunction(functor_l, &ScanFunctor::Action), base::MakeFunction(functor_l, &ScanFunctor::Action),
policy_)); policy_));
mtapi::Task task_r = node.Spawn( embb::tasks::Task task_r = node.Spawn(
mtapi::Action( embb::tasks::Action(
base::MakeFunction(functor_r, &ScanFunctor::Action), base::MakeFunction(functor_r, &ScanFunctor::Action),
policy_)); policy_));
// Wait for tasks to complete: // Wait for tasks to complete:
...@@ -131,7 +131,7 @@ class ScanFunctor { ...@@ -131,7 +131,7 @@ class ScanFunctor {
private: private:
static const int LEFT = 1; static const int LEFT = 1;
static const int RIGHT = 2; static const int RIGHT = 2;
const embb::mtapi::ExecutionPolicy& policy_; const embb::tasks::ExecutionPolicy& policy_;
size_t chunk_first_; size_t chunk_first_;
size_t chunk_last_; size_t chunk_last_;
RAIOut output_iterator_; RAIOut output_iterator_;
...@@ -168,7 +168,7 @@ typename ScanFunction, typename TransformationFunction> ...@@ -168,7 +168,7 @@ typename ScanFunction, typename TransformationFunction>
void ScanIteratorCheck(RAIIn first, RAIIn last, RAIOut output_iterator, void ScanIteratorCheck(RAIIn first, RAIIn last, RAIOut output_iterator,
ReturnType neutral, ScanFunction scan, ReturnType neutral, ScanFunction scan,
TransformationFunction transformation, TransformationFunction transformation,
const embb::mtapi::ExecutionPolicy& policy, const embb::tasks::ExecutionPolicy& policy,
size_t block_size, size_t block_size,
std::random_access_iterator_tag) { std::random_access_iterator_tag) {
typedef typename std::iterator_traits<RAIIn>::difference_type difference_type; typedef typename std::iterator_traits<RAIIn>::difference_type difference_type;
...@@ -199,15 +199,14 @@ void ScanIteratorCheck(RAIIn first, RAIIn last, RAIOut output_iterator, ...@@ -199,15 +199,14 @@ void ScanIteratorCheck(RAIIn first, RAIIn last, RAIOut output_iterator,
// it creates the tree. // it creates the tree.
typedef ScanFunctor<RAIIn, RAIOut, ReturnType, ScanFunction, typedef ScanFunctor<RAIIn, RAIOut, ReturnType, ScanFunction,
TransformationFunction> Functor; TransformationFunction> Functor;
mtapi::Node& node = mtapi::Node::GetInstance(); embb::tasks::Node& node = embb::tasks::Node::GetInstance();
BlockSizePartitioner<RAIIn> partitioner_down(first, last, block_size); BlockSizePartitioner<RAIIn> partitioner_down(first, last, block_size);
Functor functor_down(0, partitioner_down.Size() - 1, output_iterator, Functor functor_down(0, partitioner_down.Size() - 1, output_iterator,
neutral, scan, transformation, policy, partitioner_down, neutral, scan, transformation, policy, partitioner_down,
values, 0, true); values, 0, true);
mtapi::Task task_down = node.Spawn(mtapi::Action(base::MakeFunction( embb::tasks::Task task_down = node.Spawn(embb::tasks::Action(
functor_down, &Functor::Action), base::MakeFunction(functor_down, &Functor::Action), policy));
policy));
task_down.Wait(MTAPI_INFINITE); task_down.Wait(MTAPI_INFINITE);
// Second pass. Gives to each leaf the part of the prefix missing // 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, ...@@ -215,9 +214,8 @@ void ScanIteratorCheck(RAIIn first, RAIIn last, RAIOut output_iterator,
Functor functor_up(0, partitioner_up.Size() - 1, output_iterator, Functor functor_up(0, partitioner_up.Size() - 1, output_iterator,
neutral, scan, transformation, policy, partitioner_up, neutral, scan, transformation, policy, partitioner_up,
values, 0, false); values, 0, false);
mtapi::Task task_up = node.Spawn(mtapi::Action(base::MakeFunction( embb::tasks::Task task_up = node.Spawn(embb::tasks::Action(
functor_up, &Functor::Action), base::MakeFunction(functor_up, &Functor::Action), policy));
policy));
task_up.Wait(MTAPI_INFINITE); task_up.Wait(MTAPI_INFINITE);
} }
...@@ -227,7 +225,7 @@ template<typename RAIIn, typename RAIOut, typename ReturnType, ...@@ -227,7 +225,7 @@ template<typename RAIIn, typename RAIOut, typename ReturnType,
typename ScanFunction, typename TransformationFunction> typename ScanFunction, typename TransformationFunction>
void Scan(RAIIn first, RAIIn last, RAIOut output_iterator, ReturnType neutral, void Scan(RAIIn first, RAIIn last, RAIOut output_iterator, ReturnType neutral,
ScanFunction scan, TransformationFunction transformation, 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<RAIIn>::iterator_category category; typedef typename std::iterator_traits<RAIIn>::iterator_category category;
internal::ScanIteratorCheck(first, last, output_iterator, neutral, internal::ScanIteratorCheck(first, last, output_iterator, neutral,
scan, transformation, policy, block_size, category()); scan, transformation, policy, block_size, category());
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#define EMBB_ALGORITHMS_INVOKE_H_ #define EMBB_ALGORITHMS_INVOKE_H_
#include <embb/base/function.h> #include <embb/base/function.h>
#include <embb/mtapi/mtapi.h> #include <embb/tasks/tasks.h>
namespace embb { namespace embb {
namespace algorithms { namespace algorithms {
...@@ -89,15 +89,16 @@ template<typename Function> ...@@ -89,15 +89,16 @@ template<typename Function>
class TaskWrapper { class TaskWrapper {
public: 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( explicit TaskWrapper(
Function function, Function function,
const embb::mtapi::ExecutionPolicy& policy) const embb::tasks::ExecutionPolicy& policy)
: function_(function), task_() { : function_(function), task_() {
mtapi::Action action(embb::base::MakeFunction(*this, &TaskWrapper::Run), embb::tasks::Action action(embb::base::MakeFunction(
policy); *this, &TaskWrapper::Run), policy);
task_ = mtapi::Node::GetInstance().Spawn(action); task_ = embb::tasks::Node::GetInstance().Spawn(action);
} }
/** /**
...@@ -109,9 +110,9 @@ class TaskWrapper { ...@@ -109,9 +110,9 @@ class TaskWrapper {
private: private:
Function function_; Function function_;
mtapi::Task task_; embb::tasks::Task task_;
void Run(embb::mtapi::TaskContext&) { void Run(embb::tasks::TaskContext&) {
function_(); function_();
} }
}; };
...@@ -120,7 +121,7 @@ class TaskWrapper { ...@@ -120,7 +121,7 @@ class TaskWrapper {
template<typename Function1> template<typename Function1>
void Invoke( void Invoke(
Function1 func1, Function1 func1,
const embb::mtapi::ExecutionPolicy& policy) { const embb::tasks::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy); internal::TaskWrapper<Function1> wrap1(func1, policy);
} }
...@@ -128,7 +129,7 @@ template<typename Function1, typename Function2> ...@@ -128,7 +129,7 @@ template<typename Function1, typename Function2>
void Invoke( void Invoke(
Function1 func1, Function1 func1,
Function2 func2, Function2 func2,
const embb::mtapi::ExecutionPolicy& policy) { const embb::tasks::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy); internal::TaskWrapper<Function1> wrap1(func1, policy);
internal::TaskWrapper<Function2> wrap2(func2, policy); internal::TaskWrapper<Function2> wrap2(func2, policy);
} }
...@@ -138,7 +139,7 @@ void Invoke( ...@@ -138,7 +139,7 @@ void Invoke(
Function1 func1, Function1 func1,
Function2 func2, Function2 func2,
Function3 func3, Function3 func3,
const embb::mtapi::ExecutionPolicy& policy) { const embb::tasks::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy); internal::TaskWrapper<Function1> wrap1(func1, policy);
internal::TaskWrapper<Function2> wrap2(func2, policy); internal::TaskWrapper<Function2> wrap2(func2, policy);
internal::TaskWrapper<Function3> wrap3(func3, policy); internal::TaskWrapper<Function3> wrap3(func3, policy);
...@@ -151,7 +152,7 @@ template<typename Function1, typename Function2, typename Function3, ...@@ -151,7 +152,7 @@ template<typename Function1, typename Function2, typename Function3,
Function2 func2, Function2 func2,
Function3 func3, Function3 func3,
Function4 func4, Function4 func4,
const embb::mtapi::ExecutionPolicy& policy) { const embb::tasks::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy); internal::TaskWrapper<Function1> wrap1(func1, policy);
internal::TaskWrapper<Function2> wrap2(func2, policy); internal::TaskWrapper<Function2> wrap2(func2, policy);
internal::TaskWrapper<Function3> wrap3(func3, policy); internal::TaskWrapper<Function3> wrap3(func3, policy);
...@@ -166,7 +167,7 @@ template<typename Function1, typename Function2, typename Function3, ...@@ -166,7 +167,7 @@ template<typename Function1, typename Function2, typename Function3,
Function3 func3, Function3 func3,
Function4 func4, Function4 func4,
Function5 func5, Function5 func5,
const embb::mtapi::ExecutionPolicy& policy) { const embb::tasks::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy); internal::TaskWrapper<Function1> wrap1(func1, policy);
internal::TaskWrapper<Function2> wrap2(func2, policy); internal::TaskWrapper<Function2> wrap2(func2, policy);
internal::TaskWrapper<Function3> wrap3(func3, policy); internal::TaskWrapper<Function3> wrap3(func3, policy);
...@@ -183,7 +184,7 @@ template<typename Function1, typename Function2, typename Function3, ...@@ -183,7 +184,7 @@ template<typename Function1, typename Function2, typename Function3,
Function4 func4, Function4 func4,
Function5 func5, Function5 func5,
Function6 func6, Function6 func6,
const embb::mtapi::ExecutionPolicy& policy) { const embb::tasks::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy); internal::TaskWrapper<Function1> wrap1(func1, policy);
internal::TaskWrapper<Function2> wrap2(func2, policy); internal::TaskWrapper<Function2> wrap2(func2, policy);
internal::TaskWrapper<Function3> wrap3(func3, policy); internal::TaskWrapper<Function3> wrap3(func3, policy);
...@@ -203,7 +204,7 @@ template<typename Function1, typename Function2, typename Function3, ...@@ -203,7 +204,7 @@ template<typename Function1, typename Function2, typename Function3,
Function5 func5, Function5 func5,
Function6 func6, Function6 func6,
Function7 func7, Function7 func7,
const embb::mtapi::ExecutionPolicy& policy) { const embb::tasks::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy); internal::TaskWrapper<Function1> wrap1(func1, policy);
internal::TaskWrapper<Function2> wrap2(func2, policy); internal::TaskWrapper<Function2> wrap2(func2, policy);
internal::TaskWrapper<Function3> wrap3(func3, policy); internal::TaskWrapper<Function3> wrap3(func3, policy);
...@@ -225,7 +226,7 @@ template<typename Function1, typename Function2, typename Function3, ...@@ -225,7 +226,7 @@ template<typename Function1, typename Function2, typename Function3,
Function6 func6, Function6 func6,
Function7 func7, Function7 func7,
Function8 func8, Function8 func8,
const embb::mtapi::ExecutionPolicy& policy) { const embb::tasks::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy); internal::TaskWrapper<Function1> wrap1(func1, policy);
internal::TaskWrapper<Function2> wrap2(func2, policy); internal::TaskWrapper<Function2> wrap2(func2, policy);
internal::TaskWrapper<Function3> wrap3(func3, policy); internal::TaskWrapper<Function3> wrap3(func3, policy);
...@@ -249,7 +250,7 @@ template<typename Function1, typename Function2, typename Function3, ...@@ -249,7 +250,7 @@ template<typename Function1, typename Function2, typename Function3,
Function7 func7, Function7 func7,
Function8 func8, Function8 func8,
Function9 func9, Function9 func9,
const embb::mtapi::ExecutionPolicy& policy) { const embb::tasks::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy); internal::TaskWrapper<Function1> wrap1(func1, policy);
internal::TaskWrapper<Function2> wrap2(func2, policy); internal::TaskWrapper<Function2> wrap2(func2, policy);
internal::TaskWrapper<Function3> wrap3(func3, policy); internal::TaskWrapper<Function3> wrap3(func3, policy);
...@@ -276,7 +277,7 @@ template<typename Function1, typename Function2, typename Function3, ...@@ -276,7 +277,7 @@ template<typename Function1, typename Function2, typename Function3,
Function8 func8, Function8 func8,
Function9 func9, Function9 func9,
Function10 func10, Function10 func10,
const embb::mtapi::ExecutionPolicy& policy) { const embb::tasks::ExecutionPolicy& policy) {
internal::TaskWrapper<Function1> wrap1(func1, policy); internal::TaskWrapper<Function1> wrap1(func1, policy);
internal::TaskWrapper<Function2> wrap2(func2, policy); internal::TaskWrapper<Function2> wrap2(func2, policy);
internal::TaskWrapper<Function3> wrap3(func3, policy); internal::TaskWrapper<Function3> wrap3(func3, policy);
...@@ -292,21 +293,21 @@ template<typename Function1, typename Function2, typename Function3, ...@@ -292,21 +293,21 @@ template<typename Function1, typename Function2, typename Function3,
template<typename Function1> template<typename Function1>
void Invoke( void Invoke(
Function1 func1) { Function1 func1) {
Invoke(func1, embb::mtapi::ExecutionPolicy()); Invoke(func1, embb::tasks::ExecutionPolicy());
} }
template<typename Function1, typename Function2> template<typename Function1, typename Function2>
void Invoke( void Invoke(
Function1 func1, Function1 func1,
Function2 func2) { Function2 func2) {
Invoke(func1, func2, embb::mtapi::ExecutionPolicy()); Invoke(func1, func2, embb::tasks::ExecutionPolicy());
} }
template<typename Function1, typename Function2, typename Function3> template<typename Function1, typename Function2, typename Function3>
void Invoke( void Invoke(
Function1 func1, Function1 func1,
Function2 func2, Function2 func2,
Function3 func3) { Function3 func3) {
Invoke(func1, func2, func3, embb::mtapi::ExecutionPolicy()); Invoke(func1, func2, func3, embb::tasks::ExecutionPolicy());
} }
template<typename Function1, typename Function2, typename Function3, template<typename Function1, typename Function2, typename Function3,
...@@ -316,7 +317,7 @@ void Invoke( ...@@ -316,7 +317,7 @@ void Invoke(
Function2 func2, Function2 func2,
Function3 func3, Function3 func3,
Function4 func4) { Function4 func4) {
Invoke(func1, func2, func3, func4, embb::mtapi::ExecutionPolicy()); Invoke(func1, func2, func3, func4, embb::tasks::ExecutionPolicy());
} }
template<typename Function1, typename Function2, typename Function3, template<typename Function1, typename Function2, typename Function3,
...@@ -327,7 +328,7 @@ void Invoke( ...@@ -327,7 +328,7 @@ void Invoke(
Function3 func3, Function3 func3,
Function4 func4, Function4 func4,
Function5 func5) { Function5 func5) {
Invoke(func1, func2, func3, func4, func5, embb::mtapi::ExecutionPolicy()); Invoke(func1, func2, func3, func4, func5, embb::tasks::ExecutionPolicy());
} }
template<typename Function1, typename Function2, typename Function3, template<typename Function1, typename Function2, typename Function3,
...@@ -340,7 +341,7 @@ void Invoke( ...@@ -340,7 +341,7 @@ void Invoke(
Function5 func5, Function5 func5,
Function6 func6) { Function6 func6) {
Invoke(func1, func2, func3, func4, func5, func6, Invoke(func1, func2, func3, func4, func5, func6,
embb::mtapi::ExecutionPolicy()); embb::tasks::ExecutionPolicy());
} }
template<typename Function1, typename Function2, typename Function3, template<typename Function1, typename Function2, typename Function3,
...@@ -355,7 +356,7 @@ void Invoke( ...@@ -355,7 +356,7 @@ void Invoke(
Function6 func6, Function6 func6,
Function7 func7) { Function7 func7) {
Invoke(func1, func2, func3, func4, func5, func6, func7, Invoke(func1, func2, func3, func4, func5, func6, func7,
embb::mtapi::ExecutionPolicy()); embb::tasks::ExecutionPolicy());
} }
template<typename Function1, typename Function2, typename Function3, template<typename Function1, typename Function2, typename Function3,
...@@ -371,7 +372,7 @@ void Invoke( ...@@ -371,7 +372,7 @@ void Invoke(
Function7 func7, Function7 func7,
Function8 func8) { Function8 func8) {
Invoke(func1, func2, func3, func4, func5, func6, func7, func8, Invoke(func1, func2, func3, func4, func5, func6, func7, func8,
embb::mtapi::ExecutionPolicy()); embb::tasks::ExecutionPolicy());
} }
template<typename Function1, typename Function2, typename Function3, template<typename Function1, typename Function2, typename Function3,
...@@ -388,7 +389,7 @@ void Invoke( ...@@ -388,7 +389,7 @@ void Invoke(
Function8 func8, Function8 func8,
Function9 func9) { Function9 func9) {
Invoke(func1, func2, func3, func4, func5, func6, func7, func8, func9, Invoke(func1, func2, func3, func4, func5, func6, func7, func8, func9,
embb::mtapi::ExecutionPolicy()); embb::tasks::ExecutionPolicy());
} }
template<typename Function1, typename Function2, typename Function3, template<typename Function1, typename Function2, typename Function3,
...@@ -407,7 +408,7 @@ void Invoke( ...@@ -407,7 +408,7 @@ void Invoke(
Function9 func9, Function9 func9,
Function10 func10) { Function10 func10) {
Invoke(func1, func2, func3, func4, func5, func6, func7, func8, func9, func10, Invoke(func1, func2, func3, func4, func5, func6, func7, func8, func9, func10,
embb::mtapi::ExecutionPolicy()); embb::tasks::ExecutionPolicy());
} }
#endif // else DOXYGEN #endif // else DOXYGEN
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#define EMBB_ALGORITHMS_MERGE_SORT_H_ #define EMBB_ALGORITHMS_MERGE_SORT_H_
#include <functional> #include <functional>
#include <embb/mtapi/execution_policy.h> #include <embb/tasks/execution_policy.h>
#include <embb/base/memory_allocation.h> #include <embb/base/memory_allocation.h>
namespace embb { namespace embb {
...@@ -149,7 +149,7 @@ void MergeSort( ...@@ -149,7 +149,7 @@ void MergeSort(
RAI last, RAI last,
RAITemp temporary_first, RAITemp temporary_first,
ComparisonFunction comparison, ComparisonFunction comparison,
const embb::mtapi::ExecutionPolicy& policy, const embb::tasks::ExecutionPolicy& policy,
size_t block_size size_t block_size
); );
...@@ -161,7 +161,7 @@ void MergeSortAllocate( ...@@ -161,7 +161,7 @@ void MergeSortAllocate(
RAI first, RAI first,
RAI last, RAI last,
ComparisonFunction comparison, ComparisonFunction comparison,
const embb::mtapi::ExecutionPolicy& policy, const embb::tasks::ExecutionPolicy& policy,
size_t block_size size_t block_size
) { ) {
typedef base::Allocation Alloc; typedef base::Allocation Alloc;
...@@ -200,7 +200,7 @@ void MergeSortAllocate( ...@@ -200,7 +200,7 @@ void MergeSortAllocate(
) { ) {
MergeSortAllocate(first, last, MergeSortAllocate(first, last,
std::less<typename std::iterator_traits<RAI>::value_type>(), std::less<typename std::iterator_traits<RAI>::value_type>(),
embb::mtapi::ExecutionPolicy(), 0); embb::tasks::ExecutionPolicy(), 0);
} }
/** /**
...@@ -212,7 +212,7 @@ void MergeSortAllocate( ...@@ -212,7 +212,7 @@ void MergeSortAllocate(
RAI last, RAI last,
ComparisonFunction comparison ComparisonFunction comparison
) { ) {
MergeSortAllocate(first, last, comparison, embb::mtapi::ExecutionPolicy(), 0); MergeSortAllocate(first, last, comparison, embb::tasks::ExecutionPolicy(), 0);
} }
/** /**
...@@ -223,7 +223,7 @@ void MergeSortAllocate( ...@@ -223,7 +223,7 @@ void MergeSortAllocate(
RAI first, RAI first,
RAI last, RAI last,
ComparisonFunction comparison, ComparisonFunction comparison,
const embb::mtapi::ExecutionPolicy& policy const embb::tasks::ExecutionPolicy& policy
) { ) {
MergeSortAllocate(first, last, comparison, policy, 0); MergeSortAllocate(first, last, comparison, policy, 0);
} }
...@@ -239,7 +239,7 @@ void MergeSort( ...@@ -239,7 +239,7 @@ void MergeSort(
) { ) {
MergeSort(first, last, temporary_first, MergeSort(first, last, temporary_first,
std::less<typename std::iterator_traits<RAI>::value_type>(), std::less<typename std::iterator_traits<RAI>::value_type>(),
embb::mtapi::ExecutionPolicy(), 0); embb::tasks::ExecutionPolicy(), 0);
} }
/** /**
...@@ -253,7 +253,7 @@ void MergeSort( ...@@ -253,7 +253,7 @@ void MergeSort(
ComparisonFunction comparison ComparisonFunction comparison
) { ) {
MergeSort(first, last, temporary_first, comparison, MergeSort(first, last, temporary_first, comparison,
embb::mtapi::ExecutionPolicy(), 0); embb::tasks::ExecutionPolicy(), 0);
} }
/** /**
...@@ -265,7 +265,7 @@ void MergeSort( ...@@ -265,7 +265,7 @@ void MergeSort(
RAI last, RAI last,
RAITemp temporary_first, RAITemp temporary_first,
ComparisonFunction comparison, ComparisonFunction comparison,
const embb::mtapi::ExecutionPolicy& policy const embb::tasks::ExecutionPolicy& policy
) { ) {
MergeSort(first, last, temporary_first, comparison, policy, 0); MergeSort(first, last, temporary_first, comparison, policy, 0);
} }
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#define EMBB_ALGORITHMS_QUICK_SORT_H_ #define EMBB_ALGORITHMS_QUICK_SORT_H_
#include <functional> #include <functional>
#include <embb/mtapi/execution_policy.h> #include <embb/tasks/execution_policy.h>
namespace embb { namespace embb {
namespace algorithms { namespace algorithms {
...@@ -72,7 +72,7 @@ void QuickSort( ...@@ -72,7 +72,7 @@ void QuickSort(
\c a appears before an element \c b in the sorted range if \c a appears before an element \c b in the sorted range if
<tt>comparison(a, b) == true</tt>. The default value uses the <tt>comparison(a, b) == true</tt>. The default value uses the
less-than relation. */ 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 */ /**< [IN] embb::mtapi::ExecutionPolicy for the quick sort algorithm */
size_t block_size = 0 size_t block_size = 0
/**< [IN] Lower bound for partitioning the range of elements into blocks that /**< [IN] Lower bound for partitioning the range of elements into blocks that
...@@ -95,7 +95,7 @@ void QuickSort( ...@@ -95,7 +95,7 @@ void QuickSort(
RAI first, RAI first,
RAI last, RAI last,
ComparisonFunction comparison, ComparisonFunction comparison,
const embb::mtapi::ExecutionPolicy& policy, const embb::tasks::ExecutionPolicy& policy,
size_t block_size size_t block_size
); );
...@@ -109,7 +109,7 @@ void QuickSort( ...@@ -109,7 +109,7 @@ void QuickSort(
) { ) {
QuickSort(first, last, QuickSort(first, last,
std::less<typename std::iterator_traits<RAI>::value_type>(), std::less<typename std::iterator_traits<RAI>::value_type>(),
embb::mtapi::ExecutionPolicy(), 0); embb::tasks::ExecutionPolicy(), 0);
} }
/** /**
...@@ -121,7 +121,7 @@ void QuickSort( ...@@ -121,7 +121,7 @@ void QuickSort(
RAI last, RAI last,
ComparisonFunction comparison ComparisonFunction comparison
) { ) {
QuickSort(first, last, comparison, embb::mtapi::ExecutionPolicy(), 0); QuickSort(first, last, comparison, embb::tasks::ExecutionPolicy(), 0);
} }
/** /**
...@@ -132,7 +132,7 @@ void QuickSort( ...@@ -132,7 +132,7 @@ void QuickSort(
RAI first, RAI first,
RAI last, RAI last,
ComparisonFunction comparison, ComparisonFunction comparison,
const embb::mtapi::ExecutionPolicy& policy const embb::tasks::ExecutionPolicy& policy
) { ) {
QuickSort(first, last, comparison, policy, 0); QuickSort(first, last, comparison, policy, 0);
} }
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#ifndef EMBB_ALGORITHMS_REDUCE_H_ #ifndef EMBB_ALGORITHMS_REDUCE_H_
#define EMBB_ALGORITHMS_REDUCE_H_ #define EMBB_ALGORITHMS_REDUCE_H_
#include <embb/mtapi/execution_policy.h> #include <embb/tasks/execution_policy.h>
#include <embb/algorithms/identity.h> #include <embb/algorithms/identity.h>
namespace embb { namespace embb {
...@@ -113,7 +113,7 @@ ReturnType Reduce( ...@@ -113,7 +113,7 @@ ReturnType Reduce(
ReturnType neutral, ReturnType neutral,
ReductionFunction reduction, ReductionFunction reduction,
TransformationFunction transformation, TransformationFunction transformation,
const embb::mtapi::ExecutionPolicy& policy, const embb::tasks::ExecutionPolicy& policy,
size_t block_size size_t block_size
); );
...@@ -128,7 +128,7 @@ ReturnType Reduce( ...@@ -128,7 +128,7 @@ ReturnType Reduce(
ReductionFunction reduction ReductionFunction reduction
) { ) {
return Reduce(first, last, neutral, reduction, Identity(), return Reduce(first, last, neutral, reduction, Identity(),
embb::mtapi::ExecutionPolicy(), 0); embb::tasks::ExecutionPolicy(), 0);
} }
/** /**
...@@ -144,7 +144,7 @@ ReturnType Reduce( ...@@ -144,7 +144,7 @@ ReturnType Reduce(
TransformationFunction transformation TransformationFunction transformation
) { ) {
return Reduce(first, last, neutral, reduction, transformation, return Reduce(first, last, neutral, reduction, transformation,
embb::mtapi::ExecutionPolicy(), 0); embb::tasks::ExecutionPolicy(), 0);
} }
/** /**
...@@ -158,7 +158,7 @@ ReturnType Reduce( ...@@ -158,7 +158,7 @@ ReturnType Reduce(
ReturnType neutral, ReturnType neutral,
ReductionFunction reduction, ReductionFunction reduction,
TransformationFunction transformation, TransformationFunction transformation,
const embb::mtapi::ExecutionPolicy& policy const embb::tasks::ExecutionPolicy& policy
) { ) {
return Reduce(first, last, neutral, reduction, transformation, policy, 0); return Reduce(first, last, neutral, reduction, transformation, policy, 0);
} }
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#ifndef EMBB_ALGORITHMS_SCAN_H_ #ifndef EMBB_ALGORITHMS_SCAN_H_
#define EMBB_ALGORITHMS_SCAN_H_ #define EMBB_ALGORITHMS_SCAN_H_
#include <embb/mtapi/execution_policy.h> #include <embb/tasks/execution_policy.h>
#include <embb/algorithms/identity.h> #include <embb/algorithms/identity.h>
namespace embb { namespace embb {
...@@ -121,7 +121,7 @@ void Scan( ...@@ -121,7 +121,7 @@ void Scan(
ReturnType neutral, ReturnType neutral,
ScanFunction scan, ScanFunction scan,
TransformationFunction transformation, TransformationFunction transformation,
const embb::mtapi::ExecutionPolicy& policy, const embb::tasks::ExecutionPolicy& policy,
size_t block_size size_t block_size
); );
...@@ -138,7 +138,7 @@ void Scan( ...@@ -138,7 +138,7 @@ void Scan(
ScanFunction scan ScanFunction scan
) { ) {
Scan(first, last, output_iterator, neutral, scan, Identity(), Scan(first, last, output_iterator, neutral, scan, Identity(),
embb::mtapi::ExecutionPolicy(), 0); embb::tasks::ExecutionPolicy(), 0);
} }
/** /**
...@@ -155,7 +155,7 @@ void Scan( ...@@ -155,7 +155,7 @@ void Scan(
TransformationFunction transformation TransformationFunction transformation
) { ) {
Scan(first, last, output_iterator, neutral, scan, transformation, Scan(first, last, output_iterator, neutral, scan, transformation,
embb::mtapi::ExecutionPolicy(), 0); embb::tasks::ExecutionPolicy(), 0);
} }
/** /**
...@@ -170,7 +170,7 @@ void Scan( ...@@ -170,7 +170,7 @@ void Scan(
ReturnType neutral, ReturnType neutral,
ScanFunction scan, ScanFunction scan,
TransformationFunction transformation, TransformationFunction transformation,
const embb::mtapi::ExecutionPolicy& policy const embb::tasks::ExecutionPolicy& policy
) { ) {
Scan(first, last, output_iterator, neutral, scan, transformation, policy, 0); Scan(first, last, output_iterator, neutral, scan, transformation, policy, 0);
} }
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <count_test.h> #include <count_test.h>
#include <embb/algorithms/count.h> #include <embb/algorithms/count.h>
#include <embb/mtapi/execution_policy.h> #include <embb/tasks/execution_policy.h>
#include <deque> #include <deque>
#include <vector> #include <vector>
#include <functional> #include <functional>
...@@ -122,7 +122,7 @@ void CountTest::TestBlockSizes() { ...@@ -122,7 +122,7 @@ void CountTest::TestBlockSizes() {
void CountTest::TestPolicy() { void CountTest::TestPolicy() {
using embb::algorithms::Count; using embb::algorithms::Count;
using embb::mtapi::ExecutionPolicy; using embb::tasks::ExecutionPolicy;
int a[] = { 10, 20, 30, 30, 20, 10, 10, 20, 20, 20 }; int a[] = { 10, 20, 30, 30, 20, 10, 10, 20, 20, 20 };
std::vector<int> vector(a, a + (sizeof a / sizeof a[0])); std::vector<int> vector(a, a + (sizeof a / sizeof a[0]));
PT_EXPECT_EQ(Count(vector.begin(), vector.end(), 10, ExecutionPolicy()), 3); PT_EXPECT_EQ(Count(vector.begin(), vector.end(), 10, ExecutionPolicy()), 3);
...@@ -134,7 +134,7 @@ void CountTest::TestPolicy() { ...@@ -134,7 +134,7 @@ void CountTest::TestPolicy() {
void CountTest::StressTest() { void CountTest::StressTest() {
using embb::algorithms::Count; using embb::algorithms::Count;
size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() *10; size_t count = embb::tasks::Node::GetInstance().GetCoreCount() * 10;
std::vector<int> large_vector(count); std::vector<int> large_vector(count);
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
large_vector[i] = static_cast<int>(0); large_vector[i] = static_cast<int>(0);
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <for_each_test.h> #include <for_each_test.h>
#include <embb/algorithms/for_each.h> #include <embb/algorithms/for_each.h>
#include <embb/mtapi/execution_policy.h> #include <embb/tasks/execution_policy.h>
#include <vector> #include <vector>
#include <deque> #include <deque>
#include <sstream> #include <sstream>
...@@ -166,7 +166,7 @@ void ForEachTest::TestRanges() { ...@@ -166,7 +166,7 @@ void ForEachTest::TestRanges() {
void ForEachTest::TestBlockSizes() { void ForEachTest::TestBlockSizes() {
using embb::algorithms::ForEach; using embb::algorithms::ForEach;
using embb::mtapi::ExecutionPolicy; using embb::tasks::ExecutionPolicy;
size_t count = 4; size_t count = 4;
std::vector<int> init(count); std::vector<int> init(count);
std::vector<int> vector(count); std::vector<int> vector(count);
...@@ -186,7 +186,7 @@ void ForEachTest::TestBlockSizes() { ...@@ -186,7 +186,7 @@ void ForEachTest::TestBlockSizes() {
void ForEachTest::TestPolicy() { void ForEachTest::TestPolicy() {
using embb::algorithms::ForEach; using embb::algorithms::ForEach;
using embb::mtapi::ExecutionPolicy; using embb::tasks::ExecutionPolicy;
size_t count = 4; size_t count = 4;
std::vector<int> init(count); std::vector<int> init(count);
std::vector<int> vector(count); std::vector<int> vector(count);
...@@ -240,8 +240,8 @@ void ForEachTest::TestPolicy() { ...@@ -240,8 +240,8 @@ void ForEachTest::TestPolicy() {
void ForEachTest::StressTest() { void ForEachTest::StressTest() {
using embb::algorithms::ForEach; using embb::algorithms::ForEach;
using embb::mtapi::ExecutionPolicy; using embb::tasks::ExecutionPolicy;
size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() *10; size_t count = embb::tasks::Node::GetInstance().GetCoreCount() * 10;
std::vector<int> large_vector(count); std::vector<int> large_vector(count);
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
large_vector[i] = static_cast<int>((i + 2) % 1000); large_vector[i] = static_cast<int>((i + 2) % 1000);
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
*/ */
#include <partest/partest.h> #include <partest/partest.h>
#include <embb/mtapi/mtapi.h> #include <embb/tasks/tasks.h>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
...@@ -66,7 +66,7 @@ int compute1_() { ...@@ -66,7 +66,7 @@ int compute1_() {
} }
PT_MAIN("Algorithms") { 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(PartitionerTest);
PT_RUN(ForEachTest); PT_RUN(ForEachTest);
...@@ -78,7 +78,7 @@ PT_MAIN("Algorithms") { ...@@ -78,7 +78,7 @@ PT_MAIN("Algorithms") {
PT_RUN(MergeSortTest); PT_RUN(MergeSortTest);
PT_RUN(InvokeTest); PT_RUN(InvokeTest);
embb::mtapi::Node::Finalize(); embb::tasks::Node::Finalize();
PT_EXPECT(embb_get_bytes_allocated() == 0); PT_EXPECT(embb_get_bytes_allocated() == 0);
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <merge_sort_test.h> #include <merge_sort_test.h>
#include <embb/algorithms/merge_sort.h> #include <embb/algorithms/merge_sort.h>
#include <embb/mtapi/execution_policy.h> #include <embb/tasks/execution_policy.h>
#include <vector> #include <vector>
#include <deque> #include <deque>
#include <sstream> #include <sstream>
...@@ -50,7 +50,7 @@ MergeSortTest::MergeSortTest() { ...@@ -50,7 +50,7 @@ MergeSortTest::MergeSortTest() {
void MergeSortTest::TestDataStructures() { void MergeSortTest::TestDataStructures() {
using embb::algorithms::MergeSortAllocate; using embb::algorithms::MergeSortAllocate;
using embb::mtapi::ExecutionPolicy; using embb::tasks::ExecutionPolicy;
int array[kCountSize]; int array[kCountSize];
std::vector<int> vector(kCountSize); std::vector<int> vector(kCountSize);
std::deque<int> deque(kCountSize); std::deque<int> deque(kCountSize);
...@@ -75,7 +75,7 @@ void MergeSortTest::TestDataStructures() { ...@@ -75,7 +75,7 @@ void MergeSortTest::TestDataStructures() {
void MergeSortTest::TestFunctionPointers() { void MergeSortTest::TestFunctionPointers() {
using embb::algorithms::MergeSortAllocate; using embb::algorithms::MergeSortAllocate;
using embb::mtapi::ExecutionPolicy; using embb::tasks::ExecutionPolicy;
std::vector<int> vector(kCountSize); std::vector<int> vector(kCountSize);
for (size_t i = kCountSize - 1; i > 0; i--) { for (size_t i = kCountSize - 1; i > 0; i--) {
...@@ -158,7 +158,7 @@ void MergeSortTest::TestRanges() { ...@@ -158,7 +158,7 @@ void MergeSortTest::TestRanges() {
void MergeSortTest::TestBlockSizes() { void MergeSortTest::TestBlockSizes() {
using embb::algorithms::MergeSortAllocate; using embb::algorithms::MergeSortAllocate;
using embb::mtapi::ExecutionPolicy; using embb::tasks::ExecutionPolicy;
size_t count = 4; size_t count = 4;
std::vector<int> init(count); std::vector<int> init(count);
std::vector<int> vector(count); std::vector<int> vector(count);
...@@ -181,7 +181,7 @@ void MergeSortTest::TestBlockSizes() { ...@@ -181,7 +181,7 @@ void MergeSortTest::TestBlockSizes() {
void MergeSortTest::TestPolicy() { void MergeSortTest::TestPolicy() {
using embb::algorithms::MergeSortAllocate; using embb::algorithms::MergeSortAllocate;
using embb::mtapi::ExecutionPolicy; using embb::tasks::ExecutionPolicy;
size_t count = 4; size_t count = 4;
std::vector<int> init(count); std::vector<int> init(count);
std::vector<int> vector(count); std::vector<int> vector(count);
...@@ -242,7 +242,7 @@ void MergeSortTest::TestPolicy() { ...@@ -242,7 +242,7 @@ void MergeSortTest::TestPolicy() {
void MergeSortTest::StressTest() { void MergeSortTest::StressTest() {
using embb::algorithms::MergeSortAllocate; using embb::algorithms::MergeSortAllocate;
size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() * 10; size_t count = embb::tasks::Node::GetInstance().GetCoreCount() * 10;
std::vector<int> large_vector(count); std::vector<int> large_vector(count);
std::vector<int> vector_copy(count); std::vector<int> vector_copy(count);
for (size_t i = count - 1; i > 0; i--) { for (size_t i = count - 1; i > 0; i--) {
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <quick_sort_test.h> #include <quick_sort_test.h>
#include <embb/algorithms/quick_sort.h> #include <embb/algorithms/quick_sort.h>
#include <embb/mtapi/execution_policy.h> #include <embb/tasks/execution_policy.h>
#include <vector> #include <vector>
#include <deque> #include <deque>
#include <sstream> #include <sstream>
...@@ -54,7 +54,7 @@ QuickSortTest::QuickSortTest() { ...@@ -54,7 +54,7 @@ QuickSortTest::QuickSortTest() {
void QuickSortTest::TestDataStructures() { void QuickSortTest::TestDataStructures() {
using embb::algorithms::QuickSort; using embb::algorithms::QuickSort;
using embb::mtapi::ExecutionPolicy; using embb::tasks::ExecutionPolicy;
int array[kCountSize]; int array[kCountSize];
std::vector<int> vector(kCountSize); std::vector<int> vector(kCountSize);
...@@ -163,7 +163,7 @@ void QuickSortTest::TestRanges() { ...@@ -163,7 +163,7 @@ void QuickSortTest::TestRanges() {
void QuickSortTest::TestBlockSizes() { void QuickSortTest::TestBlockSizes() {
using embb::algorithms::QuickSort; using embb::algorithms::QuickSort;
using embb::mtapi::ExecutionPolicy; using embb::tasks::ExecutionPolicy;
size_t count = 4; size_t count = 4;
std::vector<int> init(count); std::vector<int> init(count);
...@@ -187,7 +187,7 @@ void QuickSortTest::TestBlockSizes() { ...@@ -187,7 +187,7 @@ void QuickSortTest::TestBlockSizes() {
void QuickSortTest::TestPolicy() { void QuickSortTest::TestPolicy() {
using embb::algorithms::QuickSort; using embb::algorithms::QuickSort;
using embb::mtapi::ExecutionPolicy; using embb::tasks::ExecutionPolicy;
size_t count = 4; size_t count = 4;
std::vector<int> init(count); std::vector<int> init(count);
std::vector<int> vector(count); std::vector<int> vector(count);
...@@ -248,7 +248,7 @@ void QuickSortTest::TestPolicy() { ...@@ -248,7 +248,7 @@ void QuickSortTest::TestPolicy() {
void QuickSortTest::StressTest() { void QuickSortTest::StressTest() {
using embb::algorithms::QuickSort; using embb::algorithms::QuickSort;
size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() *10; size_t count = embb::tasks::Node::GetInstance().GetCoreCount() * 10;
std::vector<int> large_vector(count); std::vector<int> large_vector(count);
std::vector<int> vector_copy(count); std::vector<int> vector_copy(count);
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <reduce_test.h> #include <reduce_test.h>
#include <embb/algorithms/reduce.h> #include <embb/algorithms/reduce.h>
#include <embb/mtapi/execution_policy.h> #include <embb/tasks/execution_policy.h>
#include <deque> #include <deque>
#include <vector> #include <vector>
#include <functional> #include <functional>
...@@ -163,7 +163,7 @@ void ReduceTest::TestBlockSizes() { ...@@ -163,7 +163,7 @@ void ReduceTest::TestBlockSizes() {
void ReduceTest::TestPolicy() { void ReduceTest::TestPolicy() {
using embb::algorithms::Reduce; using embb::algorithms::Reduce;
using embb::mtapi::ExecutionPolicy; using embb::tasks::ExecutionPolicy;
using embb::algorithms::Identity; using embb::algorithms::Identity;
size_t count = 4; size_t count = 4;
int sum = 0; int sum = 0;
...@@ -210,9 +210,9 @@ void ReduceTest::TestPolicy() { ...@@ -210,9 +210,9 @@ void ReduceTest::TestPolicy() {
void ReduceTest::StressTest() { void ReduceTest::StressTest() {
using embb::algorithms::Reduce; using embb::algorithms::Reduce;
using embb::mtapi::ExecutionPolicy; using embb::tasks::ExecutionPolicy;
using embb::algorithms::Identity; using embb::algorithms::Identity;
size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() *10; size_t count = embb::tasks::Node::GetInstance().GetCoreCount() * 10;
std::vector<int> large_vector(count); std::vector<int> large_vector(count);
mtapi_int32_t expected = 0; mtapi_int32_t expected = 0;
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
......
...@@ -228,7 +228,7 @@ void ScanTest::TestRanges() { ...@@ -228,7 +228,7 @@ void ScanTest::TestRanges() {
void ScanTest::TestBlockSizes() { void ScanTest::TestBlockSizes() {
using embb::algorithms::Scan; using embb::algorithms::Scan;
using embb::mtapi::ExecutionPolicy; using embb::tasks::ExecutionPolicy;
using embb::algorithms::Identity; using embb::algorithms::Identity;
size_t count = 4; size_t count = 4;
std::vector<int> init(count); std::vector<int> init(count);
...@@ -253,7 +253,7 @@ void ScanTest::TestBlockSizes() { ...@@ -253,7 +253,7 @@ void ScanTest::TestBlockSizes() {
void ScanTest::TestPolicy() { void ScanTest::TestPolicy() {
using embb::algorithms::Scan; using embb::algorithms::Scan;
using embb::mtapi::ExecutionPolicy; using embb::tasks::ExecutionPolicy;
using embb::algorithms::Identity; using embb::algorithms::Identity;
size_t count = 4; size_t count = 4;
std::vector<int> init(count); std::vector<int> init(count);
...@@ -324,8 +324,8 @@ void ScanTest::TestPolicy() { ...@@ -324,8 +324,8 @@ void ScanTest::TestPolicy() {
void ScanTest::StressTest() { void ScanTest::StressTest() {
using embb::algorithms::Scan; using embb::algorithms::Scan;
using embb::algorithms::Identity; using embb::algorithms::Identity;
using embb::mtapi::ExecutionPolicy; using embb::tasks::ExecutionPolicy;
size_t count = embb::mtapi::Node::GetInstance().GetCoreCount() *10; size_t count = embb::tasks::Node::GetInstance().GetCoreCount() *10;
std::vector<int> large_vector(count); std::vector<int> large_vector(count);
std::vector<int> large_vector_output(count); std::vector<int> large_vector_output(count);
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
......
...@@ -136,7 +136,7 @@ void ZipIteratorTest::TestZipScan() { ...@@ -136,7 +136,7 @@ void ZipIteratorTest::TestZipScan() {
Scan(embb::algorithms::Zip(vectorA.begin(), vectorB.begin()), Scan(embb::algorithms::Zip(vectorA.begin(), vectorB.begin()),
embb::algorithms::Zip(vectorA.end(), vectorB.end()), embb::algorithms::Zip(vectorA.end(), vectorB.end()),
vectorOut.begin(), 0, std::plus<int>(), DotProductFunctor(), vectorOut.begin(), 0, std::plus<int>(), DotProductFunctor(),
embb::mtapi::ExecutionPolicy(), 0); embb::tasks::ExecutionPolicy(), 0);
long sum = 0; long sum = 0;
for (size_t i = 0; i < kCountSize; i++) { for (size_t i = 0; i < kCountSize; i++) {
......
...@@ -184,6 +184,13 @@ class CoreSet { ...@@ -184,6 +184,13 @@ class CoreSet {
/** [IN] Core set on right-hand side of union operation */ /** [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: private:
/** /**
* Internal representation of core set. * Internal representation of core set.
......
...@@ -46,6 +46,9 @@ namespace base { ...@@ -46,6 +46,9 @@ namespace base {
* Represents a relative time duration for a given tick type. * Represents a relative time duration for a given tick type.
* *
* \notthreadsafe * \notthreadsafe
* \note The typedefs DurationSeconds, DurationMilliseconds,
* DurationMicroseconds, and DurationNanoseconds provide directly usable
* duration types.
* \tparam Tick Possible tick types are Seconds, Milliseconds, Microseconds, * \tparam Tick Possible tick types are Seconds, Milliseconds, Microseconds,
* Nanoseconds * Nanoseconds
* \ingroup CPP_BASE_TIMEDURATION * \ingroup CPP_BASE_TIMEDURATION
...@@ -271,6 +274,8 @@ Duration<Tick> operator+( ...@@ -271,6 +274,8 @@ Duration<Tick> operator+(
return Duration<Tick>(lhs.Count() + rhs.Count()); return Duration<Tick>(lhs.Count() + rhs.Count());
} }
namespace internal {
/** /**
* Base class for ticks. * Base class for ticks.
*/ */
...@@ -517,6 +522,33 @@ class Nanoseconds : public Tick { ...@@ -517,6 +522,33 @@ class Nanoseconds : public Tick {
static unsigned long long Max(); static unsigned long long Max();
}; };
} // namespace internal
/**
* Duration with seconds tick.
*
* \ingroup CPP_BASE_TIMEDURATION
*/
typedef Duration<internal::Seconds> DurationSeconds;
/**
* Duration with milliseconds tick.
*
* \ingroup CPP_BASE_TIMEDURATION
*/
typedef Duration<internal::Milliseconds> DurationMilliseconds;
/**
* Duration with microseconds tick.
*
* \ingroup CPP_BASE_TIMEDURATION
*/
typedef Duration<internal::Microseconds> DurationMicroseconds;
/**
* Duration with nanoseconds tick.
*
* \ingroup CPP_BASE_TIMEDURATION
*/
typedef Duration<internal::Nanoseconds> DurationNanoseconds;
} // namespace base } // namespace base
} // namespace embb } // namespace embb
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
namespace embb { namespace embb {
namespace base { namespace base {
void Tick::CheckExceptions(int status, const char* msg) { void internal::Tick::CheckExceptions(int status, const char* msg) {
switch (status) { switch (status) {
case EMBB_SUCCESS: return; case EMBB_SUCCESS: return;
case EMBB_OVERFLOW: EMBB_THROW(OverflowException, msg); case EMBB_OVERFLOW: EMBB_THROW(OverflowException, msg);
...@@ -44,16 +44,18 @@ void Tick::CheckExceptions(int status, const char* 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); 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); int status = Set(duration, ticks);
CheckExceptions(status, "Setting duration from seconds"); 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; unsigned long long ticks = 0;
int status = embb_duration_as_seconds(&duration, &ticks); int status = embb_duration_as_seconds(&duration, &ticks);
assert(status == EMBB_SUCCESS); assert(status == EMBB_SUCCESS);
...@@ -61,25 +63,27 @@ unsigned long long Seconds::Get(const embb_duration_t& duration) { ...@@ -61,25 +63,27 @@ unsigned long long Seconds::Get(const embb_duration_t& duration) {
return ticks; return ticks;
} }
unsigned long long Seconds::Min() { unsigned long long internal::Seconds::Min() {
return 1; return 1;
} }
unsigned long long Seconds::Max() { unsigned long long internal::Seconds::Max() {
return EMBB_DURATION_MAX_SECONDS; 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); return embb_duration_set_milliseconds(&duration, ticks);
} }
void Milliseconds::SetAndCheck( void internal::Milliseconds::SetAndCheck(
embb_duration_t& duration, unsigned long long ticks) { embb_duration_t& duration, unsigned long long ticks) {
int status = Set(duration, ticks); int status = Set(duration, ticks);
CheckExceptions(status, "Setting duration from milliseconds"); 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; unsigned long long ticks = 0;
int status = embb_duration_as_milliseconds(&duration, &ticks); int status = embb_duration_as_milliseconds(&duration, &ticks);
assert(status == EMBB_SUCCESS); assert(status == EMBB_SUCCESS);
...@@ -87,7 +91,7 @@ unsigned long long Milliseconds::Get(const embb_duration_t& duration) { ...@@ -87,7 +91,7 @@ unsigned long long Milliseconds::Get(const embb_duration_t& duration) {
return ticks; return ticks;
} }
unsigned long long Milliseconds::Min() { unsigned long long internal::Milliseconds::Min() {
#if EMBB_DURATION_MIN_NANOSECONDS > 1000000 #if EMBB_DURATION_MIN_NANOSECONDS > 1000000
assert(EMBB_DURATION_MIN_NANOSECONDS % 1000000 == 0); assert(EMBB_DURATION_MIN_NANOSECONDS % 1000000 == 0);
return EMBB_DURATION_MIN_NANOSECONDS / 1000000; return EMBB_DURATION_MIN_NANOSECONDS / 1000000;
...@@ -95,7 +99,7 @@ unsigned long long Milliseconds::Min() { ...@@ -95,7 +99,7 @@ unsigned long long Milliseconds::Min() {
return 1; return 1;
} }
unsigned long long Milliseconds::Max() { unsigned long long internal::Milliseconds::Max() {
#if EMBB_DURATION_MAX_SECONDS < ULLONG_MAX / 1000 #if EMBB_DURATION_MAX_SECONDS < ULLONG_MAX / 1000
return ULLONG_MAX; return ULLONG_MAX;
#else #else
...@@ -103,17 +107,19 @@ unsigned long long Milliseconds::Max() { ...@@ -103,17 +107,19 @@ unsigned long long Milliseconds::Max() {
#endif #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); return embb_duration_set_microseconds(&duration, ticks);
} }
void Microseconds::SetAndCheck( void internal::Microseconds::SetAndCheck(
embb_duration_t& duration, unsigned long long ticks) { embb_duration_t& duration, unsigned long long ticks) {
int status = Set(duration, ticks); int status = Set(duration, ticks);
CheckExceptions(status, "Setting duration from microseconds"); 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; unsigned long long ticks = 0;
int status = embb_duration_as_microseconds(&duration, &ticks); int status = embb_duration_as_microseconds(&duration, &ticks);
...@@ -123,7 +129,7 @@ unsigned long long Microseconds::Get(const embb_duration_t& duration) { ...@@ -123,7 +129,7 @@ unsigned long long Microseconds::Get(const embb_duration_t& duration) {
return ticks; return ticks;
} }
unsigned long long Microseconds::Min() { unsigned long long internal::Microseconds::Min() {
#if EMBB_DURATION_MIN_NANOSECONDS > 1000 #if EMBB_DURATION_MIN_NANOSECONDS > 1000
assert(EMBB_DURATION_MIN_NANOSECONDS % 1000 == 0); assert(EMBB_DURATION_MIN_NANOSECONDS % 1000 == 0);
return EMBB_DURATION_MIN_NANOSECONDS / 1000; return EMBB_DURATION_MIN_NANOSECONDS / 1000;
...@@ -131,7 +137,7 @@ unsigned long long Microseconds::Min() { ...@@ -131,7 +137,7 @@ unsigned long long Microseconds::Min() {
return 1; return 1;
} }
unsigned long long Microseconds::Max() { unsigned long long internal::Microseconds::Max() {
#if EMBB_DURATION_MAX_SECONDS < ULLONG_MAX / 1000000 #if EMBB_DURATION_MAX_SECONDS < ULLONG_MAX / 1000000
return ULLONG_MAX; return ULLONG_MAX;
#else #else
...@@ -139,17 +145,18 @@ unsigned long long Microseconds::Max() { ...@@ -139,17 +145,18 @@ unsigned long long Microseconds::Max() {
#endif #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); return embb_duration_set_nanoseconds(&duration, ticks);
} }
void Nanoseconds::SetAndCheck( void internal::Nanoseconds::SetAndCheck(
embb_duration_t& duration, unsigned long long ticks) { embb_duration_t& duration, unsigned long long ticks) {
int status = Set(duration, ticks); int status = Set(duration, ticks);
CheckExceptions(status, "Setting duration from microseconds"); 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; unsigned long long ticks = 0;
int status = embb_duration_as_nanoseconds(&duration, &ticks); int status = embb_duration_as_nanoseconds(&duration, &ticks);
assert(status == EMBB_SUCCESS); assert(status == EMBB_SUCCESS);
...@@ -157,11 +164,11 @@ unsigned long long Nanoseconds::Get(const embb_duration_t& duration) { ...@@ -157,11 +164,11 @@ unsigned long long Nanoseconds::Get(const embb_duration_t& duration) {
return ticks; return ticks;
} }
unsigned long long Nanoseconds::Min() { unsigned long long internal::Nanoseconds::Min() {
return EMBB_DURATION_MIN_NANOSECONDS; return EMBB_DURATION_MIN_NANOSECONDS;
} }
unsigned long long Nanoseconds::Max() { unsigned long long internal::Nanoseconds::Max() {
#if EMBB_DURATION_MAX_SECONDS < ULLONG_MAX / 1000000000 #if EMBB_DURATION_MAX_SECONDS < ULLONG_MAX / 1000000000
return ULLONG_MAX; return ULLONG_MAX;
#else #else
......
...@@ -63,15 +63,15 @@ void ConditionVarTest::TestTimedWaitTimeouts() { ...@@ -63,15 +63,15 @@ void ConditionVarTest::TestTimedWaitTimeouts() {
PT_EXPECT_EQ(success, false); PT_EXPECT_EQ(success, false);
// Wait for a future timepoint // Wait for a future timepoint
success = cond.WaitUntil(lock, Time(Duration<Milliseconds>(1))); success = cond.WaitUntil(lock, Time(DurationMilliseconds(1)));
PT_EXPECT_EQ(success, false); PT_EXPECT_EQ(success, false);
// Wait for a zero duration // Wait for a zero duration
success = cond.WaitFor(lock, Duration<Milliseconds>()); success = cond.WaitFor(lock, DurationMilliseconds());
PT_EXPECT_EQ(success, false); PT_EXPECT_EQ(success, false);
// Wait for some duration // Wait for some duration
success = cond.WaitFor(lock, Duration<Milliseconds>(1)); success = cond.WaitFor(lock, DurationMilliseconds(1));
PT_EXPECT_EQ(success, false); PT_EXPECT_EQ(success, false);
} }
...@@ -96,14 +96,14 @@ void ConditionVarTest::TestNotify() { ...@@ -96,14 +96,14 @@ void ConditionVarTest::TestNotify() {
cond_notify_.NotifyOne(); cond_notify_.NotifyOne();
cond_wait_.WaitUntil(lock_wait, Time(Duration<Milliseconds>(1))); cond_wait_.WaitUntil(lock_wait, Time(DurationMilliseconds(1)));
while (embb_counter_get(&counter_) == 0) while (embb_counter_get(&counter_) == 0)
{} // If hangs here signal has not succeeded {} // If hangs here signal has not succeeded
PT_ASSERT_EQ_MSG(embb_counter_get(&counter_), PT_ASSERT_EQ_MSG(embb_counter_get(&counter_),
static_cast<unsigned int>(1), "Only 1 thread notified"); static_cast<unsigned int>(1), "Only 1 thread notified");
cond_notify_.NotifyAll(); cond_notify_.NotifyAll();
cond_wait_.WaitUntil(lock_wait, Time(Duration<Milliseconds>(2))); cond_wait_.WaitUntil(lock_wait, Time(DurationMilliseconds(2)));
while (embb_counter_get(&counter_) != while (embb_counter_get(&counter_) !=
static_cast<unsigned int>(num_threads_-1)) static_cast<unsigned int>(num_threads_-1))
......
...@@ -31,10 +31,13 @@ namespace base { ...@@ -31,10 +31,13 @@ namespace base {
namespace test { namespace test {
DurationTest::DurationTest() { DurationTest::DurationTest() {
CreateUnit("Seconds").Add(&DurationTest::Test<Seconds>, this); CreateUnit("Seconds").Add(&DurationTest::Test<internal::Seconds>, this);
CreateUnit("Milliseconds").Add(&DurationTest::Test<Milliseconds>, this); CreateUnit("Milliseconds").Add(&DurationTest::Test<internal::Milliseconds>,
CreateUnit("Microseconds").Add(&DurationTest::Test<Microseconds>, this); this);
CreateUnit("Nanoseconds").Add(&DurationTest::Test<Nanoseconds>, this); CreateUnit("Microseconds").Add(&DurationTest::Test<internal::Microseconds>,
this);
CreateUnit("Nanoseconds").Add(&DurationTest::Test<internal::Nanoseconds>,
this);
} }
} // namespace test } // namespace test
......
...@@ -17,16 +17,16 @@ include_directories(${EMBB_DATAFLOW_CPP_INCLUDE_DIRS} ...@@ -17,16 +17,16 @@ include_directories(${EMBB_DATAFLOW_CPP_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../base_cpp/include ${CMAKE_CURRENT_BINARY_DIR}/../base_cpp/include
${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_c/include ${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_c/include
${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../tasks_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../mtapi_cpp/include) ${CMAKE_CURRENT_BINARY_DIR}/../tasks_cpp/include)
add_library (embb_dataflow_cpp ${EMBB_DATAFLOW_CPP_SOURCES} ${EMBB_DATAFLOW_CPP_HEADERS}) 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) if (BUILD_TESTS STREQUAL ON)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/../partest/include) include_directories(${CMAKE_CURRENT_BINARY_DIR}/../partest/include)
add_executable (embb_dataflow_cpp_test ${EMBB_DATAFLOW_CPP_TEST_SOURCES}) 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}) embb_base_cpp embb_base_c ${compiler_libs})
CopyBin(BIN embb_dataflow_cpp_test DEST ${local_install_dir}) CopyBin(BIN embb_dataflow_cpp_test DEST ${local_install_dir})
endif() endif()
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include <cstddef> #include <cstddef>
#include <embb/mtapi/taskcontext.h> #include <embb/tasks/task_context.h>
#include <embb/dataflow/internal/node.h> #include <embb/dataflow/internal/node.h>
...@@ -48,7 +48,7 @@ class Action { ...@@ -48,7 +48,7 @@ class Action {
pending_ = 0; pending_ = 0;
} }
void RunMTAPI(embb::mtapi::TaskContext & /*context*/) { void RunMTAPI(embb::tasks::TaskContext & /*context*/) {
pending_ = 1; pending_ = 1;
node_->Run(clock_); node_->Run(clock_);
pending_ = 0; pending_ = 0;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#ifndef EMBB_DATAFLOW_INTERNAL_INPUTS_H_ #ifndef EMBB_DATAFLOW_INTERNAL_INPUTS_H_
#define EMBB_DATAFLOW_INTERNAL_INPUTS_H_ #define EMBB_DATAFLOW_INTERNAL_INPUTS_H_
#include <embb/base/atomic.h>
#include <embb/dataflow/internal/tuple.h> #include <embb/dataflow/internal/tuple.h>
#include <embb/dataflow/internal/in.h> #include <embb/dataflow/internal/in.h>
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#define EMBB_DATAFLOW_INTERNAL_NODE_H_ #define EMBB_DATAFLOW_INTERNAL_NODE_H_
#include <cstddef> #include <cstddef>
#include <embb/base/exceptions.h>
#include <embb/dataflow/internal/scheduler.h> #include <embb/dataflow/internal/scheduler.h>
namespace embb { namespace embb {
...@@ -50,6 +50,9 @@ class Node { ...@@ -50,6 +50,9 @@ class Node {
protected: protected:
Scheduler * sched_; Scheduler * sched_;
static int next_process_id_;
static int GetNextProcessID() { return next_process_id_++; }
}; };
} // namespace internal } // namespace internal
......
...@@ -56,6 +56,13 @@ class Process< Slices, Serial, Inputs<Slices, I1, I2, I3, I4, I5>, ...@@ -56,6 +56,13 @@ class Process< Slices, Serial, Inputs<Slices, I1, I2, I3, I4, I5>,
explicit Process(FunctionType function) explicit Process(FunctionType function)
: executor_(function) { : executor_(function) {
next_clock_ = 0; next_clock_ = 0;
queued_clock_ = 0;
bool ordered = Serial;
if (ordered) {
queue_id_ = GetNextProcessID();
} else {
queue_id_ = 0;
}
inputs_.SetListener(this); inputs_.SetListener(this);
} }
...@@ -95,21 +102,39 @@ class Process< Slices, Serial, Inputs<Slices, I1, I2, I3, I4, I5>, ...@@ -95,21 +102,39 @@ class Process< Slices, Serial, Inputs<Slices, I1, I2, I3, I4, I5>,
} }
virtual void OnClock(int clock) { virtual void OnClock(int clock) {
if (!inputs_.AreAtClock(clock)) if (!inputs_.AreAtClock(clock)) {
EMBB_THROW(embb::base::ErrorException, EMBB_THROW(embb::base::ErrorException,
"Some inputs are not at expected clock.") "Some inputs are not at expected clock.")
}
bool ordered = Serial; bool ordered = Serial;
if (ordered) { if (ordered) {
lock_.Lock(); bool retry = true;
for (int ii = next_clock_; ii < next_clock_ + Slices; ii++) { 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)) { if (!inputs_.AreAtClock(ii)) {
break; break;
} }
next_clock_ = ii + 1; clk_res++;
Run(ii); }
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;
}
} }
lock_.Unlock();
} else { } else {
const int idx = clock % Slices; const int idx = clock % Slices;
action_[idx] = Action(this, clock); action_[idx] = Action(this, clock);
...@@ -121,9 +146,10 @@ class Process< Slices, Serial, Inputs<Slices, I1, I2, I3, I4, I5>, ...@@ -121,9 +146,10 @@ class Process< Slices, Serial, Inputs<Slices, I1, I2, I3, I4, I5>,
InputsType inputs_; InputsType inputs_;
OutputsType outputs_; OutputsType outputs_;
ExecutorType executor_; ExecutorType executor_;
int next_clock_;
Action action_[Slices]; Action action_[Slices];
SpinLock lock_; embb::base::Atomic<int> next_clock_;
embb::base::Atomic<int> queued_clock_;
int queue_id_;
}; };
} // namespace internal } // namespace internal
......
...@@ -38,6 +38,7 @@ class Scheduler { ...@@ -38,6 +38,7 @@ class Scheduler {
Scheduler() {} Scheduler() {}
virtual ~Scheduler() {} virtual ~Scheduler() {}
virtual void Spawn(Action & action) = 0; virtual void Spawn(Action & action) = 0;
virtual void Enqueue(int process_id, Action & action) = 0;
virtual void WaitForSlice(int slice) = 0; virtual void WaitForSlice(int slice) = 0;
}; };
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include <embb/dataflow/internal/action.h> #include <embb/dataflow/internal/action.h>
#include <embb/dataflow/internal/scheduler.h> #include <embb/dataflow/internal/scheduler.h>
#include <embb/mtapi/node.h> #include <embb/tasks/node.h>
#include <embb/base/function.h> #include <embb/base/function.h>
namespace embb { namespace embb {
...@@ -40,29 +40,51 @@ template <int Slices> ...@@ -40,29 +40,51 @@ template <int Slices>
class SchedulerMTAPI : public Scheduler { class SchedulerMTAPI : public Scheduler {
public: public:
SchedulerMTAPI() { SchedulerMTAPI() {
embb::mtapi::Node & node = embb::mtapi::Node::GetInstance(); embb::tasks::Node & node = embb::tasks::Node::GetInstance();
for (int ii = 0; ii < Slices; ii++) { for (int ii = 0; ii < Slices; ii++) {
embb::mtapi::Group & group = node.CreateGroup(); embb::tasks::Group & group = node.CreateGroup();
group_[ii] = &group; group_[ii] = &group;
} }
queue_count_ = static_cast<int>(node.GetWorkerThreadCount());
queue_ = reinterpret_cast<embb::tasks::Queue**>(
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() { 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++) { for (int ii = 0; ii < Slices; ii++) {
group_[ii]->WaitAll(MTAPI_INFINITE); group_[ii]->WaitAll(MTAPI_INFINITE);
node.DestroyGroup(*group_[ii]); 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) { virtual void Spawn(Action & action) {
const int idx = action.GetClock() % Slices; const int idx = action.GetClock() % Slices;
group_[idx]->Spawn(embb::base::MakeFunction(action, &Action::RunMTAPI)); 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) { virtual void WaitForSlice(int slice) {
group_[slice]->WaitAll(MTAPI_INFINITE); group_[slice]->WaitAll(MTAPI_INFINITE);
} }
private: private:
embb::mtapi::Group * group_[Slices]; embb::tasks::Group * group_[Slices];
embb::tasks::Queue ** queue_;
int queue_count_;
}; };
} // namespace internal } // namespace internal
......
...@@ -41,6 +41,9 @@ class SchedulerSequential : public Scheduler { ...@@ -41,6 +41,9 @@ class SchedulerSequential : public Scheduler {
virtual void Spawn(Action & action) { virtual void Spawn(Action & action) {
action.RunSequential(); action.RunSequential();
} }
virtual void Enqueue(int, Action & action) {
action.RunSequential();
}
virtual void WaitForSlice(int /*slice*/) {} virtual void WaitForSlice(int /*slice*/) {}
}; };
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#ifndef EMBB_DATAFLOW_INTERNAL_SIGNAL_H_ #ifndef EMBB_DATAFLOW_INTERNAL_SIGNAL_H_
#define EMBB_DATAFLOW_INTERNAL_SIGNAL_H_ #define EMBB_DATAFLOW_INTERNAL_SIGNAL_H_
#include <embb/dataflow/internal/spinlock.h> #include <embb/base/c/atomic.h>
namespace embb { namespace embb {
namespace dataflow { namespace dataflow {
...@@ -42,27 +42,23 @@ class Signal { ...@@ -42,27 +42,23 @@ class Signal {
Signal(Signal const & other) Signal(Signal const & other)
: blank_(other.blank_), value_(other.value_), clock_(other.clock_) {} : blank_(other.blank_), value_(other.value_), clock_(other.clock_) {}
void operator = (Signal const & rhs) { void operator = (Signal const & rhs) {
lock_.Lock();
blank_ = rhs.blank_; blank_ = rhs.blank_;
value_ = rhs.value_; value_ = rhs.value_;
clock_ = rhs.clock_; clock_ = rhs.clock_;
lock_.Unlock(); embb_atomic_memory_barrier();
} }
int GetClock() const { return clock_; } int GetClock() const { return clock_; }
bool IsBlank() const { return blank_; } bool IsBlank() const { return blank_; }
Type const & GetValue() const { return value_; } Type const & GetValue() const { return value_; }
void Clear() { void Clear() {
lock_.Lock();
blank_ = true; blank_ = true;
clock_ = -1; clock_ = -1;
lock_.Unlock();
} }
private: private:
bool blank_; bool blank_;
Type value_; Type value_;
int clock_; int clock_;
SpinLock lock_;
}; };
} // namespace internal } // namespace internal
......
...@@ -52,6 +52,8 @@ class Sink< Slices, Inputs<Slices, I1, I2, I3, I4, I5> > ...@@ -52,6 +52,8 @@ class Sink< Slices, Inputs<Slices, I1, I2, I3, I4, I5> >
explicit Sink(FunctionType function) explicit Sink(FunctionType function)
: executor_(function) { : executor_(function) {
next_clock_ = 0; next_clock_ = 0;
queued_clock_ = 0;
queue_id_ = GetNextProcessID();
inputs_.SetListener(this); inputs_.SetListener(this);
} }
...@@ -80,32 +82,47 @@ class Sink< Slices, Inputs<Slices, I1, I2, I3, I4, I5> > ...@@ -80,32 +82,47 @@ class Sink< Slices, Inputs<Slices, I1, I2, I3, I4, I5> >
} }
virtual void OnClock(int clock) { virtual void OnClock(int clock) {
TrySpawn(clock); if (!inputs_.AreAtClock(clock)) {
}
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, EMBB_THROW(embb::base::ErrorException,
"Some inputs are not at expected clock.") "Some inputs are not at expected clock.")
}
lock_.Lock(); bool retry = true;
for (int ii = next_clock_; ii < next_clock_ + Slices; ii++) { 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)) { if (!inputs_.AreAtClock(ii)) {
break; break;
} }
next_clock_ = ii + 1; clk_res++;
Run(ii); }
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]);
} }
lock_.Unlock(); queued_clock_.Store(clk_res);
retry = false;
} }
} else {
retry = false;
}
}
}
private:
InputsType inputs_;
ExecutorType executor_;
Action action_[Slices];
ClockListener * listener_;
embb::base::Atomic<int> next_clock_;
embb::base::Atomic<int> queued_clock_;
int queue_id_;
}; };
} // namespace internal } // namespace internal
......
...@@ -27,13 +27,9 @@ ...@@ -27,13 +27,9 @@
#ifndef EMBB_DATAFLOW_INTERNAL_SOURCE_H_ #ifndef EMBB_DATAFLOW_INTERNAL_SOURCE_H_
#define EMBB_DATAFLOW_INTERNAL_SOURCE_H_ #define EMBB_DATAFLOW_INTERNAL_SOURCE_H_
#include <embb/base/atomic.h>
#include <embb/base/thread.h>
#include <embb/dataflow/internal/node.h> #include <embb/dataflow/internal/node.h>
#include <embb/dataflow/internal/outputs.h> #include <embb/dataflow/internal/outputs.h>
#include <embb/dataflow/internal/source_executor.h> #include <embb/dataflow/internal/source_executor.h>
#include <embb/dataflow/internal/action.h>
namespace embb { namespace embb {
namespace dataflow { namespace dataflow {
...@@ -53,7 +49,6 @@ class Source< Slices, Outputs<Slices, O1, O2, O3, O4, O5> > ...@@ -53,7 +49,6 @@ class Source< Slices, Outputs<Slices, O1, O2, O3, O4, O5> >
explicit Source(FunctionType function) explicit Source(FunctionType function)
: executor_(function), not_done_(true) { : executor_(function), not_done_(true) {
next_clock_ = 0;
} }
virtual bool HasOutputs() const { virtual bool HasOutputs() const {
...@@ -62,7 +57,6 @@ class Source< Slices, Outputs<Slices, O1, O2, O3, O4, O5> > ...@@ -62,7 +57,6 @@ class Source< Slices, Outputs<Slices, O1, O2, O3, O4, O5> >
virtual void Run(int clock) { virtual void Run(int clock) {
not_done_ = executor_.Execute(clock, outputs_); not_done_ = executor_.Execute(clock, outputs_);
next_clock_++;
} }
virtual bool Start(int clock) { virtual bool Start(int clock) {
...@@ -89,9 +83,7 @@ class Source< Slices, Outputs<Slices, O1, O2, O3, O4, O5> > ...@@ -89,9 +83,7 @@ class Source< Slices, Outputs<Slices, O1, O2, O3, O4, O5> >
private: private:
OutputsType outputs_; OutputsType outputs_;
ExecutorType executor_; ExecutorType executor_;
Action action_[Slices];
volatile bool not_done_; volatile bool not_done_;
embb::base::Atomic<int> next_clock_;
}; };
} // namespace internal } // namespace internal
......
...@@ -24,3 +24,6 @@ ...@@ -24,3 +24,6 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <embb/dataflow/internal/node.h>
int embb::dataflow::internal::Node::next_process_id_ = 0;
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <embb/mtapi/mtapi.h> #include <embb/tasks/tasks.h>
#include <embb/base/function.h> #include <embb/base/function.h>
#include <embb/base/c/memory_allocation.h> #include <embb/base/c/memory_allocation.h>
...@@ -60,7 +60,7 @@ bool sourceFunc(int & out) { ...@@ -60,7 +60,7 @@ bool sourceFunc(int & out) {
source_array[source_counter] = out; source_array[source_counter] = out;
source_counter++; source_counter++;
return source_counter < 12; return source_counter < TEST_COUNT;
} }
embb::base::Atomic<int> pred_counter; embb::base::Atomic<int> pred_counter;
...@@ -143,7 +143,7 @@ SimpleTest::SimpleTest() { ...@@ -143,7 +143,7 @@ SimpleTest::SimpleTest() {
} }
void SimpleTest::TestBasic() { void SimpleTest::TestBasic() {
embb::mtapi::Node::Initialize(1, 1); embb::tasks::Node::Initialize(1, 1);
for (int ii = 0; ii < 10000; ii++) { for (int ii = 0; ii < 10000; ii++) {
ArraySink<TEST_COUNT> asink; ArraySink<TEST_COUNT> asink;
...@@ -203,7 +203,7 @@ void SimpleTest::TestBasic() { ...@@ -203,7 +203,7 @@ void SimpleTest::TestBasic() {
PT_EXPECT(asink.Check()); PT_EXPECT(asink.Check());
} }
embb::mtapi::Node::Finalize(); embb::tasks::Node::Finalize();
PT_EXPECT(embb_get_bytes_allocated() == 0); PT_EXPECT(embb_get_bytes_allocated() == 0);
} }
...@@ -11,7 +11,8 @@ include_directories( ...@@ -11,7 +11,8 @@ include_directories(
${CMAKE_CURRENT_BINARY_DIR}/../../base_cpp/include ${CMAKE_CURRENT_BINARY_DIR}/../../base_cpp/include
${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_c/include ${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_c/include
${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_cpp/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}/../../containers_cpp/include
${CMAKE_CURRENT_SOURCE_DIR}/../../algorithms_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../../algorithms_cpp/include
${CMAKE_CURRENT_SOURCE_DIR}/../../dataflow_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../../dataflow_cpp/include
...@@ -22,6 +23,6 @@ if(CMAKE_COMPILER_IS_GNUCXX) ...@@ -22,6 +23,6 @@ if(CMAKE_COMPILER_IS_GNUCXX)
endif() endif()
add_executable(examples ${EXAMPLES_SOURCES}) 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}) embb_mtapi_c embb_base_cpp embb_base_c embb_containers_cpp ${compiler_libs})
CopyBin(BIN examples DEST ${local_install_dir}) CopyBin(BIN examples DEST ${local_install_dir})
...@@ -25,9 +25,11 @@ ...@@ -25,9 +25,11 @@
*/ */
#include <iostream> #include <iostream>
#include <embb/base/c/thread.h>
void RunMTAPI_C(); void RunMTAPI_C();
void RunMTAPI_CPP(); void RunMTAPI_CPP();
void RunTasks();
void RunDataflowLinear(); void RunDataflowLinear();
void RunDataflowNonLinear(); void RunDataflowNonLinear();
void RunSTLForEach(); void RunSTLForEach();
...@@ -45,6 +47,8 @@ void RunQueueExamples(); ...@@ -45,6 +47,8 @@ void RunQueueExamples();
* Runs all examples and tests their correctness. * Runs all examples and tests their correctness.
*/ */
int main() { int main() {
embb_thread_set_max_count(1024);
std::cout << "Running examples ..." << std::endl; std::cout << "Running examples ..." << std::endl;
std::cout << "RunMTAPI_C() ..." << std::endl; std::cout << "RunMTAPI_C() ..." << std::endl;
...@@ -55,6 +59,10 @@ int main() { ...@@ -55,6 +59,10 @@ int main() {
RunMTAPI_CPP(); RunMTAPI_CPP();
std::cout << "RunMTAPI_CPP() ... done" << std::endl; std::cout << "RunMTAPI_CPP() ... done" << std::endl;
std::cout << "RunTasks() ..." << std::endl;
RunTasks();
std::cout << "RunTasks() ... done" << std::endl;
std::cout << "RunDataflowLinear() ..." << std::endl; std::cout << "RunDataflowLinear() ..." << std::endl;
RunDataflowLinear(); RunDataflowLinear();
std::cout << "RunDataflowLinear() ... done" << std::endl; std::cout << "RunDataflowLinear() ... done" << std::endl;
......
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
#define THIS_NODE_ID 1 #define THIS_NODE_ID 1
#define FIBONACCI_JOB 1 #define FIBONACCI_JOB 1
mtapi_job_hndl_t fibonacciJob; static mtapi_job_hndl_t fibonacciJob;
...@@ -29,9 +29,12 @@ ...@@ -29,9 +29,12 @@
#include <embb/mtapi/mtapi.h> #include <embb/mtapi/mtapi.h>
#include "mtapi/mtapi_check_status-snippet.h" #include "mtapi/mtapi_check_status-snippet.h"
#include "mtapi/mtapi_cpp_domain_node_id-snippet.h"
static 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 */ /* get the node instance */
#include "mtapi/mtapi_cpp_get_node-snippet.h" #include "mtapi/mtapi_cpp_get_node-snippet.h"
/* calculate */ /* calculate */
...@@ -39,26 +42,26 @@ static ...@@ -39,26 +42,26 @@ static
/* first recursive call spawned as task (x = fib(n - 1);) */ /* first recursive call spawned as task (x = fib(n - 1);) */
#include "mtapi/mtapi_cpp_calc_task-snippet.h" #include "mtapi/mtapi_cpp_calc_task-snippet.h"
/* second recursive call can be called directly (y = fib(n - 2);) */ /* 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 */ /* wait for completion */
#include "mtapi/mtapi_cpp_wait_task-snippet.h" #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" #include "mtapi/mtapi_write_back-snippet.h"
static static
int fibonacci(int n) { int fibonacci(int n) {
/* get the node instance, the node is initialized automatically */ #include "mtapi/mtapi_cpp_initialize-snippet.h"
embb::mtapi::Node& node = embb::mtapi::Node::GetInstance(); #include "mtapi/mtapi_cpp_register_action-snippet.h"
#include "mtapi/mtapi_cpp_get_node-snippet.h"
/* start calculation */ /* start calculation */
#include "mtapi/mtapi_cpp_start_task-snippet.h" #include "mtapi/mtapi_cpp_start_task-snippet.h"
/* wait for task completion */ /* wait for task completion */
mtapi_status_t status = task.Wait(MTAPI_INFINITE); mtapi_status_t status = task.Wait(MTAPI_INFINITE);
MTAPI_CHECK_STATUS(status); MTAPI_CHECK_STATUS(status);
#include "mtapi/mtapi_cpp_finalize-snippet.h"
return result; return result;
} }
void RunMTAPI_CPP() { void RunMTAPI_CPP() {
int result = fibonacci(6); #include "mtapi/mtapi_cpp_main-snippet.h"
std::cout << "result: " << result << std::endl;
} }
int a = n - 1; int a = n - 1;
int x; int x;
embb::mtapi::Task task = node.Spawn( embb::mtapi::Task task = node.Start(fibonacciJob, &a, &x);
embb::base::Bind(
embb::base::MakeFunction(fibonacciActionFunction),
a, /* argument */
&x, /* result */
embb::base::Placeholder::_1
)
);
#define THIS_DOMAIN_ID 1
#define THIS_NODE_ID 1
#define FIBONACCI_JOB 1
static embb::mtapi::Job fibonacciJob;
/* finalize the node */
embb::mtapi::Node::Finalize();
/* initialize the node with default attributes */
embb::mtapi::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID);
EMBB_TRY {
int result = fibonacci(6);
std::cout << "result: " << result << std::endl;
} EMBB_CATCH(embb::mtapi::StatusException &) {
std::cout << "MTAPI error occured." << std::endl;
}
/* 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);
int result; int result;
embb::mtapi::Task task = node.Spawn( embb::mtapi::Task task = node.Start(fibonacciJob, &n, &result);
embb::base::Bind(
embb::base::MakeFunction(fibonacciActionFunction),
n,
&result,
embb::base::Placeholder::_1
)
);
mtapi_status_t status = task.Wait(MTAPI_INFINITE); 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);
}
/*
* 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 <iostream>
#include <embb/tasks/tasks.h>
#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;
}
void fibonacciActionFunction( void fibonacciActionFunction(
int n, int n,
int* result, int* result,
embb::mtapi::TaskContext & task_context embb::tasks::TaskContext & task_context
) { ) {
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
)
);
embb::tasks::Node& node = embb::tasks::Node::GetInstance();
int result;
embb::tasks::Task task = node.Spawn(
embb::base::Bind(
embb::base::MakeFunction(fibonacciActionFunction),
n,
&result,
embb::base::Placeholder::_1
)
);
mtapi_status_t status = task.Wait(MTAPI_INFINITE);
MTAPI_CHECK_STATUS(status);
...@@ -148,6 +148,7 @@ INPUT = "@CMAKE_SOURCE_DIR@/doc/reference/embb.dox" \ ...@@ -148,6 +148,7 @@ INPUT = "@CMAKE_SOURCE_DIR@/doc/reference/embb.dox" \
"@CMAKE_SOURCE_DIR@/containers_cpp/include" \ "@CMAKE_SOURCE_DIR@/containers_cpp/include" \
"@CMAKE_SOURCE_DIR@/dataflow_cpp/include" \ "@CMAKE_SOURCE_DIR@/dataflow_cpp/include" \
"@CMAKE_SOURCE_DIR@/algorithms_cpp/include" \ "@CMAKE_SOURCE_DIR@/algorithms_cpp/include" \
"@CMAKE_SOURCE_DIR@/tasks_cpp/include" \
"@CMAKE_SOURCE_DIR@/mtapi_cpp/include" \ "@CMAKE_SOURCE_DIR@/mtapi_cpp/include" \
"@CMAKE_SOURCE_DIR@/base_cpp/include" \ "@CMAKE_SOURCE_DIR@/base_cpp/include" \
"@CMAKE_SOURCE_DIR@/mtapi_c/include" \ "@CMAKE_SOURCE_DIR@/mtapi_c/include" \
......
...@@ -20,10 +20,10 @@ programming interface for leveraging task parallelism in embedded ...@@ -20,10 +20,10 @@ programming interface for leveraging task parallelism in embedded
systems containing symmetric or asymmetric multicore processors. A core systems containing symmetric or asymmetric multicore processors. A core
feature of MTAPI is low-overhead scheduling of fine-grained tasks among feature of MTAPI is low-overhead scheduling of fine-grained tasks among
the available cores during runtime. Unlike existing libraries, the available cores during runtime. Unlike existing libraries,
EMB<sup>2</sup> supports task priorities, which allows the creation of EMB<sup>2</sup> supports task priorities and affinities, which allows
soft real-time systems. Additionally, the scheduling strategy can be the creation of soft real-time systems. Additionally, the scheduling
optimized for non-functional requirements such as minimal latency and strategy can be optimized for non-functional requirements such as minimal
fairness. latency and fairness.
Besides the task scheduler, EMB<sup>2</sup> provides basic parallel Besides the task scheduler, EMB<sup>2</sup> provides basic parallel
algorithms, concurrent data structures, and skeletons for implementing algorithms, concurrent data structures, and skeletons for implementing
......
...@@ -152,27 +152,21 @@ After everything is done, the action is deleted (\lstinline|mtapi_action_delete( ...@@ -152,27 +152,21 @@ After everything is done, the action is deleted (\lstinline|mtapi_action_delete(
\section{C++ Interface} \section{C++ Interface}
\label{sec:mtapi_cpp_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} \\\inputlisting{../examples/mtapi/mtapi_c_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}
% %
\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 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:
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} \\\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} \\\inputlisting{../examples/mtapi/mtapi_cpp_calc_task-snippet.h}
% %
The second part can be executed directly: 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()|: 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: ...@@ -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} \\\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} \\\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} \\\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}
\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|.}
...@@ -114,6 +114,7 @@ ...@@ -114,6 +114,7 @@
% \input{content/preface} % \input{content/preface}
\input{content/introduction} \input{content/introduction}
\input{content/mtapi} \input{content/mtapi}
\input{content/tasks}
\input{content/algorithms} \input{content/algorithms}
\input{content/dataflow} \input{content/dataflow}
\input{content/containers} \input{content/containers}
......
...@@ -304,39 +304,44 @@ int embb_mtapi_scheduler_worker(void * arg) { ...@@ -304,39 +304,44 @@ int embb_mtapi_scheduler_worker(void * arg) {
switch (task->state) { switch (task->state) {
case MTAPI_TASK_SCHEDULED: case MTAPI_TASK_SCHEDULED:
/* multi-instance task, another instance might be running */
case MTAPI_TASK_RUNNING:
/* there was work, execute it */ /* there was work, execute it */
embb_mtapi_task_context_initialize_with_thread_context_and_task( embb_mtapi_task_context_initialize_with_thread_context_and_task(
&task_context, thread_context, task); &task_context, thread_context, task);
embb_mtapi_task_execute(task, &task_context); if (embb_mtapi_task_execute(task, &task_context)) {
/* tell queue that a task is done */ /* tell queue that a task is done */
if (MTAPI_NULL != local_queue) { if (MTAPI_NULL != local_queue) {
embb_mtapi_queue_task_finished(local_queue); embb_mtapi_queue_task_finished(local_queue);
} }
}
counter = 0; counter = 0;
break; break;
case MTAPI_TASK_RETAINED: case MTAPI_TASK_RETAINED:
/* put task into queue again for later execution */ /* put task into queue again for later execution */
embb_mtapi_scheduler_schedule_task( embb_mtapi_scheduler_schedule_task(
node->scheduler, task); node->scheduler, task, 0);
/* yield, as there may be only retained tasks in the queue */ /* yield, as there may be only retained tasks in the queue */
embb_thread_yield(); embb_thread_yield();
/* task is not done, so do not notify queue */ /* task is not done, so do not notify queue */
break; break;
case MTAPI_TASK_CANCELLED: case MTAPI_TASK_CANCELLED:
/* set return value to cancelled */ /* set return value to canceled */
task->error_code = MTAPI_ERR_ACTION_CANCELLED; task->error_code = MTAPI_ERR_ACTION_CANCELLED;
if (embb_atomic_fetch_and_add_unsigned_int(
&task->instances_todo, (unsigned int)-1) == 0) {
/* tell queue that a task is done */ /* tell queue that a task is done */
if (MTAPI_NULL != local_queue) { if (MTAPI_NULL != local_queue) {
embb_mtapi_queue_task_finished(local_queue); embb_mtapi_queue_task_finished(local_queue);
} }
}
break; break;
case MTAPI_TASK_COMPLETED: case MTAPI_TASK_COMPLETED:
case MTAPI_TASK_DELETED: case MTAPI_TASK_DELETED:
case MTAPI_TASK_WAITING: case MTAPI_TASK_WAITING:
case MTAPI_TASK_RUNNING:
case MTAPI_TASK_CREATED: case MTAPI_TASK_CREATED:
case MTAPI_TASK_PRENATAL: case MTAPI_TASK_PRENATAL:
case MTAPI_TASK_ERROR: case MTAPI_TASK_ERROR:
...@@ -351,12 +356,14 @@ int embb_mtapi_scheduler_worker(void * arg) { ...@@ -351,12 +356,14 @@ int embb_mtapi_scheduler_worker(void * arg) {
counter++; counter++;
} else { } else {
/* no work, go to sleep */ /* no work, go to sleep */
embb_atomic_store_int(&thread_context->is_sleeping, 1);
embb_mutex_lock(&thread_context->work_available_mutex); embb_mutex_lock(&thread_context->work_available_mutex);
embb_condition_wait_for( embb_condition_wait_for(
&thread_context->work_available, &thread_context->work_available,
&thread_context->work_available_mutex, &thread_context->work_available_mutex,
&sleep_duration); &sleep_duration);
embb_mutex_unlock(&thread_context->work_available_mutex); 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( ...@@ -526,10 +533,11 @@ mtapi_boolean_t embb_mtapi_scheduler_process_tasks(
mtapi_boolean_t embb_mtapi_scheduler_schedule_task( mtapi_boolean_t embb_mtapi_scheduler_schedule_task(
embb_mtapi_scheduler_t * that, 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; embb_mtapi_scheduler_t * scheduler = that;
/* distribute round robin */ /* 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; mtapi_boolean_t pushed = MTAPI_FALSE;
embb_mtapi_node_t* node = embb_mtapi_node_get_instance(); embb_mtapi_node_t* node = embb_mtapi_node_get_instance();
...@@ -586,8 +594,8 @@ mtapi_boolean_t embb_mtapi_scheduler_schedule_task( ...@@ -586,8 +594,8 @@ mtapi_boolean_t embb_mtapi_scheduler_schedule_task(
} }
if (pushed) { if (pushed) {
/* signal all threads */ /* signal the worker thread a task was pushed to */
for (ii = 0; ii < scheduler->worker_count; ii++) { if (embb_atomic_load_int(&scheduler->worker_contexts[ii].is_sleeping)) {
embb_condition_notify_one( embb_condition_notify_one(
&scheduler->worker_contexts[ii].work_available); &scheduler->worker_contexts[ii].work_available);
} }
......
...@@ -198,7 +198,8 @@ mtapi_boolean_t embb_mtapi_scheduler_process_tasks( ...@@ -198,7 +198,8 @@ mtapi_boolean_t embb_mtapi_scheduler_process_tasks(
*/ */
mtapi_boolean_t embb_mtapi_scheduler_schedule_task( mtapi_boolean_t embb_mtapi_scheduler_schedule_task(
embb_mtapi_scheduler_t * that, embb_mtapi_scheduler_t * that,
embb_mtapi_task_t * task); embb_mtapi_task_t * task,
mtapi_uint_t instance);
#ifdef __cplusplus #ifdef __cplusplus
......
...@@ -51,8 +51,8 @@ void embb_mtapi_task_context_initialize_with_thread_context_and_task( ...@@ -51,8 +51,8 @@ void embb_mtapi_task_context_initialize_with_thread_context_and_task(
that->task = task; that->task = task;
that->thread_context = thread_context; that->thread_context = thread_context;
that->num_instances = task->attributes.num_instances; that->num_instances = task->attributes.num_instances;
that->instance_num = embb_atomic_fetch_and_add_unsigned_int( that->instance_num =
&task->current_instance, 1); embb_atomic_fetch_and_add_unsigned_int(&task->current_instance, 1);
} }
void embb_mtapi_task_context_finalize(embb_mtapi_task_context_t* that) { void embb_mtapi_task_context_finalize(embb_mtapi_task_context_t* that) {
......
...@@ -95,9 +95,11 @@ void embb_mtapi_task_finalize(embb_mtapi_task_t* that) { ...@@ -95,9 +95,11 @@ void embb_mtapi_task_finalize(embb_mtapi_task_t* that) {
embb_mtapi_spinlock_finalize(&that->state_lock); 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_t* that,
embb_mtapi_task_context_t * context) { embb_mtapi_task_context_t * context) {
unsigned int todo = that->attributes.num_instances;
assert(MTAPI_NULL != that); assert(MTAPI_NULL != that);
assert(MTAPI_NULL != context); assert(MTAPI_NULL != context);
...@@ -110,6 +112,8 @@ void embb_mtapi_task_execute( ...@@ -110,6 +112,8 @@ void embb_mtapi_task_execute(
embb_mtapi_action_t* local_action = embb_mtapi_action_t* local_action =
embb_mtapi_action_pool_get_storage_for_handle( embb_mtapi_action_pool_get_storage_for_handle(
context->thread_context->node->action_pool, that->action); context->thread_context->node->action_pool, that->action);
/* only continue if there was no error so far */
if (context->task->error_code == MTAPI_SUCCESS) {
local_action->action_function( local_action->action_function(
that->arguments, that->arguments,
that->arguments_size, that->arguments_size,
...@@ -118,9 +122,15 @@ void embb_mtapi_task_execute( ...@@ -118,9 +122,15 @@ void embb_mtapi_task_execute(
local_action->node_local_data, local_action->node_local_data,
local_action->node_local_data_size, local_action->node_local_data_size,
context); context);
}
embb_atomic_memory_barrier(); embb_atomic_memory_barrier();
todo = embb_atomic_fetch_and_add_unsigned_int(
&that->instances_todo, (unsigned int)-1);
if (todo == 1) {
/* task has completed successfully */ /* task has completed successfully */
embb_mtapi_task_set_state(that, MTAPI_TASK_COMPLETED); embb_mtapi_task_set_state(that, MTAPI_TASK_COMPLETED);
}
embb_atomic_fetch_and_add_int(&local_action->num_tasks, -1); embb_atomic_fetch_and_add_int(&local_action->num_tasks, -1);
} else { } else {
/* action was deleted, task did not complete */ /* action was deleted, task did not complete */
...@@ -128,6 +138,7 @@ void embb_mtapi_task_execute( ...@@ -128,6 +138,7 @@ void embb_mtapi_task_execute(
embb_mtapi_task_set_state(that, MTAPI_TASK_ERROR); embb_mtapi_task_set_state(that, MTAPI_TASK_ERROR);
} }
if (todo == 1) {
/* is task associated with a group? */ /* is task associated with a group? */
if (embb_mtapi_group_pool_is_handle_valid( if (embb_mtapi_group_pool_is_handle_valid(
context->thread_context->node->group_pool, that->group)) { context->thread_context->node->group_pool, that->group)) {
...@@ -136,6 +147,10 @@ void embb_mtapi_task_execute( ...@@ -136,6 +147,10 @@ void embb_mtapi_task_execute(
context->thread_context->node->group_pool, that->group); context->thread_context->node->group_pool, that->group);
embb_mtapi_task_queue_push(&local_group->queue, that); embb_mtapi_task_queue_push(&local_group->queue, that);
} }
return MTAPI_TRUE;
} else {
return MTAPI_FALSE;
}
} }
void embb_mtapi_task_set_state( void embb_mtapi_task_set_state(
...@@ -189,6 +204,9 @@ static mtapi_task_hndl_t embb_mtapi_task_start( ...@@ -189,6 +204,9 @@ static mtapi_task_hndl_t embb_mtapi_task_start(
mtapi_taskattr_init(&task->attributes, &local_status); 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)) { if (embb_mtapi_group_pool_is_handle_valid(node->group_pool, group)) {
embb_mtapi_group_t* local_group = embb_mtapi_group_t* local_group =
embb_mtapi_group_pool_get_storage_for_handle( embb_mtapi_group_pool_get_storage_for_handle(
...@@ -233,8 +251,12 @@ static mtapi_task_hndl_t embb_mtapi_task_start( ...@@ -233,8 +251,12 @@ static mtapi_task_hndl_t embb_mtapi_task_start(
embb_mtapi_task_set_state(task, MTAPI_TASK_SCHEDULED); embb_mtapi_task_set_state(task, MTAPI_TASK_SCHEDULED);
was_scheduled = was_scheduled = MTAPI_TRUE;
embb_mtapi_scheduler_schedule_task(scheduler, task);
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 (was_scheduled) {
/* if task is detached, do not return a handle, it will be deleted /* if task is detached, do not return a handle, it will be deleted
......
...@@ -68,6 +68,7 @@ struct embb_mtapi_task_struct { ...@@ -68,6 +68,7 @@ struct embb_mtapi_task_struct {
embb_mtapi_spinlock_t state_lock; embb_mtapi_spinlock_t state_lock;
volatile mtapi_task_state_t state; volatile mtapi_task_state_t state;
embb_atomic_unsigned_int current_instance; embb_atomic_unsigned_int current_instance;
embb_atomic_unsigned_int instances_todo;
mtapi_status_t error_code; mtapi_status_t error_code;
}; };
...@@ -106,7 +107,7 @@ void embb_mtapi_task_finalize(embb_mtapi_task_t* that); ...@@ -106,7 +107,7 @@ void embb_mtapi_task_finalize(embb_mtapi_task_t* that);
* detached. * detached.
* \memberof embb_mtapi_task_struct * \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_t* that,
embb_mtapi_task_context_t * context); embb_mtapi_task_context_t * context);
......
...@@ -70,6 +70,7 @@ void embb_mtapi_thread_context_initialize_with_node_worker_and_core( ...@@ -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_mutex_init(&that->work_available_mutex, EMBB_MUTEX_PLAIN);
embb_condition_init(&that->work_available); embb_condition_init(&that->work_available);
embb_atomic_store_int(&that->is_sleeping, 0);
} }
mtapi_boolean_t embb_mtapi_thread_context_start( mtapi_boolean_t embb_mtapi_thread_context_start(
......
...@@ -56,6 +56,7 @@ struct embb_mtapi_thread_context_struct { ...@@ -56,6 +56,7 @@ struct embb_mtapi_thread_context_struct {
embb_condition_t work_available; embb_condition_t work_available;
embb_thread_t thread; embb_thread_t thread;
embb_tss_t tss_id; embb_tss_t tss_id;
embb_atomic_int is_sleeping;
embb_mtapi_node_t* node; embb_mtapi_node_t* node;
embb_mtapi_task_queue_t** queue; embb_mtapi_task_queue_t** queue;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <embb/base/c/internal/unused.h> #include <embb/base/c/internal/unused.h>
#define JOB_TEST_TASK 42 #define JOB_TEST_TASK 42
#define JOB_TEST_MULTIINSTANCE_TASK 43
#define TASK_TEST_ID 23 #define TASK_TEST_ID 23
static void testTaskAction( static void testTaskAction(
...@@ -44,7 +45,9 @@ static void testTaskAction( ...@@ -44,7 +45,9 @@ static void testTaskAction(
mtapi_size_t /*node_local_data_size*/, mtapi_size_t /*node_local_data_size*/,
mtapi_task_context_t* task_context) { mtapi_task_context_t* task_context) {
int ii; 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); srand(core_num);
for (ii = 1000; ii < rand()%1000000; ii ++) { for (ii = 1000; ii < rand()%1000000; ii ++) {
} }
...@@ -53,6 +56,41 @@ static void testTaskAction( ...@@ -53,6 +56,41 @@ static void testTaskAction(
EMBB_UNUSED(args); 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<mtapi_uint_t*>(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() { static void testDoSomethingElse() {
} }
...@@ -151,7 +189,7 @@ void TaskTest::TestBasic() { ...@@ -151,7 +189,7 @@ void TaskTest::TestBasic() {
for (ii = 0; ii < 100; ii++) { for (ii = 0; ii < 100; ii++) {
status = MTAPI_ERR_UNKNOWN; status = MTAPI_ERR_UNKNOWN;
mtapi_task_wait(task[ii], 100, &status); mtapi_task_wait(task[ii], 100000, &status);
MTAPI_CHECK_STATUS(status); MTAPI_CHECK_STATUS(status);
} }
...@@ -160,10 +198,66 @@ void TaskTest::TestBasic() { ...@@ -160,10 +198,66 @@ void TaskTest::TestBasic() {
MTAPI_CHECK_STATUS(status); MTAPI_CHECK_STATUS(status);
status = MTAPI_ERR_UNKNOWN; 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_finalize(&status);
MTAPI_CHECK_STATUS(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"); embb_mtapi_log_info("...done\n\n");
} }
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
*/ */
#include <partest/partest.h> #include <partest/partest.h>
#include <embb/base/c/thread.h>
#include <stdio.h> #include <stdio.h>
...@@ -38,10 +39,11 @@ ...@@ -38,10 +39,11 @@
PT_MAIN("MTAPI C") { PT_MAIN("MTAPI C") {
embb_log_set_log_level(EMBB_LOG_LEVEL_NONE); embb_log_set_log_level(EMBB_LOG_LEVEL_NONE);
embb_thread_set_max_count(1024);
PT_RUN(TaskTest);
PT_RUN(ErrorTest); PT_RUN(ErrorTest);
PT_RUN(InitFinalizeTest); PT_RUN(InitFinalizeTest);
PT_RUN(TaskTest);
PT_RUN(GroupTest); PT_RUN(GroupTest);
PT_RUN(QueueTest); PT_RUN(QueueTest);
} }
...@@ -13,8 +13,6 @@ else() ...@@ -13,8 +13,6 @@ else()
endif() endif()
message(" (set with command line option -DUSE_AUTOMATIC_INITIALIZATION=ON/OFF)") 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 # Execute the GroupSources macro
include(${CMAKE_SOURCE_DIR}/CMakeCommon/GroupSourcesMSVC.cmake) include(${CMAKE_SOURCE_DIR}/CMakeCommon/GroupSourcesMSVC.cmake)
...@@ -24,7 +22,6 @@ GroupSourcesMSVC(test) ...@@ -24,7 +22,6 @@ GroupSourcesMSVC(test)
set (EMBB_MTAPI_CPP_INCLUDE_DIRS "include" "src" "test") set (EMBB_MTAPI_CPP_INCLUDE_DIRS "include" "src" "test")
include_directories(${EMBB_MTAPI_CPP_INCLUDE_DIRS} include_directories(${EMBB_MTAPI_CPP_INCLUDE_DIRS}
${CMAKE_CURRENT_BINARY_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/../base_c/include ${CMAKE_CURRENT_SOURCE_DIR}/../base_c/include
${CMAKE_CURRENT_BINARY_DIR}/../base_c/include ${CMAKE_CURRENT_BINARY_DIR}/../base_c/include
${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include
...@@ -44,6 +41,4 @@ endif() ...@@ -44,6 +41,4 @@ endif()
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
DESTINATION include FILES_MATCHING PATTERN "*.h") 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) install(TARGETS embb_mtapi_cpp DESTINATION lib)
...@@ -27,80 +27,113 @@ ...@@ -27,80 +27,113 @@
#ifndef EMBB_MTAPI_ACTION_H_ #ifndef EMBB_MTAPI_ACTION_H_
#define EMBB_MTAPI_ACTION_H_ #define EMBB_MTAPI_ACTION_H_
#include <embb/base/function.h> #include <embb/mtapi/internal/check_status.h>
#include <embb/mtapi/taskcontext.h> #include <embb/mtapi/action_attributes.h>
#include <embb/mtapi/execution_policy.h> #include <embb/mtapi/job.h>
namespace embb { namespace embb {
namespace mtapi { namespace mtapi {
/** /**
* A function to be spawned as a Task. * Holds the actual worker function used to execute a Task.
* *
* \ingroup CPP_MTAPI * \ingroup CPP_MTAPI
*/ */
class Action { class Action {
public: public:
/** /**
* Constructs an empty Action. * Constructs an Action.
*/ */
Action() Action(
: function_() mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
, execution_policy_() { mtapi_action_function_t func, /**< The action function */
// empty 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. * Constructs an Action.
*
* \tparam Function Function object
*/ */
template <typename Function>
Action( Action(
Function func /**< [in] Function object */ mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
) mtapi_action_function_t func, /**< The action function */
: function_(func) const void * node_local_data, /**< Node local data available to all
, execution_policy_() { Tasks using this Action */
// empty 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. * Constructs an Action.
*
* \tparam Function Function object
*/ */
template <typename Function>
Action( Action(
Function func, /**< [in] Function object */ mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
ExecutionPolicy execution_policy /**< [in] Execution policy */ mtapi_action_function_t func, /**< The action function */
) ActionAttributes const & attributes
: function_(func) /**< Attributes of the Action */
, execution_policy_(execution_policy) { ) {
// empty Create(job_id, func, MTAPI_NULL, 0, &attributes.GetInternal());
} }
/** /**
* Executes the Action in a given TaskContext. * Constructs an Action.
*/ */
void operator() ( Action(
TaskContext & context /**< [in, out] Context the operator mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
is executed in */ 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. * Destroys an Action.
* \return The ExecutionPolicy of the 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 * \waitfree
*/ */
ExecutionPolicy GetExecutionPolicy() const { mtapi_action_hndl_t GetInternal() const {
return execution_policy_; return handle_;
} }
private: private:
embb::base::Function<void, TaskContext &> function_; // no default constructor
ExecutionPolicy execution_policy_; 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 } // namespace mtapi
......
/*
* 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 <embb/mtapi/c/mtapi.h>
#include <embb/mtapi/internal/check_status.h>
#include <embb/mtapi/affinity.h>
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_
/*
* 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 <embb/mtapi/c/mtapi.h>
#include <embb/mtapi/internal/check_status.h>
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_
...@@ -28,8 +28,10 @@ ...@@ -28,8 +28,10 @@
#define EMBB_MTAPI_GROUP_H_ #define EMBB_MTAPI_GROUP_H_
#include <embb/mtapi/c/mtapi.h> #include <embb/mtapi/c/mtapi.h>
#include <embb/mtapi/action.h> #include <embb/mtapi/job.h>
#include <embb/mtapi/task.h> #include <embb/mtapi/task.h>
#include <embb/mtapi/task_attributes.h>
#include <embb/mtapi/group_attributes.h>
namespace embb { namespace embb {
...@@ -50,40 +52,135 @@ namespace mtapi { ...@@ -50,40 +52,135 @@ namespace mtapi {
class Group { class Group {
public: public:
/** /**
* Runs an Action within the Group. * Constructs a Group object with default attributes.
* \return A Task identifying the Action to run * Requires an initialized Node.
* \throws ErrorException if the Task object could not be constructed. */
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);
}
/**
* 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 * \threadsafe
*/ */
Task Spawn( template <typename ARGS, typename RES>
Action action /**< [in] The Action to run */ 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<ARGS>(),
results, internal::SizeOfType<RES>(),
&attributes.GetInternal());
}
/** /**
* Runs an Action within the Group. The \c id is returned by WaitAny(). * Starts a new Task in this Group.
* \return A Task identifying the Action to run *
* \throws ErrorException if the Task object could not be constructed. * \returns The handle to the started Task.
* \threadsafe * \threadsafe
*/ */
Task Spawn( template <typename ARGS, typename RES>
mtapi_task_id_t id, /**< [in] The id to return by Task Start(
WaitAny() */ mtapi_task_id_t task_id, /**< A user defined ID of the Task. */
Action action /**< [in] The Action to run */ 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<ARGS>(),
results, internal::SizeOfType<RES>(),
MTAPI_DEFAULT_TASK_ATTRIBUTES);
}
/** /**
* Waits for any Task in the Group to finish for \c timeout milliseconds. * Starts a new Task in this Group.
* \return The status of the Task that finished execution *
* \returns The handle to the started Task.
* \threadsafe * \threadsafe
*/ */
mtapi_status_t WaitAny( template <typename ARGS, typename RES>
mtapi_timeout_t timeout /**< [in] Timeout duration in Task Start(
milliseconds */ 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<ARGS>(),
results, internal::SizeOfType<RES>(),
&attributes.GetInternal());
}
/**
* Starts a new Task in this Group.
*
* \returns The handle to the started Task.
* \threadsafe
*/
template <typename ARGS, typename RES>
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<ARGS>(),
results, internal::SizeOfType<RES>(),
MTAPI_DEFAULT_TASK_ATTRIBUTES);
}
/** /**
* Waits for any Task in the Group to finish for \c timeout milliseconds and * Waits for any Task in the Group to finish for \c timeout milliseconds and
* retrieves the id given in Spawn(). * retrieves the result buffer given in Start().
* \return The status of the Task that finished execution, \c MTAPI_TIMEOUT * \return The status of the Task that finished execution, \c MTAPI_TIMEOUT
* or \c MTAPI_ERR_* * or \c MTAPI_ERR_*
* \threadsafe * \threadsafe
...@@ -91,8 +188,50 @@ class Group { ...@@ -91,8 +188,50 @@ class Group {
mtapi_status_t WaitAny( mtapi_status_t WaitAny(
mtapi_timeout_t timeout, /**< [in] Timeout duration in mtapi_timeout_t timeout, /**< [in] Timeout duration in
milliseconds */ 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 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. * Waits for all Task in the Group to finish for \c timeout milliseconds.
...@@ -103,20 +242,72 @@ class Group { ...@@ -103,20 +242,72 @@ class Group {
mtapi_status_t WaitAll( mtapi_status_t WaitAll(
mtapi_timeout_t timeout /**< [in] Timeout duration in mtapi_timeout_t timeout /**< [in] Timeout duration in
milliseconds */ 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 embb::base::Allocation;
friend class Node;
friend class Queue;
private: private:
Group(Group const & group); // not copyable
Group(); Group(Group const & other);
~Group(); 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_; mtapi_group_hndl_t handle_;
bool needs_delete_;
}; };
} // namespace mtapi } // namespace mtapi
......
/*
* 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 <embb/mtapi/c/mtapi.h>
#include <embb/mtapi/internal/check_status.h>
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_
/*
* 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 <embb/mtapi/c/mtapi.h>
namespace embb {
namespace mtapi {
namespace internal {
void CheckStatus(mtapi_status_t status);
template <typename T>
inline mtapi_size_t SizeOfType() {
return sizeof(T);
}
template <>
inline mtapi_size_t SizeOfType<void>() {
return 0u;
}
} // namespace internal
} // namespace mtapi
} // namespace embb
#endif // EMBB_MTAPI_INTERNAL_CHECK_STATUS_H_
/*
* 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 <embb/mtapi/c/mtapi.h>
#include <embb/mtapi/internal/check_status.h>
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_
...@@ -35,21 +35,12 @@ ...@@ -35,21 +35,12 @@
* \ingroup CPP * \ingroup CPP
*/ */
#include <embb/mtapi/internal/cmake_config.h> #include <embb/mtapi/job.h>
#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 <embb/mtapi/execution_policy.h>
#include <embb/mtapi/action.h> #include <embb/mtapi/action.h>
#include <embb/mtapi/continuation.h>
#include <embb/mtapi/group.h> #include <embb/mtapi/group.h>
#include <embb/mtapi/node.h>
#include <embb/mtapi/queue.h> #include <embb/mtapi/queue.h>
#include <embb/mtapi/task.h> #include <embb/mtapi/task.h>
#include <embb/mtapi/taskcontext.h> #include <embb/mtapi/task_context.h>
#include <embb/mtapi/node.h>
#endif // EMBB_MTAPI_MTAPI_H_ #endif // EMBB_MTAPI_MTAPI_H_
...@@ -27,14 +27,13 @@ ...@@ -27,14 +27,13 @@
#ifndef EMBB_MTAPI_NODE_H_ #ifndef EMBB_MTAPI_NODE_H_
#define EMBB_MTAPI_NODE_H_ #define EMBB_MTAPI_NODE_H_
#include <list> #include <embb/base/memory_allocation.h>
#include <embb/base/core_set.h>
#include <embb/mtapi/c/mtapi.h> #include <embb/mtapi/c/mtapi.h>
#include <embb/mtapi/action.h> #include <embb/mtapi/status_exception.h>
#include <embb/mtapi/node_attributes.h>
#include <embb/mtapi/task.h> #include <embb/mtapi/task.h>
#include <embb/mtapi/continuation.h> #include <embb/mtapi/task_attributes.h>
#include <embb/mtapi/group.h> #include <embb/mtapi/job.h>
#include <embb/mtapi/queue.h>
namespace embb { namespace embb {
...@@ -70,7 +69,16 @@ class Node { ...@@ -70,7 +69,16 @@ class Node {
static void Initialize( static void Initialize(
mtapi_domain_t domain_id, /**< [in] The domain id to use */ mtapi_domain_t domain_id, /**< [in] The domain id to use */
mtapi_node_t node_id /**< [in] The node 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<Node>(
domain_id, node_id, attributes);
}
}
/** /**
* Initializes the runtime singleton. * Initializes the runtime singleton.
...@@ -82,20 +90,16 @@ class Node { ...@@ -82,20 +90,16 @@ class Node {
static void Initialize( static void Initialize(
mtapi_domain_t domain_id, /**< [in] The domain id to use */ mtapi_domain_t domain_id, /**< [in] The domain id to use */
mtapi_node_t node_id, /**< [in] The node id to use */ mtapi_node_t node_id, /**< [in] The node id to use */
embb::base::CoreSet const & core_set, NodeAttributes const & attributes /**< [in] Attributes to use */
/**< [in] A set of cores MTAPI should ) {
use for its worker threads */ if (IsInitialized()) {
mtapi_uint_t max_tasks, /**< [in] Maximum number of concurrent EMBB_THROW(StatusException,
\link Task Tasks \endlink */ "MTAPI: node was already initialized.");
mtapi_uint_t max_groups, /**< [in] Maximum number of concurrent } else {
\link Group Groups \endlink */ node_instance_ = embb::base::Allocation::New<Node>(
mtapi_uint_t max_queues, /**< [in] Maximum number of concurrent domain_id, node_id, attributes);
\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. * Checks if runtime is initialized.
...@@ -103,21 +107,38 @@ class Node { ...@@ -103,21 +107,38 @@ class Node {
* otherwise * otherwise
* \waitfree * \waitfree
*/ */
static bool IsInitialized(); static bool IsInitialized() {
return NULL != node_instance_;
}
/** /**
* Gets the instance of the runtime system. * Gets the instance of the runtime system.
* \return Reference to the Node singleton * \return Reference to the Node singleton
* \threadsafe * \threadsafe
*/ */
static Node & GetInstance(); static Node & GetInstance() {
if (IsInitialized()) {
return *node_instance_;
} else {
EMBB_THROW(StatusException,
"MTAPI: node is not initialized.");
}
}
/** /**
* Shuts the runtime system down. * Shuts the runtime system down.
* \throws ErrorException if the singleton is not initialized. * \throws ErrorException if the singleton is not initialized.
* \notthreadsafe * \notthreadsafe
*/ */
static void Finalize(); 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. * Returns the number of available cores.
...@@ -138,91 +159,138 @@ class Node { ...@@ -138,91 +159,138 @@ class Node {
} }
/** /**
* Creates a Group to launch \link Task Tasks \endlink in. * Starts a new Task.
* \return A reference to the created Group *
* \throws ErrorException if the Group object could not be constructed. * \returns The handle to the started Task.
* \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 * \threadsafe
* \memory Allocates some memory depending on the configuration of the
* runtime.
*/ */
Queue & CreateQueue( template <typename ARGS, typename RES>
mtapi_uint_t priority, /**< [in] Priority of the Queue */ Task Start(
bool ordered /**< [in] \c true if the Queue should be mtapi_task_id_t task_id, /**< A user defined ID of the Task. */
ordered, otherwise \c false */ 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<ARGS>(),
results, internal::SizeOfType<RES>(),
&attributes.GetInternal());
}
/** /**
* Destroys a Queue. Running \link Task Tasks \endlink will be canceled. * Starts a new Task.
*
* \returns The handle to the started Task.
* \threadsafe * \threadsafe
*/ */
void DestroyQueue( template <typename ARGS, typename RES>
Queue & queue /**< [in,out] The Queue to destroy */ 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<ARGS>(),
results, internal::SizeOfType<RES>(),
MTAPI_DEFAULT_TASK_ATTRIBUTES);
}
/** /**
* Runs an Action. * Starts a new Task.
* \return A Task identifying the Action to run *
* \throws ErrorException if the Task object could not be constructed. * \returns The handle to the started Task.
* \threadsafe * \threadsafe
*/ */
Task Spawn( template <typename ARGS, typename RES>
Action action /**< [in] The Action to execute */ 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<ARGS>(),
results, internal::SizeOfType<RES>(),
&attributes.GetInternal());
}
/** /**
* Creates a Continuation. * Starts a new Task.
* \return A Continuation chain *
* \returns The handle to the started Task.
* \threadsafe * \threadsafe
*/ */
Continuation First( template <typename ARGS, typename RES>
Action action /**< [in] The first Action of the Task Start(
Continuation chain */ 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<ARGS>(),
results, internal::SizeOfType<RES>(),
MTAPI_DEFAULT_TASK_ATTRIBUTES);
}
friend class embb::base::Allocation; friend class embb::base::Allocation;
private: private:
// not copyable
Node(Node const & node); Node(Node const & node);
Node const & operator=(Node const & other);
Node( Node(
mtapi_domain_t domain_id, mtapi_domain_t domain_id,
mtapi_node_t node_id, mtapi_node_t node_id,
mtapi_node_attributes_t * attr); NodeAttributes const & attr) {
~Node(); mtapi_status_t status;
mtapi_info_t info;
static void action_func( mtapi_initialize(domain_id, node_id, &attr.GetInternal(), &info, &status);
const void* args, needs_finalize_ = status == MTAPI_SUCCESS;
mtapi_size_t args_size, internal::CheckStatus(status);
void* result_buffer,
mtapi_size_t result_buffer_size, core_count_ = info.hardware_concurrency;
const void* node_local_data, worker_thread_count_ = embb_core_set_count(
mtapi_size_t node_local_data_size, &attr.GetInternal().core_affinity);
mtapi_task_context_t * context); }
~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 core_count_;
mtapi_uint_t worker_thread_count_; mtapi_uint_t worker_thread_count_;
mtapi_action_hndl_t action_handle_; bool needs_finalize_;
std::list<Queue*> queues_;
std::list<Group*> groups_;
}; };
} // namespace mtapi } // namespace mtapi
......
/*
* 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 <embb/mtapi/c/mtapi.h>
#include <embb/base/core_set.h>
#include <embb/mtapi/internal/check_status.h>
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_
...@@ -28,9 +28,11 @@ ...@@ -28,9 +28,11 @@
#define EMBB_MTAPI_QUEUE_H_ #define EMBB_MTAPI_QUEUE_H_
#include <embb/mtapi/c/mtapi.h> #include <embb/mtapi/c/mtapi.h>
#include <embb/mtapi/action.h> #include <embb/mtapi/job.h>
#include <embb/mtapi/task.h> #include <embb/mtapi/task.h>
#include <embb/mtapi/group.h> #include <embb/mtapi/group.h>
#include <embb/mtapi/queue_attributes.h>
#include <embb/mtapi/task_attributes.h>
namespace embb { namespace embb {
...@@ -50,62 +52,263 @@ namespace mtapi { ...@@ -50,62 +52,263 @@ namespace mtapi {
class Queue { class Queue {
public: public:
/** /**
* 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());
}
/**
* Destroys a Queue object.
*/
~Queue() {
mtapi_queue_delete(handle_, MTAPI_INFINITE, MTAPI_NULL);
}
/**
* Enables the Queue. \link Task Tasks \endlink enqueued while the Queue was * Enables the Queue. \link Task Tasks \endlink enqueued while the Queue was
* disabled are executed. * disabled are executed.
* \waitfree * \waitfree
*/ */
void Enable(); void Enable() {
mtapi_status_t status;
mtapi_queue_enable(handle_, &status);
internal::CheckStatus(status);
}
/**
* 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);
}
/** /**
* Disables the Queue. Running \link Task Tasks \endlink are canceled. * Disables the Queue. Running \link Task Tasks \endlink are canceled. The
* Queue waits for the Tasks to finish.
* \waitfree * \waitfree
*/ */
void Disable(); void Disable() {
Disable(MTAPI_INFINITE);
}
/** /**
* Runs an Action. * Enqueues a new Task.
* \return A Task identifying the Action to run *
* \throws ErrorException if the Task object could not be constructed. * \returns The handle to the enqueued Task.
* \threadsafe
*/
template <typename ARGS, typename RES>
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<ARGS>(),
results, internal::SizeOfType<RES>(),
&attributes.GetInternal(), group.GetInternal());
}
/**
* Enqueues a new Task.
*
* \returns The handle to the enqueued Task.
* \threadsafe * \threadsafe
*/ */
Task Spawn( template <typename ARGS, typename RES>
Action action /**< [in] The Action to run */ 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<ARGS>(),
results, internal::SizeOfType<RES>(),
MTAPI_DEFAULT_TASK_ATTRIBUTES, group.GetInternal());
}
/** /**
* Runs an Action in the specified Group * Enqueues a new Task.
* \return A Task identifying the Action to run *
* \throws ErrorException if the Task object could not be constructed. * \returns The handle to the enqueued Task.
* \threadsafe * \threadsafe
*/ */
Task Spawn( template <typename ARGS, typename RES>
Group const * group, /**< [in] The Group to run the Action Task Enqueue(
in */ mtapi_task_id_t task_id, /**< A user defined ID of the Task. */
Action action /**< [in] The Action to run */ 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<ARGS>(),
results, internal::SizeOfType<RES>(),
&attributes.GetInternal(), MTAPI_GROUP_NONE);
}
/** /**
* Runs an Action in the specified Group. The \c id is returned by * Enqueues a new Task.
* Group::WaitAny(). *
* \return A Task identifying the Action to run * \returns The handle to the enqueued Task.
* \throws ErrorException if the Task object could not be constructed.
* \threadsafe * \threadsafe
*/ */
Task Spawn( template <typename ARGS, typename RES>
mtapi_task_id_t id, /**< [in] The id to return in Task Enqueue(
Group::WaitAny() */ mtapi_task_id_t task_id, /**< A user defined ID of the Task. */
Group const * group, /**< [in] The Group to run the Action const ARGS * arguments, /**< Pointer to the arguments. */
in */ RES * results /**< Pointer to the results. */
Action action /**< [in] The Action to run */ ) {
); return Enqueue(task_id,
arguments, internal::SizeOfType<ARGS>(),
results, internal::SizeOfType<RES>(),
MTAPI_DEFAULT_TASK_ATTRIBUTES, MTAPI_GROUP_NONE);
}
/**
* Enqueues a new Task.
*
* \returns The handle to the enqueued Task.
* \threadsafe
*/
template <typename ARGS, typename RES>
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<ARGS>(),
results, internal::SizeOfType<RES>(),
&attributes.GetInternal(), group.GetInternal());
}
/**
* Enqueues a new Task.
*
* \returns The handle to the enqueued Task.
* \threadsafe
*/
template <typename ARGS, typename RES>
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<ARGS>(),
results, internal::SizeOfType<RES>(),
MTAPI_DEFAULT_TASK_ATTRIBUTES, group.GetInternal());
}
/**
* Enqueues a new Task.
*
* \returns The handle to the enqueued Task.
* \threadsafe
*/
template <typename ARGS, typename RES>
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<ARGS>(),
results, internal::SizeOfType<RES>(),
&attributes.GetInternal(), MTAPI_GROUP_NONE);
}
/**
* Enqueues a new Task.
*
* \returns The handle to the enqueued Task.
* \threadsafe
*/
template <typename ARGS, typename RES>
Task Enqueue(
const ARGS * arguments, /**< Pointer to the arguments. */
RES * results /**< Pointer to the results. */
) {
return Enqueue(MTAPI_TASK_ID_NONE,
arguments, internal::SizeOfType<ARGS>(),
results, internal::SizeOfType<RES>(),
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 embb::base::Allocation;
friend class Node;
private: private:
Queue(Queue const & taskqueue); // no default constructor
Queue(mtapi_uint_t priority, bool ordered); Queue();
~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_; mtapi_queue_hndl_t handle_;
}; };
......
/*
* 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 <embb/mtapi/c/mtapi.h>
#include <embb/mtapi/internal/check_status.h>
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_
/*
* 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 <embb/base/exceptions.h>
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_
...@@ -28,34 +28,50 @@ ...@@ -28,34 +28,50 @@
#define EMBB_MTAPI_TASK_H_ #define EMBB_MTAPI_TASK_H_
#include <embb/mtapi/c/mtapi.h> #include <embb/mtapi/c/mtapi.h>
#include <embb/mtapi/action.h> #include <embb/mtapi/internal/check_status.h>
namespace embb { namespace embb {
namespace mtapi { namespace mtapi {
/** /**
* A Task represents a running Action. * A Task represents a running Action of a specific Job.
* *
* \ingroup CPP_MTAPI * \ingroup CPP_MTAPI
*/ */
class Task { class Task {
public: public:
/** /**
* Constructs an empty Task * Constructs an invalid Task.
*/ */
Task(); Task() {
handle_.id = 0;
handle_.tag = 0;
}
/** /**
* Copies a Task * Copies a Task.
*/ */
Task( Task(
Task const & task /**< The task to copy. */ Task const & other /**< The task to copy. */
); ) : handle_(other.handle_) {
// emtpy
}
/** /**
* Destroys a Task * Copies a Task.
*/ */
~Task(); void operator=(
Task const & other /**< The task to copy. */
) {
handle_ = other.handle_;
}
/**
* Destroys a Task.
*/
~Task() {
// empty
}
/** /**
* Waits for Task to finish for \c timeout milliseconds. * Waits for Task to finish for \c timeout milliseconds.
...@@ -66,47 +82,55 @@ class Task { ...@@ -66,47 +82,55 @@ class Task {
mtapi_status_t Wait( mtapi_status_t Wait(
mtapi_timeout_t timeout /**< [in] Timeout duration in mtapi_timeout_t timeout /**< [in] Timeout duration in
milliseconds */ milliseconds */
); ) {
mtapi_status_t status;
mtapi_task_wait(handle_, timeout, &status);
return status;
}
/**
* 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;
}
/** /**
* Signals the Task to cancel computation. * Signals the Task to cancel computation.
* \waitfree * \waitfree
*/ */
void Cancel(); void Cancel() {
mtapi_status_t status;
mtapi_task_cancel(handle_, &status);
internal::CheckStatus(status);
}
friend class Group; /**
friend class Queue; * Returns the internal representation of this object.
friend class Node; * Allows for interoperability with the C interface.
*
* \returns The internal mtapi_task_hndl_t.
* \waitfree
*/
mtapi_task_hndl_t GetInternal() const {
return handle_;
}
private: private:
Task( explicit Task(mtapi_task_hndl_t handle)
Action action); : handle_(handle) {
// empty
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_; mtapi_task_hndl_t handle_;
friend class Node;
friend class Group;
friend class Queue;
}; };
} // namespace mtapi } // namespace mtapi
......
/*
* 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 <embb/mtapi/c/mtapi.h>
#include <embb/mtapi/internal/check_status.h>
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_
/*
* 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 <embb/mtapi/c/mtapi.h>
#include <embb/mtapi/internal/check_status.h>
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_
/*
* 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 <embb/mtapi/task_context.h>
#include <embb/mtapi/internal/check_status.h>
#include <embb/mtapi/status_exception.h>
#include <embb/base/internal/config.h>
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
...@@ -24,251 +24,12 @@ ...@@ -24,251 +24,12 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <algorithm> #include <embb/mtapi/node.h>
#include <cstddef>
#include <cstdlib>
#include <cassert>
#include <embb/base/memory_allocation.h>
#include <embb/base/exceptions.h>
#include <embb/mtapi/mtapi.h>
#if MTAPI_CPP_AUTOMATIC_INITIALIZE
#include <embb/base/mutex.h>
#endif
namespace {
static embb::mtapi::Node * node_instance = NULL;
#if MTAPI_CPP_AUTOMATIC_INITIALIZE
static embb::base::Mutex init_mutex;
#endif
}
namespace embb { namespace embb {
namespace mtapi { namespace mtapi {
void Node::action_func( embb::mtapi::Node * embb::mtapi::Node::node_instance_ = NULL;
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<mtapi::Action*>(const_cast<void*>(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<Queue*>::iterator ii = queues_.begin();
ii != queues_.end();
++ii) {
embb::base::Allocation::Delete(*ii);
}
queues_.clear();
for (std::list<Group*>::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<Node>(
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<Node>(
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<Group>();
groups_.push_back(group);
return *group;
}
void Node::DestroyGroup(Group & group) {
std::list<Group*>::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<Queue>(priority, ordered);
queues_.push_back(queue);
return *queue;
}
void Node::DestroyQueue(Queue & queue) {
std::list<Queue*>::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 mtapi } // namespace mtapi
} // namespace embb } // namespace embb
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <partest/partest.h> #include <partest/partest.h>
#include <iostream> #include <embb/base/c/thread.h>
#include <mtapi_cpp_test_task.h> #include <mtapi_cpp_test_task.h>
#include <mtapi_cpp_test_group.h> #include <mtapi_cpp_test_group.h>
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
PT_MAIN("MTAPI C++") { PT_MAIN("MTAPI C++") {
embb_thread_set_max_count(1024);
PT_RUN(TaskTest); PT_RUN(TaskTest);
PT_RUN(GroupTest); PT_RUN(GroupTest);
PT_RUN(QueueTest); PT_RUN(QueueTest);
......
...@@ -24,65 +24,90 @@ ...@@ -24,65 +24,90 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <iostream>
#include <mtapi_cpp_test_config.h> #include <mtapi_cpp_test_config.h>
#include <mtapi_cpp_test_group.h> #include <mtapi_cpp_test_group.h>
#include <embb/base/c/memory_allocation.h> #include <embb/base/c/memory_allocation.h>
#define JOB_TEST_GROUP 5
#define TASK_COUNT 4
struct result_example_struct { struct result_example_struct {
mtapi_uint_t value1; int value1;
mtapi_uint_t value2; int value2;
}; };
typedef struct result_example_struct result_example_t; typedef struct result_example_struct result_example_t;
static void testGroupAction(embb::mtapi::TaskContext & /*context*/) { static void testGroupAction(
//std::cout << "testGroupAction on core " << const void* args,
// context.GetCurrentCoreNumber() << std::endl; 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<result_example_t const *>(args);
result_example_t * out = static_cast<result_example_t *>(results);
out->value2 = in->value1;
} }
static void testDoSomethingElse() { static void testDoSomethingElse() {
} }
GroupTest::GroupTest() { GroupTest::GroupTest() {
CreateUnit("mtapi group test").Add(&GroupTest::TestBasic, this); CreateUnit("mtapi_cpp group test").Add(&GroupTest::TestBasic, this);
} }
void GroupTest::TestBasic() { void GroupTest::TestBasic() {
//std::cout << "running testGroup..." << std::endl;
embb::mtapi::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID); embb::mtapi::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID);
embb::mtapi::Node & node = embb::mtapi::Node::GetInstance(); embb::mtapi::Job job(JOB_TEST_GROUP, THIS_DOMAIN_ID);
embb::mtapi::Group & group = node.CreateGroup(); embb::mtapi::Action action(JOB_TEST_GROUP, testGroupAction);
embb::mtapi::Task task;
//std::cout << "wait all..." << std::endl; {
embb::mtapi::Group group;
for (int ii = 0; ii < 4; ii++) { result_example_t buffer[TASK_COUNT];
task = group.Spawn(testGroupAction); for (int ii = 0; ii < TASK_COUNT; ii++) {
buffer[ii].value1 = ii;
buffer[ii].value2 = -1;
group.Start(job, &buffer[ii], &buffer[ii]);
} }
testDoSomethingElse(); testDoSomethingElse();
group.WaitAll(MTAPI_INFINITE);
//std::cout << "wait any..." << 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);
}
}
{
embb::mtapi::Group group;
result_example_t buffer[TASK_COUNT];
for (int ii = 0; ii < 4; ii++) { for (int ii = 0; ii < 4; ii++) {
task = group.Spawn(mtapi_task_id_t(ii + 1), testGroupAction); buffer[ii].value1 = ii;
buffer[ii].value2 = -1;
group.Start(job, &buffer[ii], &buffer[ii]);
} }
testDoSomethingElse(); testDoSomethingElse();
mtapi_status_t status; mtapi_status_t status;
mtapi_task_id_t result; result_example_t* result;
while (MTAPI_SUCCESS == (status = group.WaitAny(MTAPI_INFINITE, result))) { while (MTAPI_SUCCESS ==
//std::cout << "got a result from task " << result << std::endl; (status = group.WaitAny(reinterpret_cast<void**>(&result)))) {
PT_EXPECT(result != MTAPI_NULL);
PT_EXPECT_EQ(result->value1, result->value2);
}
PT_EXPECT_EQ(status, MTAPI_GROUP_COMPLETED);
} }
node.DestroyGroup(group);
embb::mtapi::Node::Finalize(); embb::mtapi::Node::Finalize();
PT_EXPECT(embb_get_bytes_allocated() == 0); PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u);
//std::cout << "...done" << std::endl << std::endl;
} }
...@@ -24,47 +24,55 @@ ...@@ -24,47 +24,55 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <cstdlib>
#include <mtapi_cpp_test_config.h> #include <mtapi_cpp_test_config.h>
#include <mtapi_cpp_test_queue.h> #include <mtapi_cpp_test_queue.h>
#include <embb/base/c/memory_allocation.h> #include <embb/base/c/memory_allocation.h>
#define JOB_TEST_TASK 42 #define JOB_TEST_QUEUE 42
#define TASK_TEST_ID 23
#define QUEUE_TEST_ID 17 static void testQueueAction(
const void* /*args*/,
static void testQueueAction(embb::mtapi::TaskContext & /*context*/) { mtapi_size_t /*args_size*/,
//std::cout << "testQueueAction on core " << void* results,
// context.GetCurrentCoreNumber() << std::endl; 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<int*>(results);
*out = 1;
ctx.SetStatus(MTAPI_ERR_ACTION_CANCELLED);
} }
static void testDoSomethingElse() { static void testDoSomethingElse() {
} }
QueueTest::QueueTest() { QueueTest::QueueTest() {
CreateUnit("mtapi queue test").Add(&QueueTest::TestBasic, this); CreateUnit("mtapi_cpp queue test").Add(&QueueTest::TestBasic, this);
} }
void QueueTest::TestBasic() { void QueueTest::TestBasic() {
//std::cout << "running testQueue..." << std::endl;
embb::mtapi::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID); embb::mtapi::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID);
embb::mtapi::Node & node = embb::mtapi::Node::GetInstance(); embb::mtapi::Job job(JOB_TEST_QUEUE, THIS_DOMAIN_ID);
embb::mtapi::Queue & queue = node.CreateQueue(0, false); 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<void, int>(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(); embb::mtapi::Node::Finalize();
PT_EXPECT(embb_get_bytes_allocated() == 0); PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u);
//std::cout << "...done" << std::endl << std::endl;
} }
...@@ -34,33 +34,32 @@ ...@@ -34,33 +34,32 @@
#include <embb/base/c/memory_allocation.h> #include <embb/base/c/memory_allocation.h>
#define JOB_TEST_TASK 42 #define JOB_TEST_TASK 42
#define TASK_TEST_ID 23 #define JOB_TEST_ERROR 17
static void testTaskAction( static void testTaskAction(
char const * msg, const void* args,
std::string * output, mtapi_size_t /*args_size*/,
embb::mtapi::TaskContext & /*context*/) { void* results,
//std::cout << "testTaskAction " << msg << " on core " << mtapi_size_t /*results_size*/,
// context.GetCurrentCoreNumber() << std::endl; const void* /*node_local_data*/,
*output = msg; mtapi_size_t /*node_local_data_size*/,
mtapi_task_context_t * context) {
embb::mtapi::TaskContext ctx(context);
const char * msg = static_cast<const char *>(args);
std::string* out = static_cast<std::string*>(results);
*out = msg;
} }
static void testRecursiveTaskAction( static void testErrorAction(
int * value, const void* /*args*/,
embb::mtapi::TaskContext & /*context*/) { mtapi_size_t /*args_size*/,
embb::mtapi::Node & node = embb::mtapi::Node::GetInstance(); void* /*results*/,
*value = *value + 1; mtapi_size_t /*results_size*/,
if (*value < 1000) { const void* /*node_local_data*/,
embb::mtapi::Task task = node.Spawn( mtapi_size_t /*node_local_data_size*/,
embb::base::Bind( mtapi_task_context_t * context) {
testRecursiveTaskAction, value, embb::base::Placeholder::_1)); embb::mtapi::TaskContext ctx(context);
task.Wait(MTAPI_INFINITE); ctx.SetStatus(MTAPI_ERR_ACTION_FAILED);
}
PT_EXPECT(*value == 1000);
}
static void testErrorTaskAction(embb::mtapi::TaskContext & context) {
context.SetStatus(MTAPI_ERR_ACTION_FAILED);
} }
static void testDoSomethingElse() { static void testDoSomethingElse() {
...@@ -71,66 +70,58 @@ TaskTest::TaskTest() { ...@@ -71,66 +70,58 @@ TaskTest::TaskTest() {
} }
void TaskTest::TestBasic() { void TaskTest::TestBasic() {
//std::cout << "running testTask..." << std::endl;
embb::mtapi::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID); embb::mtapi::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID);
embb::mtapi::Node & node = embb::mtapi::Node::GetInstance(); embb::mtapi::Node & node = embb::mtapi::Node::GetInstance();
embb::mtapi::ExecutionPolicy policy(false); {
PT_EXPECT_EQ(policy.GetAffinity(), 0u); embb::mtapi::NodeAttributes attr;
PT_EXPECT_EQ(policy.GetPriority(), 0u); attr
policy.AddWorker(0u); .SetMaxActions(1024)
PT_EXPECT_EQ(policy.GetAffinity(), 1u); .SetMaxActionsPerJob(2)
policy.AddWorker(1u); .SetMaxPriorities(4);
PT_EXPECT_EQ(policy.GetAffinity(), 3u); }
policy.RemoveWorker(0u);
PT_EXPECT_EQ(policy.GetAffinity(), 2u); {
PT_EXPECT_EQ(policy.IsSetWorker(0), false); embb::mtapi::Affinity affinity(false);
PT_EXPECT_EQ(policy.IsSetWorker(1), true); 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; std::string test;
embb::mtapi::Task task = node.Spawn( embb::mtapi::Task task = node.Start(job_task, "simple", &test);
embb::base::Bind(
testTaskAction, "simple", &test, embb::base::Placeholder::_1));
testDoSomethingElse(); testDoSomethingElse();
task.Wait(MTAPI_INFINITE); mtapi_status_t status = task.Wait();
PT_EXPECT_EQ(status, MTAPI_SUCCESS);
PT_EXPECT(test == "simple"); PT_EXPECT(test == "simple");
//std::cout << "result: " << test.c_str() << std::endl; }
std::string test1, test2, test3; {
task = node.First( embb::mtapi::Job job_error(JOB_TEST_ERROR, THIS_DOMAIN_ID);
embb::base::Bind(
testTaskAction, "first", &test1, embb::base::Placeholder::_1)). embb::mtapi::Action action_error(JOB_TEST_ERROR, testErrorAction,
Then(embb::base::Bind( embb::mtapi::ActionAttributes());
testTaskAction, "second", &test2, embb::base::Placeholder::_1)).
Then(embb::base::Bind( std::string test;
testTaskAction, "third", &test3, embb::base::Placeholder::_1)). embb::mtapi::Task task = node.Start(job_error, "simple", &test);
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(); testDoSomethingElse();
status = task.Wait(MTAPI_INFINITE); mtapi_status_t status = task.Wait();
PT_EXPECT(MTAPI_ERR_ACTION_FAILED == status); PT_EXPECT_EQ(status, MTAPI_ERR_ACTION_FAILED);
}
embb::mtapi::Node::Finalize(); embb::mtapi::Node::Finalize();
PT_EXPECT(embb_get_bytes_allocated() == 0); PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u);
//std::cout << "...done" << std::endl << std::endl;
} }
...@@ -79,7 +79,7 @@ retval=0 ...@@ -79,7 +79,7 @@ retval=0
##Excluded files ##Excluded files
RAND_FILES=( embb_mtapi_test_group.cc embb_mtapi_test_queue.cc embb_mtapi_test_task.cc queue_test-inl.h ) 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 do
echo "-> Doing project: $project" echo "-> Doing project: $project"
dir=$d/$project dir=$d/$project
......
...@@ -37,7 +37,7 @@ done ...@@ -37,7 +37,7 @@ done
DIR=`dirname "$SCRIPT_LOCATION"` DIR=`dirname "$SCRIPT_LOCATION"`
TESTS="embb_base_c_test embb_base_cpp_test embb_mtapi_c_test \ 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" embb_containers_cpp_test embb_dataflow_cpp_test"
for TEST in $TESTS; do for TEST in $TESTS; do
......
...@@ -37,7 +37,7 @@ done ...@@ -37,7 +37,7 @@ done
DIR=`dirname "$SCRIPT_LOCATION"` DIR=`dirname "$SCRIPT_LOCATION"`
TESTS="embb_base_c_test embb_base_cpp_test embb_mtapi_c_test \ 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" embb_containers_cpp_test embb_dataflow_cpp_test"
for TEST in $TESTS; do for TEST in $TESTS; do
......
...@@ -40,6 +40,9 @@ echo. ...@@ -40,6 +40,9 @@ echo.
"%DIR:~0,-1%\embb_mtapi_cpp_test.exe" "%DIR:~0,-1%\embb_mtapi_cpp_test.exe"
if not !ERRORLEVEL! ==0 set /a NUM_ERRORS=!NUM_ERRORS!+1 if not !ERRORLEVEL! ==0 set /a NUM_ERRORS=!NUM_ERRORS!+1
echo. 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" "%DIR:~0,-1%\embb_algorithms_cpp_test.exe"
if not !ERRORLEVEL! ==0 set /a NUM_ERRORS=!NUM_ERRORS!+1 if not !ERRORLEVEL! ==0 set /a NUM_ERRORS=!NUM_ERRORS!+1
echo. echo.
......
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)
/*
* 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 <embb/base/function.h>
#include <embb/tasks/task_context.h>
#include <embb/tasks/execution_policy.h>
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 <typename Function>
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 <typename Function>
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<void, TaskContext &> function_;
ExecutionPolicy execution_policy_;
};
} // namespace tasks
} // namespace embb
#endif // EMBB_TASKS_ACTION_H_
...@@ -24,21 +24,21 @@ ...@@ -24,21 +24,21 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef EMBB_MTAPI_CONTINUATION_H_ #ifndef EMBB_TASKS_CONTINUATION_H_
#define EMBB_MTAPI_CONTINUATION_H_ #define EMBB_TASKS_CONTINUATION_H_
#include <embb/mtapi/c/mtapi.h> #include <embb/mtapi/c/mtapi.h>
#include <embb/mtapi/taskcontext.h> #include <embb/tasks/task_context.h>
#include <embb/mtapi/action.h> #include <embb/tasks/action.h>
#include <embb/mtapi/task.h> #include <embb/tasks/task.h>
namespace embb { namespace embb {
namespace mtapi { namespace tasks {
/** /**
* Helper struct for Continuation. * Helper struct for Continuation.
* *
* \ingroup CPP_MTAPI * \ingroup CPP_TASKS
*/ */
struct ContinuationStage; struct ContinuationStage;
...@@ -46,19 +46,19 @@ struct ContinuationStage; ...@@ -46,19 +46,19 @@ struct ContinuationStage;
* A Continuation encapsulates a chain of \link Action Actions \endlink to be * A Continuation encapsulates a chain of \link Action Actions \endlink to be
* executed consecutively. * executed consecutively.
* *
* \ingroup CPP_MTAPI * \ingroup CPP_TASKS
*/ */
class Continuation { class Continuation {
public: public:
/** /**
* Copy constructor. * Copies a Continuation.
*/ */
Continuation( Continuation(
Continuation const & cont /**< [in] The Continuation to copy. */ Continuation const & cont /**< [in] The Continuation to copy. */
); );
/** /**
* Destructor. * Destroys a Continuation.
*/ */
~Continuation(); ~Continuation();
...@@ -99,7 +99,7 @@ class Continuation { ...@@ -99,7 +99,7 @@ class Continuation {
ContinuationStage * last_; ContinuationStage * last_;
}; };
} // namespace mtapi } // namespace tasks
} // namespace embb } // namespace embb
#endif // EMBB_MTAPI_CONTINUATION_H_ #endif // EMBB_TASKS_CONTINUATION_H_
...@@ -24,13 +24,14 @@ ...@@ -24,13 +24,14 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef EMBB_MTAPI_EXECUTION_POLICY_H_ #ifndef EMBB_TASKS_EXECUTION_POLICY_H_
#define EMBB_MTAPI_EXECUTION_POLICY_H_ #define EMBB_TASKS_EXECUTION_POLICY_H_
#include <embb/mtapi/c/mtapi.h> #include <embb/mtapi/c/mtapi.h>
namespace embb { namespace embb {
namespace mtapi { namespace tasks {
/** /**
* Describes the execution policy of a parallel algorithm. * Describes the execution policy of a parallel algorithm.
* The execution policy comprises * The execution policy comprises
...@@ -41,7 +42,7 @@ namespace mtapi { ...@@ -41,7 +42,7 @@ namespace mtapi {
* max_priorities - 1 as given during initialization using Node::Initialize(). * max_priorities - 1 as given during initialization using Node::Initialize().
* The default value of max_priorities is 4. * The default value of max_priorities is 4.
* *
* \ingroup CPP_MTAPI * \ingroup CPP_TASKS
*/ */
class ExecutionPolicy{ class ExecutionPolicy{
public: public:
...@@ -145,7 +146,8 @@ class ExecutionPolicy{ ...@@ -145,7 +146,8 @@ class ExecutionPolicy{
*/ */
mtapi_uint_t priority_; mtapi_uint_t priority_;
}; };
} // namespace mtapi
} // namespace tasks
} // namespace embb } // namespace embb
#endif // EMBB_MTAPI_EXECUTION_POLICY_H_ #endif // EMBB_TASKS_EXECUTION_POLICY_H_
/*
* 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 <embb/mtapi/c/mtapi.h>
#include <embb/tasks/action.h>
#include <embb/tasks/task.h>
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_
...@@ -24,18 +24,18 @@ ...@@ -24,18 +24,18 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef EMBB_MTAPI_INTERNAL_CMAKE_CONFIG_H_ #ifndef EMBB_TASKS_INTERNAL_CMAKE_CONFIG_H_
#define EMBB_MTAPI_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 /* 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 there, the cmake_config.h can be included as usual using
#include <embb/mtapi/internal/cmake_config.h> #include <embb/tasks/internal/cmake_config.h>
*/ */
/** /**
* Is used to enable automatic initialization of the MTAPI node * 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_
/*
* 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 <list>
#include <embb/base/core_set.h>
#include <embb/mtapi/c/mtapi.h>
#include <embb/tasks/action.h>
#include <embb/tasks/task.h>
#include <embb/tasks/continuation.h>
#include <embb/tasks/group.h>
#include <embb/tasks/queue.h>
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<Queue*> queues_;
std::list<Group*> groups_;
};
} // namespace tasks
} // namespace embb
#endif // EMBB_TASKS_NODE_H_
/*
* 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 <embb/mtapi/c/mtapi.h>
#include <embb/tasks/action.h>
#include <embb/tasks/task.h>
#include <embb/tasks/group.h>
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_
/*
* 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 <embb/mtapi/c/mtapi.h>
#include <embb/tasks/action.h>
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_
...@@ -24,18 +24,18 @@ ...@@ -24,18 +24,18 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef EMBB_MTAPI_TASKCONTEXT_H_ #ifndef EMBB_TASKS_TASK_CONTEXT_H_
#define EMBB_MTAPI_TASKCONTEXT_H_ #define EMBB_TASKS_TASK_CONTEXT_H_
#include <embb/mtapi/c/mtapi.h> #include <embb/mtapi/c/mtapi.h>
namespace embb { namespace embb {
namespace mtapi { namespace tasks {
/** /**
* Provides information about the status of the currently running Task. * Provides information about the status of the currently running Task.
* *
* \ingroup CPP_MTAPI * \ingroup CPP_TASKS
*/ */
class TaskContext { class TaskContext {
public: public:
...@@ -72,7 +72,7 @@ class TaskContext { ...@@ -72,7 +72,7 @@ class TaskContext {
mtapi_task_context_t * context_; mtapi_task_context_t * context_;
}; };
} // namespace mtapi } // namespace tasks
} // namespace embb } // namespace embb
#endif // EMBB_MTAPI_TASKCONTEXT_H_ #endif // EMBB_TASKS_TASK_CONTEXT_H_
/*
* 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 <embb/tasks/internal/cmake_config.h>
#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 <embb/tasks/execution_policy.h>
#include <embb/tasks/action.h>
#include <embb/tasks/continuation.h>
#include <embb/tasks/group.h>
#include <embb/tasks/node.h>
#include <embb/tasks/queue.h>
#include <embb/tasks/task.h>
#include <embb/tasks/task_context.h>
#endif // EMBB_TASKS_TASKS_H_
...@@ -28,12 +28,12 @@ ...@@ -28,12 +28,12 @@
#include <embb/base/memory_allocation.h> #include <embb/base/memory_allocation.h>
#include <embb/base/function.h> #include <embb/base/function.h>
#include <embb/mtapi/mtapi.h> #include <embb/tasks/tasks.h>
#include <continuationstage.h> #include <continuationstage.h>
namespace embb { namespace embb {
namespace mtapi { namespace tasks {
Continuation::Continuation(Action action) { Continuation::Continuation(Action action) {
first_ = last_ = embb::base::Allocation::New<ContinuationStage>(); first_ = last_ = embb::base::Allocation::New<ContinuationStage>();
...@@ -50,10 +50,10 @@ Continuation::~Continuation() { ...@@ -50,10 +50,10 @@ Continuation::~Continuation() {
} }
void Continuation::ExecuteContinuation(TaskContext &) { void Continuation::ExecuteContinuation(TaskContext &) {
mtapi::ContinuationStage * stage = first_; ContinuationStage * stage = first_;
mtapi::Node & node = mtapi::Node::GetInstance(); Node & node = Node::GetInstance();
while (NULL != stage) { while (NULL != stage) {
mtapi::Task task = node.Spawn(stage->action); Task task = node.Spawn(stage->action);
task.Wait(MTAPI_INFINITE); task.Wait(MTAPI_INFINITE);
stage = stage->next; stage = stage->next;
} }
...@@ -61,7 +61,7 @@ void Continuation::ExecuteContinuation(TaskContext &) { ...@@ -61,7 +61,7 @@ void Continuation::ExecuteContinuation(TaskContext &) {
// delete stages // delete stages
stage = first_; stage = first_;
while (NULL != stage) { while (NULL != stage) {
mtapi::ContinuationStage * next = stage->next; ContinuationStage * next = stage->next;
embb::base::Allocation::Delete(stage); embb::base::Allocation::Delete(stage);
stage = next; stage = next;
} }
...@@ -90,5 +90,5 @@ Task Continuation::Spawn(ExecutionPolicy execution_policy) { ...@@ -90,5 +90,5 @@ Task Continuation::Spawn(ExecutionPolicy execution_policy) {
ExecutionPolicy(execution_policy))); ExecutionPolicy(execution_policy)));
} }
} // namespace mtapi } // namespace tasks
} // namespace embb } // namespace embb
...@@ -24,20 +24,20 @@ ...@@ -24,20 +24,20 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef MTAPI_CPP_SRC_CONTINUATIONSTAGE_H_ #ifndef TASKS_CPP_SRC_CONTINUATIONSTAGE_H_
#define MTAPI_CPP_SRC_CONTINUATIONSTAGE_H_ #define TASKS_CPP_SRC_CONTINUATIONSTAGE_H_
#include <embb/mtapi/mtapi.h> #include <embb/tasks/tasks.h>
namespace embb { namespace embb {
namespace mtapi { namespace tasks {
struct ContinuationStage { struct ContinuationStage {
mtapi::Action action; Action action;
ContinuationStage * next; ContinuationStage * next;
}; };
} // namespace mtapi } // namespace tasks
} // namespace embb } // namespace embb
#endif // MTAPI_CPP_SRC_CONTINUATIONSTAGE_H_ #endif // TASKS_CPP_SRC_CONTINUATIONSTAGE_H_
...@@ -24,14 +24,14 @@ ...@@ -24,14 +24,14 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <embb/mtapi/execution_policy.h> #include <embb/tasks/execution_policy.h>
#include <embb/mtapi/mtapi.h> #include <embb/tasks/tasks.h>
#include <embb/base/exceptions.h> #include <embb/base/exceptions.h>
#include <embb/base/c/internal/bitset.h> #include <embb/base/c/internal/bitset.h>
#include <cassert> #include <cassert>
namespace embb { namespace embb {
namespace mtapi { namespace tasks {
ExecutionPolicy::ExecutionPolicy() : ExecutionPolicy::ExecutionPolicy() :
priority_(DefaultPriority) { priority_(DefaultPriority) {
...@@ -120,5 +120,5 @@ mtapi_uint_t ExecutionPolicy::GetPriority() const { ...@@ -120,5 +120,5 @@ mtapi_uint_t ExecutionPolicy::GetPriority() const {
const mtapi_uint_t ExecutionPolicy::DefaultPriority = 0; const mtapi_uint_t ExecutionPolicy::DefaultPriority = 0;
} // namespace mtapi } // namespace tasks
} // namespace embb } // namespace embb
...@@ -28,10 +28,10 @@ ...@@ -28,10 +28,10 @@
#include <cassert> #include <cassert>
#include <embb/base/exceptions.h> #include <embb/base/exceptions.h>
#include <embb/mtapi/mtapi.h> #include <embb/tasks/tasks.h>
namespace embb { namespace embb {
namespace mtapi { namespace tasks {
Group::Group() { Group::Group() {
Create(); Create();
...@@ -92,5 +92,5 @@ mtapi_status_t Group::WaitAll(mtapi_timeout_t timeout) { ...@@ -92,5 +92,5 @@ mtapi_status_t Group::WaitAll(mtapi_timeout_t timeout) {
return status; return status;
} }
} // namespace mtapi } // namespace tasks
} // namespace embb } // namespace embb
/*
* 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 <algorithm>
#include <cstddef>
#include <cstdlib>
#include <cassert>
#include <embb/base/memory_allocation.h>
#include <embb/base/exceptions.h>
#include <embb/tasks/tasks.h>
#if TASKS_CPP_AUTOMATIC_INITIALIZE
#include <embb/base/mutex.h>
#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<Action*>(const_cast<void*>(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<Queue*>::iterator ii = queues_.begin();
ii != queues_.end();
++ii) {
embb::base::Allocation::Delete(*ii);
}
queues_.clear();
for (std::list<Group*>::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<Node>(
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<Node>(
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<Group>();
groups_.push_back(group);
return *group;
}
void Node::DestroyGroup(Group & group) {
std::list<Group*>::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<Queue>(priority, ordered);
queues_.push_back(queue);
return *queue;
}
void Node::DestroyQueue(Queue & queue) {
std::list<Queue*>::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
...@@ -27,10 +27,10 @@ ...@@ -27,10 +27,10 @@
#include <cassert> #include <cassert>
#include <embb/base/exceptions.h> #include <embb/base/exceptions.h>
#include <embb/mtapi/mtapi.h> #include <embb/tasks/tasks.h>
namespace embb { namespace embb {
namespace mtapi { namespace tasks {
Queue::Queue(mtapi_uint_t priority, bool ordered) { Queue::Queue(mtapi_uint_t priority, bool ordered) {
mtapi_status_t status; mtapi_status_t status;
...@@ -51,7 +51,7 @@ Queue::Queue(mtapi_uint_t priority, bool ordered) { ...@@ -51,7 +51,7 @@ Queue::Queue(mtapi_uint_t priority, bool ordered) {
assert(MTAPI_SUCCESS == status); assert(MTAPI_SUCCESS == status);
mtapi_domain_t domain_id = mtapi_domain_id_get(&status); mtapi_domain_t domain_id = mtapi_domain_id_get(&status);
assert(MTAPI_SUCCESS == 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); assert(MTAPI_SUCCESS == status);
handle_ = mtapi_queue_create(MTAPI_QUEUE_ID_NONE, job, &attr, &status); handle_ = mtapi_queue_create(MTAPI_QUEUE_ID_NONE, job, &attr, &status);
if (MTAPI_SUCCESS != status) { if (MTAPI_SUCCESS != status) {
...@@ -86,5 +86,5 @@ Task Queue::Spawn(Group const * group, Action action) { ...@@ -86,5 +86,5 @@ Task Queue::Spawn(Group const * group, Action action) {
return Task(action, handle_, group->handle_); return Task(action, handle_, group->handle_);
} }
} // namespace mtapi } // namespace tasks
} // namespace embb } // namespace embb
...@@ -29,10 +29,10 @@ ...@@ -29,10 +29,10 @@
#include <embb/base/memory_allocation.h> #include <embb/base/memory_allocation.h>
#include <embb/base/exceptions.h> #include <embb/base/exceptions.h>
#include <embb/mtapi/mtapi.h> #include <embb/tasks/tasks.h>
namespace embb { namespace embb {
namespace mtapi { namespace tasks {
Task::Task() { Task::Task() {
handle_.id = 0; handle_.id = 0;
...@@ -59,7 +59,7 @@ Task::Task( ...@@ -59,7 +59,7 @@ Task::Task(
assert(MTAPI_SUCCESS == status); assert(MTAPI_SUCCESS == status);
mtapi_domain_t domain_id = mtapi_domain_id_get(&status); mtapi_domain_t domain_id = mtapi_domain_id_get(&status);
assert(MTAPI_SUCCESS == 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); assert(MTAPI_SUCCESS == status);
Action* holder = embb::base::Allocation::New<Action>(action); Action* holder = embb::base::Allocation::New<Action>(action);
handle_ = mtapi_task_start(MTAPI_TASK_ID_NONE, job, handle_ = mtapi_task_start(MTAPI_TASK_ID_NONE, job,
...@@ -86,7 +86,7 @@ Task::Task( ...@@ -86,7 +86,7 @@ Task::Task(
assert(MTAPI_SUCCESS == status); assert(MTAPI_SUCCESS == status);
mtapi_domain_t domain_id = mtapi_domain_id_get(&status); mtapi_domain_t domain_id = mtapi_domain_id_get(&status);
assert(MTAPI_SUCCESS == 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); assert(MTAPI_SUCCESS == status);
Action* holder = embb::base::Allocation::New<Action>(action); Action* holder = embb::base::Allocation::New<Action>(action);
handle_ = mtapi_task_start(MTAPI_TASK_ID_NONE, job, handle_ = mtapi_task_start(MTAPI_TASK_ID_NONE, job,
...@@ -114,7 +114,7 @@ Task::Task( ...@@ -114,7 +114,7 @@ Task::Task(
assert(MTAPI_SUCCESS == status); assert(MTAPI_SUCCESS == status);
mtapi_domain_t domain_id = mtapi_domain_id_get(&status); mtapi_domain_t domain_id = mtapi_domain_id_get(&status);
assert(MTAPI_SUCCESS == 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); assert(MTAPI_SUCCESS == status);
Action* holder = embb::base::Allocation::New<Action>(action); Action* holder = embb::base::Allocation::New<Action>(action);
void * idptr = MTAPI_NULL; void * idptr = MTAPI_NULL;
...@@ -216,5 +216,5 @@ void Task::Cancel() { ...@@ -216,5 +216,5 @@ void Task::Cancel() {
assert(MTAPI_SUCCESS == status); assert(MTAPI_SUCCESS == status);
} }
} // namespace mtapi } // namespace tasks
} // namespace embb } // namespace embb
...@@ -26,10 +26,10 @@ ...@@ -26,10 +26,10 @@
#include <cassert> #include <cassert>
#include <embb/mtapi/mtapi.h> #include <embb/tasks/tasks.h>
namespace embb { namespace embb {
namespace mtapi { namespace tasks {
TaskContext::TaskContext(mtapi_task_context_t * task_context) TaskContext::TaskContext(mtapi_task_context_t * task_context)
: context_(task_context) { : context_(task_context) {
...@@ -57,5 +57,5 @@ void TaskContext::SetStatus(mtapi_status_t error_code) { ...@@ -57,5 +57,5 @@ void TaskContext::SetStatus(mtapi_status_t error_code) {
assert(MTAPI_SUCCESS == status); assert(MTAPI_SUCCESS == status);
} }
} // namespace mtapi } // namespace tasks
} // namespace embb } // namespace embb
/*
* 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 <partest/partest.h>
#include <iostream>
#include <tasks_cpp_test_task.h>
#include <tasks_cpp_test_group.h>
#include <tasks_cpp_test_queue.h>
PT_MAIN("TASKS") {
PT_RUN(TaskTest);
PT_RUN(GroupTest);
PT_RUN(QueueTest);
}
/*
* 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 <partest/partest.h>
#include <embb/tasks/tasks.h>
#define THIS_DOMAIN_ID 1
#define THIS_NODE_ID 1
#endif // TASKS_CPP_TEST_TASKS_CPP_TEST_CONFIG_H_
/*
* 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 <iostream>
#include <tasks_cpp_test_config.h>
#include <tasks_cpp_test_group.h>
#include <embb/base/c/memory_allocation.h>
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);
}
/*
* 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 <partest/partest.h>
class GroupTest : public partest::TestCase {
public:
GroupTest();
private:
void TestBasic();
};
#endif // TASKS_CPP_TEST_TASKS_CPP_TEST_GROUP_H_
/*
* 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 <cstdlib>
#include <tasks_cpp_test_config.h>
#include <tasks_cpp_test_queue.h>
#include <embb/base/c/memory_allocation.h>
#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);
}
/*
* 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 <partest/partest.h>
class QueueTest : public partest::TestCase {
public:
QueueTest();
private:
void TestBasic();
};
#endif // TASKS_CPP_TEST_TASKS_CPP_TEST_QUEUE_H_
/*
* 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 <iostream>
#include <string>
#include <cassert>
#include <tasks_cpp_test_config.h>
#include <tasks_cpp_test_task.h>
#include <embb/base/c/memory_allocation.h>
#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);
}
/*
* 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 <partest/partest.h>
class TaskTest : public partest::TestCase {
public:
TaskTest();
private:
void TestBasic();
};
#endif // TASKS_CPP_TEST_TASKS_CPP_TEST_TASK_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment