Commit 0f7719f9 by Tobias Fuchs

Merge remote-tracking branch 'origin/master' into embb390_algorithms

Conflicts:
	algorithms_cpp/test/count_test.cc
	base_c/include/embb/base/c/internal/platform.h
	base_c/test/alloc_test.h
	base_c/test/condition_var_test.h
	base_c/test/core_set_test.h
	base_c/test/counter_test.h
	base_c/test/duration_test.h
	base_c/test/thread_index_test.h
	base_c/test/thread_specific_storage_test.h
	base_c/test/thread_test.h
	base_c/test/time_test.h
	base_cpp/include/embb/base/core_set.h
	base_cpp/include/embb/base/duration.h
	base_cpp/include/embb/base/exceptions.h
	base_cpp/include/embb/base/internal/duration-inl.h
	base_cpp/include/embb/base/internal/mutex-inl.h
	base_cpp/include/embb/base/internal/thread-inl.h
	base_cpp/include/embb/base/internal/thread_closures.h
	base_cpp/include/embb/base/internal/thread_specific_storage-inl.h
	base_cpp/include/embb/base/thread_specific_storage.h
	base_cpp/include/embb/base/time.h
	base_cpp/test/thread_test.h
	dataflow_cpp/include/embb/dataflow/internal/inputs.h
parents ca032936 001ddc73
...@@ -54,6 +54,7 @@ option(BUILD_EXAMPLES "Specify whether examples should be built" OFF) ...@@ -54,6 +54,7 @@ option(BUILD_EXAMPLES "Specify whether examples should be built" OFF)
option(USE_EXCEPTIONS "Specify whether exceptions should be activated in C++" ON) option(USE_EXCEPTIONS "Specify whether exceptions should be activated in C++" ON)
option(INSTALL_DOCS "Specify whether Doxygen docs should be installed" ON) option(INSTALL_DOCS "Specify whether Doxygen docs should be installed" ON)
option(WARNINGS_ARE_ERRORS "Specify whether warnings should be treated as errors" OFF) option(WARNINGS_ARE_ERRORS "Specify whether warnings should be treated as errors" OFF)
option(USE_AUTOMATIC_INITIALIZATION "Specify whether the MTAPI C++ interface, algorithms and dataflow should automatically intialize the MTAPI node if no explicit initialization is present" ON)
## LOCAL INSTALLATION OF SUBPROJECT BINARIES ## LOCAL INSTALLATION OF SUBPROJECT BINARIES
# #
......
...@@ -173,6 +173,10 @@ specified on build file generation. When exceptions are turned off, an error ...@@ -173,6 +173,10 @@ specified on build file generation. When exceptions are turned off, an error
message is emitted and the program aborts in case of an exception within EMB². message is emitted and the program aborts in case of an exception within EMB².
To disable exceptions, add the option -DUSE_EXCEPTIONS=OFF. To disable exceptions, add the option -DUSE_EXCEPTIONS=OFF.
Similarly, automatic initialization of the task scheduler by the MTAPI C++
interface can be disabled with -DUSE_AUTOMATIC_INITIALIZATION=OFF. This way,
unexpected delays after startup can be avoided, e.g. for timing measurements.
The tutorial of EMB² comes with example source files in doc/examples/. These The tutorial of EMB² comes with example source files in doc/examples/. These
can be built with the other source files using CMake option -DBUILD_EXAMPLES=ON can be built with the other source files using CMake option -DBUILD_EXAMPLES=ON
in the generation step. Note, however, that the examples use C++11 features and in the generation step. Note, however, that the examples use C++11 features and
...@@ -184,6 +188,10 @@ For a Linux Debug build with exception handling, type ...@@ -184,6 +188,10 @@ For a Linux Debug build with exception handling, type
cmake -G "Unix Makefiles" .. -DCMAKE_BUILD_TYPE=Debug cmake -G "Unix Makefiles" .. -DCMAKE_BUILD_TYPE=Debug
For a default Linux build without automatic MTAPI C++ initialization, type
cmake .. -DUSE_AUTOMATIC_INITIALIZATION=OFF
For a Windows build (VS 2013, x86) without exception handling, type For a Windows build (VS 2013, x86) without exception handling, type
cmake -G "Visual Studio 12" .. -DUSE_EXCEPTIONS=OFF cmake -G "Visual Studio 12" .. -DUSE_EXCEPTIONS=OFF
...@@ -350,6 +358,16 @@ Please use these defines for new platform specific code. If additional defines ...@@ -350,6 +358,16 @@ Please use these defines for new platform specific code. If additional defines
are needed, they can be defined in the config.h or cmake_config.h.in files. are needed, they can be defined in the config.h or cmake_config.h.in files.
Important Notes
---------------
- The MTAPI C++ interface supports automatic initialization, which allows for
easy usage of the MTAPI C++, Algorithms, and Dataflow components. For
performance measurements, explicit initialization is strongly recommended
since the measurements will otherwise include the initialization time of
MTAPI.
Links Links
----- -----
......
...@@ -17,7 +17,8 @@ include_directories(${EMBB_ALGORITHMS_CPP_INCLUDE_DIRS} ...@@ -17,7 +17,8 @@ include_directories(${EMBB_ALGORITHMS_CPP_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../base_cpp/include ${CMAKE_CURRENT_BINARY_DIR}/../base_cpp/include
${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_c/include ${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_c/include
${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_cpp/include) ${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_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})
......
...@@ -67,6 +67,7 @@ int compute1_() { ...@@ -67,6 +67,7 @@ int compute1_() {
PT_MAIN("Algorithms") { PT_MAIN("Algorithms") {
embb::mtapi::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);
PT_RUN(ReduceTest); PT_RUN(ReduceTest);
......
...@@ -61,6 +61,9 @@ void ThreadTest::TestStartingAndJoining() { ...@@ -61,6 +61,9 @@ void ThreadTest::TestStartingAndJoining() {
embb::base::Thread thread2(ThreadTest::StaticThreadStartArg1, arg1); embb::base::Thread thread2(ThreadTest::StaticThreadStartArg1, arg1);
double arg2 = 3.0; double arg2 = 3.0;
embb::base::Thread thread3(ThreadTest::StaticThreadStartArg2, arg1, arg2); embb::base::Thread thread3(ThreadTest::StaticThreadStartArg2, arg1, arg2);
embb::base::Thread::ID thread3id;
thread3id = thread3.GetID();
PT_EXPECT_EQ(thread3id, thread3.GetID());
// Non-static member start methods with functor // Non-static member start methods with functor
MemberStart<void(ThreadTest::*)()> start4(&ThreadTest::ThreadStart, this); MemberStart<void(ThreadTest::*)()> start4(&ThreadTest::ThreadStart, this);
......
...@@ -17,8 +17,8 @@ include_directories(${EMBB_DATAFLOW_CPP_INCLUDE_DIRS} ...@@ -17,8 +17,8 @@ include_directories(${EMBB_DATAFLOW_CPP_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../base_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../base_cpp/include ${CMAKE_CURRENT_BINARY_DIR}/../base_cpp/include
${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_c/include ${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_c/include
${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../mtapi_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_mtapi_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)
......
...@@ -11,6 +11,7 @@ include_directories( ...@@ -11,6 +11,7 @@ include_directories(
${CMAKE_CURRENT_BINARY_DIR}/../../base_cpp/include ${CMAKE_CURRENT_BINARY_DIR}/../../base_cpp/include
${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_c/include ${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_c/include
${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_cpp/include ${CMAKE_CURRENT_SOURCE_DIR}/../../mtapi_cpp/include
${CMAKE_CURRENT_BINARY_DIR}/../../mtapi_cpp/include
${CMAKE_CURRENT_SOURCE_DIR}/../../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
......
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <embb/base/c/log.h> #include <embb/base/c/log.h>
#define MTAPI_CHECK_STATUS(status) \ #define MTAPI_CHECK_STATUS(status) \
if (MTAPI_SUCCESS != status) { \ if (MTAPI_SUCCESS != status) { \
embb_log_error("MTAPI C Example", "...error %d\n\n", status); \ printf("...error %d\n\n", status); \
abort(); \ exit(status); \
} }
\chapter{Algorithms} \chapter{Algorithms}
\label{cha:algorithms} \label{cha:algorithms}
The \emph{Algorithms} building block of \embb provides high-level constructs for typical parallelization tasks. They are aligned to the functions provided by the C++ Standard Library, but contain additional functionality typical for embedded systems such as task priorities. Although the algorithms can be used in a black-box way, it is good to have a basic understanding of their implementation: The algorithms split computations to be performed in parallel into tasks which are executed by the MTAPI task scheduler (cf. Chapter~\ref{cha:mtapi}). For that purpose, the tasks are stored in queues and mapped to a fixed number of worker threads at runtime. Since MTAPI allocates the necessary data structures during initialization, the maximum number of tasks in flight is fixed. In case one of the algorithms exceeds this limit, an exception is thrown. The \emph{Algorithms} building block of \embb provides high-level constructs for typical parallelization tasks. They are aligned to the functions provided by the C++ Standard Library, but contain additional functionality typical for embedded systems such as task priorities. Although the algorithms can be used in a black-box way, it is good to have a basic understanding of their implementation: The algorithms split computations to be performed in parallel into tasks which are executed by the MTAPI task scheduler (cf. Chapter~\ref{cha:mtapi}). For that purpose, the tasks are stored in queues and mapped to a fixed number of worker threads at runtime. Since MTAPI allocates the necessary data structures during initialization, the maximum number of tasks in flight is fixed. In case one of the algorithms exceeds this limit, an exception is thrown.
\emph{\textbf{Note:} The \emph{Algorithms} building block is implemented using the MTAPI C++ interface. By calling \lstinline|embb::mtapi::Node::Initialize| task and other limits can be customized. Explicit initialization also eliminates unexpected delays when measuring performance. See Section~\ref{sec:mtapi_cpp_interface} for details.}
In the following, we look at parallel function invocation (Section~\ref{sec:algorithms_invoke}), sorting (Section~\ref{sec:algorithms_sorting}), counting (Section~\ref{sec:algorithms_counting}), foreach loops (Section~\ref{sec:algorithms_foreach}), reductions (Section~\ref{sec:algorithms_reductions}), and prefix computations (Section~\ref{sec:algorithms_prefix}). In the following, we look at parallel function invocation (Section~\ref{sec:algorithms_invoke}), sorting (Section~\ref{sec:algorithms_sorting}), counting (Section~\ref{sec:algorithms_counting}), foreach loops (Section~\ref{sec:algorithms_foreach}), reductions (Section~\ref{sec:algorithms_reductions}), and prefix computations (Section~\ref{sec:algorithms_prefix}).
......
...@@ -18,6 +18,8 @@ With the \emph{Dataflow} building block, \embb provides generic skeletons for th ...@@ -18,6 +18,8 @@ With the \emph{Dataflow} building block, \embb provides generic skeletons for th
% \item dynamic control of data streams (conditional execution) % \item dynamic control of data streams (conditional execution)
%\end{itemize} %\end{itemize}
\emph{\textbf{Note:} The \emph{Dataflow} building block is implemented using the MTAPI C++ interface. Since MTAPI does not allocate memory after initialization, the number of tasks and other resources are limited. By calling \lstinline|embb::mtapi::Node::Initialize| these limits can be customized. Explicit initialization also eliminates unexpected delays when measuring performance. See Section~\ref{sec:mtapi_cpp_interface} for details.}
\section{Linear Pipelines} \section{Linear Pipelines}
Before we go into detail, we demonstrate the basic concepts of this building block by means of a simple application which finds and replaces strings in a file. Let us start with the sequential implementation. The program shown in Listing~\ref{lst:replace_seq} reads a file line by line and replaces each occurrence of a given string with a new string. The main part consists of the \lstinline|while| loop which performs three steps: Before we go into detail, we demonstrate the basic concepts of this building block by means of a simple application which finds and replaces strings in a file. Let us start with the sequential implementation. The program shown in Listing~\ref{lst:replace_seq} reads a file line by line and replaces each occurrence of a given string with a new string. The main part consists of the \lstinline|while| loop which performs three steps:
...@@ -138,7 +140,7 @@ is used to construct the sink: ...@@ -138,7 +140,7 @@ is used to construct the sink:
% %
%In order to avoid that the received string is overwritten accidentally, the parameter \lstinline|str| corresponding to the input port of \lstinline|write| must be constant.\\ %In order to avoid that the received string is overwritten accidentally, the parameter \lstinline|str| corresponding to the input port of \lstinline|write| must be constant.\\
\emph{Note: If you parallelize your own application using \embb and your compiler emits a lengthy error message containing lots of templates, it is very likely that for at least one process, the ports and their directions do not match the signature of the given function.} \emph{\textbf{Note:} If you parallelize your own application using \embb and your compiler emits a lengthy error message containing lots of templates, it is very likely that for at least one process, the ports and their directions do not match the signature of the given function.}
The network needs to know about the processes declared above, so we add them to our network: The network needs to know about the processes declared above, so we add them to our network:
% %
......
...@@ -160,6 +160,8 @@ First, the node instance needs to be obtained. If the node is not initialized ye ...@@ -160,6 +160,8 @@ First, the node instance needs to be obtained. If the node is not initialized ye
% %
\\\inputlisting{../examples/mtapi/mtapi_cpp_get_node-snippet.h} \\\inputlisting{../examples/mtapi/mtapi_cpp_get_node-snippet.h}
% %
\emph{\textbf{Note:} Automatic initialization allows for easy usage of the \emph{Algorithms} and \emph{Dataflow} building blocks. For performance measurements however, explicit initialization by calling \lstinline|embb::mtapi::Node::Initialize| is imperative since the measurements will otherwise include the initialization time of MTAPI.}
Checking the arguments and the result buffer is not necessary, since everything is safely typed. However, the terminating condition of the recursion still needs to be checked: Checking the arguments and the result buffer is not necessary, since everything is safely typed. However, the terminating condition of the recursion still needs to be checked:
% %
\\\inputlisting{../examples/mtapi/mtapi_terminating_condition-snippet.h} \\\inputlisting{../examples/mtapi/mtapi_terminating_condition-snippet.h}
...@@ -190,3 +192,5 @@ The root task can be started using \lstinline|embb::mtapi::Node::Spawn()| direct ...@@ -190,3 +192,5 @@ The root task can be started using \lstinline|embb::mtapi::Node::Spawn()| direct
\\\inputlisting{../examples/mtapi/mtapi_cpp_start_task-snippet.h} \\\inputlisting{../examples/mtapi/mtapi_cpp_start_task-snippet.h}
% %
Again, the started task has to be waited for (using \lstinline|embb::mtapi::Task::Wait()|) before the result can be returned. The runtime is shut down automatically in an \lstinline|atexit()| handler. Again, the started task has to be waited for (using \lstinline|embb::mtapi::Task::Wait()|) before the result can be returned. The runtime is shut down automatically in an \lstinline|atexit()| handler.
\emph{\textbf{Note:} If the node was initialized explicitly by calling \lstinline|embb::mtapi::Node::Initialize|, the runtime must also be shut down explicitly by calling \lstinline|embb::mtapi::Node::Finalize|.}
...@@ -1050,8 +1050,14 @@ void mtapi_nodeattr_set( ...@@ -1050,8 +1050,14 @@ void mtapi_nodeattr_set(
* *
* \c attributes is a pointer to a node attributes object that was previously * \c attributes is a pointer to a node attributes object that was previously
* prepared with mtapi_nodeattr_init() and mtapi_nodeattr_set(). If * prepared with mtapi_nodeattr_init() and mtapi_nodeattr_set(). If
* \c attributes is \c MTAPI_NULL, then implementation-defined default * \c attributes is \c MTAPI_NULL, then the following default
* attributes will be used. * attributes will be used:
* - 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.
* *
* On success, \c *status is set to \c MTAPI_SUCCESS. On error, \c *status is * On success, \c *status is set to \c MTAPI_SUCCESS. On error, \c *status is
* set to the appropriate error defined below. * set to the appropriate error defined below.
......
...@@ -412,6 +412,7 @@ void mtapi_action_enable( ...@@ -412,6 +412,7 @@ void mtapi_action_enable(
embb_mtapi_action_pool_get_storage_for_handle( embb_mtapi_action_pool_get_storage_for_handle(
node->action_pool, action); node->action_pool, action);
local_action->enabled = MTAPI_TRUE; local_action->enabled = MTAPI_TRUE;
local_status = MTAPI_SUCCESS;
} else { } else {
local_status = MTAPI_ERR_ACTION_INVALID; local_status = MTAPI_ERR_ACTION_INVALID;
} }
......
...@@ -37,12 +37,12 @@ void embb_mtapi_id_pool_initialize( ...@@ -37,12 +37,12 @@ void embb_mtapi_id_pool_initialize(
that->capacity = capacity; that->capacity = capacity;
that->id_buffer = (mtapi_uint_t*) that->id_buffer = (mtapi_uint_t*)
embb_mtapi_alloc_allocate(sizeof(mtapi_uint_t)*(capacity)); embb_mtapi_alloc_allocate(sizeof(mtapi_uint_t)*(capacity + 1));
that->id_buffer[0] = EMBB_MTAPI_IDPOOL_INVALID_ID; that->id_buffer[0] = EMBB_MTAPI_IDPOOL_INVALID_ID;
for (ii = 1; ii < capacity; ii++) { for (ii = 1; ii <= capacity; ii++) {
that->id_buffer[ii] = ii; that->id_buffer[ii] = ii;
} }
that->ids_available = capacity - 1; that->ids_available = capacity;
that->put_id_position = 0; that->put_id_position = 0;
that->get_id_position = 1; that->get_id_position = 1;
embb_mtapi_spinlock_initialize(&that->lock); embb_mtapi_spinlock_initialize(&that->lock);
......
...@@ -40,9 +40,9 @@ ...@@ -40,9 +40,9 @@
mtapi_boolean_t embb_mtapi_job_initialize_list(embb_mtapi_node_t * node) { mtapi_boolean_t embb_mtapi_job_initialize_list(embb_mtapi_node_t * node) {
node->job_list = (embb_mtapi_job_t*)embb_mtapi_alloc_allocate( node->job_list = (embb_mtapi_job_t*)embb_mtapi_alloc_allocate(
sizeof(embb_mtapi_job_t)*node->attributes.max_jobs); sizeof(embb_mtapi_job_t)*(node->attributes.max_jobs + 1));
mtapi_uint_t ii; mtapi_uint_t ii;
for (ii = 0; ii < node->attributes.max_jobs; ii++) { for (ii = 0; ii <= node->attributes.max_jobs; ii++) {
embb_mtapi_job_initialize( embb_mtapi_job_initialize(
&node->job_list[ii], node->attributes.max_actions_per_job); &node->job_list[ii], node->attributes.max_actions_per_job);
node->job_list[ii].handle.id = ii; node->job_list[ii].handle.id = ii;
...@@ -53,7 +53,7 @@ mtapi_boolean_t embb_mtapi_job_initialize_list(embb_mtapi_node_t * node) { ...@@ -53,7 +53,7 @@ mtapi_boolean_t embb_mtapi_job_initialize_list(embb_mtapi_node_t * node) {
void embb_mtapi_job_finalize_list(embb_mtapi_node_t * node) { void embb_mtapi_job_finalize_list(embb_mtapi_node_t * node) {
mtapi_uint_t ii; mtapi_uint_t ii;
for (ii = 0; ii < node->attributes.max_jobs; ii++) { for (ii = 0; ii <= node->attributes.max_jobs; ii++) {
embb_mtapi_job_finalize(&node->job_list[ii]); embb_mtapi_job_finalize(&node->job_list[ii]);
node->job_list[ii].handle.id = 0; node->job_list[ii].handle.id = 0;
} }
...@@ -69,7 +69,7 @@ mtapi_boolean_t embb_mtapi_job_is_handle_valid( ...@@ -69,7 +69,7 @@ mtapi_boolean_t embb_mtapi_job_is_handle_valid(
mtapi_job_hndl_t handle) { mtapi_job_hndl_t handle) {
assert(MTAPI_NULL != node); assert(MTAPI_NULL != node);
return ((0 < handle.id) && return ((0 < handle.id) &&
(handle.id < node->attributes.max_jobs) && (handle.id <= node->attributes.max_jobs) &&
(node->job_list[handle.id].handle.tag == handle.tag)) ? (node->job_list[handle.id].handle.tag == handle.tag)) ?
MTAPI_TRUE : MTAPI_FALSE; MTAPI_TRUE : MTAPI_FALSE;
} }
...@@ -87,7 +87,7 @@ mtapi_boolean_t embb_mtapi_job_is_id_valid( ...@@ -87,7 +87,7 @@ mtapi_boolean_t embb_mtapi_job_is_id_valid(
embb_mtapi_node_t * node, embb_mtapi_node_t * node,
mtapi_job_id_t id) { mtapi_job_id_t id) {
assert(MTAPI_NULL != node); assert(MTAPI_NULL != node);
return ((0 < id) && (id < node->attributes.max_jobs)) ? return ((0 < id) && (id <= node->attributes.max_jobs)) ?
MTAPI_TRUE : MTAPI_FALSE; MTAPI_TRUE : MTAPI_FALSE;
} }
......
...@@ -60,8 +60,8 @@ mtapi_boolean_t embb_mtapi_##TYPE##_pool_initialize( \ ...@@ -60,8 +60,8 @@ mtapi_boolean_t embb_mtapi_##TYPE##_pool_initialize( \
assert(MTAPI_NULL != that); \ assert(MTAPI_NULL != that); \
embb_mtapi_id_pool_initialize(&that->id_pool, capacity); \ embb_mtapi_id_pool_initialize(&that->id_pool, capacity); \
that->storage = (embb_mtapi_##TYPE##_t*)embb_mtapi_alloc_allocate( \ that->storage = (embb_mtapi_##TYPE##_t*)embb_mtapi_alloc_allocate( \
sizeof(embb_mtapi_##TYPE##_t)*capacity); \ sizeof(embb_mtapi_##TYPE##_t)*(capacity + 1)); \
for (ii = 0; ii < capacity; ii++) { \ for (ii = 0; ii <= capacity; ii++) { \
that->storage[ii].handle.id = EMBB_MTAPI_IDPOOL_INVALID_ID; \ that->storage[ii].handle.id = EMBB_MTAPI_IDPOOL_INVALID_ID; \
that->storage[ii].handle.tag = 0; \ that->storage[ii].handle.tag = 0; \
} \ } \
...@@ -102,7 +102,7 @@ mtapi_boolean_t embb_mtapi_##TYPE##_pool_is_handle_valid( \ ...@@ -102,7 +102,7 @@ mtapi_boolean_t embb_mtapi_##TYPE##_pool_is_handle_valid( \
mtapi_##TYPE##_hndl_t handle) { \ mtapi_##TYPE##_hndl_t handle) { \
assert(MTAPI_NULL != that); \ assert(MTAPI_NULL != that); \
return ((0 < handle.id) && \ return ((0 < handle.id) && \
(handle.id < that->id_pool.capacity) && \ (handle.id <= that->id_pool.capacity) && \
(that->storage[handle.id].handle.tag == handle.tag)) ? \ (that->storage[handle.id].handle.tag == handle.tag)) ? \
MTAPI_TRUE : MTAPI_FALSE; \ MTAPI_TRUE : MTAPI_FALSE; \
} \ } \
......
...@@ -200,6 +200,7 @@ mtapi_queue_hndl_t mtapi_queue_create( ...@@ -200,6 +200,7 @@ mtapi_queue_hndl_t mtapi_queue_create(
queue->queue_id = queue_id; queue->queue_id = queue_id;
queue_hndl = queue->handle; queue_hndl = queue->handle;
} else { } else {
embb_mtapi_queue_pool_deallocate(node->queue_pool, queue);
local_status = MTAPI_ERR_JOB_INVALID; local_status = MTAPI_ERR_JOB_INVALID;
} }
} else { } else {
......
/*
* Copyright (c) 2014-2015, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MTAPI_C_TEST_EMBB_MTAPI_TEST_ERROR_H_
#define MTAPI_C_TEST_EMBB_MTAPI_TEST_ERROR_H_
#include <partest/partest.h>
class ErrorTest : public partest::TestCase {
public:
ErrorTest();
private:
void TestBasic();
};
#endif // MTAPI_C_TEST_EMBB_MTAPI_TEST_ERROR_H_
...@@ -52,7 +52,7 @@ static void testQueueAction( ...@@ -52,7 +52,7 @@ static void testQueueAction(
} }
embb_mtapi_log_info("testQueueAction %d called from worker %d...\n", embb_mtapi_log_info("testQueueAction %d called from worker %d...\n",
workload_id, core_num); workload_id, core_num);
EMBB_UNUSED_IN_RELEASE(workload_id); EMBB_UNUSED(workload_id);
} }
static void testDoSomethingElse() { static void testDoSomethingElse() {
......
...@@ -50,7 +50,7 @@ static void testTaskAction( ...@@ -50,7 +50,7 @@ static void testTaskAction(
} }
embb_mtapi_log_info("testTaskAction %d called from worker %d...\n", embb_mtapi_log_info("testTaskAction %d called from worker %d...\n",
*reinterpret_cast<const int*>(args), core_num); *reinterpret_cast<const int*>(args), core_num);
EMBB_UNUSED_IN_RELEASE(args); EMBB_UNUSED(args);
} }
static void testDoSomethingElse() { static void testDoSomethingElse() {
......
...@@ -34,10 +34,12 @@ ...@@ -34,10 +34,12 @@
#include <embb_mtapi_test_task.h> #include <embb_mtapi_test_task.h>
#include <embb_mtapi_test_group.h> #include <embb_mtapi_test_group.h>
#include <embb_mtapi_test_queue.h> #include <embb_mtapi_test_queue.h>
#include <embb_mtapi_test_error.h>
PT_MAIN("MTAPI C") { PT_MAIN("MTAPI C") {
embb_log_set_log_level(EMBB_LOG_LEVEL_NONE); embb_log_set_log_level(EMBB_LOG_LEVEL_NONE);
PT_RUN(ErrorTest);
PT_RUN(InitFinalizeTest); PT_RUN(InitFinalizeTest);
PT_RUN(TaskTest); PT_RUN(TaskTest);
PT_RUN(GroupTest); PT_RUN(GroupTest);
......
...@@ -4,6 +4,18 @@ file(GLOB_RECURSE EMBB_MTAPI_CPP_SOURCES "src/*.cc" "src/*.h") ...@@ -4,6 +4,18 @@ file(GLOB_RECURSE EMBB_MTAPI_CPP_SOURCES "src/*.cc" "src/*.h")
file(GLOB_RECURSE EMBB_MTAPI_CPP_HEADERS "include/*.h") file(GLOB_RECURSE EMBB_MTAPI_CPP_HEADERS "include/*.h")
file(GLOB_RECURSE EMBB_MTAPI_CPP_TEST_SOURCES "test/*.cc" "test/*.h") file(GLOB_RECURSE EMBB_MTAPI_CPP_TEST_SOURCES "test/*.cc" "test/*.h")
if (USE_AUTOMATIC_INITIALIZATION STREQUAL ON)
message("-- Automatic initialization enabled (default)")
set(MTAPI_CPP_AUTOMATIC_INITIALIZE 1)
else()
set(MTAPI_CPP_AUTOMATIC_INITIALIZE 0)
message("-- Automatic initialization disabled")
endif()
message(" (set with command line option -DUSE_AUTOMATIC_INITIALIZATION=ON/OFF)")
configure_file("include/embb/mtapi/internal/cmake_config.h.in"
"include/embb/mtapi/internal/cmake_config.h")
# Execute the GroupSources macro # Execute the GroupSources macro
include(${CMAKE_SOURCE_DIR}/CMakeCommon/GroupSourcesMSVC.cmake) include(${CMAKE_SOURCE_DIR}/CMakeCommon/GroupSourcesMSVC.cmake)
GroupSourcesMSVC(include) GroupSourcesMSVC(include)
...@@ -12,12 +24,12 @@ GroupSourcesMSVC(test) ...@@ -12,12 +24,12 @@ 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
${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)
)
add_library (embb_mtapi_cpp ${EMBB_MTAPI_CPP_SOURCES} ${EMBB_MTAPI_CPP_HEADERS}) add_library (embb_mtapi_cpp ${EMBB_MTAPI_CPP_SOURCES} ${EMBB_MTAPI_CPP_HEADERS})
target_link_libraries(embb_mtapi_cpp embb_mtapi_c) target_link_libraries(embb_mtapi_cpp embb_mtapi_c)
...@@ -32,4 +44,6 @@ endif() ...@@ -32,4 +44,6 @@ endif()
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
DESTINATION include FILES_MATCHING PATTERN "*.h") DESTINATION include FILES_MATCHING PATTERN "*.h")
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
DESTINATION include FILES_MATCHING PATTERN "*.h")
install(TARGETS embb_mtapi_cpp DESTINATION lib) install(TARGETS embb_mtapi_cpp DESTINATION lib)
/*
* Copyright (c) 2014-2015, Siemens AG. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EMBB_MTAPI_INTERNAL_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
its current build directory under the path builddir/embb/mtapi/internal/. From
there, the cmake_config.h can be included as usual using
#include <embb/mtapi/internal/cmake_config.h>
*/
/**
* Is used to enable automatic initialization of the MTAPI node
*/
#define MTAPI_CPP_AUTOMATIC_INITIALIZE ${MTAPI_CPP_AUTOMATIC_INITIALIZE}
#endif // EMBB_MTAPI_INTERNAL_CMAKE_CONFIG_H_
...@@ -35,8 +35,9 @@ ...@@ -35,8 +35,9 @@
* \ingroup CPP * \ingroup CPP
*/ */
#include <embb/mtapi/internal/cmake_config.h>
#define MTAPI_CPP_TASK_JOB 1 #define MTAPI_CPP_TASK_JOB 1
#define MTAPI_CPP_AUTOMATIC_INITIALIZE 1
#if MTAPI_CPP_AUTOMATIC_INITIALIZE #if MTAPI_CPP_AUTOMATIC_INITIALIZE
#define MTAPI_CPP_AUTOMATIC_DOMAIN_ID 1 #define MTAPI_CPP_AUTOMATIC_DOMAIN_ID 1
#define MTAPI_CPP_AUTOMATIC_NODE_ID 1 #define MTAPI_CPP_AUTOMATIC_NODE_ID 1
......
...@@ -60,7 +60,7 @@ class Node { ...@@ -60,7 +60,7 @@ class Node {
* - maximum number of groups is 128 * - maximum number of groups is 128
* - maximum number of queues is 16 * - maximum number of queues is 16
* - maximum queue capacity is 1024 * - maximum queue capacity is 1024
* - maximum number of priorites is 4. * - maximum number of priorities is 4.
* *
* \notthreadsafe * \notthreadsafe
* \throws ErrorException if the singleton was already initialized or the * \throws ErrorException if the singleton was already initialized or the
......
...@@ -39,7 +39,9 @@ ...@@ -39,7 +39,9 @@
namespace { namespace {
static embb::mtapi::Node * node_instance = NULL; static embb::mtapi::Node * node_instance = NULL;
#if MTAPI_CPP_AUTOMATIC_INITIALIZE
static embb::base::Mutex init_mutex; static embb::base::Mutex init_mutex;
#endif
} }
......
...@@ -77,6 +77,18 @@ void TaskTest::TestBasic() { ...@@ -77,6 +77,18 @@ void TaskTest::TestBasic() {
embb::mtapi::Node & node = embb::mtapi::Node::GetInstance(); embb::mtapi::Node & node = embb::mtapi::Node::GetInstance();
embb::mtapi::ExecutionPolicy policy(false);
PT_EXPECT_EQ(policy.GetAffinity(), 0u);
PT_EXPECT_EQ(policy.GetPriority(), 0u);
policy.AddWorker(0u);
PT_EXPECT_EQ(policy.GetAffinity(), 1u);
policy.AddWorker(1u);
PT_EXPECT_EQ(policy.GetAffinity(), 3u);
policy.RemoveWorker(0u);
PT_EXPECT_EQ(policy.GetAffinity(), 2u);
PT_EXPECT_EQ(policy.IsSetWorker(0), false);
PT_EXPECT_EQ(policy.IsSetWorker(1), true);
std::string test; std::string test;
embb::mtapi::Task task = node.Spawn( embb::mtapi::Task task = node.Spawn(
embb::base::Bind( embb::base::Bind(
......
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