diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index abda1e140f..daa3a57855 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2021-2024 Intel Corporation +# Copyright (c) 2021-2025 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -366,3 +366,53 @@ jobs: -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCMAKE_CXX_COMPILER=${{ matrix.cxx_compiler }} ` -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DTBB_CPF=${{ matrix.preview }} -DTBB_TEST=OFF -DTBB_EXAMPLES=ON .. cmake --build . -v --target light_test_examples + + linux-doc-examples-testing: + name: doc_examples_${{ matrix.os }}_${{ matrix.cxx_compiler }}_cxx${{ matrix.std }}_${{ matrix.build_type }} + runs-on: ['${{ matrix.os }}'] + timeout-minutes: 10 + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + c_compiler: gcc + cxx_compiler: g++ + std: 20 + build_type: relwithdebinfo + steps: + - uses: actions/checkout@v4 + - name: Test doc examples + run: | + mkdir build && cd build + cmake -DCMAKE_CXX_STANDARD=${{ matrix.std }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type}} \ + -DCMAKE_CXX_COMPILER=${{ matrix.cxx_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} \ + -DTBB_TEST=OFF -DTBB_DOC_EXAMPLES=ON .. + cmake --build . -v --parallel --target build-doc-examples + ctest -C ${{ matrix.build_type }} --timeout ${env:TEST_TIMEOUT} --output-on-failure -L doc-examples + + windows-doc-examples-testing: + name: doc_examples_${{ matrix.os }}_${{ matrix.cxx_compiler }}_cxx${{ matrix.std }}_${{ matrix.build_type }} + runs-on: ['${{ matrix.os }}'] + timeout-minutes: 10 + strategy: + fail-fast: false + matrix: + include: + - os: windows-2022 + generator: "Visual Studio 17 2022" + c_compiler: cl + cxx_compiler: cl + std: 20 + build_type: relwithdebinfo + steps: + - uses: actions/checkout@v4 + - name: Test doc examples + run: | + mkdir build + cd build + cmake -G "${{ matrix.generator }}" -A x64 -DCMAKE_CXX_STANDARD=${{ matrix.std }} ` + -DCMAKE_BUILD_TYPE=${{ matrix.build_type}} -DCMAKE_CXX_COMPILER=${{ matrix.cxx_compiler }} ` + -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DTBB_TEST=OFF -DTBB_DOC_EXAMPLES=ON .. + cmake --build . --config ${{ matrix.build_type }} -v --parallel --target build-doc-examples + ctest -C ${{ matrix.build_type }} --timeout ${env:TEST_TIMEOUT} --output-on-failure -L doc-examples diff --git a/CMakeLists.txt b/CMakeLists.txt index 12273b3e36..cdb89fd22b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -330,6 +330,18 @@ if (TBB_EXAMPLES) add_subdirectory(examples) endif() + +if (TBB_DOC_EXAMPLES) + set(TBB_DOC_EXAMPLES_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/doc/main/examples_testing") + if (NOT EXISTS ${TBB_DOC_EXAMPLES_DIRECTORY}) + message(FATAL_ERROR "Documentation examples are not found while testing was enabled") + else() + message(STATUS "Enabling testing for examples from documentation") + enable_testing() + add_subdirectory(${TBB_DOC_EXAMPLES_DIRECTORY}) + endif() +endif() + if (TBB_BENCH) if (NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/benchmark) message(FATAL_ERROR "Benchmarks are not supported yet") diff --git a/doc/main/examples_testing/CMakeLists.txt b/doc/main/examples_testing/CMakeLists.txt new file mode 100644 index 0000000000..133132c58c --- /dev/null +++ b/doc/main/examples_testing/CMakeLists.txt @@ -0,0 +1,41 @@ +# Copyright (c) 2025 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.11) +project(doc_examples_testing LANGUAGES CXX) + +set(_reference_examples_path "${CMAKE_CURRENT_SOURCE_DIR}/../reference/examples") +set(_userguide_examples_path "${CMAKE_CURRENT_SOURCE_DIR}/../tbb_userguide/examples") + +add_custom_target(build-doc-examples + COMMENT "Build oneTBB documentation samples") +set(doc_examples_test_label "doc-examples") + +macro(add_doc_example _doc_example_path) + get_filename_component(_doc_example_name "${_doc_example_path}" NAME_WE) + add_executable(${_doc_example_name} EXCLUDE_FROM_ALL "${_doc_example_path}") + + add_dependencies(${_doc_example_name} TBB::tbb TBB::tbbmalloc TBB::tbbmalloc_proxy) + target_link_libraries(${_doc_example_name} TBB::tbb TBB::tbbmalloc TBB::tbbmalloc_proxy) + + add_dependencies(build-doc-examples ${_doc_example_name}) + add_test(NAME ${_doc_example_name} COMMAND ${_doc_example_name}) + set_tests_properties(${_doc_example_name} PROPERTIES LABELS "${doc_examples_test_label}") +endmacro() + +file(GLOB_RECURSE DOC_EXAMPLES_LIST "${_reference_examples_path}/*.cpp" "${_userguide_examples_path}/*.cpp") + +foreach(_doc_example_path IN LISTS DOC_EXAMPLES_LIST) + add_doc_example(${_doc_example_path}) +endforeach() diff --git a/doc/main/reference/custom_mutex_chmap.rst b/doc/main/reference/custom_mutex_chmap.rst index acf502e66d..f3abbe7f64 100644 --- a/doc/main/reference/custom_mutex_chmap.rst +++ b/doc/main/reference/custom_mutex_chmap.rst @@ -67,92 +67,7 @@ and ``oneapi::tbb::rw_mutex`` meet the requirements above. The example below demonstrates how to wrap ``std::shared_mutex`` (C++17) to meet the requirements of `ReaderWriterMutex` and how to customize ``concurrent_hash_map`` to use this mutex. -.. code:: cpp - - #define TBB_PREVIEW_CONCURRENT_HASH_MAP_EXTENSIONS 1 - #include "oneapi/tbb/concurrent_hash_map.h" - #include - - class SharedMutexWrapper { - public: - // ReaderWriterMutex requirements - - static constexpr bool is_rw_mutex = true; - static constexpr bool is_recursive_mutex = false; - static constexpr bool is_fair_mutex = false; - - class scoped_lock { - public: - scoped_lock() : my_mutex_ptr(nullptr), my_writer_flag(false) {} - scoped_lock(SharedMutexWrapper& mutex, bool write = true) - : my_mutex_ptr(&mutex), my_writer_flag(write) - { - if (my_writer_flag) { - my_mutex_ptr->my_mutex.lock(); - } else { - my_mutex_ptr->my_mutex.lock_shared(); - } - } - - ~scoped_lock() { - if (my_mutex_ptr) release(); - } - - void acquire(SharedMutexWrapper& mutex, bool write = true) { - if (my_mutex_ptr) release(); - - my_mutex_ptr = &mutex; - my_writer_flag = write; - - if (my_writer_flag) { - my_mutex_ptr->my_mutex.lock(); - } else { - my_mutex_ptr->my_mutex.lock_shared(); - } - } - - void release() { - if (my_writer_flag) { - my_mutex_ptr->my_mutex.unlock(); - } else { - my_mutex_ptr->my_mutex.unlock_shared(); - } - } - - bool upgrade_to_writer() { - // std::shared_mutex does not have the upgrade/downgrade parallel_for_each_semantics - if (my_writer_flag) return true; // Already a writer - - my_mutex_ptr->my_mutex.unlock_shared(); - my_mutex_ptr->my_mutex.lock(); - return false; // The lock was reacquired - } - - bool downgrade_to_reader() { - if (!my_writer_flag) return true; // Already a reader - - my_mutex_ptr->my_mutex.unlock(); - my_mutex_ptr->my_mutex.lock_shared(); - return false; - } - - bool is_writer() const { - return my_writer_flag; - } - - private: - SharedMutexWrapper* my_mutex_ptr; - bool my_writer_flag; - }; - private: - std::shared_mutex my_mutex; - }; // struct SharedMutexWrapper - - int main() { - using map_type = oneapi::tbb::concurrent_hash_map, - oneapi::tbb::tbb_allocator>, - SharedMutexWrapper>; - - map_type map; // This object will use SharedMutexWrapper for thread safety of insert/find/erase operations - } +.. literalinclude:: ./examples/custom_mutex_chmap_example.cpp + :language: c++ + :start-after: /*begin_custom_mutex_chmap_example*/ + :end-before: /*end_custom_mutex_chmap_example*/ diff --git a/doc/main/reference/examples/custom_mutex_chmap_example.cpp b/doc/main/reference/examples/custom_mutex_chmap_example.cpp new file mode 100644 index 0000000000..b136241a76 --- /dev/null +++ b/doc/main/reference/examples/custom_mutex_chmap_example.cpp @@ -0,0 +1,129 @@ +/* + Copyright (c) 2025 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#if __cplusplus >= 201703L + +/*begin_custom_mutex_chmap_example*/ +#define TBB_PREVIEW_CONCURRENT_HASH_MAP_EXTENSIONS 1 +#include "oneapi/tbb/concurrent_hash_map.h" +#include + +class SharedMutexWrapper { +public: + // ReaderWriterMutex requirements + + static constexpr bool is_rw_mutex = true; + static constexpr bool is_recursive_mutex = false; + static constexpr bool is_fair_mutex = false; + + class scoped_lock { + public: + scoped_lock() : my_mutex_ptr(nullptr), my_writer_flag(false) {} + scoped_lock(SharedMutexWrapper& mutex, bool write = true) + : my_mutex_ptr(&mutex), my_writer_flag(write) + { + if (my_writer_flag) { + my_mutex_ptr->my_mutex.lock(); + } else { + my_mutex_ptr->my_mutex.lock_shared(); + } + } + + ~scoped_lock() { + if (my_mutex_ptr) release(); + } + + void acquire(SharedMutexWrapper& mutex, bool write = true) { + if (my_mutex_ptr) release(); + + my_mutex_ptr = &mutex; + my_writer_flag = write; + + if (my_writer_flag) { + my_mutex_ptr->my_mutex.lock(); + } else { + my_mutex_ptr->my_mutex.lock_shared(); + } + } + + bool try_acquire(SharedMutexWrapper& mutex, bool write = true) { + if (my_mutex_ptr) release(); + + my_mutex_ptr = &mutex; + + bool result = false; + + if (my_writer_flag) { + result = my_mutex_ptr->my_mutex.try_lock(); + } else { + result = my_mutex_ptr->my_mutex.try_lock_shared(); + } + + if (result) my_writer_flag = write; + return result; + } + + void release() { + if (my_writer_flag) { + my_mutex_ptr->my_mutex.unlock(); + } else { + my_mutex_ptr->my_mutex.unlock_shared(); + } + } + + bool upgrade_to_writer() { + // std::shared_mutex does not have the upgrade/downgrade semantics + if (my_writer_flag) return true; // Already a writer + + my_mutex_ptr->my_mutex.unlock_shared(); + my_mutex_ptr->my_mutex.lock(); + return false; // The lock was reacquired + } + + bool downgrade_to_reader() { + if (!my_writer_flag) return true; // Already a reader + + my_mutex_ptr->my_mutex.unlock(); + my_mutex_ptr->my_mutex.lock_shared(); + return false; + } + + bool is_writer() const { + return my_writer_flag; + } + + private: + SharedMutexWrapper* my_mutex_ptr; + bool my_writer_flag; + }; +private: + std::shared_mutex my_mutex; +}; // struct SharedMutexWrapper + +int main() { + using map_type = oneapi::tbb::concurrent_hash_map, + oneapi::tbb::tbb_allocator>, + SharedMutexWrapper>; + + map_type map; // This object will use SharedMutexWrapper for thread safety of insert/find/erase operations +} +/*end_custom_mutex_chmap_example*/ + +#else // C++17 +// Skip +int main() {} +#endif diff --git a/doc/main/reference/examples/fixed_pool_example.cpp b/doc/main/reference/examples/fixed_pool_example.cpp new file mode 100644 index 0000000000..b39fded234 --- /dev/null +++ b/doc/main/reference/examples/fixed_pool_example.cpp @@ -0,0 +1,28 @@ +/* + Copyright (c) 2025 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/*begin_fixed_pool_example*/ +#define TBB_PREVIEW_MEMORY_POOL 1 +#include "oneapi/tbb/memory_pool.h" + +int main() { + char buf[1024*1024]; + oneapi::tbb::fixed_pool my_pool(buf, 1024*1024); + + void* my_ptr = my_pool.malloc(10); + my_pool.free(my_ptr); +} +/*end_fixed_pool_example*/ diff --git a/doc/main/reference/examples/helpers_for_expressing_graphs_preview_api_example.cpp b/doc/main/reference/examples/helpers_for_expressing_graphs_preview_api_example.cpp new file mode 100644 index 0000000000..6b7eb4144c --- /dev/null +++ b/doc/main/reference/examples/helpers_for_expressing_graphs_preview_api_example.cpp @@ -0,0 +1,54 @@ +/* + Copyright (c) 2025 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#if __cplusplus >= 201703L + +/*begin_helpers_for_expressing_graphs_preview_api_example*/ +#define TBB_PREVIEW_FLOW_GRAPH_FEATURES 1 +#include + +int main() { + using namespace oneapi::tbb::flow; + + graph g; + + function_node doubler(g, unlimited, [](const int& v) { return 2 * v; }); + function_node squarer(g, unlimited, [](const int& v) { return v * v; }); + function_node cuber(g, unlimited, [](const int& v) { return v * v * v; }); + + auto handlers = make_node_set(doubler, squarer, cuber); + + broadcast_node input(precedes(handlers)); + join_node join(follows(handlers)); + + int sum = 0; + function_node summer(follows(join), serial, + [&](const std::tuple& v) { + int sub_sum = std::get<0>(v) + std::get<1>(v) + std::get<2>(v); + sum += sub_sum; + return sub_sum; + }); + + for (int i = 1; i <= 10; ++i) { + input.try_put(i); + } + g.wait_for_all(); +} +/*end_helpers_for_expressing_graphs_preview_api_example*/ +#else +// Skip +int main() {} +#endif diff --git a/doc/main/reference/examples/helpers_for_expressing_graphs_regular_api_example.cpp b/doc/main/reference/examples/helpers_for_expressing_graphs_regular_api_example.cpp new file mode 100644 index 0000000000..d87e7a02d5 --- /dev/null +++ b/doc/main/reference/examples/helpers_for_expressing_graphs_regular_api_example.cpp @@ -0,0 +1,60 @@ +/* + Copyright (c) 2025 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#if __cplusplus >= 201703L + +/*begin_helpers_for_expressing_graphs_preview_api_example*/ +#include + +int main() { + using namespace oneapi::tbb::flow; + + graph g; + + broadcast_node input(g); + + function_node doubler(g, unlimited, [](const int& v) { return 2 * v; }); + function_node squarer(g, unlimited, [](const int& v) { return v * v; }); + function_node cuber(g, unlimited, [](const int& v) { return v * v * v; }); + + join_node> join(g); + + int sum = 0; + function_node summer(g, serial, [&](const std::tuple& v) { + int sub_sum = std::get<0>(v) + std::get<1>(v) + std::get<2>(v); + sum += sub_sum; + return sub_sum; + }); + + make_edge(input, doubler); + make_edge(input, squarer); + make_edge(input, cuber); + make_edge(doubler, std::get<0>(join.input_ports())); + make_edge(squarer, std::get<1>(join.input_ports())); + make_edge(cuber, std::get<2>(join.input_ports())); + make_edge(join, summer); + + for (int i = 1; i <= 10; ++i) { + input.try_put(i); + } + g.wait_for_all(); +} +/*end_helpers_for_expressing_graphs_preview_api_example*/ + +#else +// Skip +int main() {} +#endif diff --git a/doc/main/reference/examples/make_edges_function_example.cpp b/doc/main/reference/examples/make_edges_function_example.cpp new file mode 100644 index 0000000000..d2ee0c83d8 --- /dev/null +++ b/doc/main/reference/examples/make_edges_function_example.cpp @@ -0,0 +1,49 @@ +/* + Copyright (c) 2025 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#if __cplusplus >= 201703L + +/*begin_make_edges_function_example*/ +#define TBB_PREVIEW_FLOW_GRAPH_FEATURES 1 +#include + +int main() { + using namespace oneapi::tbb::flow; + + graph g; + broadcast_node input(g); + + function_node doubler(g, unlimited, [](const int& i) { return 2 * i; }); + function_node squarer(g, unlimited, [](const int& i) { return i * i; }); + function_node cuber(g, unlimited, [](const int& i) { return i * i * i; }); + + buffer_node buffer(g); + + auto handlers = make_node_set(doubler, squarer, cuber); + make_edges(input, handlers); + make_edges(handlers, buffer); + + for (int i = 1; i <= 10; ++i) { + input.try_put(i); + } + g.wait_for_all(); +} +/*end_make_edges_function_example*/ + +#else +// Skip +int main() {} +#endif diff --git a/doc/main/reference/examples/malloc_replacement_log_example.cpp b/doc/main/reference/examples/malloc_replacement_log_example.cpp new file mode 100644 index 0000000000..4c6aba8366 --- /dev/null +++ b/doc/main/reference/examples/malloc_replacement_log_example.cpp @@ -0,0 +1,41 @@ +/* + Copyright (c) 2025 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#if _WIN32 + +/*begin_malloc_replacement_log_example*/ +#include "oneapi/tbb/tbbmalloc_proxy.h" +#include + +int main(){ + char **func_replacement_log; + int func_replacement_status = TBB_malloc_replacement_log(&func_replacement_log); + + if (func_replacement_status != 0) { + printf("tbbmalloc_proxy cannot replace memory allocation routines\n"); + for (char** log_string = func_replacement_log; *log_string != 0; log_string++) { + printf("%s\n",*log_string); + } + } + + return 0; +} +/*end_malloc_replacement_log_example*/ + +#else +// Skip +int main() {} +#endif diff --git a/doc/main/reference/examples/memory_pool_allocator_example.cpp b/doc/main/reference/examples/memory_pool_allocator_example.cpp new file mode 100644 index 0000000000..9cd971b780 --- /dev/null +++ b/doc/main/reference/examples/memory_pool_allocator_example.cpp @@ -0,0 +1,30 @@ +/* + Copyright (c) 2025 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/*begin_memory_pool_allocator_example*/ +#define TBB_PREVIEW_MEMORY_POOL 1 +#include "oneapi/tbb/memory_pool.h" +#include + +int main() { + oneapi::tbb::memory_pool> my_pool; + + typedef oneapi::tbb::memory_pool_allocator pool_allocator_t; + std::list my_list(pool_allocator_t{my_pool}); + + my_list.emplace_back(1); +} +/*end_memory_pool_allocator_example*/ diff --git a/doc/main/reference/examples/memory_pool_example.cpp b/doc/main/reference/examples/memory_pool_example.cpp new file mode 100644 index 0000000000..0382343d88 --- /dev/null +++ b/doc/main/reference/examples/memory_pool_example.cpp @@ -0,0 +1,27 @@ +/* + Copyright (c) 2025 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/*begin_memory_pool_example*/ +#define TBB_PREVIEW_MEMORY_POOL 1 +#include "oneapi/tbb/memory_pool.h" + +int main() { + oneapi::tbb::memory_pool> my_pool; + + void* my_ptr = my_pool.malloc(10); + my_pool.free(my_ptr); +} +/*end_memory_pool_example*/ diff --git a/doc/main/reference/examples/parallel_sort_ranges_extension_example.cpp b/doc/main/reference/examples/parallel_sort_ranges_extension_example.cpp new file mode 100644 index 0000000000..74a1292bf4 --- /dev/null +++ b/doc/main/reference/examples/parallel_sort_ranges_extension_example.cpp @@ -0,0 +1,37 @@ +/* + Copyright (c) 2025 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#if __cplusplus >= 202002L + +/*begin_parallel_sort_ranges_extension_example*/ +#include +#include // requires C++20 +#include + +std::span get_span() { + static std::array arr = {3, 2, 1}; + return std::span(arr); +} + +int main() { + tbb::parallel_sort(get_span()); +} +/*end_parallel_sort_ranges_extension_example*/ + +#else +// Skip +int main() {} +#endif diff --git a/doc/main/reference/examples/rvalue_reduce.cpp b/doc/main/reference/examples/rvalue_reduce.cpp new file mode 100644 index 0000000000..330498e1a8 --- /dev/null +++ b/doc/main/reference/examples/rvalue_reduce.cpp @@ -0,0 +1,50 @@ +/* + Copyright (c) 2025 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#if __cplusplus >= 201703L + +/*begin_rvalue_reduce_example*/ +// C++17 +#include +#include +#include +#include + +int main() { + std::vector> sets; + + oneapi::tbb::parallel_reduce(oneapi::tbb::blocked_range(0, sets.size()), + std::set{}, // identity element - empty set + [&](const oneapi::tbb::blocked_range& range, std::set&& value) { + for (size_t i = range.begin(); i < range.end(); ++i) { + // Having value as a non-const rvalue reference allows to efficiently + // transfer nodes from sets[i] without copying/moving the data + value.merge(std::move(sets[i])); + } + return value; + }, + [&](std::set&& x, std::set&& y) { + x.merge(std::move(y)); + return x; + } + ); +} +/*end_rvalue_reduce_example*/ + +#else +// Skip +int main() {} +#endif diff --git a/doc/main/reference/examples/try_put_and_wait_example.cpp b/doc/main/reference/examples/try_put_and_wait_example.cpp new file mode 100644 index 0000000000..d86f8e0767 --- /dev/null +++ b/doc/main/reference/examples/try_put_and_wait_example.cpp @@ -0,0 +1,75 @@ +/* + Copyright (c) 2025 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include + +// dummy bodies +struct f1_body { + int operator()(int input) { return input; }; +}; + +struct f2_body : f1_body {}; +struct f3_body : f1_body {}; + +struct f4_body { + int operator()(const std::tuple& input) { + return 0; + } +}; + +/*begin_try_put_and_wait_example*/ +#define TBB_PREVIEW_FLOW_GRAPH_TRY_PUT_AND_WAIT 1 +#include +#include +#include + +struct f1_body; +struct f2_body; +struct f3_body; +struct f4_body; + +int main() { + using namespace oneapi::tbb; + + flow::graph g; + flow::broadcast_node start_node(g); + + flow::function_node f1(g, flow::unlimited, f1_body{}); + flow::function_node f2(g, flow::unlimited, f2_body{}); + flow::function_node f3(g, flow::unlimited, f3_body{}); + + flow::join_node> join(g); + + flow::function_node, int> f4(g, flow::serial, f4_body{}); + + flow::make_edge(start_node, f1); + flow::make_edge(f1, f2); + + flow::make_edge(start_node, f3); + + flow::make_edge(f2, flow::input_port<0>(join)); + flow::make_edge(f3, flow::input_port<1>(join)); + + flow::make_edge(join, f4); + + // Submit work into the graph + parallel_for(0, 100, [&](int input) { + start_node.try_put_and_wait(input); + + // Post processing the result of input + }); +} +/*end_try_put_and_wait_example*/ diff --git a/doc/main/reference/helpers_for_expressing_graphs.rst b/doc/main/reference/helpers_for_expressing_graphs.rst index 537fda0f13..ef42331af8 100644 --- a/doc/main/reference/helpers_for_expressing_graphs.rst +++ b/doc/main/reference/helpers_for_expressing_graphs.rst @@ -44,75 +44,14 @@ to avoid template parameter specification where possible. **Regular API** -.. code:: cpp - - #include - - int main() { - using namespace oneapi::tbb::flow; - - graph g; - - broadcast_node input(g); - - function_node doubler(g, unlimited, [](const int& v) { return 2 * v; }); - function_node squarer(g, unlimited, [](const int&) { return v * v; }); - function_node cuber(g, unlimited, [](const int& v) { return v * v * v; }); - - join_node> join(g); - - int sum = 0; - function_node summer(g, serial, [&](const std::tuple& v) { - int sub_sum = std::get<0>(v) + std::get<1>(v) + std::get<2>(v); - sum += sub_sum; - return sub_sum; - }); - - make_edge(input, doubler); - make_edge(input, squarer); - make_edge(input, cuber); - make_edge(doubler, std::get<0>(join.input_ports())); - make_edge(squarer, std::get<1>(join.input_ports())); - make_edge(cuber, std::get<2>(join.input_ports())); - make_edge(join, summer); - - for (int i = 1; i <= 10; ++i) { - input.try_put(i); - } - g.wait_for_all(); - } +.. literalinclude:: ./examples/helpers_for_expressing_graphs_regular_api_example.cpp + :language: c++ + :start-after: /*begin_helpers_for_expressing_graphs_regular_api_example*/ + :end-before: /*end_helpers_for_expressing_graphs_regular_api_example*/ **Preview API** -.. code:: cpp - - #define TBB_PREVIEW_FLOW_GRAPH_FEATURES 1 - #include - - int main() { - using namespace oneapi::tbb::flow; - - graph g; - - function_node doubler(g, unlimited, [](const int& v) { return 2 * v; }); - function_node squarer(g, unlimited, [](const int&) { return v * v; }); - function_node cuber(g, unlimited, [](const int& v) { return v * v * v; }); - - auto handlers = make_node_set(doubler, squarer, cuber); - - broadcast_node input(precedes(handlers)); - join_node join(follows(handlers)); - - int sum = 0; - function_node summer(follows(join), serial, - [&](const std::tuple& v) { - int sub_sum = std::get<0>(v) + std::get<1>(v) + std::get<2>(v); - sum += sub_sum; - return sub_sum; - }); - - for (int i = 1; i <= 10; ++i) { - input.try_put(i); - } - g.wait_for_all(); - } +.. literalinclude:: ./examples/helpers_for_expressing_graphs_preview_api_example.cpp + :language: c++ + :start-after: /*begin_helpers_for_expressing_graphs_preview_api_example*/ + :end-before: /*end_helpers_for_expressing_graphs_preview_api_example*/ diff --git a/doc/main/reference/make_edges_function.rst b/doc/main/reference/make_edges_function.rst index 4035463db6..63fb6e28e2 100644 --- a/doc/main/reference/make_edges_function.rst +++ b/doc/main/reference/make_edges_function.rst @@ -53,29 +53,7 @@ The example implements the graph structure in the picture below. .. figure:: ./Resources/make_edges_example.png :align: center -.. code:: cpp - - #define TBB_PREVIEW_FLOW_GRAPH_FEATURES 1 - #include - - int main() { - using namespace oneapi::tbb::flow; - - graph g; - broadcast_node input(g); - - function_node doubler(g, unlimited, [](const int& i) { return 2 * i; }); - function_node squarer(g, unlimited, [](const int& i) { return i * i; }); - function_node cuber(g, unlimited, [](const int& i) { return i * i * i; }); - - buffer_node buffer(g); - - auto handlers = make_node_set(doubler, squarer, cuber); - make_edges(input, handlers); - make_edges(handlers, buffer); - - for (int i = 1; i <= 10; ++i) { - input.try_put(i); - } - g.wait_for_all(); - } +.. literalinclude:: ./examples/make_edges_function_example.cpp + :language: c++ + :start-after: /*begin_make_edges_function_example*/ + :end-before: /*end_make_edges_function_example*/ diff --git a/doc/main/reference/parallel_sort_ranges_extension.rst b/doc/main/reference/parallel_sort_ranges_extension.rst index cad65b54b0..cd8fb6ee41 100644 --- a/doc/main/reference/parallel_sort_ranges_extension.rst +++ b/doc/main/reference/parallel_sort_ranges_extension.rst @@ -56,17 +56,7 @@ Example This interface may be used for sorting rvalue or constant views: -.. code:: cpp - - #include - #include // requires C++20 - #include - - std::span get_span() { - static std::array arr = {3, 2, 1}; - return std::span(arr); - } - - int main() { - tbb::parallel_sort(get_span()); - } +.. literalinclude:: ./examples/parallel_sort_ranges_extension_example.cpp + :language: c++ + :start-after: /*begin_parallel_sort_ranges_extension_example*/ + :end-before: /*end_parallel_sort_ranges_extension_example*/ diff --git a/doc/main/reference/rvalue_reduce.rst b/doc/main/reference/rvalue_reduce.rst index 7cf66d86b3..02235562f1 100644 --- a/doc/main/reference/rvalue_reduce.rst +++ b/doc/main/reference/rvalue_reduce.rst @@ -33,8 +33,8 @@ or .. cpp:function:: Value Func::operator()(const Range& range, const Value& x) const - Accumulates the result for a subrange, starting with initial value ``x``. The ``Range`` type must meet the - `Range requirements `_. + Accumulates the result for a subrange, starting with initial value ``x``. The ``Range`` type must meet the + `Range requirements `_. The ``Value`` type must be the same as a corresponding template parameter for the `parallel_reduce algorithm `_. If both ``rvalue`` and ``lvalue`` forms are provided, the ``rvalue`` is preferred. @@ -55,33 +55,8 @@ or Example ******* -.. code:: cpp - - // C++17 - #include - #include - #include - #include - - int main() { - std::vector> sets = ...; - - oneapi::tbb::parallel_reduce(oneapi::tbb::blocked_range(0, sets.size()), - std::set{}, // identity element - empty set - [&](const oneapi::tbb::blocked_range& range, std::set&& value) { - for (size_t i = range.begin(); i < range.end(); ++i) { - // Having value as a non-const rvalue reference allows to efficiently - // transfer nodes from sets[i] without copying/moving the data - value.merge(std::move(sets[i])); - } - return value; - }, - [&](std::set&& x, std::set&& y) { - x.merge(std::move(y)); - return x; - } - ); - } +.. literalinclude:: ./examples/rvalue_reduce.h + :language: c++ .. rubric:: See also diff --git a/doc/main/reference/scalable_memory_pools/fixed_pool_cls.rst b/doc/main/reference/scalable_memory_pools/fixed_pool_cls.rst index 283842572a..df7b24d779 100644 --- a/doc/main/reference/scalable_memory_pools/fixed_pool_cls.rst +++ b/doc/main/reference/scalable_memory_pools/fixed_pool_cls.rst @@ -64,13 +64,7 @@ Examples The code below provides a simple example of allocation from a fixed pool. -.. code:: cpp - - #define TBB_PREVIEW_MEMORY_POOL 1 - #include "oneapi/tbb/memory_pool.h" - ... - char buf[1024*1024]; - oneapi::tbb::fixed_pool my_pool(buf, 1024*1024); - void* my_ptr = my_pool.malloc(10); - my_pool.free(my_ptr);} - +.. literalinclude:: ../examples/fixed_pool_example.cpp + :language: c++ + :start-after: /*begin_fixed_pool_example*/ + :end-before: /*end_fixed_pool_example*/ diff --git a/doc/main/reference/scalable_memory_pools/malloc_replacement_log.rst b/doc/main/reference/scalable_memory_pools/malloc_replacement_log.rst index 8fea89f949..4c14503d69 100644 --- a/doc/main/reference/scalable_memory_pools/malloc_replacement_log.rst +++ b/doc/main/reference/scalable_memory_pools/malloc_replacement_log.rst @@ -3,7 +3,7 @@ TBB_malloc_replacement_log Function =================================== -.. note:: This function is for Windows* OS only. +.. note:: This function is for Windows* OS only. Summary ******* @@ -13,7 +13,7 @@ Provides information about the status of dynamic memory allocation replacement. Syntax ******* -:: +:: extern "C" int TBB_malloc_replacement_log(char *** log_ptr); @@ -29,9 +29,9 @@ Header Description *********** -Dynamic replacement of memory allocation functions on Windows* OS uses in-memory binary instrumentation techniques. +Dynamic replacement of memory allocation functions on Windows* OS uses in-memory binary instrumentation techniques. To make sure that such instrumentation is safe, oneTBB first searches for a subset of replaced functions in the Visual C++* runtime DLLs -and checks if each one has a known bytecode pattern. If any required function is not found or its bytecode pattern is unknown, the replacement is skipped, +and checks if each one has a known bytecode pattern. If any required function is not found or its bytecode pattern is unknown, the replacement is skipped, and the program continues to use the standard memory allocation functions. The ``TBB_malloc_replacement_log`` function allows the program to check if the dynamic memory replacement happens and to get a log of the performed checks. @@ -39,45 +39,30 @@ The ``TBB_malloc_replacement_log`` function allows the program to check if the d **Returns:** * 0, if all necessary functions are successfully found and the replacement takes place. -* 1, otherwise. +* 1, otherwise. -The ``log_ptr`` parameter must be an address of a char** variable or be ``NULL``. If it is not ``NULL``, the function writes there the address of an array of +The ``log_ptr`` parameter must be an address of a char** variable or be ``NULL``. If it is not ``NULL``, the function writes there the address of an array of NULL-terminated strings containing detailed information about the searched functions in the following format: :: search_status: function_name (dll_name), byte pattern: - -For more information about the replacement of dynamic memory allocation functions, see :ref:`Windows_C_Dynamic_Memory_Interface_Replacement`. - - -Example -******* - -:: - - #include "oneapi/tbb/tbbmalloc_proxy.h" - #include - int main(){ - char **func_replacement_log; - int func_replacement_status = TBB_malloc_replacement_log(&func_replacement_log); +For more information about the replacement of dynamic memory allocation functions, see :ref:`Windows_C_Dynamic_Memory_Interface_Replacement`. - if (func_replacement_status != 0) { - printf("tbbmalloc_proxy cannot replace memory allocation routines\n"); - for (char** log_string = func_replacement_log; *log_string != 0; log_string++) { - printf("%s\n",*log_string); - } - } - return 0; - } +Example +******* +.. literalinclude:: ../examples/malloc_replacement_log_example.cpp + :language: c++ + :start-after: /*begin_malloc_replacement_log_example*/ + :end-before: /*end_malloc_replacement_log_example*/ Example output: -:: +:: tbbmalloc_proxy cannot replace memory allocation routines Success: free (ucrtbase.dll), byte pattern: diff --git a/doc/main/reference/scalable_memory_pools/memory_pool_allocator_cls.rst b/doc/main/reference/scalable_memory_pools/memory_pool_allocator_cls.rst index d275c02f5e..0e957b5963 100644 --- a/doc/main/reference/scalable_memory_pools/memory_pool_allocator_cls.rst +++ b/doc/main/reference/scalable_memory_pools/memory_pool_allocator_cls.rst @@ -107,11 +107,7 @@ Examples The code below provides a simple example of container construction with the use of a memory pool. -.. code:: cpp - - #define TBB_PREVIEW_MEMORY_POOL 1 - #include "oneapi/tbb/memory_pool.h" - ... - typedef oneapi::tbb::memory_pool_allocator - pool_allocator_t; - std::list my_list(pool_allocator_t( my_pool )); +.. literalinclude:: ../examples/memory_pool_allocator_example.cpp + :language: c++ + :start-after: /*begin_memory_pool_allocator_example*/ + :end-before: /*end_memory_pool_allocator_example*/ diff --git a/doc/main/reference/scalable_memory_pools/memory_pool_cls.rst b/doc/main/reference/scalable_memory_pools/memory_pool_cls.rst index fefade1c61..7e6afbcf07 100644 --- a/doc/main/reference/scalable_memory_pools/memory_pool_cls.rst +++ b/doc/main/reference/scalable_memory_pools/memory_pool_cls.rst @@ -70,11 +70,7 @@ Examples The code below provides a simple example of allocation from an extensible memory pool. -.. code:: cpp - - #define TBB_PREVIEW_MEMORY_POOL 1 - #include "oneapi/tbb/memory_pool.h" - ... - oneapi::tbb::memory_pool > my_pool; - void* my_ptr = my_pool.malloc(10); - my_pool.free(my_ptr); +.. literalinclude:: ../examples/memory_pool_example.cpp + :language: c++ + :start-after: /*begin_memory_pool_example*/ + :end-before: /*end_memory_pool_example*/ diff --git a/doc/main/reference/try_put_and_wait.rst b/doc/main/reference/try_put_and_wait.rst index 4e05961f39..7efbb659e0 100644 --- a/doc/main/reference/try_put_and_wait.rst +++ b/doc/main/reference/try_put_and_wait.rst @@ -276,48 +276,10 @@ related to ``input`` are executed, and no related objects remain in any buffer w Example ******* -.. code:: cpp - - #define TBB_PREVIEW_FLOW_GRAPH_TRY_PUT_AND_WAIT - #include - #include - - struct f1_body; - struct f2_body; - struct f3_body; - struct f4_body; - - int main() { - using namespace oneapi::tbb; - - flow::graph g; - flow::broadcast_node start_node(g); - - flow::function_node f1(g, flow::unlimited, f1_body{}); - flow::function_node f2(g, flow::unlimited, f2_body{}); - flow::function_node f3(g, flow::unlimited, f3_body{}); - - flow::join_node> join(g); - - flow::function_node, int> f4(g, flow::serial, f4_body{}); - - flow::make_edge(start_node, f1); - flow::make_edge(f1, f2); - - flow::make_edge(start_node, f3); - - flow::make_edge(f2, flow::input_port<0>(join)); - flow::make_edge(f3, flow::input_port<1>(join)); - - flow::make_edge(join, f4); - - // Submit work into the graph - parallel_for(0, 100, [](int input) { - start_node.try_put_and_wait(input); - - // Post processing the result of input - }); - } +.. literalinclude:: ./examples/try_put_and_wait_example.cpp + :language: c++ + :start-after: /*begin_try_put_and_wait_example*/ + :end-before: /*end_try_put_and_wait_example*/ Each iteration of ``parallel_for`` submits an input into the Flow Graph. After returning from ``try_put_and_wait(input)``, it is guaranteed that all of the work related to the completion of ``input`` is done by all of the nodes in the graph. Tasks related to inputs diff --git a/doc/main/tbb_userguide/Advanced_Topic_Other_Kinds_of_Iteration_Spaces.rst b/doc/main/tbb_userguide/Advanced_Topic_Other_Kinds_of_Iteration_Spaces.rst index 99446ab659..056ff4a185 100644 --- a/doc/main/tbb_userguide/Advanced_Topic_Other_Kinds_of_Iteration_Spaces.rst +++ b/doc/main/tbb_userguide/Advanced_Topic_Other_Kinds_of_Iteration_Spaces.rst @@ -107,5 +107,7 @@ the received 3D subrange in nested loops, using the method ``dim`` to get the loop boundaries for each dimension. -.. literalinclude:: ./snippets/blocked_nd_range_example.h +.. literalinclude:: ./examples/blocked_nd_range_example.cpp :language: c++ + :start-after: /*begin_blocked_nd_range_example*/ + :end-before: /*end_blocked_nd_range_example*/ \ No newline at end of file diff --git a/doc/main/tbb_userguide/Lambda_Expressions.rst b/doc/main/tbb_userguide/Lambda_Expressions.rst index e2408c1e0f..ca6e100e28 100644 --- a/doc/main/tbb_userguide/Lambda_Expressions.rst +++ b/doc/main/tbb_userguide/Lambda_Expressions.rst @@ -4,7 +4,7 @@ Lambda Expressions ================== -C++11 lambda expressions make the |full_name| +C++11 lambda expressions make the |full_name| ``parallel_for`` much easier to use. A lambda expression lets the compiler do the tedious work of creating a function object. @@ -14,24 +14,10 @@ expression. The lambda expression, replaces both the declaration and constructio example of the previous section. -:: - - - #include "oneapi/tbb.h" -   - - using namespace oneapi::tbb; -   - - void ParallelApplyFoo( float* a, size_t n ) { - parallel_for( blocked_range(0,n), - [=](const blocked_range& r) { - for(size_t i=r.begin(); i!=r.end(); ++i) - Foo(a[i]); - } - ); - } - +.. literalinclude:: ./examples/parallel_for_lambda_example_1.cpp + :language: c++ + :start-after: /*begin_parallel_for_lambda_1*/ + :end-before: /*end_parallel_for_lambda_1*/ The [=] introduces the lambda expression. The expression creates a function object very similar to ``ApplyFoo``. When local variables like @@ -54,18 +40,18 @@ shows the option for turning it on. .. container:: tablenoborder - .. list-table:: + .. list-table:: :header-rows: 1 - * - Environment - - Intel® C++ Compiler Classic - - Intel® oneAPI DPC++/C++ Compiler - * - Windows\* OS systems - - \ ``icl /Qstd=c++11 foo.cpp`` - - \ ``icx /Qstd=c++11 foo.cpp`` - * - Linux\* OS systems - - \ ``icc -std=c++11 foo.cpp`` - - \ ``icx -std=c++11 foo.cpp`` + * - Environment + - Intel® C++ Compiler Classic + - Intel® oneAPI DPC++/C++ Compiler + * - Windows\* OS systems + - \ ``icl /Qstd=c++11 foo.cpp`` + - \ ``icx /Qstd=c++11 foo.cpp`` + * - Linux\* OS systems + - \ ``icc -std=c++11 foo.cpp`` + - \ ``icx -std=c++11 foo.cpp`` @@ -78,25 +64,11 @@ each f(i) can be evaluated in parallel if resources permit. The ``step`` parameter is optional. Here is the previous example rewritten in the compact form: - -:: - - - #include "oneapi/tbb.h" -   - - using namespace oneapi::tbb; -   - - #pragma warning(disable: 588) -   - - void ParallelApplyFoo(float a[], size_t n) { - parallel_for(size_t(0), n, [=](size_t i) {Foo(a[i]);}); - } - +.. literalinclude:: ./examples/parallel_for_lambda_example_2.cpp + :language: c++ + :start-after: /*begin_parallel_for_lambda_2*/ + :end-before: /*end_parallel_for_lambda_2*/ The compact form supports only unidimensional iteration spaces of integers and the automatic chunking feature detailed on the following section. - diff --git a/doc/main/tbb_userguide/attach_flow_graph_to_arena.rst b/doc/main/tbb_userguide/attach_flow_graph_to_arena.rst index c31387f9ef..41d2dbd6f9 100644 --- a/doc/main/tbb_userguide/attach_flow_graph_to_arena.rst +++ b/doc/main/tbb_userguide/attach_flow_graph_to_arena.rst @@ -16,7 +16,7 @@ This example shows how to set the most performant core type as the preferred one for a graph execution: -.. literalinclude:: ./snippets/flow_graph_examples.cpp +.. literalinclude:: ./examples/flow_graph_examples.cpp :language: c++ :start-after: /*begin_attach_to_arena_1*/ :end-before: /*end_attach_to_arena_1*/ @@ -32,7 +32,7 @@ of the graph, it is spawned in the arena of a graph it is attached to, disregard the arena of the thread that the task is spawned from: -.. literalinclude:: ./snippets/flow_graph_examples.cpp +.. literalinclude:: ./examples/flow_graph_examples.cpp :language: c++ :start-after: /*begin_attach_to_arena_2*/ :end-before: /*end_attach_to_arena_2*/ @@ -44,4 +44,3 @@ See the following topics to learn more: ../tbb_userguide/Guiding_Task_Scheduler_Execution ../tbb_userguide/work_isolation - diff --git a/doc/main/tbb_userguide/examples/blocked_nd_range_example.cpp b/doc/main/tbb_userguide/examples/blocked_nd_range_example.cpp new file mode 100644 index 0000000000..4fc1473b7b --- /dev/null +++ b/doc/main/tbb_userguide/examples/blocked_nd_range_example.cpp @@ -0,0 +1,92 @@ +/* + Copyright (c) 2025 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/*begin_blocked_nd_range_example*/ +#include "oneapi/tbb/blocked_nd_range.h" +#include "oneapi/tbb/parallel_for.h" + +template +float kernel3d(const Features& feature_maps, int i, int j, int k, + int kernel_length, int kernel_width, int kernel_height) { + float result = 0.f; + + for (int feature_i = i; feature_i < i + kernel_length; ++feature_i) + for (int feature_j = j; feature_j < j + kernel_width; ++feature_j) + for (int feature_k = k; feature_k < k + kernel_width; ++feature_k) + result += feature_maps[feature_i][feature_j][feature_k]; + + return result; +} + +template +void convolution3d(const Features& feature_maps, Output& out, + int out_length, int out_width, int out_heigth, + int kernel_length, int kernel_width, int kernel_height) { + using range_t = oneapi::tbb::blocked_nd_range; + + oneapi::tbb::parallel_for( + range_t({0, out_length}, {0, out_width}, {0, out_heigth}), + [&](const range_t& out_range) { + auto out_x = out_range.dim(0); + auto out_y = out_range.dim(1); + auto out_z = out_range.dim(2); + + for (int i = out_x.begin(); i < out_x.end(); ++i) + for (int j = out_y.begin(); j < out_y.end(); ++j) + for (int k = out_z.begin(); k < out_z.end(); ++k) + out[i][j][k] = kernel3d(feature_maps, i, j, k, + kernel_length, kernel_width, kernel_height); + } + ); +} +/*end_blocked_nd_range_example*/ + +#include +#include + +int main() { + const int kernel_length = 9; + const int kernel_width = 5; + const int kernel_height = 5; + + const int feature_maps_length = 128; + const int feature_maps_width = 16; + const int feature_maps_heigth = 16; + + const int out_length = feature_maps_length - kernel_length + 1; + const int out_width = feature_maps_width - kernel_width + 1; + const int out_heigth = feature_maps_heigth - kernel_height + 1; + + // Initializes feature maps with 1 in each cell and out with zeros. + std::vector>> feature_maps(feature_maps_length, std::vector>(feature_maps_width, std::vector(feature_maps_heigth, 1.0f))); + std::vector>> out(out_length, std::vector>(out_width, std::vector(out_heigth, 0.f))); + + // 3D convolution calculates the sum of all elements in the kernel + convolution3d(feature_maps, out, + out_length, out_width, out_heigth, + kernel_length, kernel_width, kernel_height); + + // Checks correctness of convolution by equality to the expected sum of elements + float expected = float(kernel_length * kernel_height * kernel_width); + for (auto i : out) { + for (auto j : i) { + for (auto k : j) { + assert(k == expected && "convolution failed to calculate correctly"); + } + } + } + return 0; +} diff --git a/doc/main/tbb_userguide/snippets/flow_graph_examples.cpp b/doc/main/tbb_userguide/examples/flow_graph_examples.cpp similarity index 97% rename from doc/main/tbb_userguide/snippets/flow_graph_examples.cpp rename to doc/main/tbb_userguide/examples/flow_graph_examples.cpp index 72c594c5c7..5c66a9c8e6 100644 --- a/doc/main/tbb_userguide/snippets/flow_graph_examples.cpp +++ b/doc/main/tbb_userguide/examples/flow_graph_examples.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2022 Intel Corporation + Copyright (c) 2022-2025 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/doc/main/tbb_userguide/examples/parallel_for_lambda_example_1.cpp b/doc/main/tbb_userguide/examples/parallel_for_lambda_example_1.cpp new file mode 100644 index 0000000000..6d14eec14d --- /dev/null +++ b/doc/main/tbb_userguide/examples/parallel_for_lambda_example_1.cpp @@ -0,0 +1,39 @@ +/* + Copyright (c) 2025 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +void Foo(float) {} + +/*begin_parallel_for_lambda_1*/ +#include "oneapi/tbb.h" + +using namespace oneapi::tbb; + +void ParallelApplyFoo( float* a, size_t n ) { + parallel_for( blocked_range(0,n), + [=](const blocked_range& r) { + for(size_t i=r.begin(); i!=r.end(); ++i) + Foo(a[i]); + } + ); +} +/*end_parallel_for_lambda_1*/ + +int main() { + constexpr std::size_t size = 10; + float array[size] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + + ParallelApplyFoo(array, size); +} diff --git a/doc/main/tbb_userguide/examples/parallel_for_lambda_example_2.cpp b/doc/main/tbb_userguide/examples/parallel_for_lambda_example_2.cpp new file mode 100644 index 0000000000..043abb7770 --- /dev/null +++ b/doc/main/tbb_userguide/examples/parallel_for_lambda_example_2.cpp @@ -0,0 +1,36 @@ +/* + Copyright (c) 2025 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +void Foo(float) {} + +/*begin_parallel_for_lambda_2*/ +#include "oneapi/tbb.h" + +using namespace oneapi::tbb; + +#pragma warning(disable: 588) + +void ParallelApplyFoo(float a[], size_t n) { + parallel_for(size_t(0), n, [=](size_t i) {Foo(a[i]);}); +} +/*end_parallel_for_lambda_2*/ + +int main() { + constexpr std::size_t size = 10; + float array[size] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + + ParallelApplyFoo(array, size); +} diff --git a/doc/main/tbb_userguide/examples/parallel_for_os_example.cpp b/doc/main/tbb_userguide/examples/parallel_for_os_example.cpp new file mode 100644 index 0000000000..66759388f2 --- /dev/null +++ b/doc/main/tbb_userguide/examples/parallel_for_os_example.cpp @@ -0,0 +1,51 @@ +/* + Copyright (c) 2025 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +void Foo(float) {} + +/*begin_parallel_for_os_1*/ +#include "oneapi/tbb.h" + +using namespace oneapi::tbb; + +class ApplyFoo { + float *const my_a; +public: + void operator()( const blocked_range& r ) const { + float *a = my_a; + for( size_t i=r.begin(); i!=r.end(); ++i ) + Foo(a[i]); + } + ApplyFoo( float a[] ) : + my_a(a) + {} +}; +/*end_parallel_for_os_1*/ + +/*begin_parallel_for_os_2*/ +#include "oneapi/tbb.h" + +void ParallelApplyFoo( float a[], size_t n ) { + parallel_for(blocked_range(0,n), ApplyFoo(a)); +} +/*end_parallel_for_os_2*/ + +int main() { + constexpr std::size_t size = 10; + float array[size] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + + ParallelApplyFoo(array, size); +} diff --git a/doc/main/tbb_userguide/parallel_for_os.rst b/doc/main/tbb_userguide/parallel_for_os.rst index cbc7578f4c..3880c1f52a 100644 --- a/doc/main/tbb_userguide/parallel_for_os.rst +++ b/doc/main/tbb_userguide/parallel_for_os.rst @@ -26,25 +26,10 @@ that operates on a chunk. The form is an STL-style function object, called the *body* object, in which ``operator()`` processes a chunk. The following code declares the body object. -:: - - #include "oneapi/tbb.h" - - using namespace oneapi::tbb; - - class ApplyFoo { - float *const my_a; - public: - void operator()( const blocked_range& r ) const { - float *a = my_a; - for( size_t i=r.begin(); i!=r.end(); ++i ) - Foo(a[i]); - } - ApplyFoo( float a[] ) : - my_a(a) - {} - }; - +.. literalinclude:: ./examples/parallel_for_os_example.cpp + :language: c++ + :start-after: /*begin_parallel_for_os_1*/ + :end-before: /*end_parallel_for_os_1*/ The ``using`` directive in the example enables you to use the library identifiers without having to write out the namespace prefix ``oneapi::tbb`` @@ -98,17 +83,10 @@ example: Once you have the loop body written as a body object, invoke the template function ``parallel_for``, as follows: - -:: - - - #include "oneapi/tbb.h" -   - - void ParallelApplyFoo( float a[], size_t n ) { - parallel_for(blocked_range(0,n), ApplyFoo(a)); - } - +.. literalinclude:: ./examples/parallel_for_os_example.cpp + :language: c++ + :start-after: /*begin_parallel_for_os_2*/ + :end-before: /*end_parallel_for_os_2*/ The ``blocked_range`` constructed here represents the entire iteration space from 0 to n-1, which ``parallel_for`` divides into subspaces for @@ -122,4 +100,3 @@ example uses the default grainsize of 1 because by default grainsize. .. include:: parallel_for_toctree.rst - diff --git a/doc/main/tbb_userguide/snippets/blocked_nd_range_example.cpp b/doc/main/tbb_userguide/snippets/blocked_nd_range_example.cpp deleted file mode 100644 index 7417123999..0000000000 --- a/doc/main/tbb_userguide/snippets/blocked_nd_range_example.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "blocked_nd_range_example.h" -#include -#include - -int main() { - const int kernel_length = 9; - const int kernel_width = 5; - const int kernel_height = 5; - - const int feature_maps_length = 128; - const int feature_maps_width = 16; - const int feature_maps_heigth = 16; - - const int out_length = feature_maps_length - kernel_length + 1; - const int out_width = feature_maps_width - kernel_width + 1; - const int out_heigth = feature_maps_heigth - kernel_height + 1; - - // Initializes feature maps with 1 in each cell and out with zeros. - std::vector>> feature_maps(feature_maps_length, std::vector>(feature_maps_width, std::vector(feature_maps_heigth, 1.0f))); - std::vector>> out(out_length, std::vector>(out_width, std::vector(out_heigth, 0.f))); - - // 3D convolution calculates the sum of all elements in the kernel - convolution3d(feature_maps, out, - out_length, out_width, out_heigth, - kernel_length, kernel_width, kernel_height); - - // Checks correctness of convolution by equality to the expected sum of elements - float expected = float(kernel_length * kernel_height * kernel_width); - for (auto i : out) { - for (auto j : i) { - for (auto k : j) { - assert(k == expected && "convolution failed to calculate correctly"); - } - } - } - return 0; -} diff --git a/doc/main/tbb_userguide/snippets/blocked_nd_range_example.h b/doc/main/tbb_userguide/snippets/blocked_nd_range_example.h deleted file mode 100644 index ded2a09c57..0000000000 --- a/doc/main/tbb_userguide/snippets/blocked_nd_range_example.h +++ /dev/null @@ -1,37 +0,0 @@ -#include "oneapi/tbb/blocked_nd_range.h" -#include "oneapi/tbb/parallel_for.h" - -template -float kernel3d(const Features& feature_maps, int i, int j, int k, - int kernel_length, int kernel_width, int kernel_height) { - float result = 0.f; - - for (int feature_i = i; feature_i < i + kernel_length; ++feature_i) - for (int feature_j = j; feature_j < j + kernel_width; ++feature_j) - for (int feature_k = k; feature_k < k + kernel_width; ++feature_k) - result += feature_maps[feature_i][feature_j][feature_k]; - - return result; -} - -template -void convolution3d(const Features& feature_maps, Output& out, - int out_length, int out_width, int out_heigth, - int kernel_length, int kernel_width, int kernel_height) { - using range_t = oneapi::tbb::blocked_nd_range; - - oneapi::tbb::parallel_for( - range_t({0, out_length}, {0, out_width}, {0, out_heigth}), - [&](const range_t& out_range) { - auto out_x = out_range.dim(0); - auto out_y = out_range.dim(1); - auto out_z = out_range.dim(2); - - for (int i = out_x.begin(); i < out_x.end(); ++i) - for (int j = out_y.begin(); j < out_y.end(); ++j) - for (int k = out_z.begin(); k < out_z.end(); ++k) - out[i][j][k] = kernel3d(feature_maps, i, j, k, - kernel_length, kernel_width, kernel_height); - } - ); -}