From c8504c4ec866eb474d323e9df326778f30f9850d Mon Sep 17 00:00:00 2001 From: Valentina Kats Date: Tue, 9 Aug 2022 20:59:37 +0200 Subject: [PATCH] Update documentation for oneTBB 2021.6 (#836) * Update pull_request_template.md (#751) Signed-off-by: Alexandra Epanchinzeva alexandra.epanchinzeva@intel.com (cherry picked from commit 4eda0f93a78ae15facf2d1d7d47e8a971ef5a164) * Update CONTRIBUTING.md (#765) (cherry picked from commit e274a9e4b3b7dff8fb943f86f1e128f29605b87c) * Documentation update for unpreview `task_handle` and related stuff (#755) * Unpreview task_handle and related stuff Signed-off-by: Anton Potapov Co-authored-by: Alexandra (cherry picked from commit fd76f452157ec53c7112be199941f26800b3699e) * Update conf.py (#774) (cherry picked from commit 6666292fbf255a7e7058212710c699103b17a505) * Actualize documentation about proportional splitting constructor in Range (#728) Actualize documentation about proportional splitting Signed-off-by: Fedotov, Aleksei (cherry picked from commit e5cbe500d20311f3467f8814392c09c7e523d6ff) * Update doc structure and add new files (#791) (cherry picked from commit ce0d258e7240fa5951d0034b46967dd10c1cfbca) * Instruction for building the docs locally (#778) (cherry picked from commit e386960a777c43c2111f8411259c33fdb7bfea18) * Document a way to flow graph can be attached to arbitrary task_arena (#785) * Document a way to flow graph can be attached to arbitrary task_arena task_arena interface provides mechanisms to guide tasks execution within the arena by setting the preferred computation units or restricting part of computation units. In some cases, you may want to use mechanisms within a flow graph. Signed-off-by: Serov, Vladimir Co-authored-by: Aleksei Fedotov Co-authored-by: Alexandra Epanchinzeva (cherry picked from commit a938322524f08e37edfb926b789596b2161b9340) * Add topic about "Lazy Initiliazation" pattern to Design patterns (#790) New topic about Lazy initialization pattern and how it can be implemented using oneapi::tbb::collaborative_call_once has been added. Signed-off-by: Ilya Isaev (cherry picked from commit 1da8f0d33b21f09239e11cefab453cc973b5d58b) * Update Get Started Guide (#803) (cherry picked from commit 05023723ff17dc436668a989a5f2c1873e994e72) * Update intro_gsg.rst (#808) (cherry picked from commit 2c4f282e861d4f6d2f4742ca96b544e0e04c7883) * Update conf.py (#810) (cherry picked from commit 0a0a5926ee86119e521a5acef9277764344d0afa) * TBB DOC : Dev Guide: Task Scheduler Bypass and How Does Task Scheduler Works (#521) * TBB DOC : Dev Guide: Task Scheduler Bypass and How Task Scheduler Works Signed-off-by: Anton Potapov Co-authored-by: Alexandra (cherry picked from commit ed9d4b5e9aed70df9816a935f710771001208dbe) * Update intro_gsg.rst (#811) (cherry picked from commit efea9935d1e3fddbfca8e5438e31d8d7be2427c8) * Update conf.py (#812) (cherry picked from commit 3859d1111f6260a295374d9739c6fc3249c5b6b8) * Update examples.rst (#816) (cherry picked from commit 4aa0b0b2db3f60c22702df0711d637f248e35cb0) * Update layout.html (#815) (cherry picked from commit 3e352b48127b3c79d61df5618607d2daab3f2caa) * Update RELEASE_NOTES.md for oneTBB 2021.6 (#835) (cherry picked from commit faaf43c4ab22cb4b4267d65d5e218fa58800eea8) Co-authored-by: Alexandra Co-authored-by: Anton Potapov Co-authored-by: Aleksei Fedotov Co-authored-by: Vladimir Serov Co-authored-by: Ilya Isaev Co-authored-by: Anton Potapov --- .github/pull_request_template.md | 12 +- CONTRIBUTING.md | 9 +- RELEASE_NOTES.md | 26 +++-- doc/GSG/Images/how-oneTBB-works.png | Bin 0 -> 53481 bytes doc/GSG/examples.rst | 45 ++++++++ doc/GSG/installation.rst | 7 ++ doc/GSG/intro_gsg.rst | 26 +++-- doc/Makefile | 36 ++++++ doc/README.md | 34 ++++++ doc/conf.py | 32 ++--- doc/index/index_intro.rst | 1 + doc/index/toctree.rst | 36 ++++-- doc/main/_templates/layout.html | 10 +- doc/main/intro/introducing_main_os.rst | 30 ----- doc/main/reference/reference.rst | 2 - doc/main/reference/task_arena_extensions.rst | 61 ---------- doc/main/reference/task_group_extensions.rst | 48 ++------ .../task_group_extensions/task_handle.rst | 101 ---------------- .../reference/this_task_arena_extensions.rst | 71 ------------ ..._Topic_Other_Kinds_of_Iteration_Spaces.rst | 24 ++-- .../Flow_Graph_resource_tips.rst | 3 +- .../How_Task_Scheduler_Works.rst | 50 ++++++++ .../Migration_Guide/Task_API.rst | 6 +- .../tbb_userguide/Task_Scheduler_Bypass.rst | 20 ++++ .../tbb_userguide/Task_Scheduler_Summary.rst | 11 -- doc/main/tbb_userguide/The_Task_Scheduler.rst | 3 +- .../attach_flow_graph_to_arena.rst | 47 ++++++++ .../design_patterns/Design_Patterns.rst | 1 + .../design_patterns/Images/image008a.jpg | Bin 0 -> 30488 bytes .../design_patterns/Images/image009a.jpg | Bin 0 -> 21793 bytes .../design_patterns/Lazy_Initialization.rst | 109 ++++++++++++++++++ .../snippets/flow_graph_examples.cpp | 76 ++++++++++++ doc/make.bat | 53 +++++++++ test/tbb/test_partitioner.h | 44 ------- 34 files changed, 604 insertions(+), 430 deletions(-) create mode 100644 doc/GSG/Images/how-oneTBB-works.png create mode 100644 doc/GSG/examples.rst create mode 100644 doc/GSG/installation.rst create mode 100644 doc/Makefile create mode 100644 doc/README.md delete mode 100644 doc/main/intro/introducing_main_os.rst delete mode 100644 doc/main/reference/task_arena_extensions.rst delete mode 100644 doc/main/reference/task_group_extensions/task_handle.rst delete mode 100644 doc/main/reference/this_task_arena_extensions.rst create mode 100644 doc/main/tbb_userguide/How_Task_Scheduler_Works.rst create mode 100644 doc/main/tbb_userguide/Task_Scheduler_Bypass.rst delete mode 100644 doc/main/tbb_userguide/Task_Scheduler_Summary.rst create mode 100644 doc/main/tbb_userguide/attach_flow_graph_to_arena.rst create mode 100644 doc/main/tbb_userguide/design_patterns/Images/image008a.jpg create mode 100644 doc/main/tbb_userguide/design_patterns/Images/image009a.jpg create mode 100644 doc/main/tbb_userguide/design_patterns/Lazy_Initialization.rst create mode 100644 doc/main/tbb_userguide/snippets/flow_graph_examples.cpp create mode 100644 doc/make.bat diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index b5e8da36ac..caf80fff86 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,26 +1,26 @@ ### Description -_Add comprehensive description of proposed changes_ +_Add a comprehensive description of proposed changes_ Fixes # - _issue number(s) if exists_ -- [ ] - git commit message contains appropriate signed-off-by string _(see [CONTRIBUTING.md](https://github.com/oneapi-src/oneTBB/blob/master/CONTRIBUTING.md#pull-requests) for details)_ +- [ ] - git commit message contains an appropriate signed-off-by string _(see [CONTRIBUTING.md](https://github.com/oneapi-src/oneTBB/blob/master/CONTRIBUTING.md#pull-requests) for details)_ ### Type of change _Choose one or multiple, leave empty if none of the other choices apply_ -_Add respective label(s) to PR if you have permissions_ +_Add a respective label(s) to PR if you have permissions_ -- [ ] bug fix - _change which fixes an issue_ -- [ ] new feature - _change which adds functionality_ +- [ ] bug fix - _change that fixes an issue_ +- [ ] new feature - _change that adds functionality_ - [ ] tests - _change in tests_ - [ ] infrastructure - _change in infrastructure and CI_ - [ ] documentation - _documentation update_ ### Tests -- [ ] added - _required for new features and for some bug fixes_ +- [ ] added - _required for new features and some bug fixes_ - [ ] not needed ### Documentation diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 74063b7b9e..c8b437083a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -38,18 +38,21 @@ You can use issues to report a problem, make a feature request, or add comments You can find all [open oneTBB pull requests](https://github.com/oneapi-src/oneTBB/pulls) on GitHub. -No anonymous contributions are accepted. The name in the commit message Signed-of-by line and your email must match the change authorship information. Make sure your .gitconfig is set up correctly so you can use `git commit -s` for signing your patches: +No anonymous contributions are accepted. The name in the commit message Signed-off-by line and your email must match the change authorship information. Make sure your .gitconfig is set up correctly so you can use `git commit -s` for signing your patches: `git config --global user.name "Taylor Developer"` `git config --global user.email taylor.developer@company.com` - -Before contributing changes directly to the oneTBB repository: +### Before contributing changes directly to the oneTBB repository * Make sure you can build the product and run all the tests with your patch. * For a larger feature, provide a relevant test. * Document your code. The oneTBB project uses reStructuredText for documentation. +* Update the copyright year in the first line of the changing file(s). + For example, if you commit your changes in 2022: + * the copyright year should be `2005-2022` for existing files + * the copyright year should be `2022` for new files * Submit a pull request into the master branch. You can submit changes with a pull request (preferred) or by sending an email patch. Continuous Integration (CI) testing is enabled for the repository. Your pull request must pass all checks before it can be merged. We will review your contribution and may provide feedback to guide you if any additional fixes or modifications are necessary. When reviewed and accepted, your pull request will be merged into our GitHub repository. diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 3f6f1c0686..6e7093059a 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -18,17 +18,15 @@ This document contains changes of oneTBB compared to the last release. ## Table of Contents -- [Preview Features](#preview-features) - [New Features](#new_features) - [Known Limitations](#known-limitations) - [Fixed Issues](#fixed-issues) - - -## :computer: Preview Features -- Extended task_group interface with a new run_and_wait overload to accept task_handle. +- [Open-source Contributions Integrated](#open-source-contributions-integrated) ## :white_check_mark: New Features -- Enabled Microsoft Visual Studio* 2022 and Python 3.9 support. +- Improved support and use of the latest C++ standards for parallel_sort that allows using this algorithm with user-defined and standard library-defined objects with modern semantics. +- The following features are now fully functional: task_arena extensions, collaborative_call_once, adaptive mutexes, heterogeneous overloads for concurrent_hash_map, and task_scheduler_handle. +- Added support for Windows* Server 2022 and Python 3.10. ## :rotating_light: Known Limitations - An application using Parallel STL algorithms in libstdc++ versions 9 and 10 may fail to compile due to incompatible interface changes between earlier versions of Threading Building Blocks (TBB) and oneAPI Threading Building Blocks (oneTBB). Disable support for Parallel STL algorithms by defining PSTL_USE_PARALLEL_POLICIES (in libstdc++ 9) or _GLIBCXX_USE_TBB_PAR_BACKEND (in libstdc++ 10) macro to zero before inclusion of the first standard header file in each translation unit. @@ -41,7 +39,15 @@ This document contains changes of oneTBB compared to the last release. - C++ exception handling mechanism on Windows* OS on ARM64* might corrupt memory if an exception is thrown from any oneTBB parallel algorithm (see Windows* OS on ARM64* compiler issue: https://developercommunity.visualstudio.com/t/ARM64-incorrect-stack-unwinding-for-alig/1544293). ## :hammer: Fixed Issues -- Reworked synchronization mechanism to reduce contention when multiple task_arena's are used concurrently. -- Fixed possible correctness issue in queuing_rw_mutex on non-Intel platforms. -- Fixed GCC* 11 warnings. -- Fixed sporadic memory corruption. +- Memory allocator crash on a system with an incomplete /proc/meminfo (GitHub* [#584](https://github.com/oneapi-src/oneTBB/issues/584)). +- Incorrect blocking of task stealing (GitHub* #[478](https://github.com/oneapi-src/oneTBB/issues/478)). +- Hang due to incorrect decrement of a limiter_node (GitHub* [#634](https://github.com/oneapi-src/oneTBB/issues/634)). +- Memory corruption in some rare cases when passing big messages in a flow graph (GitHub* [#639](https://github.com/oneapi-src/oneTBB/issues/639)). +- Possible deadlock in a throwable flow graph node with a lightweight policy. The lightweight policy is now ignored for functors that can throw exceptions (GitHub* [#420](https://github.com/oneapi-src/oneTBB/issues/420)). +- Crash when obtaining a range from empty ordered and unordered containers (GitHub* [#641](https://github.com/oneapi-src/oneTBB/issues/641)). +- Deadlock in a concurrent_vector resize() that could happen when the new size is less than the previous size (GitHub* [#733](https://github.com/oneapi-src/oneTBB/issues/733)). + +## :octocat: Open-source Contributions Integrated +- Improved aligned memory allocation. Contributed by Andrey Semashev (https://github.com/oneapi-src/oneTBB/pull/671). +- Optimized usage of atomic_fence on IA-32 and Intel(R) 64 architectures. Contributed by Andrey Semashev (https://github.com/oneapi-src/oneTBB/pull/328). +- Fixed incorrect definition of the assignment operator in containers. Contributed by Andrey Semashev (https://github.com/oneapi-src/oneTBB/issues/372). diff --git a/doc/GSG/Images/how-oneTBB-works.png b/doc/GSG/Images/how-oneTBB-works.png new file mode 100644 index 0000000000000000000000000000000000000000..f72427a81429a79c3bd783d0a8813dd5427c6800 GIT binary patch literal 53481 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

E+2V|Cac!INiKD;u^mb4>C5iu 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 + * `concurrent_priority_queue `_ + +* `Flow Graph `_ + * `A solution to the binpacking problem using a queue_node, a buffer_node, and function_node. `_ + * `Cholesky Factorization algorithm `_ + * `An implementation of dining philosophers in graph using the reserving join_node `_ + * `A parallel implementation of bzip2 block-sorting file compressor `_ + * `An example of a collection of digital logic gates that can be easily composed into larger circuits `_ + * `An example of a Kohonen Self-Organizing Map using cancellation `_ + * `Split computational kernel for execution between CPU and GPU `_ + +* **Algorithms** + + * `parallel_for `_ + * `Game of life overlay `_ + * `Polygon overlay `_ + * `Parallel seismic wave simulation `_ + * `Parallel 2-D raytracer/renderer `_ + * `Find largest matching substrings `_ + * `Resumable task: Split computational kernel for execution between CPU and GPU `_ + * `parallel_for_each `_ + * `parallel_pipeline `_ + * `parallel_reduce `_ + +* **Task Scheduler** + + * `task_arena `_ + * `task_group `_ + * `Execute similar computational kernels, with one task executing the SYCL* code and the other task executing the oneTBB code `_ + +* **Other** + + * `Compute Fibonacci numbers in different ways `_ + + diff --git a/doc/GSG/installation.rst b/doc/GSG/installation.rst new file mode 100644 index 0000000000..e6b6a09c34 --- /dev/null +++ b/doc/GSG/installation.rst @@ -0,0 +1,7 @@ +.. _installation: + +Installation +============ + +See the `installation instructions `_ +that will help you to install |short_name| successfully. \ No newline at end of file diff --git a/doc/GSG/intro_gsg.rst b/doc/GSG/intro_gsg.rst index dfef1897c4..49fda780f6 100644 --- a/doc/GSG/intro_gsg.rst +++ b/doc/GSG/intro_gsg.rst @@ -1,13 +1,23 @@ .. _Intro_gsg: -|short_name| is a runtime-based parallel programming model for C++ code that uses threads. -It enables you to simplify parallel programming by breaking -computation into parallel running tasks. -The library consists of a template-based runtime library to help you harness the latent performance -of multi-core processors. Use |short_name| to write scalable applications that: +|full_name| is a runtime-based parallel programming model for C++ code that uses threads. +It consists of a template-based runtime library to help you harness the latent performance of multi-core processors. +oneTBB enables you to simplify parallel programming by breaking computation into parallel running tasks. Within a single process, +parallelism is carried out through threads, an operating system mechanism that allows the same or different sets of instructions +to be executed simultaneously. -- Specify logical parallel structure instead of threads -- Emphasize data parallel programming -- Take advantage of concurrent collections and parallel algorithms +Here you can see one of the possible executions of tasks by threads. + +.. figure:: /GSG/Images/how-oneTBB-works.png + :scale: 70% + :align: center + +Use oneTBB to write scalable applications that: + +* Specify logical parallel structure instead of threads +* Emphasize data-parallel programming +* Take advantage of concurrent collections and parallel algorithms + +oneTBB supports nested parallelism and load balancing. It means that you can use the library without being worried about oversubscribing a system. diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000000..3ac68fcfb6 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,36 @@ +#=============================================================================== +# Copyright (C) 2022 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. +#=============================================================================== + +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = doc +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 0000000000..0cdd56f9c1 --- /dev/null +++ b/doc/README.md @@ -0,0 +1,34 @@ +# How to build oneTBB documentation + +Our documentation is written in restructured text markup (.rst) and built using [Sphinx](http://www.sphinx-doc.org/en/master/). + +This document explains how to build oneTBB documentation locally. + +## Prerequisites +- Python 3.7.0 or higher +- Sphinx + +## Build documentation + +Do the following to generate HTML output of the documentation: + +1. Clone oneTBB repository: + +``` +git clone https://github.com/oneapi-src/oneTBB.git +``` + +2. Go to the `doc` folder: + +``` +cd oneTBB/doc +``` + +3. Run in the command line: + +``` +make html +``` + + +That's it! Your built documentation is located in the ``build/html`` folder. diff --git a/doc/conf.py b/doc/conf.py index 3cc3f403fe..4c7e2b8a4b 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -29,7 +29,7 @@ project = u'IntelĀ® oneAPI Threading Building Blocks (oneTBB)' else: project = u'oneTBB' -copyright = u'2021, Intel Corporation' +copyright = u'2022, Intel Corporation' author = u'Intel' # The short X.Y version @@ -60,7 +60,7 @@ ] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ['main/_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: @@ -120,21 +120,26 @@ # further. For a list of options available for each theme, see the # documentation. # -if BUILD_TYPE == 'oneapi' or BUILD_TYPE == 'dita': - html_theme = 'sphinx_rtd_theme' + +html_theme = 'sphinx_book_theme' + +if BUILD_TYPE == 'dita': + html_theme_options = { + 'repository_url': 'https://github.com/oneapi-src/oneTBB', + 'path_to_docs': 'doc', + 'repository_branch': 'master' + } else: - html_theme = 'sphinx_book_theme' html_theme_options = { - 'repository_url': 'https://github.com/oneapi-src/oneTBB', - 'path_to_docs': 'doc/main', - 'use_issues_button': True, - 'use_edit_page_button': True, - 'repository_branch': 'master', - 'extra_footer': '

Cookies

' + 'repository_url': 'https://github.com/oneapi-src/oneTBB', + 'path_to_docs': 'doc/main', + 'use_issues_button': True, + 'use_edit_page_button': True, + 'repository_branch': 'master', + 'extra_footer': '

Cookies

' } - # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". @@ -148,8 +153,9 @@ } else: html_js_files = ['custom.js'] - html_logo = '_static/oneAPI-rgb-rev-100.png' + +html_logo = '_static/oneAPI-rgb-rev-100.png' html_favicon = '_static/favicons.png' # Custom sidebar templates, must be a dictionary that maps document names diff --git a/doc/index/index_intro.rst b/doc/index/index_intro.rst index b82c487997..72055fe8d3 100644 --- a/doc/index/index_intro.rst +++ b/doc/index/index_intro.rst @@ -2,3 +2,4 @@ This document contains information about |short_name|. It is a flexible performance library that let you break computation into parallel running tasks. + diff --git a/doc/index/toctree.rst b/doc/index/toctree.rst index 364d52aefc..60cfe1e362 100644 --- a/doc/index/toctree.rst +++ b/doc/index/toctree.rst @@ -1,13 +1,33 @@ .. _toctree: .. toctree:: + :caption: About + :maxdepth: 1 + + /main/intro/help_support + /main/intro/notation + /main/intro/intro_os + /main/intro/Benefits + + +.. toctree:: + :caption: Get Started :maxdepth: 2 - main/intro/help_support - main/intro/notation - main/intro/intro_os - main/intro/Benefits - GSG/get_started - main/tbb_userguide/title - main/reference/reference - main/intro/notices_and_disclaimers \ No newline at end of file + /GSG/get_started + /GSG/installation + /GSG/examples + + +.. toctree:: + :maxdepth: 3 + :caption: Developer Guide + + /main/tbb_userguide/title + + +.. toctree:: + :maxdepth: 3 + :caption: Developer Reference + + /main/reference/reference diff --git a/doc/main/_templates/layout.html b/doc/main/_templates/layout.html index 2629d21887..eedbf5b39d 100644 --- a/doc/main/_templates/layout.html +++ b/doc/main/_templates/layout.html @@ -6,10 +6,12 @@ var wapLocalCode = 'us-en'; // Dynamically set per localized site, see mapping table for values var wapSection = "oneapi-tbb"; // WAP team will give you a unique section for your site // Load TMS - (function () { - var url = 'https://www.intel.com/content/dam/www/global/wap/tms-loader.js'; // WAP file URL - var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true; po.src = url; - var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s); + if(document.location.href.contains("oneapi-src.github.io")){ + (function () { + var url = 'https://www.intel.com/content/dam/www/global/wap/tms-loader.js'; // WAP file URL + var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true; po.src = url; + var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s); })(); + } {% endblock %} diff --git a/doc/main/intro/introducing_main_os.rst b/doc/main/intro/introducing_main_os.rst deleted file mode 100644 index 0d6a1be95f..0000000000 --- a/doc/main/intro/introducing_main_os.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _introducing_main: - -Introduction -============ - - -|full_name| is a library that supports scalable parallel programming using -standard ISO C++ code. It does not require special languages or -compilers. It is designed to promote scalable data parallel programming. -Additionally, it fully supports nested parallelism, so you can build -larger parallel components from smaller parallel components. To use the -library, you specify tasks, not threads, and let the library map tasks -onto threads in an efficient manner. - - -Many of the library interfaces employ generic programming, in which -interfaces are defined by requirements on types and not specific types. -The C++ Standard Template Library (STL) is an example of generic -programming. Generic programming enables oneTBB to be flexible yet -efficient. The generic interfaces enable you to customize components to -your specific needs. - - -.. note:: - |full_name| requires C++11 standard compiler support. - - -The net result is that oneTBB enables you to specify parallelism far -more conveniently than using raw threads, and at the same time can -improve performance. \ No newline at end of file diff --git a/doc/main/reference/reference.rst b/doc/main/reference/reference.rst index 855c3a869a..8990508206 100644 --- a/doc/main/reference/reference.rst +++ b/doc/main/reference/reference.rst @@ -50,6 +50,4 @@ The key properties of a preview feature are: constraints_extensions info_namespace_extensions task_group_extensions - task_arena_extensions - this_task_arena_extensions custom_mutex_chmap diff --git a/doc/main/reference/task_arena_extensions.rst b/doc/main/reference/task_arena_extensions.rst deleted file mode 100644 index 8cde3b29c1..0000000000 --- a/doc/main/reference/task_arena_extensions.rst +++ /dev/null @@ -1,61 +0,0 @@ -.. _task_arena_extensions: - -task_arena extensions -===================== - -.. note:: - To enable these extensions, set the ``TBB_PREVIEW_TASK_GROUP_EXTENSIONS`` macro to 1. - -.. contents:: - :local: - :depth: 1 - -Description -*********** - -|full_name| implementation extends the `tbb::task_arena specification `_ -with an overload of ``enqueue`` method accepting ``task_handle``. - - -API -*** - -Header ------- - -.. code:: cpp - - #include - -Synopsis --------- - -.. code:: cpp - - namespace oneapi { - namespace tbb { - - class task_arena { - public: - void enqueue(task_handle&& h); - }; - - } // namespace tbb - } // namespace oneapi - -Member Functions ----------------- - -.. cpp:function:: void enqueue(task_handle&& h) - -Enqueues a task owned by ``h`` into the ``task_arena`` for procession. - -Behavior of this function is identical to generic version (``template void task_arena::enqueue(F&& f)``) except parameter type. - -.. note:: - ``h`` should not be empty to avoid undefined behavior. - -.. rubric:: See also - -* `oneapi::tbb::task_arena specification `_ -* :ref:`task_handle` diff --git a/doc/main/reference/task_group_extensions.rst b/doc/main/reference/task_group_extensions.rst index ea4a7437ef..c2be6acca6 100644 --- a/doc/main/reference/task_group_extensions.rst +++ b/doc/main/reference/task_group_extensions.rst @@ -15,8 +15,6 @@ Description |full_name| implementation extends the `tbb::task_group specification `_ with the following members: - - constructor that takes a custom ``tbb::task_group_context`` object as an argument - - methods to create and run deferred tasks with ``task_handle`` - requirements for a user-provided function object @@ -40,15 +38,15 @@ Synopsis class task_group { public: - task_group(task_group_context& context); - + + //only the requirements for the return type of function F are changed template task_handle defer(F&& f); - void run(task_handle&& h); - - task_group_status run_and_wait(task_handle&&); - + //only the requirements for the return type of function F are changed + template + task_group_status run_and_wait(const F& f); + //only the requirements for the return type of function F are changed template void run(F&& f); @@ -62,43 +60,19 @@ Synopsis Member Functions ---------------- -.. cpp:function:: task_group(task_group_context& context) - -Constructs an empty ``task_group``, which tasks are associated with the ``context``. - - .. cpp:function:: template task_handle defer(F&& f) -Creates a deferred task to compute ``f()`` and returns ``task_handle`` pointing to it. - -The task is not scheduled for execution until explicitly requested. For example, with the ``task_group::run`` method. -However, the task is still added into the ``task_group``, thus the ``task_group::wait`` method waits until the ``task_handle`` is either scheduled or destroyed. - -The ``F`` type must meet the `Function Objects` requirements described in the [function.objects] section of the ISO C++ Standard. - As an optimization hint, ``F`` might return a ``task_handle``, which task object can be executed next. .. note:: - The ``task_handle`` returned by the function must be created with ``*this`` ``task_group``. It means, with the one for which run method is called, otherwise it is an undefined behavior. - -**Returns:** ``task_handle`` object pointing to task to compute ``f()``. - - -.. cpp:function:: void run(task_handle&& h) - -Schedules the task object pointed by the ``h`` for execution. + The ``task_handle`` returned by the function must be created using ``*this`` ``task_group``. That is, the one for which the run method is called, otherwise it is undefined behavior. -.. caution:: If ``h`` is empty or ``*this`` is not the same ``task_group`` that ``h`` is created with, the behavior is undefined. +.. cpp:function:: template task_group_status run_and_wait(const F& f) +As an optimization hint, ``F`` might return a ``task_handle``, which task object can be executed next. -.. cpp:function:: task_group_status run_and_wait(task_handle&& h) - -Equivalent to ``{run(std::move(h)); return wait();}``. - -**Returns**: The status of ``task_group``. - -.. caution:: - If ``h`` is empty or ``*this`` is not the same ``task_group`` that ``h`` is created with, the behavior is undefined. +.. note:: + The ``task_handle`` returned by the function must be created using ``*this`` ``task_group``. That is, the one for which the run method is called, otherwise it is undefined behavior. .. cpp:function:: template void run(F&& f) diff --git a/doc/main/reference/task_group_extensions/task_handle.rst b/doc/main/reference/task_group_extensions/task_handle.rst deleted file mode 100644 index b9b576d430..0000000000 --- a/doc/main/reference/task_group_extensions/task_handle.rst +++ /dev/null @@ -1,101 +0,0 @@ -.. _task_handle: - -task_handle -=========== - -.. note:: To enable these extensions, set the ``TBB_PREVIEW_TASK_GROUP_EXTENSIONS`` macro to 1. - - -.. contents:: - :local: - :depth: 1 - -Description -*********** - -This class owns a deferred task object. - -API -*** - -Header ------- - -.. code:: cpp - - #include - -Synopsis --------- - -.. code:: cpp - - namespace oneapi { - namespace tbb { - - class task_handle { - public: - task_handle(); - task_handle(task_handle&& src); - - ~task_handle(); - - task_handle& operator=(task_handle&& src); - - explicit operator bool() const noexcept; - }; - - bool operator==(task_handle const& h, std::nullptr_t) noexcept; - bool operator==(std::nullptr_t, task_handle const& h) noexcept; - - bool operator!=(task_handle const& h, std::nullptr_t) noexcept; - bool operator!=(std::nullptr_t, task_handle const& h) noexcept; - - } // namespace tbb - } // namespace oneapi - -Member Functions ----------------- - -.. cpp:function:: task_handle() - -Creates an empty ``task_handle`` object. - -.. cpp:function:: task_handle(task_handle&& src) - -Constructs ``task_handle`` object with the content of ``src`` using move semantics. ``src`` is left in an empty state. - -.. cpp:function:: ~task_handle() - -Destroys the ``task_handle`` object and associated task if it exists. - -.. cpp:function:: task_handle& operator=(task_handle&& src) - -Replaces the content of ``task_handle`` object with the content of ``src`` using move semantics. ``src`` is left in an empty state. -The previously associated task object, if any, is destroyed before the assignment. - -**Returns:** Reference to ``*this``. - -.. cpp:function:: explicit operator bool() const noexcept - -Checks if ``*this`` has an associated task object. - -**Returns:** ``true`` if ``*this`` is not empty, ``false`` otherwise. - -Non-Member Functions --------------------- - -.. code:: cpp - - bool operator==(task_handle const& h, std::nullptr_t) noexcept - bool operator==(std::nullptr_t, task_handle const& h) noexcept - -**Returns**: ``true`` if ``h`` is empty, ``false`` otherwise. - -.. code:: cpp - - bool operator!=(task_handle const& h, std::nullptr_t) noexcept - bool operator!=(std::nullptr_t, task_handle const& h) noexcept - -**Returns**: ``true`` if ``h`` is not empty, ``false`` otherwise. - diff --git a/doc/main/reference/this_task_arena_extensions.rst b/doc/main/reference/this_task_arena_extensions.rst deleted file mode 100644 index ddd0c31439..0000000000 --- a/doc/main/reference/this_task_arena_extensions.rst +++ /dev/null @@ -1,71 +0,0 @@ -.. _this_task_arena_extensions: - -this_task_arena extensions -========================== - -.. note:: - To enable these extensions, set the ``TBB_PREVIEW_TASK_GROUP_EXTENSIONS`` macro to 1. - -.. contents:: - :local: - :depth: 1 - -Description -*********** - -|full_name| implementation extends the `tbb::this_task_arena specification `_ -with an overloaded ``enqueue`` function. - - -API -*** - -Header ------- - -.. code:: cpp - - #include - -Synopsis --------- - -.. code:: cpp - - namespace oneapi { - namespace tbb { - namespace this_task_arena { - void enqueue(task_handle&& h); - - template - void enqueue(F&& f) ; - } // namespace this_task_arena - } // namespace tbb - } // namespace oneapi - -Member Functions ----------------- - - -.. cpp:function:: template void enqueue(F&& f) - -Enqueues a task into the ``task_arena`` currently used by the calling thread to process the specified functor, then immediately returns. -The ``F`` type must meet the `Function Objects` requirements described in the [function.objects] section of the ISO C++ Standard. - -Behavior of this function is identical to ``template void task_arena::enqueue(F&& f)`` applied to ``task_arena`` object constructed with ``attach`` parameter. - -.. cpp:function:: void enqueue(task_handle&& h) - -Enqueues a task owned by ``h`` into the ``task_arena`` that is currently used by the calling thread. - -Behavior of this function is identical to generic version (``template void enqueue(F&& f)``) except the parameter type. - -.. note:: - ``h`` should not be empty to avoid undefined behavior. - - -.. rubric:: See also: - -* `oneapi::tbb::this_task_arena specification `_ -* `oneapi::tbb::task_arena specification `_ -* :ref:`task_handle` 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 e5d572c3e4..3352dd8d32 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 @@ -4,15 +4,13 @@ Advanced Topic: Other Kinds of Iteration Spaces =============================================== -The examples so far have used the class ``blocked_range`` to specify -ranges. This class is useful in many situations, but it does not fit -every situation. You can use |full_name| -to define your own iteration space objects. The object must specify how -it can be split into subspaces by providing a basic splitting -constructor, an optional proportional splitting constructor (accompanied -with a trait value that enables its usage), and two predicate methods. -If your class is called ``R``, the methods and constructors should be as -follows: +The examples so far have used the class ``blocked_range`` to specify ranges. +This class is useful in many situations, but it does not fit every situation. +You can use |full_name| to define your own iteration space objects. The object +must specify how it can be split into subspaces by providing a basic splitting +constructor, an optional proportional splitting constructor, and two predicate +methods. If your class is called ``R``, the methods and constructors should be +as follows: :: @@ -25,10 +23,8 @@ follows: bool is_divisible() const; // Splits r into subranges r and *this R( R& r, split ); - // Splits r into subranges r and *this in proportion p + // (optional) Splits r into subranges r and *this in proportion p R( R& r, proportional_split p ); - // Allows usage of proportional splitting constructor - static const bool is_splittable_in_proportion = true; ... }; @@ -60,9 +56,7 @@ constructor is optional and takes the second argument of type that return the values of the proportion. These values should be used to split ``r`` accordingly, so that the updated ``r`` corresponds to the left part of the proportion, and the constructed object corresponds to -the right part. The proportional splitting constructor will be used only -if the static constant ``is_splittable_in_proportion`` is defined in the -class and assigned the value of ``true``. +the right part. Both splitting constructors should guarantee that the updated ``r`` part diff --git a/doc/main/tbb_userguide/Flow_Graph_resource_tips.rst b/doc/main/tbb_userguide/Flow_Graph_resource_tips.rst index b202fc2275..27dd524c5b 100644 --- a/doc/main/tbb_userguide/Flow_Graph_resource_tips.rst +++ b/doc/main/tbb_userguide/Flow_Graph_resource_tips.rst @@ -14,4 +14,5 @@ in a flow graph. ../tbb_userguide/use_limiter_node ../tbb_userguide/use_concurrency_limits - ../tbb_userguide/create_token_based_system \ No newline at end of file + ../tbb_userguide/create_token_based_system + ../tbb_userguide/attach_flow_graph_to_arena \ No newline at end of file diff --git a/doc/main/tbb_userguide/How_Task_Scheduler_Works.rst b/doc/main/tbb_userguide/How_Task_Scheduler_Works.rst new file mode 100644 index 0000000000..5ad1670baa --- /dev/null +++ b/doc/main/tbb_userguide/How_Task_Scheduler_Works.rst @@ -0,0 +1,50 @@ +.. _How_Task_Scheduler_Works.rst: + +How Task Scheduler Works +======================== + + +While the task scheduler is not bound to any particular type of parallelism, +it was designed to work efficiently for fork-join parallelism with lots of forks. +This type of parallelism is typical for parallel algorithms such as `oneapi::tbb::parallel_for +`_. + +Let's consider the mapping of fork-join parallelism on the task scheduler in more detail. + +The scheduler runs tasks in a way that tries to achieve several targets simultaneously: + - Enable as many threads as possible, by creating enough job, to achieve actual parallelism + - Preserve data locality to make a single thread execution more efficient + - Minimize both memory demands and cross-thread communication to reduce an overhead + +To achieve this, a balance between depth-first and breadth-first execution strategies +must be reached. Assuming that the task graph is finite, depth-first is better for +a sequential execution because: + +- **Strike when the cache is hot**. The deepest tasks are the most recently created tasks and therefore are the hottest in the cache. + Also, if they can be completed, tasks that depend on it can continue executing, and though not the hottest in a cache, + they are still warmer than the older tasks deeper in the dequeue. + +- **Minimize space**. Execution of the shallowest task leads to the breadth-first unfolding of a graph. It creates an exponential + number of nodes that co-exist simultaneously. In contrast, depth-first execution creates the same number + of nodes, but only a linear number can exists at the same time, since it creates a stack of other ready + tasks. + +Each thread has its deque of tasks that are ready to run. When a +thread spawns a task, it pushes it onto the bottom of its deque. + +When a thread participates in the evaluation of tasks, it constantly executes +a task obtained by the first rule that applies from the roughly equivalent ruleset: + +- Get the task returned by the previous one, if any. + +- Take a task from the bottom of its deque, if any. + +- Steal a task from the top of another randomly chosen deque. If the + selected deque is empty, the thread tries again to execute this rule until it succeeds. + +Rule 1 is described in :doc:`Task Scheduler Bypass `. +The overall effect of rule 2 is to execute the *youngest* task spawned by the thread, +which causes the depth-first execution until the thread runs out of work. +Then rule 3 applies. It steals the *oldest* task spawned by another thread, +which causes temporary breadth-first execution that converts potential parallelism +into actual parallelism. diff --git a/doc/main/tbb_userguide/Migration_Guide/Task_API.rst b/doc/main/tbb_userguide/Migration_Guide/Task_API.rst index 08d66b5c82..cdf922a316 100644 --- a/doc/main/tbb_userguide/Migration_Guide/Task_API.rst +++ b/doc/main/tbb_userguide/Migration_Guide/Task_API.rst @@ -364,11 +364,10 @@ is not guaranteed to be executed next by the current thread. root.wait_for_all();; } -In oneTBB this can be done using the preview feature of ``oneapi::tbb::task_group``. +In oneTBB, this can be done using ``oneapi::tbb::task_group``. .. code:: cpp - #define TBB_PREVIEW_TASK_GROUP_EXTENSIONS 1 #include // Assuming OtherTask is defined. @@ -421,11 +420,10 @@ and waiting on it is implemented as follows: // i.e. after the callback is called } -In oneTBB this can be done using the preview feature of ``oneapi::tbb::task_group``. +In oneTBB, this can be done using ``oneapi::tbb::task_group``. .. code:: cpp - #define TBB_PREVIEW_TASK_GROUP_EXTENSIONS 1 #include int main(){ diff --git a/doc/main/tbb_userguide/Task_Scheduler_Bypass.rst b/doc/main/tbb_userguide/Task_Scheduler_Bypass.rst new file mode 100644 index 0000000000..c198f6ac6b --- /dev/null +++ b/doc/main/tbb_userguide/Task_Scheduler_Bypass.rst @@ -0,0 +1,20 @@ +.. _Task_Scheduler_Bypass: + +Task Scheduler Bypass +===================== + +Scheduler bypass is an optimization where you directly specify the next task to run. +According to the rules of execution described in :doc:`How Task Scheduler Works `, +the spawning of the new task to be executed by the current thread involves the next steps: + + - Push a new task onto the thread's deque. + - Continue to execute the current task until it is completed. + - Take a task from the thread's deque, unless it is stolen by another thread. + +Steps 1 and 3 introduce unnecessary deque operations or, even worse, allow stealing that can hurt +locality without adding significant parallelism. These problems can be avoided by using "Task Scheduler Bypass" technique to directly point the preferable task to be executed next +instead of spawning it. When, as described in :doc:`How Task Scheduler Works `, +the returned task becomes the first candidate for the next task to be executed by the thread. Furthermore, this approach almost guarantees that +the task is executed by the current thread and not by any other thread. + +Please note that at the moment the only way to use this optimization is to use `preview feature of ``onepai::tbb::task_group`` \ No newline at end of file diff --git a/doc/main/tbb_userguide/Task_Scheduler_Summary.rst b/doc/main/tbb_userguide/Task_Scheduler_Summary.rst deleted file mode 100644 index 7c77d8f9df..0000000000 --- a/doc/main/tbb_userguide/Task_Scheduler_Summary.rst +++ /dev/null @@ -1,11 +0,0 @@ -.. _Task_Scheduler_Summary: - -Task Scheduler Summary -====================== - - -The task scheduler works most efficiently for fork-join parallelism with -lots of forks, so that the task-stealing can cause sufficient -breadth-first behavior to occupy threads, which then conduct themselves -in a depth-first manner until they need to steal more work. - diff --git a/doc/main/tbb_userguide/The_Task_Scheduler.rst b/doc/main/tbb_userguide/The_Task_Scheduler.rst index ac57e02037..d9e6056e1c 100644 --- a/doc/main/tbb_userguide/The_Task_Scheduler.rst +++ b/doc/main/tbb_userguide/The_Task_Scheduler.rst @@ -16,5 +16,6 @@ onto one of the high-level templates, use the task scheduler. ../tbb_userguide/Task-Based_Programming ../tbb_userguide/When_Task-Based_Programming_Is_Inappropriate - ../tbb_userguide/Task_Scheduler_Summary + ../tbb_userguide/How_Task_Scheduler_Works + ../tbb_userguide/Task_Scheduler_Bypass ../tbb_userguide/Guiding_Task_Scheduler_Execution \ No newline at end of file diff --git a/doc/main/tbb_userguide/attach_flow_graph_to_arena.rst b/doc/main/tbb_userguide/attach_flow_graph_to_arena.rst new file mode 100644 index 0000000000..d887d4b223 --- /dev/null +++ b/doc/main/tbb_userguide/attach_flow_graph_to_arena.rst @@ -0,0 +1,47 @@ +.. _attach_flow_graph_to_arena: + +Attach Flow Graph to an Arbitrary Task Arena +====================== + + +|short_name| ``task_arena`` interface provides mechanisms to guide tasks +execution within the arena by setting the preferred computation units, +restricting part of computation units, or limiting arena concurrency. In some +cases, you may want to apply such mechanisms when a flow graph executes. + +During its construction, a ``graph`` object attaches to the arena, in which the constructing +thread occupies a slot. + +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 + :language: c++ + :start-after: /*begin_attach_to_arena_1*/ + :end-before: /*end_attach_to_arena_1*/ + + +A ``graph`` object can be reattached to a different ``task_arena`` by calling +the ``graph::reset()`` function. It reinitializes and reattaches the ``graph`` to +the task arena instance, inside which the ``graph::reset()`` method is executed. + +This example shows how to reattach existing graph to an arena with the most performant +core type as the preferred one for a work execution. Whenever a task is spawned on behalf +of the graph, it is spawned in the arena of a graph it is attached to, disregarding +the arena of the thread that the task is spawned from: + + +.. literalinclude:: ./snippets/flow_graph_examples.cpp + :language: c++ + :start-after: /*begin_attach_to_arena_2*/ + :end-before: /*end_attach_to_arena_2*/ + +See the following topics to learn more: + +.. toctree:: + :maxdepth: 4 + + ../tbb_userguide/Guiding_Task_Scheduler_Execution + ../tbb_userguide/work_isolation + diff --git a/doc/main/tbb_userguide/design_patterns/Design_Patterns.rst b/doc/main/tbb_userguide/design_patterns/Design_Patterns.rst index 48d04618db..5daa696b5b 100644 --- a/doc/main/tbb_userguide/design_patterns/Design_Patterns.rst +++ b/doc/main/tbb_userguide/design_patterns/Design_Patterns.rst @@ -51,6 +51,7 @@ expressions into equivalent C++03 code. ../../tbb_userguide/design_patterns/Divide_and_Conquer ../../tbb_userguide/design_patterns/GUI_Thread ../../tbb_userguide/design_patterns/Non-Preemptive_Priorities + ../../tbb_userguide/design_patterns/Lazy_Initialization ../../tbb_userguide/design_patterns/Local_Serializer ../../tbb_userguide/design_patterns/Fenced_Data_Transfer ../../tbb_userguide/design_patterns/Reference_Counting diff --git a/doc/main/tbb_userguide/design_patterns/Images/image008a.jpg b/doc/main/tbb_userguide/design_patterns/Images/image008a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f1199dbaef58e49168a2d87cdeac29c9139097ae GIT binary patch literal 30488 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⩔Ul#U6s#G<7+7T95tkjR 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 I`D^dL0qy(f1ONa4 literal 0 HcmV?d00001 diff --git a/doc/main/tbb_userguide/design_patterns/Images/image009a.jpg b/doc/main/tbb_userguide/design_patterns/Images/image009a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..02cd19606791c00b1344b68af34b84f5440cf937 GIT binary patch literal 21793 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 O`VZ~;U&*kZ4E;ZP>d9RI literal 0 HcmV?d00001 diff --git a/doc/main/tbb_userguide/design_patterns/Lazy_Initialization.rst b/doc/main/tbb_userguide/design_patterns/Lazy_Initialization.rst new file mode 100644 index 0000000000..ccba0d2499 --- /dev/null +++ b/doc/main/tbb_userguide/design_patterns/Lazy_Initialization.rst @@ -0,0 +1,109 @@ +.. _Lazy_Initialization: + +Lazy Initialization +================== + + +.. container:: section + + + .. rubric:: Problem + :class: sectiontitle + + Delay the creation of an object, potentially expensive, until it is accessed. + In parallel programming, initialization must also be guarded against race conditions. + + +.. container:: section + + + .. rubric:: Context + :class: sectiontitle + + The cost of operations that take place during the initialization + of the object may be considerably high. In that case, the object + should be initialized only when needed. Lazy initialization is + the common tactic that allows implementing such an approach. + + +.. container:: section + + + .. rubric:: Solution + :class: sectiontitle + + Using ``oneapi::tbb::collaborative_call_once`` with ``oneapi::tbb::collaborative_once_flag`` + helps to implement thread-safe lazy initialization for a user object. + + + In addition, ``collaborative_call_once`` allows other thread blocked on + the same ``collaborative_once_flag`` to join other |short_name| + parallel constructions called within the initializing function. + + +.. container:: section + + + .. rubric:: Example + :class: sectiontitle + + This example illustrates the implementation of lazy initialization + for the calculation of the Fibonacci numbers. Here is a graphical + representation of the Fibonacci recursion tree for N=4. + + + |image0| + + + As seen in the diagram, some elements are recalculated more than once. These operations are redundant, + so the "lazy initialized" Fibonacci numbers are relevant here. + + + An implementation without the use of lazy initialization would have *O(2^N)* time complexity due to + the full recursion tree traversal and recalculation of values. Since all the nodes are traversed once, + the tree becomes a list, making the time complexity *O(N)*. + + + |image1| + + + Here you can see the code for the implementation. Already calculated values are stored in a buffer + paired with ``collaborative_once_flag`` and will not be recalculated when ``collaborative_call_once`` + is invoked when initialization has already been done. + + + :: + + + using FibBuffer = std::vector>; + + std::uint64_t LazyFibHelper(int n, FibBuffer& buffer) { + // Base case + if (n <= 1) { + return n; + } + // Calculate nth value only once and store it in the buffer. + // Other threads won't be blocked on already taken collaborative_once_flag + // but join parallelism inside functor + oneapi::tbb::collaborative_call_once(buffer[n].first, [&]() { + std::uint64_t a, b; + oneapi::tbb::parallel_invoke([&] { a = LazyFibHelper(n - 2, buffer); }, + [&] { b = LazyFibHelper(n - 1, buffer); }); + buffer[n].second = a + b; + }); + + return buffer[n].second; + } + + std::uint64_t Fib(int n) { + FibBuffer buffer(n+1); + return LazyFibHelper(n, buffer); + } + + +.. |image0| image:: Images/image008a.jpg + :width: 744px + :height: 367px +.. |image1| image:: Images/image009a.jpg + :width: 744px + :height: 367px diff --git a/doc/main/tbb_userguide/snippets/flow_graph_examples.cpp b/doc/main/tbb_userguide/snippets/flow_graph_examples.cpp new file mode 100644 index 0000000000..c1b97975c3 --- /dev/null +++ b/doc/main/tbb_userguide/snippets/flow_graph_examples.cpp @@ -0,0 +1,76 @@ +/* + Copyright (c) 2022 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. +*/ + +/* Flow Graph Code Example for the Userguide. +*/ + +//! Enable extended task_arena constraints feature for supporting Intel Hybrid Technology +//! and Intel Hyper-Threading Technology. +#define TBB_PREVIEW_TASK_ARENA_CONSTRAINTS_EXTENSION 1 + +#include +#include + +using namespace tbb::flow; + +//! Example shows how to set the most performant core type as the preferred one +//! for a graph execution. +static void flow_graph_attach_to_arena_1() { +/*begin_attach_to_arena_1*/ + std::vector core_types = tbb::info::core_types(); + tbb::task_arena arena( + tbb::task_arena::constraints{}.set_core_type(core_types.back()) + ); + + arena.execute( [&]() { + graph g; + function_node< int > f( g, unlimited, []( int ) { + /*the most performant core type is defined as preferred.*/ + } ); + f.try_put(1); + g.wait_for_all(); + } ); +/*end_attach_to_arena_1*/ +} + +//! Reattach existing graph to an arena with the most performant core type as +//! the preferred one for a work execution. +static void flow_graph_attach_to_arena_2() { +/*begin_attach_to_arena_2*/ + graph g; + function_node< int > f( g, unlimited, []( int ) { + /*the most performant core type is defined as preferred.*/ + } ); + + std::vector core_types = tbb::info::core_types(); + tbb::task_arena arena( + tbb::task_arena::constraints{}.set_core_type(core_types.back()) + ); + + arena.execute( [&]() { + g.reset(); + } ); + f.try_put(1); + g.wait_for_all(); +/*end_attach_to_arena_2*/ +} + +int main() { + flow_graph_attach_to_arena_1(); + flow_graph_attach_to_arena_2(); + + return 0; +} diff --git a/doc/make.bat b/doc/make.bat new file mode 100644 index 0000000000..557ecc5b62 --- /dev/null +++ b/doc/make.bat @@ -0,0 +1,53 @@ +@ECHO OFF + +rem ============================================================================ +rem Copyright (C) 2022 Intel Corporation +rem +rem Licensed under the Apache License, Version 2.0 (the "License"); +rem you may not use this file except in compliance with the License. +rem You may obtain a copy of the License at +rem +rem http://www.apache.org/licenses/LICENSE-2.0 +rem +rem Unless required by applicable law or agreed to in writing, software +rem distributed under the License is distributed on an "AS IS" BASIS, +rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +rem See the License for the specific language governing permissions and +rem limitations under the License. +rem ============================================================================ + + + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=doc +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/test/tbb/test_partitioner.h b/test/tbb/test_partitioner.h index 073ca17c47..81cb738ec6 100644 --- a/test/tbb/test_partitioner.h +++ b/test/tbb/test_partitioner.h @@ -481,50 +481,6 @@ class SplitConstructorAssertedRange { } }; -/* - * Possible use cases are: - * ------------------------------------------------------------------------------------------------------------- - * Range# is_splittable_in_proportion Range proportional ctor Used partitioner Result Effect - * ------------------------------------------------------------------------------------------------------------- - * 1 true available proportional pMN, r(p), part(p) - * ------------------------------------------------------------------------------------------------------------- - * 2 false available proportional p11, r(p), part(p) - * ------------------------------------------------------------------------------------------------------------- - * 3 not defined available proportional p11, r(p), part(p) - * ------------------------------------------------------------------------------------------------------------- - * 4 true not available proportional pMN, r(s), part(p) * - * ------------------------------------------------------------------------------------------------------------- - * 5 false not available proportional p11, r(s), part(p) - * ------------------------------------------------------------------------------------------------------------- - * 6 not defined not available proportional p11, r(s), part(p) - * ------------------------------------------------------------------------------------------------------------- - * 1 true available simple s, r(s), part(s) - * ------------------------------------------------------------------------------------------------------------- - * 2 false available simple s, r(s), part(s) - * ------------------------------------------------------------------------------------------------------------- - * 3 not defined available simple s, r(s), part(s) - * ------------------------------------------------------------------------------------------------------------- - * 4 true not available simple s, r(s), part(s) - * ------------------------------------------------------------------------------------------------------------- - * 5 false not available simple s, r(s), part(s) - * ------------------------------------------------------------------------------------------------------------- - * 6 not defined not available simple s, r(s), part(s) - * ------------------------------------------------------------------------------------------------------------- - * - * Legend: - * proportional - with proportional splits (e.g. affinity_partitioner) - * simple - without proportional splits (e.g. simple_partitioner, auto_partitioner) - * pMN - proportional_split object with proportion M to N is created. (p11 - proportion 1 to 1) - * s - split object is created - * r(p) - range's proportional split constructor is called - * r(s) - range's ordinary split constructor is called - * part(p) - partitioner's proportional split constructor is called - * part(s) - partitioner's ordinary split constructor is called - * * - incorrect split behavior is possible (e.g. partitioner divides at an arbitrary ratio while - * range divides into halves) - */ - - // proportional_split ctor defined class Range1: public SplitConstructorAssertedRange { public: