Commit 29799f7f by Tobias Schuele

Merge branch 'development' into embb582_contributing_readme_file

parents 03ee9d41 ed3f573b
# Copyright (c) 2014-2016, Siemens AG. All rights reserved. # Copyright (c) 2014-2016, Siemens AG. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause #
# 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.
language: cpp language: cpp
compiler: compiler:
- gcc - gcc
- clang - clang
install: install:
- sudo apt-get install -qq cppcheck
- sudo add-apt-repository --yes ppa:kalakris/cmake - sudo add-apt-repository --yes ppa:kalakris/cmake
- sudo apt-get update -qq - sudo apt-get update -qq
- sudo apt-get install cmake - sudo apt-get install cmake
script: script:
- cppcheck -q --enable=all *_c*
- mkdir build && cd build - mkdir build && cd build
- cmake .. - cmake ..
- make - make
......
...@@ -6,84 +6,37 @@ Version 0.4.0 ...@@ -6,84 +6,37 @@ Version 0.4.0
------------- -------------
### Features: ### Features:
- Added C++ wrapper and tests for logging facilities - Added consistency checking functionality to dataflow
- Added C++ wrapper for base_c logging functions
- Reworked dataflow_cpp interface for easier usage
### Changes and improvements: ### Changes and improvements:
* Base: - Improved network plugin with better error checking and task cancellation support
- Changed assertions on user input into checks with error code return - Revised dataflow_cpp so that network token count can now be set at runtime
- Improved checks and documentation in time, duration, and log - Added automatic determination of token count to dataflow_cpp
- Added exceptions when errors occur that depend on user input - Added checks for NULL pointers in C interface functions
- Added volatile keyword to member of internal atomic struct - Extended mtapi_info_t to conform to the standard
- Changed spin lock implementaion to yield every 1024 spins - Fixed CodeSonar warnings across the code base
* MTAPI: - Changed spinlock implementation to yield every 1024 spins now
- Created defines for MTAPI version - Changed asserts on interface visible parameters to execeptions
- Added missing fields in mtapi_info_t structure, in particular organization ID - Enabled reuse of main thread, which is configurable via node attributes
- Changed reporting of number of domains and nodes to "unlimited"
- Changed group deleted and task state attributes to atomic
- Enabled reuse of main thread, which is configurable via node attributes
- Set result to MTAPI_NULL on error in mtapi_group_wait_any
- Network plugin:
- Disabled adress reuse for listening socket
- Solved problem with port reuse on Linux
- Set values to zero on failure for buffer pop operations
- Improved protocol for better error handling
- Changed signaling of task completion to atomic
- Introduced tagging of operations
- Improved task cancellation support
- Changed sending of result messages to complete ones only
* Tasks:
- Added function to query the maximum number of queues
- Added function to query the task limit
- Changed initalization in the implementaion of ExecutionPolicy
- Made creation of groups and queues thread-safe as documented
* Dataflow:
- Added connection chain test
- Added connection checks in outputs
- Added check for cycles in graph
- Added default token count to network
- Changed internal exceptions to assertions
- Changed return type of operator >> to allow for connection chains
- Changed semantics of source process (emit tokens only if function returns true)
- Changed initalization so that the number of slices can now be set at runtime
- Added automatic computation of maximum number of slices
- Changed done sync to atomics
- Removed Network::Make for simpler usage
- Added Network:IsValid to check network for errors
* Containers:
- Added missing PT_ASSERT calls in hazard pointer test
* All:
- Resolved several Codesonar warnings
### Bug fixes: ### Bug fixes:
* Base: - Fixed problem causing low performance on the Jetson TK1 board
- Fixed uninitialized variables in failure cases - Fixed bug in mtapi_c causing a task wait to hang
- Changed implementation of atomic store on Windows to ensure sequential consistency - Fixes issue with the AMD APP SDK in the OpenCL plugin
- Fixed memory leak in test for thread-specific storage - Fixed problem with automatic initialization in tasks_cpp
* MTAPI: - Fixed memory leaks in tests
- Fixed bug causing mtapi_task_wait to hang when a task was cancelled before it was running
- Fixed potential null pointer dereferences
- Fixed issue with AMD APP SDK in OpenCL plugin
- Fixed race condition in OpenCL plugin
* Dataflow:
- Fixed bug with global network instances in MTAPI scheduler
- Fixed initalization of input
- Fixed memory leaks
* Containers:
- Fixed uninitialized variables in test
### Build system: ### Build system:
- Moved MTAPI plugins to folder mtapi_plugins_c - Removed dependency on an installed OpenCL SDK
- Removed dependency on installed OpenCL SDK, adapted test to succeed when OpenCL is unavailable - Moved all MTAPI plugins into folder mtapi_plugins_c
- Resolved MSVC warnings and build problem - Resolved MSVC warnings and build problem
### Documentation: ### Documentation:
- Changed documentation to reflect that atomics are initialized to zero by default - Updated README to reflect new directory structure
- Improved documentation for functions without error code return - Updated Doxygen documentation of dataflow_cpp for the improved interface
- Updated year in license headers and tutorial - Updated tutorial and examples to show the usage of dataflow_cpp
- Updated documentation of spinlock implementations
- Changed encoding of COPYING.md file to UTF-8
- Adapted tutorial and examples to reflect changes to dataflow_cpp
- Revised README.md to reflect new directory structure and removed UTF8 BOM
Version 0.3.2 Version 0.3.2
......
...@@ -98,9 +98,9 @@ endif() ...@@ -98,9 +98,9 @@ endif()
message(" (set with command line option -DWARNINGS_ARE_ERRORS=ON/OFF)") message(" (set with command line option -DWARNINGS_ARE_ERRORS=ON/OFF)")
if (USE_AUTOMATIC_INITIALIZATION STREQUAL ON) if (USE_AUTOMATIC_INITIALIZATION STREQUAL ON)
message("-- MTAPI/Tasks automatic initialization enabled (default)") message("-- MTAPI automatic initialization enabled (default)")
else() else()
message("-- MTAPI/Tasks automatic initialization disabled") message("-- MTAPI automatic initialization disabled")
endif() endif()
message(" (set with command line option -DUSE_AUTOMATIC_INITIALIZATION=ON/OFF)") message(" (set with command line option -DUSE_AUTOMATIC_INITIALIZATION=ON/OFF)")
...@@ -137,7 +137,6 @@ set(EXPECTED_EMBB_TEST_EXECUTABLES "embb_algorithms_cpp_test" ...@@ -137,7 +137,6 @@ set(EXPECTED_EMBB_TEST_EXECUTABLES "embb_algorithms_cpp_test"
"embb_mtapi_c_test" "embb_mtapi_c_test"
"embb_mtapi_cpp_test" "embb_mtapi_cpp_test"
"embb_mtapi_network_c_test" "embb_mtapi_network_c_test"
"embb_tasks_cpp_test"
) )
# if opencl is there, we also expect the mtapi opencl test to be generated # if opencl is there, we also expect the mtapi opencl test to be generated
...@@ -180,7 +179,6 @@ add_subdirectory(mtapi_plugins_c/mtapi_network_c) ...@@ -180,7 +179,6 @@ add_subdirectory(mtapi_plugins_c/mtapi_network_c)
if(BUILD_OPENCL_PLUGIN STREQUAL ON) if(BUILD_OPENCL_PLUGIN STREQUAL ON)
add_subdirectory(mtapi_plugins_c/mtapi_opencl_c) add_subdirectory(mtapi_plugins_c/mtapi_opencl_c)
endif() endif()
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)
......
...@@ -59,7 +59,7 @@ Subscription: ...@@ -59,7 +59,7 @@ Subscription:
Contact: Contact:
- embb.info@gmail.com or - embb.info@gmail.com or
- tobias.schuele@siemens.com - tobias.schuele@siemens.com, sebnem.rusitschka@siemens.com
License License
...@@ -100,7 +100,6 @@ Currently, EMB² contains the following components: ...@@ -100,7 +100,6 @@ Currently, EMB² contains the following components:
- base: base_c, base_cpp - base: base_c, base_cpp
- mtapi: mtapi_c, mtapi_cpp and - mtapi: mtapi_c, mtapi_cpp and
mtapi_plugins_c (mtapi_network_c and mtapi_opencl_c) mtapi_plugins_c (mtapi_network_c and mtapi_opencl_c)
- tasks: tasks_cpp
- algorithms: algorithms_cpp - algorithms: algorithms_cpp
- dataflow: dataflow_cpp - dataflow: dataflow_cpp
- containers: containers_cpp - containers: containers_cpp
...@@ -114,10 +113,9 @@ implemented in C. Component base_cpp is mainly a C++ wrapper around the base_c ...@@ -114,10 +113,9 @@ implemented in C. Component base_cpp is mainly a C++ wrapper around the base_c
functions. Component mtapi_c is a task scheduler written in C and mtapi_cpp a functions. Component mtapi_c is a task scheduler written in C and mtapi_cpp a
C++ wrapper for the scheduler (mtapi_network_c and mtapi_opencl_c are scheduler C++ wrapper for the scheduler (mtapi_network_c and mtapi_opencl_c are scheduler
plugins for distributed and OpenCL-based heterogeneous systems, respectively). plugins for distributed and OpenCL-based heterogeneous systems, respectively).
To simplify programming of homogeneous systems, tasks_cpp contains abstractions Component algorithms_cpp provides high-level constructs for typical
to the MTAPI interfaces. Component algorithms_cpp provides high-level constructs parallelization tasks in C++, and dataflow_cpp generic skeletons for the
for typical parallelization tasks in C++, and dataflow_cpp generic skeletons for development of parallel stream-based applications. Finally, containers_cpp
the development of parallel stream-based applications. Finally, containers_cpp
provides data structures for storing objects in a thread-safe way. provides data structures for storing objects in a thread-safe way.
...@@ -370,6 +368,10 @@ Important Notes ...@@ -370,6 +368,10 @@ Important Notes
performance measurements, explicit initialization is strongly recommended performance measurements, explicit initialization is strongly recommended
since the measurements will otherwise include the initialization time of since the measurements will otherwise include the initialization time of
MTAPI. MTAPI.
- When using ThreadSanitizer there is a bug that causes the built-in CMake type
size determination to fail which in turn leads to a broken configuration.
Therefore, you have to do a normal build first and then rerun CMake with
flags and libs configured for ThreadSanitizer.
Links Links
......
...@@ -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}/../tasks_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../tasks_cpp/include) ${CMAKE_CURRENT_BINARY_DIR}/../mtapi_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_tasks_cpp) target_link_libraries(embb_algorithms_cpp embb_mtapi_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_tasks_cpp embb_mtapi_c partest embb_base_cpp embb_mtapi_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()
...@@ -36,3 +36,8 @@ endif() ...@@ -36,3 +36,8 @@ endif()
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/embb install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/embb
DESTINATION include FILES_MATCHING PATTERN "*.h") DESTINATION include FILES_MATCHING PATTERN "*.h")
install(TARGETS embb_algorithms_cpp DESTINATION lib) install(TARGETS embb_algorithms_cpp DESTINATION lib)
if (MSVC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/embb_algorithms_cpp.pdb
DESTINATION lib
CONFIGURATIONS Debug)
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/tasks/execution_policy.h> #include <embb/mtapi/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::tasks::ExecutionPolicy& policy, const embb::mtapi::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::tasks::ExecutionPolicy(), 0); return Count(first, last, value, embb::mtapi::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::tasks::ExecutionPolicy& policy const embb::mtapi::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::tasks::ExecutionPolicy& policy, const embb::mtapi::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::tasks::ExecutionPolicy(), 0); return CountIf(first, last, comparison, embb::mtapi::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::tasks::ExecutionPolicy& policy const embb::mtapi::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/tasks/execution_policy.h> #include <embb/mtapi/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::tasks::ExecutionPolicy& policy, const embb::mtapi::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::tasks::ExecutionPolicy(), 0); ForEach(first, last, unary, embb::mtapi::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::tasks::ExecutionPolicy& policy const embb::mtapi::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::tasks::ExecutionPolicy& policy, size_t block_size) { const embb::mtapi::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::tasks::ExecutionPolicy& policy, size_t block_size) { const embb::mtapi::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/tasks/tasks.h> #include <embb/mtapi/mtapi.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::tasks::ExecutionPolicy& policy, const embb::mtapi::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(embb::tasks::TaskContext&) { void Action(embb::mtapi::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,14 +71,13 @@ class ForEachFunctor { ...@@ -71,14 +71,13 @@ 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_);
embb::tasks::Task task_l = embb::tasks::Node::GetInstance().Spawn( embb::mtapi::Node& node = embb::mtapi::Node::GetInstance();
embb::tasks::Action( embb::mtapi::Task task_l = node.Start(
base::MakeFunction(functor_l, &self_t::Action), embb::base::MakeFunction(functor_l, &self_t::Action),
policy_)); policy_);
embb::tasks::Task task_r = embb::tasks::Node::GetInstance().Spawn( embb::mtapi::Task task_r = node.Start(
embb::tasks::Action( embb::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);
task_r.Wait(MTAPI_INFINITE); task_r.Wait(MTAPI_INFINITE);
} }
...@@ -91,7 +90,7 @@ class ForEachFunctor { ...@@ -91,7 +90,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::tasks::ExecutionPolicy& policy_; const embb::mtapi::ExecutionPolicy& policy_;
const BlockSizePartitioner<RAI>& partitioner_; const BlockSizePartitioner<RAI>& partitioner_;
/** /**
...@@ -102,7 +101,7 @@ class ForEachFunctor { ...@@ -102,7 +101,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::tasks::ExecutionPolicy& policy, size_t block_size) { const embb::mtapi::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 +113,7 @@ void ForEachRecursive(RAI first, RAI last, Function unary, ...@@ -114,7 +113,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");
} }
embb::tasks::Node& node = embb::tasks::Node::GetInstance(); embb::mtapi::Node& node = embb::mtapi::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);
...@@ -129,19 +128,19 @@ void ForEachRecursive(RAI first, RAI last, Function unary, ...@@ -129,19 +128,19 @@ void ForEachRecursive(RAI first, RAI last, Function unary,
} }
BlockSizePartitioner<RAI> partitioner(first, last, block_size); BlockSizePartitioner<RAI> partitioner(first, last, block_size);
ForEachFunctor<RAI, Function> functor(0, typedef ForEachFunctor<RAI, Function> functor_t;
partitioner.Size() - 1, functor_t functor(0,
unary, policy, partitioner); partitioner.Size() - 1,
embb::tasks::Task task = node.Spawn(embb::tasks::Action( unary, policy, partitioner);
base::MakeFunction(functor, embb::mtapi::Task task = node.Start(
&ForEachFunctor<RAI, Function>::Action), embb::base::MakeFunction(functor, &functor_t::Action),
policy)); policy);
task.Wait(MTAPI_INFINITE); task.Wait(MTAPI_INFINITE);
} }
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::tasks::ExecutionPolicy& policy, size_t block_size, const embb::mtapi::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 +149,7 @@ void ForEachIteratorCheck(RAI first, RAI last, Function unary, ...@@ -150,7 +149,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::tasks::ExecutionPolicy& policy, size_t block_size) { const embb::mtapi::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/tasks/tasks.h> #include <embb/mtapi/mtapi.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::tasks::ExecutionPolicy& policy, const embb::mtapi::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(embb::tasks::TaskContext&) { void Action(embb::mtapi::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,15 +77,13 @@ class MergeSortFunctor { ...@@ -77,15 +77,13 @@ class MergeSortFunctor {
temp_first_, temp_first_,
comparison_, policy_, partitioner_, comparison_, policy_, partitioner_,
global_first_, depth_ + 1); global_first_, depth_ + 1);
embb::tasks::Node& node = embb::tasks::Node::GetInstance(); embb::mtapi::Node& node = embb::mtapi::Node::GetInstance();
embb::tasks::Task task_l = node.Spawn( embb::mtapi::Task task_l = node.Start(
embb::tasks::Action( base::MakeFunction(functor_l, &self_t::Action),
base::MakeFunction(functor_l, &self_t::Action), policy_);
policy_)); embb::mtapi::Task task_r = node.Start(
embb::tasks::Task task_r = node.Spawn( base::MakeFunction(functor_r, &self_t::Action),
embb::tasks::Action( policy_);
base::MakeFunction(functor_r, &self_t::Action),
policy_));
task_l.Wait(MTAPI_INFINITE); task_l.Wait(MTAPI_INFINITE);
task_r.Wait(MTAPI_INFINITE); task_r.Wait(MTAPI_INFINITE);
...@@ -177,7 +175,7 @@ class MergeSortFunctor { ...@@ -177,7 +175,7 @@ class MergeSortFunctor {
size_t chunk_last_; size_t chunk_last_;
RAITemp temp_first_; RAITemp temp_first_;
ComparisonFunction comparison_; ComparisonFunction comparison_;
const embb::tasks::ExecutionPolicy& policy_; const embb::mtapi::ExecutionPolicy& policy_;
const BlockSizePartitioner<RAI>& partitioner_; const BlockSizePartitioner<RAI>& partitioner_;
const RAI& global_first_; const RAI& global_first_;
int depth_; int depth_;
...@@ -219,7 +217,7 @@ void MergeSortIteratorCheck( ...@@ -219,7 +217,7 @@ void MergeSortIteratorCheck(
RAI last, RAI last,
RAITemp temporary_first, RAITemp temporary_first,
ComparisonFunction comparison, ComparisonFunction comparison,
const embb::tasks::ExecutionPolicy& policy, const embb::mtapi::ExecutionPolicy& policy,
size_t block_size, size_t block_size,
std::random_access_iterator_tag std::random_access_iterator_tag
) { ) {
...@@ -257,10 +255,9 @@ void MergeSortIteratorCheck( ...@@ -257,10 +255,9 @@ void MergeSortIteratorCheck(
partitioner, partitioner,
first, first,
0); 0);
embb::tasks::Task task = embb::tasks::Node::GetInstance().Spawn( embb::mtapi::Task task = embb::mtapi::Node::GetInstance().Start(
embb::tasks::Action( base::MakeFunction(functor, &functor_t::Action),
base::MakeFunction(functor, &functor_t::Action), policy);
policy));
task.Wait(MTAPI_INFINITE); task.Wait(MTAPI_INFINITE);
} }
...@@ -269,7 +266,7 @@ void MergeSortIteratorCheck( ...@@ -269,7 +266,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::tasks::ExecutionPolicy& policy, ComparisonFunction comparison, const embb::mtapi::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<RAI>::ChunkPartitioner( ...@@ -93,7 +93,7 @@ ChunkPartitioner<RAI>::ChunkPartitioner(
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
embb::tasks::Node& node = embb::tasks::Node::GetInstance(); embb::mtapi::Node& node = embb::mtapi::Node::GetInstance();
size_ = node.GetWorkerThreadCount(); size_ = node.GetWorkerThreadCount();
} }
elements_count_ = static_cast<size_t>(std::distance(first_, last_)); elements_count_ = static_cast<size_t>(std::distance(first_, last_));
......
...@@ -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/tasks/tasks.h> #include <embb/mtapi/mtapi.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/tasks/tasks.h> #include <embb/mtapi/mtapi.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::tasks::ExecutionPolicy& policy, size_t block_size) const embb::mtapi::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(embb::tasks::TaskContext&) { void Action(embb::mtapi::TaskContext&) {
Difference distance = last_ - first_; Difference distance = last_ - first_;
if (distance <= 1) { if (distance <= 1) {
return; return;
...@@ -68,15 +68,17 @@ class QuickSortFunctor { ...@@ -68,15 +68,17 @@ class QuickSortFunctor {
SerialQuickSort(first_, mid); SerialQuickSort(first_, mid);
SerialQuickSort(mid, last_); SerialQuickSort(mid, last_);
} else { } else {
embb::tasks::Node& node = embb::tasks::Node::GetInstance(); embb::mtapi::Node& node = embb::mtapi::Node::GetInstance();
QuickSortFunctor functor_l(first_, mid, comparison_, policy_, QuickSortFunctor functor_l(first_, mid, comparison_, policy_,
block_size_); block_size_);
embb::tasks::Task task_l = node.Spawn(embb::tasks::Action( embb::mtapi::Task task_l = node.Start(
base::MakeFunction(functor_l, &QuickSortFunctor::Action))); base::MakeFunction(functor_l, &QuickSortFunctor::Action),
policy_);
QuickSortFunctor functor_r(mid, last_, comparison_, policy_, QuickSortFunctor functor_r(mid, last_, comparison_, policy_,
block_size_); block_size_);
embb::tasks::Task task_r = node.Spawn(embb::tasks::Action( embb::mtapi::Task task_r = node.Start(
base::MakeFunction(functor_r, &QuickSortFunctor::Action))); base::MakeFunction(functor_r, &QuickSortFunctor::Action),
policy_);
task_l.Wait(MTAPI_INFINITE); task_l.Wait(MTAPI_INFINITE);
task_r.Wait(MTAPI_INFINITE); task_r.Wait(MTAPI_INFINITE);
} }
...@@ -87,7 +89,7 @@ class QuickSortFunctor { ...@@ -87,7 +89,7 @@ class QuickSortFunctor {
RAI first_; RAI first_;
RAI last_; RAI last_;
ComparisonFunction comparison_; ComparisonFunction comparison_;
const embb::tasks::ExecutionPolicy& policy_; const embb::mtapi::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 +191,10 @@ class QuickSortFunctor { ...@@ -189,10 +191,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::tasks::ExecutionPolicy& policy, const embb::mtapi::ExecutionPolicy& policy,
size_t block_size, size_t block_size,
std::random_access_iterator_tag) { std::random_access_iterator_tag) {
embb::tasks::Node& node = embb::tasks::Node::GetInstance(); embb::mtapi::Node& node = embb::mtapi::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,8 +217,10 @@ void QuickSortIteratorCheck(RAI first, RAI last, ...@@ -215,8 +217,10 @@ 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);
embb::tasks::Task task = node.Spawn(embb::tasks::Action(base::MakeFunction( embb::mtapi::Task task = node.Start(
functor, &QuickSortFunctor<RAI, ComparisonFunction>::Action))); embb::base::MakeFunction(functor,
&QuickSortFunctor<RAI, ComparisonFunction>::Action),
policy);
task.Wait(MTAPI_INFINITE); task.Wait(MTAPI_INFINITE);
} }
...@@ -224,7 +228,7 @@ void QuickSortIteratorCheck(RAI first, RAI last, ...@@ -224,7 +228,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::tasks::ExecutionPolicy& policy, size_t block_size) { const embb::mtapi::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/tasks/tasks.h> #include <embb/mtapi/mtapi.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::tasks::ExecutionPolicy& policy, const embb::mtapi::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(embb::tasks::TaskContext&) { void Action(embb::mtapi::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,16 +81,12 @@ class ReduceFunctor { ...@@ -81,16 +81,12 @@ class ReduceFunctor {
neutral_, reduction_, transformation_, policy_, neutral_, reduction_, transformation_, policy_,
partitioner_, partitioner_,
result_r); result_r);
embb::tasks::Task task_l = embb::tasks::Node::GetInstance().Spawn( embb::mtapi::Task task_l = embb::mtapi::Node::GetInstance().Start(
embb::tasks::Action( base::MakeFunction(functor_l, &self_t::Action),
base::MakeFunction( policy_);
functor_l, &self_t::Action), embb::mtapi::Task task_r = embb::mtapi::Node::GetInstance().Start(
policy_)); base::MakeFunction(functor_r, &self_t::Action),
embb::tasks::Task task_r = embb::tasks::Node::GetInstance().Spawn( policy_);
embb::tasks::Action(
base::MakeFunction(
functor_r, &self_t::Action),
policy_));
task_l.Wait(MTAPI_INFINITE); task_l.Wait(MTAPI_INFINITE);
task_r.Wait(MTAPI_INFINITE); task_r.Wait(MTAPI_INFINITE);
result_ = reduction_(result_l, result_r); result_ = reduction_(result_l, result_r);
...@@ -108,7 +104,7 @@ class ReduceFunctor { ...@@ -108,7 +104,7 @@ class ReduceFunctor {
ReturnType neutral_; ReturnType neutral_;
ReductionFunction reduction_; ReductionFunction reduction_;
TransformationFunction transformation_; TransformationFunction transformation_;
const embb::tasks::ExecutionPolicy& policy_; const embb::mtapi::ExecutionPolicy& policy_;
const BlockSizePartitioner<RAI>& partitioner_; const BlockSizePartitioner<RAI>& partitioner_;
ReturnType& result_; ReturnType& result_;
...@@ -124,7 +120,7 @@ template<typename RAI, typename ReturnType, typename ReductionFunction, ...@@ -124,7 +120,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::tasks::ExecutionPolicy& policy, const embb::mtapi::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 +133,7 @@ ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral, ...@@ -137,7 +133,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");
} }
embb::tasks::Node& node = embb::tasks::Node::GetInstance(); embb::mtapi::Node& node = embb::mtapi::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,9 +158,9 @@ ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral, ...@@ -162,9 +158,9 @@ ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral,
policy, policy,
partitioner, partitioner,
result); result);
embb::tasks::Task task = node.Spawn( embb::mtapi::Task task = node.Start(
embb::tasks::Action(base::MakeFunction( base::MakeFunction(functor, &Functor::Action),
functor, &Functor::Action), policy)); policy);
task.Wait(MTAPI_INFINITE); task.Wait(MTAPI_INFINITE);
return result; return result;
} }
...@@ -174,7 +170,7 @@ template<typename RAI, typename TransformationFunction, ...@@ -174,7 +170,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::tasks::ExecutionPolicy& policy, const embb::mtapi::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 +184,7 @@ template<typename RAI, typename ReturnType, typename ReductionFunction, ...@@ -188,7 +184,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::tasks::ExecutionPolicy& policy, const embb::mtapi::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/tasks/tasks.h> #include <embb/base/function.h>
#include <embb/tasks/execution_policy.h> #include <embb/mtapi/mtapi.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::tasks::ExecutionPolicy& policy, const embb::mtapi::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(embb::tasks::TaskContext&) { void Action(embb::mtapi::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,15 +104,13 @@ class ScanFunctor { ...@@ -104,15 +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:
embb::tasks::Node& node = embb::tasks::Node::GetInstance(); embb::mtapi::Node& node = embb::mtapi::Node::GetInstance();
embb::tasks::Task task_l = node.Spawn( embb::mtapi::Task task_l = node.Start(
embb::tasks::Action( base::MakeFunction(functor_l, &ScanFunctor::Action),
base::MakeFunction(functor_l, &ScanFunctor::Action), policy_);
policy_)); embb::mtapi::Task task_r = node.Start(
embb::tasks::Task task_r = node.Spawn( base::MakeFunction(functor_r, &ScanFunctor::Action),
embb::tasks::Action( policy_);
base::MakeFunction(functor_r, &ScanFunctor::Action),
policy_));
// Wait for tasks to complete: // Wait for tasks to complete:
task_l.Wait(MTAPI_INFINITE); task_l.Wait(MTAPI_INFINITE);
task_r.Wait(MTAPI_INFINITE); task_r.Wait(MTAPI_INFINITE);
...@@ -131,7 +129,7 @@ class ScanFunctor { ...@@ -131,7 +129,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::tasks::ExecutionPolicy& policy_; const embb::mtapi::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 +166,7 @@ typename ScanFunction, typename TransformationFunction> ...@@ -168,7 +166,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::tasks::ExecutionPolicy& policy, const embb::mtapi::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,14 +197,15 @@ void ScanIteratorCheck(RAIIn first, RAIIn last, RAIOut output_iterator, ...@@ -199,14 +197,15 @@ 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;
embb::tasks::Node& node = embb::tasks::Node::GetInstance(); embb::mtapi::Node& node = embb::mtapi::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);
embb::tasks::Task task_down = node.Spawn(embb::tasks::Action( embb::mtapi::Task task_down = node.Start(
base::MakeFunction(functor_down, &Functor::Action), policy)); base::MakeFunction(functor_down, &Functor::Action),
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
...@@ -214,8 +213,9 @@ void ScanIteratorCheck(RAIIn first, RAIIn last, RAIOut output_iterator, ...@@ -214,8 +213,9 @@ 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);
embb::tasks::Task task_up = node.Spawn(embb::tasks::Action( embb::mtapi::Task task_up = node.Start(
base::MakeFunction(functor_up, &Functor::Action), policy)); base::MakeFunction(functor_up, &Functor::Action),
policy);
task_up.Wait(MTAPI_INFINITE); task_up.Wait(MTAPI_INFINITE);
} }
...@@ -225,7 +225,7 @@ template<typename RAIIn, typename RAIOut, typename ReturnType, ...@@ -225,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::tasks::ExecutionPolicy& policy, size_t block_size) { const embb::mtapi::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/tasks/tasks.h> #include <embb/mtapi/mtapi.h>
namespace embb { namespace embb {
namespace algorithms { namespace algorithms {
...@@ -78,8 +78,8 @@ void Invoke( ...@@ -78,8 +78,8 @@ void Invoke(
Function2 func2, Function2 func2,
/**< [in] Second function object to invoke */ /**< [in] Second function object to invoke */
..., ...,
const embb::tasks::ExecutionPolicy & policy const embb::mtapi::ExecutionPolicy & policy
/**< [in] embb::tasks::ExecutionPolicy to use */ /**< [in] embb::mtapi::ExecutionPolicy to use */
); );
#else // DOXYGEN #else // DOXYGEN
...@@ -98,11 +98,11 @@ class TaskWrapper { ...@@ -98,11 +98,11 @@ class TaskWrapper {
*/ */
explicit TaskWrapper( explicit TaskWrapper(
Function function, Function function,
const embb::tasks::ExecutionPolicy& policy) const embb::mtapi::ExecutionPolicy& policy)
: function_(function), task_() { : function_(function), task_() {
embb::tasks::Action action(embb::base::MakeFunction( task_ = embb::mtapi::Node::GetInstance().Start(
*this, &TaskWrapper::Run), policy); embb::base::MakeFunction(*this, &TaskWrapper::Run),
task_ = embb::tasks::Node::GetInstance().Spawn(action); policy);
} }
/** /**
...@@ -114,9 +114,9 @@ class TaskWrapper { ...@@ -114,9 +114,9 @@ class TaskWrapper {
private: private:
Function function_; Function function_;
embb::tasks::Task task_; embb::mtapi::Task task_;
void Run(embb::tasks::TaskContext&) { void Run(embb::mtapi::TaskContext&) {
function_(); function_();
} }
}; };
...@@ -126,7 +126,7 @@ template<typename Function1, typename Function2> ...@@ -126,7 +126,7 @@ template<typename Function1, typename Function2>
void Invoke( void Invoke(
Function1 func1, Function1 func1,
Function2 func2, Function2 func2,
const embb::tasks::ExecutionPolicy& policy) { const embb::mtapi::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);
} }
...@@ -136,7 +136,7 @@ void Invoke( ...@@ -136,7 +136,7 @@ void Invoke(
Function1 func1, Function1 func1,
Function2 func2, Function2 func2,
Function3 func3, Function3 func3,
const embb::tasks::ExecutionPolicy& policy) { const embb::mtapi::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);
...@@ -149,7 +149,7 @@ template<typename Function1, typename Function2, typename Function3, ...@@ -149,7 +149,7 @@ template<typename Function1, typename Function2, typename Function3,
Function2 func2, Function2 func2,
Function3 func3, Function3 func3,
Function4 func4, Function4 func4,
const embb::tasks::ExecutionPolicy& policy) { const embb::mtapi::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);
...@@ -164,7 +164,7 @@ template<typename Function1, typename Function2, typename Function3, ...@@ -164,7 +164,7 @@ template<typename Function1, typename Function2, typename Function3,
Function3 func3, Function3 func3,
Function4 func4, Function4 func4,
Function5 func5, Function5 func5,
const embb::tasks::ExecutionPolicy& policy) { const embb::mtapi::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);
...@@ -181,7 +181,7 @@ template<typename Function1, typename Function2, typename Function3, ...@@ -181,7 +181,7 @@ template<typename Function1, typename Function2, typename Function3,
Function4 func4, Function4 func4,
Function5 func5, Function5 func5,
Function6 func6, Function6 func6,
const embb::tasks::ExecutionPolicy& policy) { const embb::mtapi::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);
...@@ -201,7 +201,7 @@ template<typename Function1, typename Function2, typename Function3, ...@@ -201,7 +201,7 @@ template<typename Function1, typename Function2, typename Function3,
Function5 func5, Function5 func5,
Function6 func6, Function6 func6,
Function7 func7, Function7 func7,
const embb::tasks::ExecutionPolicy& policy) { const embb::mtapi::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);
...@@ -223,7 +223,7 @@ template<typename Function1, typename Function2, typename Function3, ...@@ -223,7 +223,7 @@ template<typename Function1, typename Function2, typename Function3,
Function6 func6, Function6 func6,
Function7 func7, Function7 func7,
Function8 func8, Function8 func8,
const embb::tasks::ExecutionPolicy& policy) { const embb::mtapi::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);
...@@ -247,7 +247,7 @@ template<typename Function1, typename Function2, typename Function3, ...@@ -247,7 +247,7 @@ template<typename Function1, typename Function2, typename Function3,
Function7 func7, Function7 func7,
Function8 func8, Function8 func8,
Function9 func9, Function9 func9,
const embb::tasks::ExecutionPolicy& policy) { const embb::mtapi::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);
...@@ -274,7 +274,7 @@ template<typename Function1, typename Function2, typename Function3, ...@@ -274,7 +274,7 @@ template<typename Function1, typename Function2, typename Function3,
Function8 func8, Function8 func8,
Function9 func9, Function9 func9,
Function10 func10, Function10 func10,
const embb::tasks::ExecutionPolicy& policy) { const embb::mtapi::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);
...@@ -291,14 +291,14 @@ template<typename Function1, typename Function2> ...@@ -291,14 +291,14 @@ template<typename Function1, typename Function2>
void Invoke( void Invoke(
Function1 func1, Function1 func1,
Function2 func2) { Function2 func2) {
Invoke(func1, func2, embb::tasks::ExecutionPolicy()); Invoke(func1, func2, embb::mtapi::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::tasks::ExecutionPolicy()); Invoke(func1, func2, func3, embb::mtapi::ExecutionPolicy());
} }
template<typename Function1, typename Function2, typename Function3, template<typename Function1, typename Function2, typename Function3,
...@@ -308,7 +308,7 @@ void Invoke( ...@@ -308,7 +308,7 @@ void Invoke(
Function2 func2, Function2 func2,
Function3 func3, Function3 func3,
Function4 func4) { Function4 func4) {
Invoke(func1, func2, func3, func4, embb::tasks::ExecutionPolicy()); Invoke(func1, func2, func3, func4, embb::mtapi::ExecutionPolicy());
} }
template<typename Function1, typename Function2, typename Function3, template<typename Function1, typename Function2, typename Function3,
...@@ -319,7 +319,7 @@ void Invoke( ...@@ -319,7 +319,7 @@ void Invoke(
Function3 func3, Function3 func3,
Function4 func4, Function4 func4,
Function5 func5) { Function5 func5) {
Invoke(func1, func2, func3, func4, func5, embb::tasks::ExecutionPolicy()); Invoke(func1, func2, func3, func4, func5, embb::mtapi::ExecutionPolicy());
} }
template<typename Function1, typename Function2, typename Function3, template<typename Function1, typename Function2, typename Function3,
...@@ -332,7 +332,7 @@ void Invoke( ...@@ -332,7 +332,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::tasks::ExecutionPolicy()); embb::mtapi::ExecutionPolicy());
} }
template<typename Function1, typename Function2, typename Function3, template<typename Function1, typename Function2, typename Function3,
...@@ -347,7 +347,7 @@ void Invoke( ...@@ -347,7 +347,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::tasks::ExecutionPolicy()); embb::mtapi::ExecutionPolicy());
} }
template<typename Function1, typename Function2, typename Function3, template<typename Function1, typename Function2, typename Function3,
...@@ -363,7 +363,7 @@ void Invoke( ...@@ -363,7 +363,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::tasks::ExecutionPolicy()); embb::mtapi::ExecutionPolicy());
} }
template<typename Function1, typename Function2, typename Function3, template<typename Function1, typename Function2, typename Function3,
...@@ -380,7 +380,7 @@ void Invoke( ...@@ -380,7 +380,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::tasks::ExecutionPolicy()); embb::mtapi::ExecutionPolicy());
} }
template<typename Function1, typename Function2, typename Function3, template<typename Function1, typename Function2, typename Function3,
...@@ -399,7 +399,7 @@ void Invoke( ...@@ -399,7 +399,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::tasks::ExecutionPolicy()); embb::mtapi::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/tasks/execution_policy.h> #include <embb/mtapi/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::tasks::ExecutionPolicy& policy, const embb::mtapi::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::tasks::ExecutionPolicy& policy, const embb::mtapi::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::tasks::ExecutionPolicy(), 0); embb::mtapi::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::tasks::ExecutionPolicy(), 0); MergeSortAllocate(first, last, comparison, embb::mtapi::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::tasks::ExecutionPolicy& policy const embb::mtapi::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::tasks::ExecutionPolicy(), 0); embb::mtapi::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::tasks::ExecutionPolicy(), 0); embb::mtapi::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::tasks::ExecutionPolicy& policy const embb::mtapi::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/tasks/execution_policy.h> #include <embb/mtapi/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::tasks::ExecutionPolicy& policy = embb::tasks::ExecutionPolicy(), const embb::mtapi::ExecutionPolicy& policy = embb::mtapi::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::tasks::ExecutionPolicy& policy, const embb::mtapi::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::tasks::ExecutionPolicy(), 0); embb::mtapi::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::tasks::ExecutionPolicy(), 0); QuickSort(first, last, comparison, embb::mtapi::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::tasks::ExecutionPolicy& policy const embb::mtapi::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/tasks/execution_policy.h> #include <embb/mtapi/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::tasks::ExecutionPolicy& policy, const embb::mtapi::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::tasks::ExecutionPolicy(), 0); embb::mtapi::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::tasks::ExecutionPolicy(), 0); embb::mtapi::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::tasks::ExecutionPolicy& policy const embb::mtapi::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/tasks/execution_policy.h> #include <embb/mtapi/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::tasks::ExecutionPolicy& policy, const embb::mtapi::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::tasks::ExecutionPolicy(), 0); embb::mtapi::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::tasks::ExecutionPolicy(), 0); embb::mtapi::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::tasks::ExecutionPolicy& policy const embb::mtapi::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/tasks/execution_policy.h> #include <embb/mtapi/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::tasks::ExecutionPolicy; using embb::mtapi::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::tasks::Node::GetInstance().GetCoreCount() * 10; size_t count = embb::mtapi::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/tasks/execution_policy.h> #include <embb/mtapi/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::tasks::ExecutionPolicy; using embb::mtapi::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::tasks::ExecutionPolicy; using embb::mtapi::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::tasks::ExecutionPolicy; using embb::mtapi::ExecutionPolicy;
size_t count = embb::tasks::Node::GetInstance().GetCoreCount() * 10; size_t count = embb::mtapi::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);
......
...@@ -61,7 +61,7 @@ void InvokeTest::Test() { ...@@ -61,7 +61,7 @@ void InvokeTest::Test() {
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, &Invocable5, Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, &Invocable5,
&Invocable6, &Invocable7, &Invocable8, &Invocable9, &Invocable10); &Invocable6, &Invocable7, &Invocable8, &Invocable9, &Invocable10);
embb::tasks::ExecutionPolicy policy; embb::mtapi::ExecutionPolicy policy;
Invoke(&Invocable1, &Invocable2, policy); Invoke(&Invocable1, &Invocable2, policy);
Invoke(&Invocable1, &Invocable2, &Invocable3, policy); Invoke(&Invocable1, &Invocable2, &Invocable3, policy);
Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, policy); Invoke(&Invocable1, &Invocable2, &Invocable3, &Invocable4, policy);
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
*/ */
#include <partest/partest.h> #include <partest/partest.h>
#include <embb/tasks/tasks.h> #include <embb/mtapi/mtapi.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::tasks::Node::Initialize(THIS_DOMAIN_ID, THIS_NODE_ID); embb::mtapi::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::tasks::Node::Finalize(); embb::mtapi::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/tasks/execution_policy.h> #include <embb/mtapi/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::tasks::ExecutionPolicy; using embb::mtapi::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::tasks::ExecutionPolicy; using embb::mtapi::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::tasks::ExecutionPolicy; using embb::mtapi::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::tasks::ExecutionPolicy; using embb::mtapi::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::tasks::Node::GetInstance().GetCoreCount() * 10; size_t count = embb::mtapi::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/tasks/execution_policy.h> #include <embb/mtapi/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::tasks::ExecutionPolicy; using embb::mtapi::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::tasks::ExecutionPolicy; using embb::mtapi::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::tasks::ExecutionPolicy; using embb::mtapi::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::tasks::Node::GetInstance().GetCoreCount() * 10; size_t count = embb::mtapi::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/tasks/execution_policy.h> #include <embb/mtapi/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::tasks::ExecutionPolicy; using embb::mtapi::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::tasks::ExecutionPolicy; using embb::mtapi::ExecutionPolicy;
using embb::algorithms::Identity; using embb::algorithms::Identity;
size_t count = embb::tasks::Node::GetInstance().GetCoreCount() * 10; size_t count = embb::mtapi::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::tasks::ExecutionPolicy; using embb::mtapi::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::tasks::ExecutionPolicy; using embb::mtapi::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::tasks::ExecutionPolicy; using embb::mtapi::ExecutionPolicy;
size_t count = embb::tasks::Node::GetInstance().GetCoreCount() *10; size_t count = embb::mtapi::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::tasks::ExecutionPolicy(), 0); embb::mtapi::ExecutionPolicy(), 0);
long sum = 0; long sum = 0;
for (size_t i = 0; i < kCountSize; i++) { for (size_t i = 0; i < kCountSize; i++) {
......
...@@ -122,3 +122,8 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/embb ...@@ -122,3 +122,8 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/embb
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/embb install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/embb
DESTINATION include FILES_MATCHING PATTERN "*.h") DESTINATION include FILES_MATCHING PATTERN "*.h")
install(TARGETS embb_base_c DESTINATION lib) install(TARGETS embb_base_c DESTINATION lib)
if (MSVC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/embb_base_c.pdb
DESTINATION lib
CONFIGURATIONS Debug)
endif()
...@@ -110,6 +110,9 @@ int embb_condition_notify_all( ...@@ -110,6 +110,9 @@ int embb_condition_notify_all(
* \threadsafe * \threadsafe
* \see embb_condition_notify_one(), embb_condition_notify_all(), * \see embb_condition_notify_one(), embb_condition_notify_all(),
* embb_condition_wait_until(), embb_condition_wait_for() * embb_condition_wait_until(), embb_condition_wait_for()
* \note It is strongly recommended checking the condition in a loop in order
* to deal with spurious wakeups and situations where another thread has
* locked the mutex between notification and wakeup.
*/ */
int embb_condition_wait( int embb_condition_wait(
embb_condition_t* condition_var, embb_condition_t* condition_var,
...@@ -131,6 +134,9 @@ int embb_condition_wait( ...@@ -131,6 +134,9 @@ int embb_condition_wait(
* \threadsafe * \threadsafe
* \see embb_condition_notify_one(), embb_condition_notify_all(), * \see embb_condition_notify_one(), embb_condition_notify_all(),
* embb_condition_wait(), embb_condition_wait_for() * embb_condition_wait(), embb_condition_wait_for()
* \note It is strongly recommended checking the condition in a loop in order
* to deal with spurious wakeups and situations where another thread has
* locked the mutex between notification and wakeup.
*/ */
int embb_condition_wait_until( int embb_condition_wait_until(
embb_condition_t* condition_var, embb_condition_t* condition_var,
...@@ -154,6 +160,9 @@ int embb_condition_wait_until( ...@@ -154,6 +160,9 @@ int embb_condition_wait_until(
* \threadsafe * \threadsafe
* \see embb_condition_notify_one(), embb_condition_notify_all(), * \see embb_condition_notify_one(), embb_condition_notify_all(),
* embb_condition_wait(), embb_condition_wait_until() * embb_condition_wait(), embb_condition_wait_until()
* \note It is strongly recommended checking the condition in a loop in order
* to deal with spurious wakeups and situations where another thread has
* locked the mutex between notification and wakeup.
*/ */
int embb_condition_wait_for( int embb_condition_wait_for(
embb_condition_t* condition_var, embb_condition_t* condition_var,
......
...@@ -46,3 +46,8 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/embb ...@@ -46,3 +46,8 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/embb
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/embb install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/embb
DESTINATION include FILES_MATCHING PATTERN "*.h") DESTINATION include FILES_MATCHING PATTERN "*.h")
install(TARGETS embb_base_cpp DESTINATION lib) install(TARGETS embb_base_cpp DESTINATION lib)
if (MSVC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/embb_base_cpp.pdb
DESTINATION lib
CONFIGURATIONS Debug)
endif()
...@@ -99,6 +99,10 @@ class ConditionVariable { ...@@ -99,6 +99,10 @@ class ConditionVariable {
* \threadsafe * \threadsafe
* *
* \see NotifyOne(), NotifyAll() * \see NotifyOne(), NotifyAll()
*
* \note It is strongly recommended checking the condition in a loop in order
* to deal with spurious wakeups and situations where another thread has
* locked the mutex between notification and wakeup.
*/ */
void Wait( void Wait(
UniqueLock<Mutex>& lock UniqueLock<Mutex>& lock
...@@ -118,6 +122,10 @@ class ConditionVariable { ...@@ -118,6 +122,10 @@ class ConditionVariable {
* \throws embb::base::ErrorException if an error occurred * \throws embb::base::ErrorException if an error occurred
* *
* \threadsafe * \threadsafe
*
* \note It is strongly recommended checking the condition in a loop in order
* to deal with spurious wakeups and situations where another thread has
* locked the mutex between notification and wakeup.
*/ */
bool WaitUntil( bool WaitUntil(
UniqueLock<Mutex>& lock, UniqueLock<Mutex>& lock,
...@@ -141,6 +149,10 @@ class ConditionVariable { ...@@ -141,6 +149,10 @@ class ConditionVariable {
* \threadsafe * \threadsafe
* *
* \tparam Tick Type of tick of the duration. See Duration. * \tparam Tick Type of tick of the duration. See Duration.
*
* \note It is strongly recommended checking the condition in a loop in order
* to deal with spurious wakeups and situations where another thread has
* locked the mutex between notification and wakeup.
*/ */
template<typename Tick> template<typename Tick>
bool WaitFor( bool WaitFor(
......
...@@ -31,3 +31,8 @@ endif() ...@@ -31,3 +31,8 @@ endif()
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/embb install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/embb
DESTINATION include FILES_MATCHING PATTERN "*.h") DESTINATION include FILES_MATCHING PATTERN "*.h")
install(TARGETS embb_containers_cpp DESTINATION lib) install(TARGETS embb_containers_cpp DESTINATION lib)
if (MSVC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/embb_containers_cpp.pdb
DESTINATION lib
CONFIGURATIONS Debug)
endif()
...@@ -74,7 +74,7 @@ int* IntObjectTestPool::Allocate() { ...@@ -74,7 +74,7 @@ int* IntObjectTestPool::Allocate() {
} }
void IntObjectTestPool::Release(int* object_pointer) { void IntObjectTestPool::Release(int* object_pointer) {
int cell = object_pointer - simplePoolObjects; int cell = static_cast<int>(object_pointer - simplePoolObjects);
simplePool[cell].Store(FREE_MARKER); simplePool[cell].Store(FREE_MARKER);
} }
......
...@@ -24,13 +24,25 @@ ...@@ -24,13 +24,25 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <embb/base/c/memory_allocation.h>
#ifdef EMBB_PLATFORM_COMPILER_MSVC
// Suppress warning generated by malloc.h(160): expression before comma
// has no effect: expected expression with side effect
#pragma warning(push)
#pragma warning(disable : 4548)
#endif
#include <embb/containers/lock_free_tree_value_pool.h> #include <embb/containers/lock_free_tree_value_pool.h>
#include <embb/containers/wait_free_array_value_pool.h> #include <embb/containers/wait_free_array_value_pool.h>
#include <embb/containers/wait_free_spsc_queue.h> #include <embb/containers/wait_free_spsc_queue.h>
#include <embb/containers/object_pool.h> #include <embb/containers/object_pool.h>
#include <embb/containers/lock_free_stack.h> #include <embb/containers/lock_free_stack.h>
#include <embb/containers/lock_free_mpmc_queue.h> #include <embb/containers/lock_free_mpmc_queue.h>
#include <embb/base/c/memory_allocation.h>
#ifdef EMBB_PLATFORM_COMPILER_MSVC
#pragma warning(pop) // Reset warning 4548
#endif
#include <partest/partest.h> #include <partest/partest.h>
#include <embb/base/thread.h> #include <embb/base/thread.h>
......
...@@ -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}/../tasks_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../tasks_cpp/include) ${CMAKE_CURRENT_BINARY_DIR}/../mtapi_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_tasks_cpp embb_base_cpp embb_mtapi_c embb_base_c) target_link_libraries(embb_dataflow_cpp embb_mtapi_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_dataflow_cpp embb_tasks_cpp embb_mtapi_c partest target_link_libraries(embb_dataflow_cpp_test embb_dataflow_cpp embb_mtapi_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()
...@@ -34,3 +34,8 @@ endif() ...@@ -34,3 +34,8 @@ 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(TARGETS embb_dataflow_cpp DESTINATION lib) install(TARGETS embb_dataflow_cpp DESTINATION lib)
if (MSVC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/embb_dataflow_cpp.pdb
DESTINATION lib
CONFIGURATIONS Debug)
endif()
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include <cstddef> #include <cstddef>
#include <embb/tasks/task_context.h> #include <embb/mtapi/task_context.h>
#include <embb/dataflow/internal/node.h> #include <embb/dataflow/internal/node.h>
...@@ -46,7 +46,7 @@ class Action { ...@@ -46,7 +46,7 @@ class Action {
node_->Run(clock_); node_->Run(clock_);
} }
void RunMTAPI(embb::tasks::TaskContext & /*context*/) { void RunMTAPI(embb::mtapi::TaskContext & /*context*/) {
node_->Run(clock_); node_->Run(clock_);
} }
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <cstddef> #include <cstddef>
#include <embb/base/exceptions.h> #include <embb/base/exceptions.h>
#include <embb/mtapi/execution_policy.h>
#include <embb/dataflow/internal/scheduler.h> #include <embb/dataflow/internal/scheduler.h>
#include <embb/dataflow/internal/clock_listener.h> #include <embb/dataflow/internal/clock_listener.h>
...@@ -58,10 +59,14 @@ class Node { ...@@ -58,10 +59,14 @@ class Node {
SetSlices(0); SetSlices(0);
} }
} }
void SetPolicy(embb::mtapi::ExecutionPolicy const & policy) {
policy_ = policy;
}
protected: protected:
Scheduler * sched_; Scheduler * sched_;
static int next_process_id_; static int next_process_id_;
embb::mtapi::ExecutionPolicy policy_;
static int GetNextProcessID() { return next_process_id_++; } static int GetNextProcessID() { return next_process_id_++; }
virtual void SetSlices(int /*slices*/) {} virtual void SetSlices(int /*slices*/) {}
......
...@@ -146,7 +146,7 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>, ...@@ -146,7 +146,7 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>,
for (int ii = clk; ii < clk_res; ii++) { for (int ii = clk; ii < clk_res; ii++) {
const int idx = ii % slices_; const int idx = ii % slices_;
action_[idx] = Action(this, ii); action_[idx] = Action(this, ii);
sched_->Enqueue(queue_id_, action_[idx]); sched_->Enqueue(queue_id_, action_[idx], policy_);
} }
queued_clock_.Store(clk_res); queued_clock_.Store(clk_res);
retry = false; retry = false;
...@@ -158,7 +158,7 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>, ...@@ -158,7 +158,7 @@ class Process< Serial, Inputs<I1, I2, I3, I4, I5>,
} else { } else {
const int idx = clock % slices_; const int idx = clock % slices_;
action_[idx] = Action(this, clock); action_[idx] = Action(this, clock);
sched_->Spawn(action_[idx]); sched_->Start(action_[idx], policy_);
} }
} }
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#ifndef EMBB_DATAFLOW_INTERNAL_SCHEDULER_H_ #ifndef EMBB_DATAFLOW_INTERNAL_SCHEDULER_H_
#define EMBB_DATAFLOW_INTERNAL_SCHEDULER_H_ #define EMBB_DATAFLOW_INTERNAL_SCHEDULER_H_
#include <embb/mtapi/execution_policy.h>
namespace embb { namespace embb {
namespace dataflow { namespace dataflow {
namespace internal { namespace internal {
...@@ -37,8 +39,13 @@ class Scheduler { ...@@ -37,8 +39,13 @@ class Scheduler {
public: public:
Scheduler() {} Scheduler() {}
virtual ~Scheduler() {} virtual ~Scheduler() {}
virtual void Spawn(Action & action) = 0; virtual void Start(
virtual void Enqueue(int process_id, Action & action) = 0; Action & action,
embb::mtapi::ExecutionPolicy const & policy) = 0;
virtual void Enqueue(
int process_id,
Action & action,
embb::mtapi::ExecutionPolicy const & policy) = 0;
virtual void WaitForSlice(int slice) = 0; virtual void WaitForSlice(int slice) = 0;
virtual int GetSlices() = 0; virtual int GetSlices() = 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/tasks/node.h> #include <embb/mtapi/mtapi.h>
#include <embb/base/function.h> #include <embb/base/function.h>
#include <algorithm> #include <algorithm>
...@@ -38,11 +38,13 @@ namespace embb { ...@@ -38,11 +38,13 @@ namespace embb {
namespace dataflow { namespace dataflow {
namespace internal { namespace internal {
#define EMBB_DATAFLOW_JOB_ID 1
class SchedulerMTAPI : public Scheduler { class SchedulerMTAPI : public Scheduler {
public: public:
explicit SchedulerMTAPI(int slices) explicit SchedulerMTAPI(int slices)
: slices_(slices) { : slices_(slices) {
embb::tasks::Node & node = embb::tasks::Node::GetInstance(); embb::mtapi::Node & node = embb::mtapi::Node::GetInstance();
int tl = std::min( int tl = std::min(
static_cast<int>(node.GetTaskLimit()), static_cast<int>(node.GetTaskLimit()),
...@@ -51,60 +53,96 @@ class SchedulerMTAPI : public Scheduler { ...@@ -51,60 +53,96 @@ class SchedulerMTAPI : public Scheduler {
slices_ = tl; slices_ = tl;
} }
group_ = reinterpret_cast<embb::tasks::Group**>( job_ = node.GetJob(EMBB_DATAFLOW_JOB_ID);
action_ = node.CreateAction(EMBB_DATAFLOW_JOB_ID,
SchedulerMTAPI::action_func);
group_ = reinterpret_cast<embb::mtapi::Group*>(
embb::base::Allocation::Allocate( embb::base::Allocation::Allocate(
sizeof(embb::tasks::Group*)*slices_)); sizeof(embb::mtapi::Group)*slices_));
for (int ii = 0; ii < slices_; ii++) { for (int ii = 0; ii < slices_; ii++) {
embb::tasks::Group & group = node.CreateGroup(); group_[ii] = node.CreateGroup();
group_[ii] = &group;
} }
queue_count_ = std::min( queue_count_ = std::min(
static_cast<int>(node.GetQueueCount()), static_cast<int>(node.GetQueueCount()),
static_cast<int>(node.GetWorkerThreadCount()) ); static_cast<int>(node.GetWorkerThreadCount()) );
queue_ = reinterpret_cast<embb::tasks::Queue**>( queue_ = reinterpret_cast<embb::mtapi::Queue*>(
embb::base::Allocation::Allocate( embb::base::Allocation::Allocate(
sizeof(embb::tasks::Queue*)*queue_count_)); sizeof(embb::mtapi::Queue)*queue_count_));
embb::mtapi::QueueAttributes queue_attr;
queue_attr
.SetPriority(0)
.SetOrdered(true);
for (int ii = 0; ii < queue_count_; ii++) { for (int ii = 0; ii < queue_count_; ii++) {
embb::tasks::Queue & queue = node.CreateQueue(0, true); queue_[ii] = node.CreateQueue(job_, queue_attr);
queue_[ii] = &queue;
} }
} }
virtual ~SchedulerMTAPI() { virtual ~SchedulerMTAPI() {
if (embb::tasks::Node::IsInitialized()) { if (embb::mtapi::Node::IsInitialized()) {
// only destroy groups and queues if there still is an instance // only destroy groups and queues if there still is an instance
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]); group_[ii].Delete();
} }
for (int ii = 0; ii < queue_count_; ii++) { for (int ii = 0; ii < queue_count_; ii++) {
node.DestroyQueue(*queue_[ii]); queue_[ii].Delete();
} }
// delete action as well
action_.Delete();
} }
embb::base::Allocation::Free(group_); embb::base::Allocation::Free(group_);
embb::base::Allocation::Free(queue_); embb::base::Allocation::Free(queue_);
} }
virtual void Spawn(Action & action) { virtual void Start(
Action & action,
embb::mtapi::ExecutionPolicy const & policy) {
const int idx = action.GetClock() % slices_; const int idx = action.GetClock() % slices_;
group_[idx]->Spawn(embb::base::MakeFunction(action, &Action::RunMTAPI)); embb::mtapi::TaskAttributes task_attr;
task_attr.SetPolicy(policy);
group_[idx].Start(job_, &action, static_cast<void*>(NULL),
task_attr);
} }
virtual void Enqueue(int process_id, Action & action) { virtual void Enqueue(
int process_id,
Action & action,
embb::mtapi::ExecutionPolicy const & policy) {
const int idx = action.GetClock() % slices_; const int idx = action.GetClock() % slices_;
const int queue_id = process_id % queue_count_; const int queue_id = process_id % queue_count_;
queue_[queue_id]->Spawn(group_[idx], embb::mtapi::TaskAttributes task_attr;
embb::base::MakeFunction(action, &Action::RunMTAPI)); task_attr.SetPolicy(policy);
queue_[queue_id].Enqueue(&action, static_cast<void*>(NULL),
task_attr, group_[idx]);
} }
virtual void WaitForSlice(int slice) { virtual void WaitForSlice(int slice) {
group_[slice]->WaitAll(MTAPI_INFINITE); group_[slice].WaitAll(MTAPI_INFINITE);
// group is invalid now, recreate
embb::mtapi::Node & node = embb::mtapi::Node::GetInstance();
group_[slice] = node.CreateGroup();
} }
virtual int GetSlices() { return slices_; } virtual int GetSlices() { return slices_; }
private: private:
embb::tasks::Group ** group_; static void action_func(
embb::tasks::Queue ** queue_; 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));
embb::mtapi::TaskContext task_context(context);
action->RunMTAPI(task_context);
}
embb::mtapi::Action action_;
embb::mtapi::Job job_;
embb::mtapi::Group * group_;
embb::mtapi::Queue * queue_;
int queue_count_; int queue_count_;
int slices_; int slices_;
}; };
......
...@@ -38,10 +38,15 @@ class SchedulerSequential : public Scheduler { ...@@ -38,10 +38,15 @@ class SchedulerSequential : public Scheduler {
public: public:
SchedulerSequential() {} SchedulerSequential() {}
virtual ~SchedulerSequential() {} virtual ~SchedulerSequential() {}
virtual void Spawn(Action & action) { virtual void Start(
Action & action,
embb::mtapi::ExecutionPolicy const &) {
action.RunSequential(); action.RunSequential();
} }
virtual void Enqueue(int, Action & action) { virtual void Enqueue(
int,
Action & action,
embb::mtapi::ExecutionPolicy const &) {
action.RunSequential(); action.RunSequential();
} }
virtual void WaitForSlice(int /*slice*/) {} virtual void WaitForSlice(int /*slice*/) {}
......
...@@ -113,7 +113,7 @@ class Sink< Inputs<I1, I2, I3, I4, I5> > ...@@ -113,7 +113,7 @@ class Sink< Inputs<I1, I2, I3, I4, I5> >
for (int ii = clk; ii < clk_res; ii++) { for (int ii = clk; ii < clk_res; ii++) {
const int idx = ii % slices_; const int idx = ii % slices_;
action_[idx] = Action(this, ii); action_[idx] = Action(this, ii);
sched_->Enqueue(queue_id_, action_[idx]); sched_->Enqueue(queue_id_, action_[idx], policy_);
} }
queued_clock_.Store(clk_res); queued_clock_.Store(clk_res);
retry = false; retry = false;
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <embb/tasks/tasks.h> #include <embb/mtapi/mtapi.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>
...@@ -153,15 +153,14 @@ SimpleTest::SimpleTest() { ...@@ -153,15 +153,14 @@ SimpleTest::SimpleTest() {
void SimpleTest::TestBasic() { void SimpleTest::TestBasic() {
// All available cores // All available cores
embb::base::CoreSet core_set(true); embb::base::CoreSet core_set(true);
embb::tasks::Node::Initialize( embb::mtapi::NodeAttributes node_attr;
node_attr
.SetCoreAffinity(core_set)
.SetMaxQueues(2);
embb::mtapi::Node::Initialize(
MTAPI_DOMAIN_ID, MTAPI_DOMAIN_ID,
MTAPI_NODE_ID, MTAPI_NODE_ID,
core_set, node_attr);
1024, // max tasks (default: 1024)
128, // max groups (default: 128)
2, // max queues (default: 16)
1024, // queue capacity (default: 1024)
4); // num priorities (default: 4)
for (int ii = 0; ii < 10000; ii++) { for (int ii = 0; ii < 10000; ii++) {
ArraySink<TEST_COUNT> asink; ArraySink<TEST_COUNT> asink;
...@@ -221,7 +220,7 @@ void SimpleTest::TestBasic() { ...@@ -221,7 +220,7 @@ void SimpleTest::TestBasic() {
PT_EXPECT(asink.Check()); PT_EXPECT(asink.Check());
} }
embb::tasks::Node::Finalize(); embb::mtapi::Node::Finalize();
PT_EXPECT(embb_get_bytes_allocated() == 0); PT_EXPECT(embb_get_bytes_allocated() == 0);
} }
......
...@@ -14,8 +14,7 @@ include_directories( ...@@ -14,8 +14,7 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_c/src ${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_c/src
${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_plugins_c/mtapi_network_c/include ${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_plugins_c/mtapi_network_c/include
${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_cpp/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
${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
...@@ -46,7 +45,7 @@ IF(MSVC) ...@@ -46,7 +45,7 @@ IF(MSVC)
ENDIF() ENDIF()
add_executable(examples ${EXAMPLES_SOURCES}) add_executable(examples ${EXAMPLES_SOURCES})
target_link_libraries(examples embb_dataflow_cpp embb_algorithms_cpp embb_tasks_cpp embb_mtapi_cpp target_link_libraries(examples embb_dataflow_cpp embb_algorithms_cpp embb_mtapi_cpp
embb_mtapi_network_c ${EMBB_MTAPI_OPENCL_C_CONDITIONAL} embb_mtapi_c embb_mtapi_network_c ${EMBB_MTAPI_OPENCL_C_CONDITIONAL} embb_mtapi_c
embb_base_cpp embb_base_c embb_containers_cpp embb_base_cpp embb_base_c embb_containers_cpp
${EXTRA_LIBS} ${compiler_libs}) ${EXTRA_LIBS} ${compiler_libs})
......
...@@ -34,7 +34,6 @@ void RunMTAPI_C_Network(); ...@@ -34,7 +34,6 @@ void RunMTAPI_C_Network();
void RunMTAPI_C_OpenCL(); void RunMTAPI_C_OpenCL();
#endif #endif
void RunMTAPI_CPP(); void RunMTAPI_CPP();
void RunTasks();
void RunDataflowLinear(); void RunDataflowLinear();
void RunDataflowNonLinear(); void RunDataflowNonLinear();
void RunSTLForEach(); void RunSTLForEach();
...@@ -78,10 +77,6 @@ int main() { ...@@ -78,10 +77,6 @@ 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;
......
...@@ -51,8 +51,8 @@ static ...@@ -51,8 +51,8 @@ static
static static
int fibonacci(int n) { int fibonacci(int n) {
#include "mtapi/mtapi_cpp_initialize-snippet.h" #include "mtapi/mtapi_cpp_initialize-snippet.h"
#include "mtapi/mtapi_cpp_register_action-snippet.h"
#include "mtapi/mtapi_cpp_get_node-snippet.h" #include "mtapi/mtapi_cpp_get_node-snippet.h"
#include "mtapi/mtapi_cpp_register_action-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 */
......
/* create action */ /* create action */
embb::mtapi::Action fibonacciAction( embb::mtapi::Action fibonacciAction = node.CreateAction(
FIBONACCI_JOB, /* action ID, defined by the FIBONACCI_JOB, /* action ID, defined by the
application */ application */
(fibonacciActionFunction) /* action function */ (fibonacciActionFunction) /* action function */
); );
/* get job */ /* get job */
fibonacciJob = embb::mtapi::Job(FIBONACCI_JOB, THIS_DOMAIN_ID); fibonacciJob = node.GetJob(FIBONACCI_JOB, THIS_DOMAIN_ID);
void simpleActionFunction(
TaskContext & task_context
) {
// something useful
}
int result;
embb::mtapi::Task task = node.Start(simpleActionFunction);
mtapi_status_t status = task.Wait(MTAPI_INFINITE); mtapi_status_t task_status = task.Wait(MTAPI_INFINITE);
if (status != MTAPI_SUCCESS) { if (task_status != MTAPI_SUCCESS) {
printf("task failed with error: %d\n\n", status); printf("task failed with error: %d\n\n", task_status);
exit(status); exit(task_status);
} }
/*
* Copyright (c) 2014-2016, 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(
int n,
int* result,
embb::tasks::TaskContext & task_context
) {
int b = n - 2;
int y;
fibonacciActionFunction(
b,
&y,
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,7 +148,6 @@ INPUT = "@CMAKE_SOURCE_DIR@/doc/reference/embb.dox" \ ...@@ -148,7 +148,6 @@ 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" \
......
...@@ -152,7 +152,11 @@ After everything is done, the action is deleted (\lstinline|mtapi_action_delete( ...@@ -152,7 +152,11 @@ 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. The signature of the action function for the C++ interface is the same as in the C interface: \embb provides C++ wrappers for the MTAPI C interface. The full interface provides functions for all MTAPI releated tasks and supports heterogeneous systems. For ease of use a simpler version for SMP systems is provided.
\subsection{Full Interface}
The signature of the action function for the C++ interface is the same as in the C interface:
% %
\\\inputlisting{../examples/mtapi/mtapi_c_action_signature-snippet.h} \\\inputlisting{../examples/mtapi/mtapi_c_action_signature-snippet.h}
% %
...@@ -193,7 +197,7 @@ After that, the action function needs to be associated to a job. By instancing a ...@@ -193,7 +197,7 @@ After that, the action function needs to be associated to a job. By instancing a
% %
\\\inputlisting{../examples/mtapi/mtapi_cpp_register_action-snippet.h} \\\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: Now 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}
% %
...@@ -203,6 +207,19 @@ The registered action will be unregistered when it goes out of scope. ...@@ -203,6 +207,19 @@ The registered action will be unregistered when it goes out of scope.
The runtime needs to be shut down by calling: The runtime needs to be shut down by calling:
\\\inputlisting{../examples/mtapi/mtapi_cpp_finalize-snippet.h} \\\inputlisting{../examples/mtapi/mtapi_cpp_finalize-snippet.h}
\subsection{Simplified Interface for SMP actions}
MTAPI CPP provides a simpler version of the MTAPI interface for SMP actions. The signature of the
action function for the simplified API looks like this:
%
\\\inputlisting{../examples/mtapi/mtapi_cpp_simple_action_signature-snippet.h}
%
The action function does not need to be registered with a job. Instead a preregistered job is used that expects a \lstinline|embb::base::Function<void, embb::mtapi::TaskContext &>| object. Therefore a task can be scheduled directly using only the function above:
%
\\\inputlisting{../examples/mtapi/mtapi_cpp_simple_start_task-snippet.h}
%
\section{Plugins} \section{Plugins}
The \embb implementation of MTAPI provides an extension to allow for custom actions that are not executed by the scheduler for software actions as detailed in the previous sections. The \embb implementation of MTAPI provides an extension to allow for custom actions that are not executed by the scheduler for software actions as detailed in the previous sections.
......
\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,7 +114,6 @@ ...@@ -114,7 +114,6 @@
% \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}
......
...@@ -39,3 +39,8 @@ endif() ...@@ -39,3 +39,8 @@ 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(TARGETS embb_mtapi_c DESTINATION lib) install(TARGETS embb_mtapi_c DESTINATION lib)
if (MSVC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/embb_mtapi_c.pdb
DESTINATION lib
CONFIGURATIONS Debug)
endif()
...@@ -289,10 +289,12 @@ void mtapi_action_delete( ...@@ -289,10 +289,12 @@ void mtapi_action_delete(
embb_mtapi_thread_context_t * context = NULL; embb_mtapi_thread_context_t * context = NULL;
embb_duration_t wait_duration; embb_duration_t wait_duration;
embb_time_t start_time;
embb_time_t end_time; embb_time_t end_time;
if (MTAPI_INFINITE < timeout) { if (MTAPI_INFINITE < timeout) {
embb_duration_set_milliseconds( embb_duration_set_milliseconds(
&wait_duration, (unsigned long long)timeout); &wait_duration, (unsigned long long)timeout);
embb_time_now(&start_time);
embb_time_in(&end_time, &wait_duration); embb_time_in(&end_time, &wait_duration);
} }
...@@ -309,6 +311,12 @@ void mtapi_action_delete( ...@@ -309,6 +311,12 @@ void mtapi_action_delete(
if (MTAPI_INFINITE < timeout) { if (MTAPI_INFINITE < timeout) {
embb_time_t current_time; embb_time_t current_time;
embb_time_now(&current_time); embb_time_now(&current_time);
if (embb_time_compare(&current_time, &start_time) < 0) {
/* time has moved backwards, maybe a wraparound or jitter
move end_time backward to avoid endeless loop */
start_time = current_time;
embb_time_in(&end_time, &wait_duration);
}
if (embb_time_compare(&current_time, &end_time) > 0) { if (embb_time_compare(&current_time, &end_time) > 0) {
/* timeout! */ /* timeout! */
local_status = MTAPI_TIMEOUT; local_status = MTAPI_TIMEOUT;
...@@ -362,10 +370,12 @@ void mtapi_action_disable( ...@@ -362,10 +370,12 @@ void mtapi_action_disable(
embb_mtapi_thread_context_t * context = NULL; embb_mtapi_thread_context_t * context = NULL;
embb_duration_t wait_duration; embb_duration_t wait_duration;
embb_time_t start_time;
embb_time_t end_time; embb_time_t end_time;
if (MTAPI_INFINITE < timeout) { if (MTAPI_INFINITE < timeout) {
embb_duration_set_milliseconds( embb_duration_set_milliseconds(
&wait_duration, (unsigned long long)timeout); &wait_duration, (unsigned long long)timeout);
embb_time_now(&start_time);
embb_time_in(&end_time, &wait_duration); embb_time_in(&end_time, &wait_duration);
} }
...@@ -382,6 +392,12 @@ void mtapi_action_disable( ...@@ -382,6 +392,12 @@ void mtapi_action_disable(
if (MTAPI_INFINITE < timeout) { if (MTAPI_INFINITE < timeout) {
embb_time_t current_time; embb_time_t current_time;
embb_time_now(&current_time); embb_time_now(&current_time);
if (embb_time_compare(&current_time, &start_time) < 0) {
/* time has moved backwards, maybe a wraparound or jitter
move end_time backward to avoid endeless loop */
start_time = current_time;
embb_time_in(&end_time, &wait_duration);
}
if (embb_time_compare(&current_time, &end_time) > 0) { if (embb_time_compare(&current_time, &end_time) > 0) {
/* timeout! */ /* timeout! */
local_status = MTAPI_TIMEOUT; local_status = MTAPI_TIMEOUT;
......
...@@ -213,10 +213,12 @@ void mtapi_group_wait_all( ...@@ -213,10 +213,12 @@ void mtapi_group_wait_all(
node->group_pool, group); node->group_pool, group);
embb_duration_t wait_duration; embb_duration_t wait_duration;
embb_time_t start_time;
embb_time_t end_time; embb_time_t end_time;
if (MTAPI_INFINITE < timeout) { if (MTAPI_INFINITE < timeout) {
embb_duration_set_milliseconds( embb_duration_set_milliseconds(
&wait_duration, (unsigned long long)timeout); &wait_duration, (unsigned long long)timeout);
embb_time_now(&start_time);
embb_time_in(&end_time, &wait_duration); embb_time_in(&end_time, &wait_duration);
} }
...@@ -232,6 +234,12 @@ void mtapi_group_wait_all( ...@@ -232,6 +234,12 @@ void mtapi_group_wait_all(
if (MTAPI_INFINITE < timeout) { if (MTAPI_INFINITE < timeout) {
embb_time_t current_time; embb_time_t current_time;
embb_time_now(&current_time); embb_time_now(&current_time);
if (embb_time_compare(&current_time, &start_time) < 0) {
/* time has moved backwards, maybe a wraparound or jitter
move end_time backward to avoid endeless loop */
start_time = current_time;
embb_time_in(&end_time, &wait_duration);
}
if (embb_time_compare(&current_time, &end_time) > 0) { if (embb_time_compare(&current_time, &end_time) > 0) {
/* timeout! */ /* timeout! */
local_status = MTAPI_TIMEOUT; local_status = MTAPI_TIMEOUT;
...@@ -300,10 +308,12 @@ void mtapi_group_wait_any( ...@@ -300,10 +308,12 @@ void mtapi_group_wait_any(
embb_mtapi_thread_context_t * context = NULL; embb_mtapi_thread_context_t * context = NULL;
embb_duration_t wait_duration; embb_duration_t wait_duration;
embb_time_t start_time;
embb_time_t end_time; embb_time_t end_time;
if (MTAPI_INFINITE < timeout) { if (MTAPI_INFINITE < timeout) {
embb_duration_set_milliseconds( embb_duration_set_milliseconds(
&wait_duration, (unsigned long long)timeout); &wait_duration, (unsigned long long)timeout);
embb_time_now(&start_time);
embb_time_in(&end_time, &wait_duration); embb_time_in(&end_time, &wait_duration);
} }
...@@ -318,6 +328,12 @@ void mtapi_group_wait_any( ...@@ -318,6 +328,12 @@ void mtapi_group_wait_any(
if (MTAPI_INFINITE < timeout) { if (MTAPI_INFINITE < timeout) {
embb_time_t current_time; embb_time_t current_time;
embb_time_now(&current_time); embb_time_now(&current_time);
if (embb_time_compare(&current_time, &start_time) < 0) {
/* time has moved backwards, maybe a wraparound or jitter
move end_time backward to avoid endeless loop */
start_time = current_time;
embb_time_in(&end_time, &wait_duration);
}
if (embb_time_compare(&current_time, &end_time) > 0) { if (embb_time_compare(&current_time, &end_time) > 0) {
/* timeout! */ /* timeout! */
local_status = MTAPI_TIMEOUT; local_status = MTAPI_TIMEOUT;
......
...@@ -360,10 +360,12 @@ void mtapi_queue_delete( ...@@ -360,10 +360,12 @@ void mtapi_queue_delete(
embb_mtapi_thread_context_t * context = NULL; embb_mtapi_thread_context_t * context = NULL;
embb_duration_t wait_duration; embb_duration_t wait_duration;
embb_time_t start_time;
embb_time_t end_time; embb_time_t end_time;
if (MTAPI_INFINITE < timeout) { if (MTAPI_INFINITE < timeout) {
embb_duration_set_milliseconds( embb_duration_set_milliseconds(
&wait_duration, (unsigned long long)timeout); &wait_duration, (unsigned long long)timeout);
embb_time_now(&start_time);
embb_time_in(&end_time, &wait_duration); embb_time_in(&end_time, &wait_duration);
} }
...@@ -381,6 +383,12 @@ void mtapi_queue_delete( ...@@ -381,6 +383,12 @@ void mtapi_queue_delete(
if (MTAPI_INFINITE < timeout) { if (MTAPI_INFINITE < timeout) {
embb_time_t current_time; embb_time_t current_time;
embb_time_now(&current_time); embb_time_now(&current_time);
if (embb_time_compare(&current_time, &start_time) < 0) {
/* time has moved backwards, maybe a wraparound or jitter
move end_time backward to avoid endeless loop */
start_time = current_time;
embb_time_in(&end_time, &wait_duration);
}
if (embb_time_compare(&current_time, &end_time) > 0) { if (embb_time_compare(&current_time, &end_time) > 0) {
/* timeout! */ /* timeout! */
local_status = MTAPI_TIMEOUT; local_status = MTAPI_TIMEOUT;
...@@ -435,10 +443,12 @@ void mtapi_queue_disable( ...@@ -435,10 +443,12 @@ void mtapi_queue_disable(
embb_mtapi_scheduler_get_current_thread_context(node->scheduler); embb_mtapi_scheduler_get_current_thread_context(node->scheduler);
embb_duration_t wait_duration; embb_duration_t wait_duration;
embb_time_t start_time;
embb_time_t end_time; embb_time_t end_time;
if (MTAPI_INFINITE < timeout) { if (MTAPI_INFINITE < timeout) {
embb_duration_set_milliseconds( embb_duration_set_milliseconds(
&wait_duration, (unsigned long long)timeout); &wait_duration, (unsigned long long)timeout);
embb_time_now(&start_time);
embb_time_in(&end_time, &wait_duration); embb_time_in(&end_time, &wait_duration);
} }
...@@ -448,6 +458,12 @@ void mtapi_queue_disable( ...@@ -448,6 +458,12 @@ void mtapi_queue_disable(
if (MTAPI_INFINITE < timeout) { if (MTAPI_INFINITE < timeout) {
embb_time_t current_time; embb_time_t current_time;
embb_time_now(&current_time); embb_time_now(&current_time);
if (embb_time_compare(&current_time, &start_time) < 0) {
/* time has moved backwards, maybe a wraparound or jitter
move end_time backward to avoid endeless loop */
start_time = current_time;
embb_time_in(&end_time, &wait_duration);
}
if (embb_time_compare(&current_time, &end_time) > 0) { if (embb_time_compare(&current_time, &end_time) > 0) {
/* timeout! */ /* timeout! */
local_status = MTAPI_TIMEOUT; local_status = MTAPI_TIMEOUT;
......
...@@ -407,6 +407,7 @@ mtapi_boolean_t embb_mtapi_scheduler_wait_for_task( ...@@ -407,6 +407,7 @@ mtapi_boolean_t embb_mtapi_scheduler_wait_for_task(
embb_mtapi_node_t* node = embb_mtapi_node_get_instance(); embb_mtapi_node_t* node = embb_mtapi_node_get_instance();
embb_mtapi_thread_context_t * context = NULL; embb_mtapi_thread_context_t * context = NULL;
embb_duration_t wait_duration; embb_duration_t wait_duration;
embb_time_t start_time;
embb_time_t end_time; embb_time_t end_time;
assert(MTAPI_NULL != node); assert(MTAPI_NULL != node);
...@@ -414,6 +415,7 @@ mtapi_boolean_t embb_mtapi_scheduler_wait_for_task( ...@@ -414,6 +415,7 @@ mtapi_boolean_t embb_mtapi_scheduler_wait_for_task(
if (MTAPI_INFINITE < timeout) { if (MTAPI_INFINITE < timeout) {
embb_duration_set_milliseconds(&wait_duration, (unsigned long long)timeout); embb_duration_set_milliseconds(&wait_duration, (unsigned long long)timeout);
embb_time_now(&start_time);
embb_time_in(&end_time, &wait_duration); embb_time_in(&end_time, &wait_duration);
} }
...@@ -431,6 +433,12 @@ mtapi_boolean_t embb_mtapi_scheduler_wait_for_task( ...@@ -431,6 +433,12 @@ mtapi_boolean_t embb_mtapi_scheduler_wait_for_task(
if (MTAPI_INFINITE < timeout) { if (MTAPI_INFINITE < timeout) {
embb_time_t current_time; embb_time_t current_time;
embb_time_now(&current_time); embb_time_now(&current_time);
if (embb_time_compare(&current_time, &start_time) < 0) {
/* time has moved backwards, maybe a wraparound or jitter
move end_time backward to avoid endeless loop */
start_time = current_time;
embb_time_in(&end_time, &wait_duration);
}
if (embb_time_compare(&current_time, &end_time) > 0) { if (embb_time_compare(&current_time, &end_time) > 0) {
/* timeout! */ /* timeout! */
return MTAPI_FALSE; return MTAPI_FALSE;
......
...@@ -54,7 +54,8 @@ mtapi_boolean_t embb_mtapi_thread_context_initialize_with_node_worker_and_core( ...@@ -54,7 +54,8 @@ mtapi_boolean_t embb_mtapi_thread_context_initialize_with_node_worker_and_core(
that->core_num = core_num; that->core_num = core_num;
that->priorities = node->attributes.max_priorities; that->priorities = node->attributes.max_priorities;
that->is_initialized = MTAPI_FALSE; that->is_initialized = MTAPI_FALSE;
that->is_main_thread = (worker_index == 0) ? node->attributes.reuse_main_thread : MTAPI_FALSE; that->is_main_thread = (worker_index == 0) ?
node->attributes.reuse_main_thread : MTAPI_FALSE;
embb_atomic_store_int(&that->run, 0); embb_atomic_store_int(&that->run, 0);
that->queue = (embb_mtapi_task_queue_t**)embb_mtapi_alloc_allocate( that->queue = (embb_mtapi_task_queue_t**)embb_mtapi_alloc_allocate(
......
...@@ -10,6 +10,9 @@ else() ...@@ -10,6 +10,9 @@ else()
set(MTAPI_CPP_AUTOMATIC_INITIALIZE 0) set(MTAPI_CPP_AUTOMATIC_INITIALIZE 0)
endif() endif()
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)
GroupSourcesMSVC(include) GroupSourcesMSVC(include)
...@@ -18,6 +21,7 @@ GroupSourcesMSVC(test) ...@@ -18,6 +21,7 @@ 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
...@@ -38,3 +42,8 @@ endif() ...@@ -38,3 +42,8 @@ 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(TARGETS embb_mtapi_cpp DESTINATION lib) install(TARGETS embb_mtapi_cpp DESTINATION lib)
if (MSVC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/embb_mtapi_cpp.pdb
DESTINATION lib
CONFIGURATIONS Debug)
endif()
...@@ -43,60 +43,26 @@ class Action { ...@@ -43,60 +43,26 @@ class Action {
public: public:
/** /**
* Constructs an Action. * Constructs an Action.
* The Action object will be invalid.
*/ */
Action( Action() {
mtapi_job_id_t job_id, /**< Job ID the Action belongs to */ handle_.id = 0;
mtapi_action_function_t func, /**< The action function */ handle_.tag = 0;
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());
} }
/** Action(Action const & other) : handle_(other.handle_) {
* Constructs an Action. // empty
*/
Action(
mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
mtapi_action_function_t func, /**< The action function */
const void * node_local_data, /**< Node local data available to all
Tasks using this Action */
mtapi_size_t node_local_data_size /**< Size of node local data */
) {
Create(job_id, func, node_local_data, node_local_data_size,
MTAPI_DEFAULT_ACTION_ATTRIBUTES);
}
/**
* Constructs an Action.
*/
Action(
mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
mtapi_action_function_t func, /**< The action function */
ActionAttributes const & attributes
/**< Attributes of the Action */
) {
Create(job_id, func, MTAPI_NULL, 0, &attributes.GetInternal());
} }
/** Action & operator=(Action const & other) {
* Constructs an Action. handle_ = other.handle_;
*/ return *this;
Action(
mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
mtapi_action_function_t func /**< The action function */
) {
Create(job_id, func, MTAPI_NULL, 0, MTAPI_DEFAULT_ACTION_ATTRIBUTES);
} }
/** /**
* Destroys an Action. * Deletes an Action.
*/ */
~Action() { void Delete() {
mtapi_action_delete(handle_, MTAPI_INFINITE, MTAPI_NULL); mtapi_action_delete(handle_, MTAPI_INFINITE, MTAPI_NULL);
} }
...@@ -111,20 +77,20 @@ class Action { ...@@ -111,20 +77,20 @@ class Action {
return handle_; return handle_;
} }
private: friend class Node;
// no default constructor
Action();
// not copyable
Action(Action const & other);
void operator=(Action const & other);
void Create( private:
mtapi_job_id_t job_id, /**
mtapi_action_function_t func, * Constructs an Action.
const void * node_local_data, */
mtapi_size_t node_local_data_size, Action(
mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
mtapi_action_function_t func, /**< The action function */
const void * node_local_data, /**< Node local data available to all
Tasks using this Action */
mtapi_size_t node_local_data_size, /**< Size of node local data */
mtapi_action_attributes_t const * attributes mtapi_action_attributes_t const * attributes
/**< Attributes of the Action */
) { ) {
mtapi_status_t status; mtapi_status_t status;
handle_ = mtapi_action_create(job_id, func, handle_ = mtapi_action_create(job_id, func,
......
...@@ -24,13 +24,14 @@ ...@@ -24,13 +24,14 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef EMBB_TASKS_EXECUTION_POLICY_H_ #ifndef EMBB_MTAPI_EXECUTION_POLICY_H_
#define EMBB_TASKS_EXECUTION_POLICY_H_ #define EMBB_MTAPI_EXECUTION_POLICY_H_
#include <embb/mtapi/c/mtapi.h> #include <embb/mtapi/c/mtapi.h>
#include <embb/mtapi/internal/cmake_config.h>
namespace embb { namespace embb {
namespace tasks { namespace mtapi {
/** /**
* Describes the execution policy of a parallel algorithm. * Describes the execution policy of a parallel algorithm.
...@@ -42,7 +43,7 @@ namespace tasks { ...@@ -42,7 +43,7 @@ namespace tasks {
* 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_TASKS * \ingroup CPP_MTAPI
*/ */
class ExecutionPolicy{ class ExecutionPolicy{
public: public:
...@@ -118,7 +119,7 @@ class ExecutionPolicy{ ...@@ -118,7 +119,7 @@ class ExecutionPolicy{
* *
* \return the affinity * \return the affinity
*/ */
const mtapi_affinity_t &GetAffinity() const; mtapi_affinity_t GetAffinity() const;
/** Returns the priority /** Returns the priority
* *
...@@ -147,7 +148,7 @@ class ExecutionPolicy{ ...@@ -147,7 +148,7 @@ class ExecutionPolicy{
mtapi_uint_t priority_; mtapi_uint_t priority_;
}; };
} // namespace tasks } // namespace mtapi
} // namespace embb } // namespace embb
#endif // EMBB_TASKS_EXECUTION_POLICY_H_ #endif // EMBB_MTAPI_EXECUTION_POLICY_H_
...@@ -51,49 +51,19 @@ namespace mtapi { ...@@ -51,49 +51,19 @@ namespace mtapi {
*/ */
class Group { class Group {
public: public:
/** Group(Group const & other) : handle_(other.handle_) {
* Constructs a Group object with default attributes. // empty
* Requires an initialized Node.
*/
Group() {
Create(MTAPI_GROUP_ID_NONE, MTAPI_DEFAULT_GROUP_ATTRIBUTES);
} }
/** Group & operator=(Group const & other) {
* Constructs a Group object using the given Attributes. handle_ = other.handle_;
* Requires an initialized Node. return *this;
*/
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. * Deletes a Group object.
* Requires an initialized Node.
*/ */
Group( void Delete() {
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 // delete the group, ignore status
mtapi_group_delete(handle_, MTAPI_NULL); mtapi_group_delete(handle_, MTAPI_NULL);
} }
...@@ -194,7 +164,6 @@ class Group { ...@@ -194,7 +164,6 @@ class Group {
) { ) {
mtapi_status_t status; mtapi_status_t status;
mtapi_group_wait_any(handle_, result, timeout, &status); mtapi_group_wait_any(handle_, result, timeout, &status);
needs_delete_ = status != MTAPI_GROUP_COMPLETED;
return status; return status;
} }
...@@ -245,7 +214,6 @@ class Group { ...@@ -245,7 +214,6 @@ class Group {
) { ) {
mtapi_status_t status; mtapi_status_t status;
mtapi_group_wait_all(handle_, timeout, &status); mtapi_group_wait_all(handle_, timeout, &status);
needs_delete_ = status != MTAPI_SUCCESS;
return status; return status;
} }
...@@ -271,21 +239,21 @@ class Group { ...@@ -271,21 +239,21 @@ class Group {
} }
friend class embb::base::Allocation; friend class embb::base::Allocation;
friend class Node;
private: private:
// not copyable /**
Group(Group const & other); * Constructs a Group object with given attributes and ID.
void operator=(Group const & other); * Requires an initialized Node.
*/
void Create( Group(
mtapi_group_id_t group_id, mtapi_group_id_t id, /**< A user defined ID of the Group. */
mtapi_group_attributes_t const * attributes mtapi_group_attributes_t const * attributes
/**< The GroupAttributes to use. */
) { ) {
needs_delete_ = false;
mtapi_status_t status; mtapi_status_t status;
handle_ = mtapi_group_create(group_id, attributes, &status); handle_ = mtapi_group_create(id, attributes, &status);
internal::CheckStatus(status); internal::CheckStatus(status);
needs_delete_ = true;
} }
Task Start( Task Start(
...@@ -307,7 +275,6 @@ class Group { ...@@ -307,7 +275,6 @@ class Group {
} }
mtapi_group_hndl_t handle_; mtapi_group_hndl_t handle_;
bool needs_delete_;
}; };
} // namespace mtapi } // namespace mtapi
......
...@@ -24,8 +24,8 @@ ...@@ -24,8 +24,8 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef EMBB_TASKS_INTERNAL_CMAKE_CONFIG_H_ #ifndef EMBB_MTAPI_INTERNAL_CMAKE_CONFIG_H_
#define EMBB_TASKS_INTERNAL_CMAKE_CONFIG_H_ #define EMBB_MTAPI_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/tasks/internal/. From its current build directory under the path builddir/embb/tasks/internal/. From
...@@ -36,6 +36,6 @@ ...@@ -36,6 +36,6 @@
/** /**
* Is used to enable automatic initialization of the MTAPI node * Is used to enable automatic initialization of the MTAPI node
*/ */
#define TASKS_CPP_AUTOMATIC_INITIALIZE ${TASKS_CPP_AUTOMATIC_INITIALIZE} #define MTAPI_CPP_AUTOMATIC_INITIALIZE ${MTAPI_CPP_AUTOMATIC_INITIALIZE}
#endif // EMBB_TASKS_INTERNAL_CMAKE_CONFIG_H_ #endif // EMBB_MTAPI_INTERNAL_CMAKE_CONFIG_H_
...@@ -50,19 +50,6 @@ class Job { ...@@ -50,19 +50,6 @@ class Job {
} }
/** /**
* 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. * Copies a Job object.
*/ */
Job( Job(
...@@ -91,7 +78,22 @@ class Job { ...@@ -91,7 +78,22 @@ class Job {
return handle_; return handle_;
} }
friend class Node;
private: private:
/**
* 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);
}
mtapi_job_hndl_t handle_; mtapi_job_hndl_t handle_;
}; };
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
* \ingroup CPP * \ingroup CPP
*/ */
#include <embb/mtapi/execution_policy.h>
#include <embb/mtapi/job.h> #include <embb/mtapi/job.h>
#include <embb/mtapi/action.h> #include <embb/mtapi/action.h>
#include <embb/mtapi/group.h> #include <embb/mtapi/group.h>
......
...@@ -28,12 +28,28 @@ ...@@ -28,12 +28,28 @@
#define EMBB_MTAPI_NODE_H_ #define EMBB_MTAPI_NODE_H_
#include <embb/base/memory_allocation.h> #include <embb/base/memory_allocation.h>
#include <embb/base/function.h>
#include <embb/mtapi/c/mtapi.h> #include <embb/mtapi/c/mtapi.h>
#include <embb/mtapi/execution_policy.h>
#include <embb/mtapi/status_exception.h> #include <embb/mtapi/status_exception.h>
#include <embb/mtapi/node_attributes.h> #include <embb/mtapi/node_attributes.h>
#include <embb/mtapi/group.h>
#include <embb/mtapi/queue.h>
#include <embb/mtapi/task.h> #include <embb/mtapi/task.h>
#include <embb/mtapi/task_attributes.h> #include <embb/mtapi/task_attributes.h>
#include <embb/mtapi/job.h> #include <embb/mtapi/job.h>
#include <embb/mtapi/action.h>
#include <embb/mtapi/task_context.h>
#ifdef GetJob
#undef GetJob
#endif
#ifdef MTAPI_CPP_AUTOMATIC_INITIALIZE
#define MTAPI_CPP_AUTOMATIC_DOMAIN_ID 1
#define MTAPI_CPP_AUTOMATIC_NODE_ID 1
#endif
#define EMBB_MTAPI_FUNCTION_JOB_ID 2
namespace embb { namespace embb {
...@@ -52,6 +68,8 @@ namespace mtapi { ...@@ -52,6 +68,8 @@ namespace mtapi {
*/ */
class Node { class Node {
public: public:
typedef embb::base::Function<void, TaskContext &> SMPFunction;
/** /**
* Initializes the runtime singleton using default values: * Initializes the runtime singleton using default values:
* - all available cores will be used * - all available cores will be used
...@@ -69,16 +87,7 @@ class Node { ...@@ -69,16 +87,7 @@ 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.
...@@ -91,15 +100,7 @@ class Node { ...@@ -91,15 +100,7 @@ class Node {
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 */
NodeAttributes const & attributes /**< [in] Attributes to use */ NodeAttributes const & attributes /**< [in] Attributes to use */
) { );
if (IsInitialized()) {
EMBB_THROW(StatusException,
"MTAPI: node was already initialized.");
} else {
node_instance_ = embb::base::Allocation::New<Node>(
domain_id, node_id, attributes);
}
}
/** /**
* Checks if runtime is initialized. * Checks if runtime is initialized.
...@@ -116,29 +117,14 @@ class Node { ...@@ -116,29 +117,14 @@ class Node {
* \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.
...@@ -159,6 +145,67 @@ class Node { ...@@ -159,6 +145,67 @@ class Node {
} }
/** /**
* Returns the number of available queues.
* \return The number of available queues
* \waitfree
*/
mtapi_uint_t GetQueueCount() const {
return queue_count_;
}
/**
* Returns the number of available groups.
* \return The number of available groups
* \waitfree
*/
mtapi_uint_t GetGroupCount() const {
return group_count_;
}
/**
* Returns the number of available tasks.
* \return The number of available tasks
* \waitfree
*/
mtapi_uint_t GetTaskLimit() const {
return task_limit_;
}
/**
* Starts a new Task.
*
* \returns The handle to the started Task.
* \threadsafe
*/
Task Start(
SMPFunction const & func /**< Function to use for the task. */
) {
Job job = GetJob(EMBB_MTAPI_FUNCTION_JOB_ID);
void * res = NULL;
return Start(
job, embb::base::Allocation::New<SMPFunction>(func), res);
}
/**
* Starts a new Task with a given affinity and priority.
*
* \returns The handle to the started Task.
* \threadsafe
*/
Task Start(
SMPFunction const & func, /**< Function to use for the task. */
ExecutionPolicy const & policy /**< Affinity and priority of the
task. */
) {
Job job = GetJob(EMBB_MTAPI_FUNCTION_JOB_ID);
void * res = NULL;
TaskAttributes task_attr;
task_attr.SetPolicy(policy);
return Start(
job, embb::base::Allocation::New<SMPFunction>(func), res, task_attr);
}
/**
* Starts a new Task. * Starts a new Task.
* *
* \returns The handle to the started Task. * \returns The handle to the started Task.
...@@ -238,6 +285,119 @@ class Node { ...@@ -238,6 +285,119 @@ class Node {
MTAPI_DEFAULT_TASK_ATTRIBUTES); MTAPI_DEFAULT_TASK_ATTRIBUTES);
} }
Job GetJob(mtapi_job_id_t job_id) {
return Job(job_id, domain_id_);
}
Job GetJob(mtapi_job_id_t job_id, mtapi_domain_t domain_id) {
return Job(job_id, domain_id);
}
/**
* Constructs an Action.
*/
Action CreateAction(
mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
mtapi_action_function_t func, /**< The action function */
const void * node_local_data, /**< Node local data available to all
Tasks using this Action */
mtapi_size_t node_local_data_size, /**< Size of node local data */
ActionAttributes const & attributes
/**< Attributes of the Action */
) {
return Action(job_id, func, node_local_data, node_local_data_size,
&attributes.GetInternal());
}
/**
* Constructs an Action.
*/
Action CreateAction(
mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
mtapi_action_function_t func, /**< The action function */
const void * node_local_data, /**< Node local data available to all
Tasks using this Action */
mtapi_size_t node_local_data_size /**< Size of node local data */
) {
return Action(job_id, func, node_local_data, node_local_data_size,
MTAPI_DEFAULT_ACTION_ATTRIBUTES);
}
/**
* Constructs an Action.
*/
Action CreateAction(
mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
mtapi_action_function_t func, /**< The action function */
ActionAttributes const & attributes
/**< Attributes of the Action */
) {
return Action(job_id, func, MTAPI_NULL, 0, &attributes.GetInternal());
}
/**
* Constructs an Action.
*/
Action CreateAction(
mtapi_job_id_t job_id, /**< Job ID the Action belongs to */
mtapi_action_function_t func /**< The action function */
) {
return Action(job_id, func, MTAPI_NULL, 0, MTAPI_DEFAULT_ACTION_ATTRIBUTES);
}
/**
* Constructs a Group object with default attributes.
*/
Group CreateGroup() {
return Group(MTAPI_GROUP_ID_NONE, MTAPI_DEFAULT_GROUP_ATTRIBUTES);
}
/**
* Constructs a Group object with default attributes and the given ID.
*/
Group CreateGroup(
mtapi_group_id_t id /**< A user defined ID of the Group. */
) {
return Group(id, MTAPI_DEFAULT_GROUP_ATTRIBUTES);
}
/**
* Constructs a Group object using the given Attributes.
*/
Group CreateGroup(
GroupAttributes const & group_attr) {
return Group(MTAPI_GROUP_ID_NONE, &group_attr.GetInternal());
}
/**
* Constructs a Group object with given attributes and ID.
*/
Group CreateGroup(
mtapi_group_id_t id, /**< A user defined ID of the Group. */
GroupAttributes const & group_attr /**< The GroupAttributes to use. */
) {
return Group(id, &group_attr.GetInternal());
}
/**
* Constructs a Queue with the given Job and default attributes.
*/
Queue CreateQueue(
Job & job /**< The Job to use for the Queue. */
) {
return Queue(MTAPI_QUEUE_ID_NONE, job, MTAPI_DEFAULT_QUEUE_ATTRIBUTES);
}
/**
* Constructs a Queue with the given Job and QueueAttributes.
*/
Queue CreateQueue(
Job const & job, /**< The Job to use for the Queue. */
QueueAttributes const & attr /**< The attributes to use. */
) {
return Queue(MTAPI_QUEUE_ID_NONE, job, &attr.GetInternal());
}
friend class embb::base::Allocation; friend class embb::base::Allocation;
private: private:
...@@ -251,21 +411,17 @@ class Node { ...@@ -251,21 +411,17 @@ class Node {
NodeAttributes const & attr) { NodeAttributes const & attr) {
mtapi_status_t status; mtapi_status_t status;
mtapi_info_t info; mtapi_info_t info;
queue_count_ = attr.GetInternal().max_queues;
group_count_ = attr.GetInternal().max_groups;
task_limit_ = attr.GetInternal().max_tasks;
mtapi_initialize(domain_id, node_id, &attr.GetInternal(), &info, &status); mtapi_initialize(domain_id, node_id, &attr.GetInternal(), &info, &status);
needs_finalize_ = status == MTAPI_SUCCESS;
internal::CheckStatus(status); internal::CheckStatus(status);
core_count_ = info.hardware_concurrency; core_count_ = info.hardware_concurrency;
worker_thread_count_ = embb_core_set_count( worker_thread_count_ = embb_core_set_count(
&attr.GetInternal().core_affinity); &attr.GetInternal().core_affinity);
}
~Node() { domain_id_ = domain_id;
if (needs_finalize_) {
mtapi_status_t status;
mtapi_finalize(&status);
internal::CheckStatus(status);
}
} }
Task Start( Task Start(
...@@ -286,11 +442,31 @@ class Node { ...@@ -286,11 +442,31 @@ class Node {
return Task(task_hndl); return Task(task_hndl);
} }
static void ActionFunction(
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) {
TaskContext task_context(context);
embb::base::Function<void, TaskContext &> * func =
reinterpret_cast<embb::base::Function<void, TaskContext &>*>(
const_cast<void*>(args));
(*func)(task_context);
embb::base::Allocation::Delete(func);
}
static embb::mtapi::Node * node_instance_; static embb::mtapi::Node * node_instance_;
mtapi_domain_t domain_id_;
mtapi_uint_t core_count_; mtapi_uint_t core_count_;
mtapi_uint_t worker_thread_count_; mtapi_uint_t worker_thread_count_;
bool needs_finalize_; mtapi_uint_t queue_count_;
mtapi_uint_t group_count_;
mtapi_uint_t task_limit_;
Action function_action_;
}; };
} // namespace mtapi } // namespace mtapi
......
...@@ -51,31 +51,19 @@ namespace mtapi { ...@@ -51,31 +51,19 @@ namespace mtapi {
*/ */
class Queue { class Queue {
public: public:
/** Queue(Queue const & other) : handle_(other.handle_) {
* Constructs a Queue with the given Job and default attributes. // empty
* 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);
} }
/** Queue & operator=(Queue const & other) {
* Constructs a Queue with the given Job and QueueAttributes. handle_ = other.handle_;
* Requires an initialized Node. return *this;
*/
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. * Deletes a Queue object.
*/ */
~Queue() { void Delete() {
mtapi_queue_delete(handle_, MTAPI_INFINITE, MTAPI_NULL); mtapi_queue_delete(handle_, MTAPI_INFINITE, MTAPI_NULL);
} }
...@@ -272,16 +260,13 @@ class Queue { ...@@ -272,16 +260,13 @@ class Queue {
} }
friend class embb::base::Allocation; friend class embb::base::Allocation;
friend class Node;
private: private:
// no default constructor // no default constructor
Queue(); Queue();
// not copyable Queue(
Queue(Queue const & other);
void operator=(Queue const & other);
void Create(
mtapi_queue_id_t queue_id, mtapi_queue_id_t queue_id,
Job const & job, Job const & job,
mtapi_queue_attributes_t const * attributes mtapi_queue_attributes_t const * attributes
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <embb/mtapi/c/mtapi.h> #include <embb/mtapi/c/mtapi.h>
#include <embb/mtapi/internal/check_status.h> #include <embb/mtapi/internal/check_status.h>
#include <embb/mtapi/execution_policy.h>
namespace embb { namespace embb {
namespace mtapi { namespace mtapi {
...@@ -86,6 +87,31 @@ class TaskAttributes { ...@@ -86,6 +87,31 @@ class TaskAttributes {
} }
/** /**
* Sets the affinity of a Task.
* The affinity influences on which worker the Task will be executed.
*
* \returns Reference to this object.
* \notthreadsafe
*/
TaskAttributes & SetAffinity(
mtapi_affinity_t affinity /**< The affinity to set. */
) {
mtapi_status_t status;
mtapi_taskattr_set(&attributes_, MTAPI_TASK_AFFINITY,
&affinity, sizeof(affinity), &status);
internal::CheckStatus(status);
return *this;
}
TaskAttributes & SetPolicy(
ExecutionPolicy const & policy
) {
SetPriority(policy.GetPriority());
SetAffinity(policy.GetAffinity());
return *this;
}
/**
* Sets the number of instances in a Task. * Sets the number of instances in a Task.
* The Task will be launched \c instances times. In the action function, * 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 number of instances and the current instance can be queried from
......
...@@ -24,18 +24,18 @@ ...@@ -24,18 +24,18 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <embb/tasks/execution_policy.h> #include <embb/mtapi/execution_policy.h>
#include <embb/tasks/tasks.h> #include <embb/mtapi/node.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 tasks { namespace mtapi {
ExecutionPolicy::ExecutionPolicy() : ExecutionPolicy::ExecutionPolicy() :
priority_(DefaultPriority) { priority_(DefaultPriority) {
#if TASKS_CPP_AUTOMATIC_INITIALIZE #if MTAPI_CPP_AUTOMATIC_INITIALIZE
Node::GetInstance(); // MTAPI has to be initialized Node::GetInstance(); // MTAPI has to be initialized
#endif #endif
mtapi_status_t status; mtapi_status_t status;
...@@ -48,7 +48,7 @@ ExecutionPolicy::ExecutionPolicy() : ...@@ -48,7 +48,7 @@ ExecutionPolicy::ExecutionPolicy() :
ExecutionPolicy::ExecutionPolicy(bool initial_affinity, mtapi_uint_t priority) ExecutionPolicy::ExecutionPolicy(bool initial_affinity, mtapi_uint_t priority)
:priority_(priority) { :priority_(priority) {
#if TASKS_CPP_AUTOMATIC_INITIALIZE #if MTAPI_CPP_AUTOMATIC_INITIALIZE
Node::GetInstance(); // MTAPI has to be initialized Node::GetInstance(); // MTAPI has to be initialized
#endif #endif
mtapi_status_t status; mtapi_status_t status;
...@@ -62,7 +62,7 @@ ExecutionPolicy::ExecutionPolicy(bool initial_affinity, mtapi_uint_t priority) ...@@ -62,7 +62,7 @@ ExecutionPolicy::ExecutionPolicy(bool initial_affinity, mtapi_uint_t priority)
ExecutionPolicy::ExecutionPolicy(mtapi_uint_t priority) ExecutionPolicy::ExecutionPolicy(mtapi_uint_t priority)
:priority_(priority) { :priority_(priority) {
#if TASKS_CPP_AUTOMATIC_INITIALIZE #if MTAPI_CPP_AUTOMATIC_INITIALIZE
Node::GetInstance(); // MTAPI has to be initialized Node::GetInstance(); // MTAPI has to be initialized
#endif #endif
mtapi_status_t status; mtapi_status_t status;
...@@ -75,7 +75,7 @@ ExecutionPolicy::ExecutionPolicy(mtapi_uint_t priority) ...@@ -75,7 +75,7 @@ ExecutionPolicy::ExecutionPolicy(mtapi_uint_t priority)
ExecutionPolicy::ExecutionPolicy(bool initial_affinity) ExecutionPolicy::ExecutionPolicy(bool initial_affinity)
:priority_(DefaultPriority) { :priority_(DefaultPriority) {
#if TASKS_CPP_AUTOMATIC_INITIALIZE #if MTAPI_CPP_AUTOMATIC_INITIALIZE
Node::GetInstance(); // MTAPI has to be initialized Node::GetInstance(); // MTAPI has to be initialized
#endif #endif
mtapi_status_t status; mtapi_status_t status;
...@@ -110,7 +110,7 @@ unsigned int ExecutionPolicy::GetCoreCount() const { ...@@ -110,7 +110,7 @@ unsigned int ExecutionPolicy::GetCoreCount() const {
return embb_bitset_count(&affinity_); return embb_bitset_count(&affinity_);
} }
const mtapi_affinity_t &ExecutionPolicy::GetAffinity() const { mtapi_affinity_t ExecutionPolicy::GetAffinity() const {
return affinity_; return affinity_;
} }
...@@ -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 tasks } // namespace mtapi
} // namespace embb } // namespace embb
...@@ -25,11 +25,79 @@ ...@@ -25,11 +25,79 @@
*/ */
#include <embb/mtapi/node.h> #include <embb/mtapi/node.h>
#include <embb/base/c/mutex.h>
namespace embb { namespace embb {
namespace mtapi { namespace mtapi {
embb::mtapi::Node * embb::mtapi::Node::node_instance_ = NULL; embb::mtapi::Node * embb::mtapi::Node::node_instance_ = NULL;
#if MTAPI_CPP_AUTOMATIC_INITIALIZE
static embb_spinlock_t init_mutex = { { 0 } };
#endif
void Node::Initialize(
mtapi_domain_t domain_id,
mtapi_node_t node_id
) {
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);
node_instance_->function_action_ =
node_instance_->CreateAction(EMBB_MTAPI_FUNCTION_JOB_ID, ActionFunction);
}
}
void Node::Initialize(
mtapi_domain_t domain_id,
mtapi_node_t node_id,
NodeAttributes const & attributes
) {
if (IsInitialized()) {
EMBB_THROW(StatusException,
"MTAPI: node was already initialized.");
} else {
node_instance_ = embb::base::Allocation::New<Node>(
domain_id, node_id, attributes);
}
}
Node & Node::GetInstance() {
#if MTAPI_CPP_AUTOMATIC_INITIALIZE
if (!IsInitialized()) {
embb_spin_lock(&init_mutex);
if (!IsInitialized()) {
Node::Initialize(
MTAPI_CPP_AUTOMATIC_DOMAIN_ID, MTAPI_CPP_AUTOMATIC_NODE_ID);
atexit(Node::Finalize);
}
embb_spin_unlock(&init_mutex);
}
return *node_instance_;
#else
if (IsInitialized()) {
return *node_instance_;
} else {
EMBB_THROW(StatusException,
"MTAPI: node is not initialized.");
}
#endif
}
void Node::Finalize() {
if (IsInitialized()) {
node_instance_->function_action_.Delete();
mtapi_finalize(MTAPI_NULL);
embb::base::Allocation::Delete(node_instance_);
node_instance_ = NULL;
} else {
EMBB_THROW(StatusException,
"MTAPI: node is not initialized.");
}
}
} // namespace mtapi } // namespace mtapi
} // namespace embb } // namespace embb
...@@ -61,12 +61,14 @@ GroupTest::GroupTest() { ...@@ -61,12 +61,14 @@ GroupTest::GroupTest() {
void GroupTest::TestBasic() { void GroupTest::TestBasic() {
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::Job job = node.GetJob(JOB_TEST_GROUP);
embb::mtapi::Action action(JOB_TEST_GROUP, testGroupAction); embb::mtapi::Action action =
node.CreateAction(JOB_TEST_GROUP, testGroupAction);
{ {
embb::mtapi::Group group; embb::mtapi::Group group = node.CreateGroup();
result_example_t buffer[TASK_COUNT]; result_example_t buffer[TASK_COUNT];
for (int ii = 0; ii < TASK_COUNT; ii++) { for (int ii = 0; ii < TASK_COUNT; ii++) {
...@@ -86,7 +88,7 @@ void GroupTest::TestBasic() { ...@@ -86,7 +88,7 @@ void GroupTest::TestBasic() {
} }
{ {
embb::mtapi::Group group; embb::mtapi::Group group = node.CreateGroup();
result_example_t buffer[TASK_COUNT]; result_example_t buffer[TASK_COUNT];
for (int ii = 0; ii < 4; ii++) { for (int ii = 0; ii < 4; ii++) {
...@@ -107,6 +109,7 @@ void GroupTest::TestBasic() { ...@@ -107,6 +109,7 @@ void GroupTest::TestBasic() {
PT_EXPECT_EQ(status, MTAPI_GROUP_COMPLETED); PT_EXPECT_EQ(status, MTAPI_GROUP_COMPLETED);
} }
action.Delete();
embb::mtapi::Node::Finalize(); embb::mtapi::Node::Finalize();
PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u); PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u);
......
...@@ -54,13 +54,14 @@ QueueTest::QueueTest() { ...@@ -54,13 +54,14 @@ QueueTest::QueueTest() {
void QueueTest::TestBasic() { void QueueTest::TestBasic() {
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::Job job = node.GetJob(JOB_TEST_QUEUE);
embb::mtapi::Action action(JOB_TEST_QUEUE, testQueueAction, embb::mtapi::Action action = node.CreateAction(
MTAPI_NULL, 0); JOB_TEST_QUEUE, testQueueAction, MTAPI_NULL, 0);
{ {
embb::mtapi::Queue queue(job); embb::mtapi::Queue queue = node.CreateQueue(job);
int result = 0; int result = 0;
embb::mtapi::Task task = queue.Enqueue<void, int>(MTAPI_NULL, &result); embb::mtapi::Task task = queue.Enqueue<void, int>(MTAPI_NULL, &result);
...@@ -72,6 +73,7 @@ void QueueTest::TestBasic() { ...@@ -72,6 +73,7 @@ void QueueTest::TestBasic() {
PT_EXPECT_EQ(result, 1); PT_EXPECT_EQ(result, 1);
} }
action.Delete();
embb::mtapi::Node::Finalize(); embb::mtapi::Node::Finalize();
PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u); PT_EXPECT_EQ(embb_get_bytes_allocated(), 0u);
......
...@@ -96,9 +96,10 @@ void TaskTest::TestBasic() { ...@@ -96,9 +96,10 @@ void TaskTest::TestBasic() {
} }
{ {
embb::mtapi::Job job_task(JOB_TEST_TASK, THIS_DOMAIN_ID); embb::mtapi::Job job_task = node.GetJob(JOB_TEST_TASK);
embb::mtapi::Action action_task(JOB_TEST_TASK, testTaskAction); embb::mtapi::Action action_task =
node.CreateAction(JOB_TEST_TASK, testTaskAction);
std::string test; std::string test;
embb::mtapi::Task task = node.Start(job_task, "simple", &test); embb::mtapi::Task task = node.Start(job_task, "simple", &test);
...@@ -106,19 +107,23 @@ void TaskTest::TestBasic() { ...@@ -106,19 +107,23 @@ void TaskTest::TestBasic() {
mtapi_status_t status = task.Wait(); mtapi_status_t status = task.Wait();
PT_EXPECT_EQ(status, MTAPI_SUCCESS); PT_EXPECT_EQ(status, MTAPI_SUCCESS);
PT_EXPECT(test == "simple"); PT_EXPECT(test == "simple");
action_task.Delete();
} }
{ {
embb::mtapi::Job job_error(JOB_TEST_ERROR, THIS_DOMAIN_ID); embb::mtapi::Job job_error = node.GetJob(JOB_TEST_ERROR);
embb::mtapi::Action action_error(JOB_TEST_ERROR, testErrorAction, embb::mtapi::Action action_error =
embb::mtapi::ActionAttributes()); node.CreateAction(JOB_TEST_ERROR, testErrorAction);
std::string test; std::string test;
embb::mtapi::Task task = node.Start(job_error, "simple", &test); embb::mtapi::Task task = node.Start(job_error, "simple", &test);
testDoSomethingElse(); testDoSomethingElse();
mtapi_status_t status = task.Wait(); mtapi_status_t status = task.Wait();
PT_EXPECT_EQ(status, MTAPI_ERR_ACTION_FAILED); PT_EXPECT_EQ(status, MTAPI_ERR_ACTION_FAILED);
action_error.Delete();
} }
embb::mtapi::Node::Finalize(); embb::mtapi::Node::Finalize();
......
...@@ -45,3 +45,8 @@ endif() ...@@ -45,3 +45,8 @@ 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(TARGETS embb_mtapi_network_c DESTINATION lib) install(TARGETS embb_mtapi_network_c DESTINATION lib)
if (MSVC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/embb_mtapi_network_c.pdb
DESTINATION lib
CONFIGURATIONS Debug)
endif()
...@@ -45,3 +45,8 @@ endif() ...@@ -45,3 +45,8 @@ 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(TARGETS embb_mtapi_opencl_c DESTINATION lib) install(TARGETS embb_mtapi_opencl_c DESTINATION lib)
if (MSVC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/embb_mtapi_opencl_c.pdb
DESTINATION lib
CONFIGURATIONS Debug)
endif()
...@@ -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 mtapi_plugins_c/mtapi_network_c mtapi_plugins_c/mtapi_opencl_c base_cpp mtapi_cpp tasks_cpp algorithms_cpp containers_cpp dataflow_cpp for project in base_c mtapi_c mtapi_plugins_c/mtapi_network_c mtapi_plugins_c/mtapi_opencl_c base_cpp mtapi_cpp algorithms_cpp containers_cpp dataflow_cpp
do do
echo "-> Doing project: $project" echo "-> Doing project: $project"
dir=$d/$project dir=$d/$project
......
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)
set(TASKS_CPP_AUTOMATIC_INITIALIZE 1)
else()
set(TASKS_CPP_AUTOMATIC_INITIALIZE 0)
endif()
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-2016, 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_
/*
* Copyright (c) 2014-2016, 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_CONTINUATION_H_
#define EMBB_TASKS_CONTINUATION_H_
#include <embb/mtapi/c/mtapi.h>
#include <embb/tasks/task_context.h>
#include <embb/tasks/action.h>
#include <embb/tasks/task.h>
namespace embb {
namespace tasks {
/**
* Helper struct for Continuation.
*
* \ingroup CPP_TASKS
*/
struct ContinuationStage;
/**
* A Continuation encapsulates a chain of \link Action Actions \endlink to be
* executed consecutively.
*
* \ingroup CPP_TASKS
*/
class Continuation {
public:
/**
* Copies a Continuation.
*/
Continuation(
Continuation const & cont /**< [in] The Continuation to copy. */
);
/**
* Destroys a Continuation.
*/
~Continuation();
/**
* Appends an Action to the Continuation chain.
* \returns A reference to this Continuation chain.
* \notthreadsafe
*/
Continuation & Then(
Action action /**< [in] The Action to append to the
continuation */
);
/**
* Runs the Continuation chain.
* \returns The Task representing the Continuation chain.
* \notthreadsafe
*/
Task Spawn();
/**
* Runs the Continuation chain with the specified execution_policy.
* \returns The Task representing the Continuation chain.
* \notthreadsafe
*/
Task Spawn(
ExecutionPolicy execution_policy /**< [in] The execution policy to use */
);
friend class Node;
private:
explicit Continuation(Action action);
void ExecuteContinuation(TaskContext & context);
ContinuationStage * first_;
ContinuationStage * last_;
};
} // namespace tasks
} // namespace embb
#endif // EMBB_TASKS_CONTINUATION_H_
/*
* Copyright (c) 2014-2016, 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_
/*
* Copyright (c) 2014-2016, 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/base/mutex.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 queues.
* \return The number of available queues
* \waitfree
*/
mtapi_uint_t GetQueueCount() const {
return queue_count_;
}
/**
* Returns the number of available groups.
* \return The number of available groups
* \waitfree
*/
mtapi_uint_t GetGroupCount() const {
return group_count_;
}
/**
* Returns the number of available tasks.
* \return The number of available tasks
* \waitfree
*/
mtapi_uint_t GetTaskLimit() const {
return task_limit_;
}
/**
* 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 queue_count_;
mtapi_uint_t group_count_;
mtapi_uint_t task_limit_;
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_;
embb::base::Spinlock queue_lock_;
embb::base::Spinlock group_lock_;
};
} // namespace tasks
} // namespace embb
#endif // EMBB_TASKS_NODE_H_
/*
* Copyright (c) 2014-2016, 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-2016, 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_
/*
* Copyright (c) 2014-2016, 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_CONTEXT_H_
#define EMBB_TASKS_TASK_CONTEXT_H_
#include <embb/mtapi/c/mtapi.h>
namespace embb {
namespace tasks {
/**
* Provides information about the status of the currently running Task.
*
* \ingroup CPP_TASKS
*/
class TaskContext {
public:
/**
* Queries whether the Task running in the TaskContext should finish.
* \return \c true if the Task should finish, otherwise \c false
* \notthreadsafe
*/
bool ShouldCancel();
/**
* 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 GetCurrentCoreNumber();
/**
* 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() */
);
friend class Node;
private:
explicit TaskContext(mtapi_task_context_t * task_context);
mtapi_task_context_t * context_;
};
} // namespace tasks
} // namespace embb
#endif // EMBB_TASKS_TASK_CONTEXT_H_
/*
* Copyright (c) 2014-2016, 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_
/*
* Copyright (c) 2014-2016, 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 <cstddef>
#include <embb/base/memory_allocation.h>
#include <embb/base/function.h>
#include <embb/tasks/tasks.h>
#include <continuationstage.h>
namespace embb {
namespace tasks {
Continuation::Continuation(Action action) {
first_ = last_ = embb::base::Allocation::New<ContinuationStage>();
first_->action = action;
first_->next = NULL;
}
Continuation::Continuation(Continuation const & cont)
: first_(cont.first_)
, last_(cont.last_) {
}
Continuation::~Continuation() {
}
void Continuation::ExecuteContinuation(TaskContext &) {
ContinuationStage * stage = first_;
Node & node = Node::GetInstance();
while (NULL != stage) {
Task task = node.Spawn(stage->action);
task.Wait(MTAPI_INFINITE);
stage = stage->next;
}
// delete stages
stage = first_;
while (NULL != stage) {
ContinuationStage * next = stage->next;
embb::base::Allocation::Delete(stage);
stage = next;
}
}
Continuation & Continuation::Then(Action action) {
ContinuationStage * cur = embb::base::Allocation::New<ContinuationStage>();
cur->action = action;
cur->next = NULL;
last_->next = cur;
last_ = cur;
return *this;
}
Task Continuation::Spawn() {
return Spawn(ExecutionPolicy());
}
Task Continuation::Spawn(ExecutionPolicy execution_policy) {
Node & node = Node::GetInstance();
return node.Spawn(
Action(
embb::base::MakeFunction(*this, &Continuation::ExecuteContinuation),
ExecutionPolicy(execution_policy)));
}
} // namespace tasks
} // namespace embb
/*
* Copyright (c) 2014-2016, 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_SRC_CONTINUATIONSTAGE_H_
#define TASKS_CPP_SRC_CONTINUATIONSTAGE_H_
#include <embb/tasks/tasks.h>
namespace embb {
namespace tasks {
struct ContinuationStage {
Action action;
ContinuationStage * next;
};
} // namespace tasks
} // namespace embb
#endif // TASKS_CPP_SRC_CONTINUATIONSTAGE_H_
/*
* Copyright (c) 2014-2016, 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 <cstring>
#include <cassert>
#include <embb/base/exceptions.h>
#include <embb/tasks/tasks.h>
namespace embb {
namespace tasks {
Group::Group() {
Create();
}
Group::~Group() {
mtapi_status_t status;
mtapi_group_delete(handle_, &status);
assert(MTAPI_SUCCESS == status);
}
void Group::Create() {
mtapi_status_t status;
handle_ = mtapi_group_create(MTAPI_GROUP_ID_NONE, MTAPI_NULL, &status);
if (MTAPI_SUCCESS != status) {
EMBB_THROW(embb::base::ErrorException,
"mtapi::Group could not be constructed");
}
}
Task Group::Spawn(Action action) {
return Task(action, handle_);
}
Task Group::Spawn(mtapi_task_id_t id, Action action) {
return Task(id, action, handle_);
}
mtapi_status_t Group::WaitAny(mtapi_timeout_t timeout) {
mtapi_status_t status;
mtapi_group_wait_any(handle_, MTAPI_NULL, timeout, &status);
if (MTAPI_GROUP_COMPLETED == status) {
// group has been deleted, so recreate it for simplicity
Create();
}
return status;
}
mtapi_status_t Group::WaitAny(
mtapi_timeout_t timeout,
mtapi_task_id_t & result) {
mtapi_status_t status;
void * res;
mtapi_group_wait_any(handle_, &res, timeout, &status);
memcpy(&result, &res, sizeof(result));
if (MTAPI_GROUP_COMPLETED == status) {
// group has been deleted, so recreate it for simplicity
Create();
}
return status;
}
mtapi_status_t Group::WaitAll(mtapi_timeout_t timeout) {
mtapi_status_t status;
mtapi_group_wait_all(handle_, timeout, &status);
// group has been deleted, so recreate it for simplicity
Create();
return status;
}
} // namespace tasks
} // namespace embb
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