Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2da407b4d |
@@ -16,4 +16,4 @@
|
||||
# use Bazel internally. The Bazel build can have security risks or
|
||||
# optimization gaps.
|
||||
|
||||
build --symlink_prefix=/ # Out of source build
|
||||
build --symlink_prefix=/ # Out of source build
|
||||
+1
-1
@@ -1 +1 @@
|
||||
4.2.1
|
||||
4.1.0
|
||||
@@ -1,40 +0,0 @@
|
||||
### Description
|
||||
_Add 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)_
|
||||
|
||||
### 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_
|
||||
|
||||
- [ ] bug fix - _change which fixes an issue_
|
||||
- [ ] new feature - _change which 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_
|
||||
- [ ] not needed
|
||||
|
||||
### Documentation
|
||||
|
||||
- [ ] updated in # - _add PR number_
|
||||
- [ ] needs to be updated
|
||||
- [ ] not needed
|
||||
|
||||
### Breaks backward compatibility
|
||||
- [ ] Yes
|
||||
- [ ] No
|
||||
- [ ] Unknown
|
||||
|
||||
### Notify the following users
|
||||
_List users with `@` to send notifications_
|
||||
|
||||
### Other information
|
||||
@@ -48,9 +48,8 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run scan
|
||||
run: |
|
||||
command -v clang-format-10
|
||||
cp -r examples examples_formatted
|
||||
find examples_formatted -regex '.*\.\(cpp\|hpp\)' -exec clang-format-10 -style=file -i {} \;
|
||||
find examples_formatted -regex '.*\.\(cpp\|hpp\)' -exec clang-format-9 -style=file -i {} \;
|
||||
diff -r examples examples_formatted
|
||||
|
||||
documentation:
|
||||
|
||||
+3
-6
@@ -35,12 +35,9 @@ cc_library(
|
||||
"include/oneapi/tbb/*.h",
|
||||
"include/oneapi/tbb/detail/*.h",
|
||||
]),
|
||||
copts = ["-w"] + select({
|
||||
"@bazel_tools//platforms:windows": [
|
||||
"",
|
||||
],
|
||||
"//conditions:default": ["-mwaitpkg"],
|
||||
}),
|
||||
copts = [
|
||||
"-w",
|
||||
],
|
||||
defines =
|
||||
select({
|
||||
"@platforms//cpu:x86_64": ["__TBB_NO_IMPLICIT_LINKAGE"],
|
||||
|
||||
@@ -1,38 +1,24 @@
|
||||
# Bazel* build support
|
||||
# Bazel build support
|
||||
|
||||
The main build system of oneTBB is CMake*.
|
||||
[Bazel*](https://bazel.build/) support is community-based.
|
||||
The Bazel configuration may not include recommended compiler and/or linker flags used in the official CMake configuration.
|
||||
The main build system of oneTBB is CMake.
|
||||
Bazel support is community-based.
|
||||
The maintainers do not use Bazel internally.
|
||||
The Bazel configuration may not include recommended compiler and linker flags used in official CMake configuration.
|
||||
|
||||
---
|
||||
**NOTE**
|
||||
The Bazel build of oneTBB currently only aims for a subset of oneTBB that suffices restricted use cases of the usage of oneTBB.
|
||||
Pull requests to improve the Bazel build experience are welcomed.
|
||||
|
||||
Bazel is not recommended for use by oneTBB maintainers. Thus, it is not used internally.
|
||||
The standard approach of how Bazel handles third-party libraries is static linking.
|
||||
Even this is not recommended by the oneTBB maintainers this is chosen since this is considered as the best practice in the Bazel ecosystem.
|
||||
|
||||
---
|
||||
## Example usage
|
||||
|
||||
1. [Install Bazel](https://docs.bazel.build/versions/main/install.html).
|
||||
|
||||
The Bazel oneTBB build is currently only intended for a subset of oneTBB that suffices restricted use cases.
|
||||
Pull requests to improve the Bazel build experience are welcome.
|
||||
|
||||
The standard Bazel approach to handling third-party libraries is static linking. It is the best practice within the Bazel ecosystem.
|
||||
|
||||
## Using oneTBB as a dependency
|
||||
|
||||
This example demonstrates how to use oneTBB as a dependency within a Bazel project.
|
||||
|
||||
The following file structure is assumed:
|
||||
|
||||
```
|
||||
example
|
||||
├── .bazelrc
|
||||
├── BUILD.bazel
|
||||
├── main.cpp
|
||||
└── WORKSPACE.bazel
|
||||
```
|
||||
2. Create the following files in one folder (this folder will be considered as the workspace folder):
|
||||
|
||||
_WORKSPACE.bazel_:
|
||||
```python
|
||||
```
|
||||
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
||||
|
||||
git_repository(
|
||||
@@ -42,11 +28,8 @@ git_repository(
|
||||
)
|
||||
```
|
||||
|
||||
In the *WORKSPACE* file, the oneTBB GitHub* repository is fetched.
|
||||
|
||||
_BUILD.bazel_:
|
||||
|
||||
```python
|
||||
_BUILD_:
|
||||
```
|
||||
cc_binary(
|
||||
name = "Demo",
|
||||
srcs = ["main.cpp"],
|
||||
@@ -54,11 +37,8 @@ cc_binary(
|
||||
)
|
||||
```
|
||||
|
||||
The *BUILD* file defines a binary named `Demo` that has a dependency to oneTBB.
|
||||
|
||||
_main.cpp_:
|
||||
|
||||
```c++
|
||||
```
|
||||
#include "oneapi/tbb/version.h"
|
||||
|
||||
#include <iostream>
|
||||
@@ -74,23 +54,7 @@ int main() {
|
||||
}
|
||||
```
|
||||
|
||||
The expected output of this program is the current version of oneTBB.
|
||||
3. Switch to the folder where you create the files.
|
||||
|
||||
Switch to the folder with the files created earlier and run the binary with `bazel run //:Demo`.
|
||||
|
||||
## Build oneTBB using Bazel
|
||||
|
||||
Run ```bazel build //...``` in the oneTBB root directory.
|
||||
|
||||
## Compiler support
|
||||
|
||||
The Bazel build uses the compiler flag `-mwaitpkg` in non-Windows* builds.
|
||||
This flag is supported by the GNU* Compiler Collection (GCC) version 9.3, Clang* 12, and newer versions of those tools.
|
||||
|
||||
|
||||
---
|
||||
**NOTE**
|
||||
|
||||
To use the Bazel build with earlier versions of GCC, remove `-mwaitpkg` flag as it leads to errors during compilation.
|
||||
|
||||
---
|
||||
4. Execute the command `bazel run //:Demo`.
|
||||
As an expected output, you should see the oneTBB version.
|
||||
|
||||
+1
-20
@@ -103,7 +103,6 @@ option(TBBMALLOC_BUILD "Enable tbbmalloc build" ON)
|
||||
option(TBB_CPF "Enable preview features of the library" OFF)
|
||||
option(TBB_FIND_PACKAGE "Enable search for external oneTBB using find_package instead of build from sources" OFF)
|
||||
option(TBB_DISABLE_HWLOC_AUTOMATIC_SEARCH "Disable HWLOC automatic search by pkg-config tool" OFF)
|
||||
option(TBB_ENABLE_IPO "Enable Interprocedural Optimization (IPO) during the compilation" ON)
|
||||
|
||||
if (NOT DEFINED BUILD_SHARED_LIBS)
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
@@ -182,22 +181,6 @@ foreach(FILE_WITH_EXTRA_TARGETS ${FILES_WITH_EXTRA_TARGETS})
|
||||
include(${FILE_WITH_EXTRA_TARGETS})
|
||||
endforeach()
|
||||
|
||||
# - Enabling LTO on Android causes the NDK bug.
|
||||
# NDK throws the warning: "argument unused during compilation: '-Wa,--noexecstack'"
|
||||
# - For some reason GCC does not instrument code with Thread Sanitizer when lto is enabled and C linker is used.
|
||||
if (TBB_ENABLE_IPO AND BUILD_SHARED_LIBS AND NOT ANDROID_PLATFORM AND NOT TBB_SANITIZE MATCHES "thread")
|
||||
if (NOT CMAKE_VERSION VERSION_LESS 3.9)
|
||||
cmake_policy(SET CMP0069 NEW)
|
||||
include(CheckIPOSupported)
|
||||
check_ipo_supported(RESULT TBB_IPO_PROPERTY)
|
||||
else()
|
||||
set(TBB_IPO_FLAGS TRUE)
|
||||
endif()
|
||||
if (TBB_IPO_PROPERTY OR TBB_IPO_FLAGS)
|
||||
message(STATUS "IPO enabled")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(TBB_COMPILER_SETTINGS_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/compilers/${CMAKE_CXX_COMPILER_ID}.cmake)
|
||||
if (EXISTS ${TBB_COMPILER_SETTINGS_FILE})
|
||||
include(${TBB_COMPILER_SETTINGS_FILE})
|
||||
@@ -217,9 +200,7 @@ else()
|
||||
if (NOT "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "mips")
|
||||
if (TBBMALLOC_BUILD)
|
||||
add_subdirectory(src/tbbmalloc)
|
||||
if (NOT "${MSVC_CXX_ARCHITECTURE_ID}" MATCHES "ARM64")
|
||||
add_subdirectory(src/tbbmalloc_proxy)
|
||||
endif()
|
||||
add_subdirectory(src/tbbmalloc_proxy)
|
||||
endif()
|
||||
if (APPLE)
|
||||
message(STATUS "TBBBind build targets are disabled due to unsupported environment")
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
# Installation from Sources
|
||||
|
||||
Required Software:
|
||||
* DPC++/C++ Compiler
|
||||
* Microsoft* Visual Studio* (Windows* OS only)
|
||||
* GNU Compilers (gcc) 4.8.5–10
|
||||
* GNU C Library (glibc) version 2.17–2.32
|
||||
* Clang* 4.2–11.0
|
||||
|
||||
The project uses CMake build configuration. Make sure that you have CMake version 3.1 or higher.
|
||||
|
||||
Before installing the library, learn how to [configure, build, and test](cmake\README.md) the project.
|
||||
|
||||
NOTE: Be careful about installation. Avoid commands like `make install` unless you fully understand the consequences.
|
||||
|
||||
The following installation components are supported:
|
||||
|
||||
`runtime` - oneTBB runtime package (core shared libraries and .dll files on Windows).
|
||||
`devel` - oneTBB development package (header files, CMake integration files, library symbolic links, and .lib files on Windows).
|
||||
`tbb4py` - oneTBB Module for Python.
|
||||
|
||||
To install the specific components after configuration and build, run:
|
||||
|
||||
```bash
|
||||
cmake -DCOMPONENT=<component> [-DBUILD_TYPE=<build-type>] -P cmake_install.cmake
|
||||
```
|
||||
|
||||
Simple packaging using CPack is supported.
|
||||
The following commands allow to create a simple portable package that includes header files, libraries, and integration files for CMake:
|
||||
|
||||
```bash
|
||||
cmake <options> ..
|
||||
cpack
|
||||
```
|
||||
@@ -2,21 +2,22 @@
|
||||
[](LICENSE.txt) [](https://github.com/oneapi-src/oneTBB/actions/workflows/ci.yml?query=branch%3Amaster)
|
||||
|
||||
oneAPI Threading Building Blocks (oneTBB) lets you easily write parallel C++ programs that take
|
||||
full advantage of multicore performance, that are portable, composable and have future-proof scalability.
|
||||
full advantage of multicore performance that are portable, composable, and have future-proof scalability.
|
||||
|
||||
## Release Information
|
||||
Here are [Release Notes](RELEASE_NOTES.md) and [System Requirements](SYSTEM_REQUIREMENTS.md).
|
||||
## Installation
|
||||
You can install oneTBB from [GitHub*](https://github.com/oneapi-src/oneTBB/releases).
|
||||
See [Installation from Sources](INSTALL.md) for details.
|
||||
|
||||
## Documentation
|
||||
* [oneTBB Specification](https://spec.oneapi.com/versions/latest/elements/oneTBB/source/nested-index.html)
|
||||
* [oneTBB Developer Guide and Reference](https://oneapi-src.github.io/oneTBB)
|
||||
* [oneTBB Developer Guide and Reference](https://oneapi-src.github.io/oneTBB/)
|
||||
* [Migrating from TBB to oneTBB](https://oneapi-src.github.io/oneTBB/tbb_userguide/Migration_Guide.html)
|
||||
* [README for a build system](cmake/README.md)
|
||||
* [README for build system](cmake/README.md)
|
||||
* [Basic support for the Bazel build system](Bazel.md)
|
||||
* [oneTBB Discussions](https://github.com/oneapi-src/oneTBB/discussions)
|
||||
|
||||
## Support
|
||||
Please report issues and suggestions via [GitHub issues](https://github.com/oneapi-src/oneTBB/issues). See our [documentation](./CONTRIBUTING.md##Issues) to learn how to work with them.
|
||||
Please report issues and suggestions via
|
||||
[GitHub issues](https://github.com/oneapi-src/oneTBB/issues).
|
||||
|
||||
## How to Contribute
|
||||
We welcome community contributions, so check our [contributing guidelines](CONTRIBUTING.md)
|
||||
@@ -26,9 +27,8 @@ to learn more.
|
||||
oneAPI Threading Building Blocks is licensed under [Apache License, Version 2.0](LICENSE.txt).
|
||||
By its terms, contributions submitted to the project are also done under that license.
|
||||
|
||||
|
||||
## Engineering team contacts
|
||||
* [Email us.](mailto:inteltbbdevelopers@intel.com)
|
||||
* [E-mail us.](mailto:inteltbbdevelopers@intel.com)
|
||||
|
||||
------------------------------------------------------------------------
|
||||
\* All names and brands may be claimed as the property of others.
|
||||
\* All names and brands may be claimed as the property of others.
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
<!--
|
||||
******************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*******************************************************************************/-->
|
||||
|
||||
# Release Notes <!-- omit in toc -->
|
||||
This document contains changes of oneTBB compared to the last release.
|
||||
|
||||
## Table of Contents <!-- omit in toc -->
|
||||
- [Preview Features](#preview-features)
|
||||
- [Known Limitations](#known-limitations)
|
||||
- [Fixed Issues](#fixed-issues)
|
||||
- [Open-source Contributions Integrated](#open-source-contributions-integrated)
|
||||
|
||||
|
||||
## Preview Features
|
||||
- Introduced the collaborative_call_once algorithm that executes the callable object exactly once, but allows other threads to join oneTBB parallel construction used inside this callable object. Inspired by Ben FrantzDale and Henry Heffan.
|
||||
|
||||
## 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.
|
||||
- On Linux* OS, if oneAPI Threading Building Blocks (oneTBB) or Threading Building Blocks (TBB) are installed in a system folder like /usr/lib64, the application may fail to link due to the order in which the linker searches for libraries. Use the -L linker option to specify the correct location of oneTBB library. This issue does not affect the program execution.
|
||||
- The oneapi::tbb::info namespace interfaces might unexpectedly change the process affinity mask on Windows* OS systems (see https://github.com/open-mpi/hwloc/issues/366 for details) when using hwloc version lower than 2.5.
|
||||
- Using a hwloc version other than 1.11, 2.0, or 2.5 may cause an undefined behavior on Windows OS. See https://github.com/open-mpi/hwloc/issues/477 for details.
|
||||
- The NUMA topology may be detected incorrectly on Windows OS machines where the number of NUMA node threads exceeds the size of 1 processor group.
|
||||
- On Windows OS on ARM64*, when compiling an application using oneTBB with the Microsoft* Compiler, the compiler issues a warning C4324 that a structure was padded due to the alignment specifier. Consider suppressing the warning by specifying /wd4324 to the compiler command line.
|
||||
- oneTBB does not support fork(), to work-around the issue, consider using task_scheduler_handle to join oneTBB worker threads before using fork().
|
||||
|
||||
## Fixed Issues
|
||||
- Enabled full support of Address Sanitizer and Thread Sanitizer.
|
||||
- Fixed a race condition in tbbmalloc that may cause a crash in realloc() when using tbbmalloc_proxy.
|
||||
- Enabled GCC* 11 support.
|
||||
- Fixed limiter_node behavior when an integral type is used as an argument for the DecrementType template parameter.
|
||||
- Fixed a possible memory leak when the static or affinity partitioners are used.
|
||||
- Fixed possible system oversubscription when using a process mask and an explicit number of threads in the task arena.
|
||||
|
||||
## Open-source Contributions Integrated
|
||||
- Enabled PowerPC* Linux* OS support. Contributed by Mircho Rodozov (https://github.com/oneapi-src/oneTBB/pull/461)
|
||||
- Improved UNIX* system support and enabled QNX Neutrino* RTOS support. Contributed by Pablo Romero (https://github.com/oneapi-src/oneTBB/pull/440)
|
||||
- Enabled experimental Bazel* build system support. Contributed by Julian Amann (https://github.com/oneapi-src/oneTBB/pull/442)
|
||||
- Enabled oneTBB build for Windows* OS on ARM64*. Contributed by Michael Vitrano (https://github.com/oneapi-src/oneTBB/pull/507)
|
||||
- Added MinGW* and export attributes support. Contributed by Long Nguyen (https://github.com/oneapi-src/oneTBB/pull/351)
|
||||
@@ -1,63 +0,0 @@
|
||||
<!--
|
||||
******************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*******************************************************************************/-->
|
||||
|
||||
# System Requirements <!-- omit in toc -->
|
||||
This document provides details about hardware, operating system, and software prerequisites for the oneAPI Threading Building Blocks (oneTBB).
|
||||
|
||||
## Table of Contents <!-- omit in toc -->
|
||||
- [Supported Hardware](#supported-hardware)
|
||||
- [Software](#software)
|
||||
-[Supported Operating Systems](#supported-operating-systems)
|
||||
-[Supported Compilers](#supported-compilers)
|
||||
|
||||
|
||||
## Supported Hardware
|
||||
- Intel(R) Celeron(R) processor family
|
||||
- Intel(R) Core* processor family
|
||||
- Intel(R) Xeon(R) processor family
|
||||
- Intel(R) Xeon Phi* processor family
|
||||
- Intel(R) Atom* processor family
|
||||
- Non-Intel(R) processors compatible with the processors listed above
|
||||
|
||||
|
||||
## Software
|
||||
|
||||
### Supported Operating Systems
|
||||
- Systems with Microsoft* Windows* operating systems
|
||||
- Microsoft* Windows* 10
|
||||
- Microsoft* Windows* Server 2016
|
||||
- Microsoft* Windows* Server 2019
|
||||
- Systems with Linux* operating systems
|
||||
- Clear Linux*
|
||||
- Amazon* Linux 2
|
||||
- CentOS* 8
|
||||
- Debian* 10
|
||||
- Fedora* 34
|
||||
- Red Hat* Enterprise Linux* 7, 8
|
||||
- SuSE* Linux* Enterprise Server 15
|
||||
- Ubuntu* 18.04 LTS, 20.04, 21.04
|
||||
- Systems with macOS* operating systems: macOS* 10.15, 11.x
|
||||
- Systems with Android* operating systems: Android* 9
|
||||
|
||||
### Supported Compilers
|
||||
- Intel* oneAPI DPC++/C++ Compiler
|
||||
- Intel* C++ Compiler 19.0 and 19.1 version
|
||||
- Microsoft* Visual C++ 14.1 (Microsoft* Visual Studio* 2017, Windows* OS only)
|
||||
- Microsoft* Visual C++ 14.2 (Microsoft* Visual Studio* 2019, Windows* OS only)
|
||||
- For each supported Linux* operating system, the standard gcc version provided with that operating system is supported
|
||||
- GNU Compilers (gcc) 4.8.5 - 11.1.1
|
||||
- GNU C Library (glibc) version 2.17 - 2.33
|
||||
- Clang* 6.0.0 - 12.0.0
|
||||
+1
-1
@@ -16,4 +16,4 @@
|
||||
# use Bazel internally. The Bazel build can have security risks or
|
||||
# optimization gaps.
|
||||
|
||||
workspace(name = "oneTBB")
|
||||
workspace(name = "oneTBB")
|
||||
@@ -16,7 +16,6 @@ TBB_CPF:BOOL - Enable preview features of the library (OFF by default)
|
||||
TBB_INSTALL_VARS:BOOL - Enable auto-generated vars installation(packages generated by `cpack` and `make install` will also include the vars script)(OFF by default)
|
||||
TBB_VALGRIND_MEMCHECK:BOOL - Enable scan for memory leaks using Valgrind (OFF by default)
|
||||
TBB_DISABLE_HWLOC_AUTOMATIC_SEARCH - Disable HWLOC automatic search by pkg-config tool (OFF by default)
|
||||
TBB_ENABLE_IPO - Enable Interprocedural Optimization (IPO) during the compilation (ON by default)
|
||||
```
|
||||
|
||||
## Configure, build and test
|
||||
|
||||
@@ -31,9 +31,9 @@ if (NOT TBB_STRICT AND COMMAND tbb_remove_compile_flag)
|
||||
tbb_remove_compile_flag(-Werror)
|
||||
endif()
|
||||
|
||||
# Enable Intel(R) Transactional Synchronization Extensions (-mrtm) and WAITPKG instructions support (-mwaitpkg) on relevant processors
|
||||
if (NOT "${CMAKE_OSX_ARCHITECTURES}" MATCHES "^arm64$" AND CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|amd64|AMD64)") # OSX systems are 64-bit only
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -mrtm $<$<NOT:$<VERSION_LESS:${CMAKE_CXX_COMPILER_VERSION},12.0>>:-mwaitpkg>)
|
||||
# Enable Intel(R) Transactional Synchronization Extensions (-mrtm) on relevant processors
|
||||
if (NOT "${CMAKE_OSX_ARCHITECTURES}" MATCHES "^arm64$" AND CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|AMD64)") # OSX systems are 64-bit only
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -mrtm)
|
||||
endif()
|
||||
|
||||
# TBB malloc settings
|
||||
|
||||
@@ -44,7 +44,7 @@ if (NOT TBB_STRICT AND COMMAND tbb_remove_compile_flag)
|
||||
endif()
|
||||
|
||||
# Enable Intel(R) Transactional Synchronization Extensions (-mrtm) and WAITPKG instructions support (-mwaitpkg) on relevant processors
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "(AMD64|amd64|i.86|x86)")
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86|AMD64)")
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -mrtm $<$<NOT:$<VERSION_LESS:${CMAKE_CXX_COMPILER_VERSION},12.0>>:-mwaitpkg>)
|
||||
endif()
|
||||
|
||||
@@ -58,8 +58,12 @@ if (MINGW)
|
||||
list(APPEND TBB_COMMON_COMPILE_FLAGS -U__STRICT_ANSI__)
|
||||
endif()
|
||||
|
||||
set(TBB_IPO_COMPILE_FLAGS $<$<NOT:$<CONFIG:Debug>>:-flto>)
|
||||
set(TBB_IPO_LINK_FLAGS $<$<NOT:$<CONFIG:Debug>>:-flto>)
|
||||
# Enabling LTO on Android causes the NDK bug.
|
||||
# NDK throws the warning: "argument unused during compilation: '-Wa,--noexecstack'"
|
||||
if (NOT ANDROID_PLATFORM AND BUILD_SHARED_LIBS)
|
||||
set(TBB_IPO_COMPILE_FLAGS $<$<NOT:$<CONFIG:Debug>>:-flto>)
|
||||
set(TBB_IPO_LINK_FLAGS $<$<NOT:$<CONFIG:Debug>>:-flto>)
|
||||
endif()
|
||||
|
||||
# TBB malloc settings
|
||||
set(TBBMALLOC_LIB_COMPILE_FLAGS -fno-rtti -fno-exceptions)
|
||||
|
||||
@@ -36,7 +36,7 @@ if (NOT CMAKE_GENERATOR MATCHES "Ninja" AND NOT CMAKE_CXX_DEPENDS_USE_COMPILER)
|
||||
endif()
|
||||
|
||||
# Enable Intel(R) Transactional Synchronization Extensions (-mrtm) and WAITPKG instructions support (-mwaitpkg) on relevant processors
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "(AMD64|amd64|i.86|x86)")
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86|AMD64)")
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -mrtm $<$<AND:$<NOT:$<CXX_COMPILER_ID:Intel>>,$<NOT:$<VERSION_LESS:${CMAKE_CXX_COMPILER_VERSION},11.0>>>:-mwaitpkg>)
|
||||
endif()
|
||||
|
||||
@@ -59,13 +59,15 @@ if ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "mips")
|
||||
set(TBB_TEST_COMPILE_FLAGS ${TBB_TEST_COMPILE_FLAGS} -DTBB_TEST_LOW_WORKLOAD $<$<CONFIG:DEBUG>:-mxgot>)
|
||||
endif()
|
||||
|
||||
set(TBB_IPO_COMPILE_FLAGS $<$<NOT:$<CONFIG:Debug>>:-flto>)
|
||||
set(TBB_IPO_LINK_FLAGS $<$<NOT:$<CONFIG:Debug>>:-flto>)
|
||||
if (MINGW)
|
||||
list(APPEND TBB_COMMON_COMPILE_FLAGS -U__STRICT_ANSI__)
|
||||
endif()
|
||||
|
||||
|
||||
if (MINGW AND CMAKE_SYSTEM_PROCESSOR MATCHES "i.86")
|
||||
list (APPEND TBB_COMMON_COMPILE_FLAGS -msse2)
|
||||
endif ()
|
||||
# For some reason GCC does not instrument code with Thread Sanitizer when lto is enabled and C linker is used.
|
||||
if (NOT TBB_SANITIZE MATCHES "thread")
|
||||
set(TBB_IPO_COMPILE_FLAGS $<$<NOT:$<CONFIG:Debug>>:-flto>)
|
||||
set(TBB_IPO_LINK_FLAGS $<$<NOT:$<CONFIG:Debug>>:-flto>)
|
||||
endif()
|
||||
|
||||
# TBB malloc settings
|
||||
set(TBBMALLOC_LIB_COMPILE_FLAGS -fno-rtti -fno-exceptions)
|
||||
|
||||
@@ -24,7 +24,7 @@ set(TBB_WARNING_LEVEL $<$<NOT:$<CXX_COMPILER_ID:Intel>>:/W4> $<$<BOOL:${TBB_STRI
|
||||
# Warning suppression C4324: structure was padded due to alignment specifier
|
||||
set(TBB_WARNING_SUPPRESS /wd4324)
|
||||
|
||||
set(TBB_TEST_COMPILE_FLAGS ${TBB_TEST_COMPILE_FLAGS} /bigobj)
|
||||
set(TBB_TEST_COMPILE_FLAGS /bigobj)
|
||||
if (MSVC_VERSION LESS_EQUAL 1900)
|
||||
# Warning suppression C4503 for VS2015 and earlier:
|
||||
# decorated name length exceeded, name was truncated.
|
||||
@@ -33,7 +33,7 @@ if (MSVC_VERSION LESS_EQUAL 1900)
|
||||
set(TBB_TEST_COMPILE_FLAGS ${TBB_TEST_COMPILE_FLAGS} /wd4503)
|
||||
endif()
|
||||
set(TBB_LIB_COMPILE_FLAGS -D_CRT_SECURE_NO_WARNINGS /GS)
|
||||
set(TBB_COMMON_COMPILE_FLAGS /volatile:iso /FS /EHsc)
|
||||
set(TBB_COMMON_COMPILE_FLAGS /volatile:iso /FS)
|
||||
|
||||
# Ignore /WX set through add_compile_options() or added to CMAKE_CXX_FLAGS if TBB_STRICT is disabled.
|
||||
if (NOT TBB_STRICT AND COMMAND tbb_remove_compile_flag)
|
||||
@@ -72,12 +72,11 @@ if (TBB_WINDOWS_DRIVER)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "(Clang|IntelLLVM)")
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86|AMD64|i.86)")
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86|AMD64)")
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -mrtm -mwaitpkg)
|
||||
endif()
|
||||
set(TBB_OPENMP_NO_LINK_FLAG TRUE)
|
||||
set(TBB_IPO_COMPILE_FLAGS $<$<NOT:$<CONFIG:Debug>>:-flto>)
|
||||
set(TBB_IPO_LINK_FLAGS $<$<NOT:$<CONFIG:Debug>>:-flto>)
|
||||
else()
|
||||
set(TBB_IPO_COMPILE_FLAGS $<$<NOT:$<CONFIG:Debug>>:/GL>)
|
||||
set(TBB_IPO_LINK_FLAGS $<$<NOT:$<CONFIG:Debug>>:-LTCG> $<$<NOT:$<CONFIG:Debug>>:-INCREMENTAL:NO>)
|
||||
|
||||
@@ -44,16 +44,3 @@ macro(tbb_install_target target)
|
||||
COMPONENT devel)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(tbb_handle_ipo target)
|
||||
if (TBB_IPO_PROPERTY)
|
||||
set_target_properties(${target} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
elseif (TBB_IPO_FLAGS)
|
||||
target_compile_options(${target} PRIVATE ${TBB_IPO_COMPILE_FLAGS})
|
||||
if (COMMAND target_link_options)
|
||||
target_link_options(${target} PRIVATE ${TBB_IPO_LINK_FLAGS})
|
||||
else()
|
||||
target_link_libraries(${target} PRIVATE ${TBB_IPO_LINK_FLAGS})
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
window.MathJax = {
|
||||
TeX: {
|
||||
Macros: {
|
||||
src: '\\operatorname{src}',
|
||||
srclayer: '\\operatorname{src\\_layer}',
|
||||
srciter: '\\operatorname{src\\_iter}',
|
||||
srciterc: '\\operatorname{src\\_iter\\_c}',
|
||||
weights: '\\operatorname{weights}',
|
||||
weightslayer: '\\operatorname{weights\\_layer}',
|
||||
weightsiter: '\\operatorname{weights\\_iter}',
|
||||
weightspeephole: '\\operatorname{weights\\_peephole}',
|
||||
weightsprojection: '\\operatorname{weights\\_projection}',
|
||||
bias: '\\operatorname{bias}',
|
||||
dst: '\\operatorname{dst}',
|
||||
dstlayer: '\\operatorname{dst\\_layer}',
|
||||
dstiter: '\\operatorname{dst\\_iter}',
|
||||
dstiterc: '\\operatorname{dst\\_iter\\_c}',
|
||||
diffsrc: '\\operatorname{diff\\_src}',
|
||||
diffsrclayer: '\\operatorname{diff\\_src\\_layer}',
|
||||
diffsrciter: '\\operatorname{diff\\_src\\_iter}',
|
||||
diffsrciterc: '\\operatorname{diff\\_src\\_iter\\_c}',
|
||||
diffweights: '\\operatorname{diff\\_weights}',
|
||||
diffweightslayer: '\\operatorname{diff\\_weights\\_layer}',
|
||||
diffweightsiter: '\\operatorname{diff\\_weights\\_iter}',
|
||||
diffweightspeephole: '\\operatorname{diff\\_weights\\_peephole}',
|
||||
diffweightsprojection: '\\operatorname{diff\\_weights\\_projection}',
|
||||
diffbias: '\\operatorname{diff\\_bias}',
|
||||
diffdst: '\\operatorname{diff\\_dst}',
|
||||
diffdstlayer: '\\operatorname{diff\\_dst\\_layer}',
|
||||
diffdstiter: '\\operatorname{diff\\_dst\\_iter}',
|
||||
diffdstiterc: '\\operatorname{diff\\_dst\\_iter\\_c}',
|
||||
diffgamma: '\\operatorname{diff\\_\\gamma}',
|
||||
diffbeta: '\\operatorname{diff\\_\\beta}',
|
||||
workspace: '\\operatorname{workspace}'
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 467 B |
Binary file not shown.
|
Before Width: | Height: | Size: 7.2 KiB |
@@ -1,13 +0,0 @@
|
||||
/* override table width restrictions */
|
||||
@media screen and (min-width: 767px) {
|
||||
|
||||
.wy-table-responsive table td {
|
||||
/* !important prevents the common CSS stylesheets from overriding
|
||||
this as on RTD they are loaded after this stylesheet */
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
.wy-table-responsive {
|
||||
overflow: visible !important;
|
||||
}
|
||||
}
|
||||
+3
-39
@@ -26,10 +26,7 @@ BUILD_TYPE = os.getenv("BUILD_TYPE")
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
|
||||
if BUILD_TYPE == 'oneapi' or BUILD_TYPE == 'dita':
|
||||
project = u'Intel® oneAPI Threading Building Blocks (oneTBB)'
|
||||
else:
|
||||
project = u'oneAPI Threading Building Blocks (oneTBB)'
|
||||
project = u'Intel® oneAPI Threading Building Blocks (oneTBB)'
|
||||
copyright = u'2021, Intel Corporation'
|
||||
author = u'Intel'
|
||||
|
||||
@@ -93,8 +90,7 @@ pygments_style = None
|
||||
highlight_language = 'cpp'
|
||||
|
||||
|
||||
if BUILD_TYPE == 'oneapi' or BUILD_TYPE == 'dita':
|
||||
rst_prolog = """
|
||||
rst_prolog = """
|
||||
.. |full_name| replace:: Intel\ |reg|\ oneAPI Threading Building Blocks (oneTBB)
|
||||
.. |short_name| replace:: oneTBB
|
||||
.. |product| replace:: oneTBB
|
||||
@@ -103,16 +99,6 @@ if BUILD_TYPE == 'oneapi' or BUILD_TYPE == 'dita':
|
||||
.. |base_tk| replace:: Intel\ |reg|\ oneAPI Base Toolkit
|
||||
.. |dpcpp| replace:: Intel\ |reg|\ oneAPI DPC++/C++ Compiler
|
||||
"""
|
||||
else:
|
||||
rst_prolog = """
|
||||
.. |full_name| replace:: oneAPI Threading Building Blocks (oneTBB)
|
||||
.. |short_name| replace:: oneTBB
|
||||
.. |product| replace:: oneTBB
|
||||
.. |reg| unicode:: U+000AE
|
||||
.. |copy| unicode:: U+000A9
|
||||
.. |base_tk| replace:: Intel\ |reg|\ oneAPI Base Toolkit
|
||||
.. |dpcpp| replace:: Intel\ |reg|\ oneAPI DPC++/C++ Compiler
|
||||
"""
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
@@ -124,35 +110,13 @@ else:
|
||||
# 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'
|
||||
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': '<p align="right"><a href="https://www.intel.com/content/www/us/en/privacy/intel-cookie-notice.html">Cookies</a></p>'
|
||||
}
|
||||
html_theme = 'sphinx_book_theme'
|
||||
|
||||
# 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".
|
||||
html_static_path = ['_static']
|
||||
|
||||
if BUILD_TYPE == 'oneapi' or BUILD_TYPE == 'dita':
|
||||
html_context = {
|
||||
'css_files': [
|
||||
'_static/theme_overrides.css', # override wide tables in RTD theme
|
||||
],
|
||||
}
|
||||
else:
|
||||
html_js_files = ['custom.js']
|
||||
html_logo = '_static/oneAPI-rgb-rev-100.png'
|
||||
html_favicon = '_static/favicons.png'
|
||||
|
||||
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
|
||||
+3
-27
@@ -16,18 +16,9 @@ of multi-core processors. Use |short_name| to write scalable applications that:
|
||||
- Emphasize data parallel programming
|
||||
- Take advantage of concurrent collections and parallel algorithms
|
||||
|
||||
System Requirements
|
||||
*******************
|
||||
|
||||
Refer to the `oneTBB System Requirements <https://software.intel.com/content/www/us/en/develop/articles/intel-oneapi-threading-building-blocks-system-requirements.html>`_.
|
||||
|
||||
|
||||
Before You Begin
|
||||
****************
|
||||
|
||||
Download |short_name| as a `stand-alone product <https://software.intel.com/content/www/us/en/develop/articles/oneapi-standalone-components.html#onetbb>`_
|
||||
or as a part of the `Intel(R) oneAPI Base Toolkit <https://software.intel.com/content/www/us/en/develop/tools/oneapi/base-toolkit/download.html>`_.
|
||||
|
||||
After installing |short_name|, you need to set the environment variables:
|
||||
|
||||
#. Go to the oneTBB installation directory (``<install_dir>``). By default, ``<install_dir>`` is the following:
|
||||
@@ -52,25 +43,10 @@ After installing |short_name|, you need to set the environment variables:
|
||||
``vars.bat in <install_dir>/tbb/latest/env``
|
||||
|
||||
|
||||
Example
|
||||
*******
|
||||
System Requirements
|
||||
*******************
|
||||
|
||||
Below you can find a typical example for a |short_name| algorithm.
|
||||
The sample calculates a sum of all integer numbers from 1 to 100.
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
int sum = oneapi::tbb::parallel_reduce(oneapi::tbb::blocked_range<int>(1,101), 0,
|
||||
[](oneapi::tbb::blocked_range<int> const& r, int init) -> int {
|
||||
for (int v = r.begin(); v != r.end(); v++ ) {
|
||||
init += v;
|
||||
}
|
||||
return init;
|
||||
},
|
||||
[](int lhs, int rhs) -> int {
|
||||
return lhs + rhs;
|
||||
}
|
||||
);
|
||||
Refer to the `oneTBB System Requirements <https://software.intel.com/content/www/us/en/develop/articles/intel-oneapi-threading-building-blocks-system-requirements.html>`_.
|
||||
|
||||
Find more
|
||||
*********
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
//configure tms
|
||||
var wapLocalCode = 'us-en';
|
||||
//dynamically set per localized site, see mapping table for values
|
||||
var wapSection = "oneapi-docs";
|
||||
//load tms
|
||||
(function() {
|
||||
var host = (window.document.location.protocol == 'http:') ? "http://www.intel.com" : "https://www.intel.com";
|
||||
var url = host+"/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);
|
||||
})();
|
||||
|
||||
window.MathJax = {
|
||||
TeX: {
|
||||
Macros: {
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
{% extends "!layout.html" %}
|
||||
{% block extrahead %}
|
||||
<script defer type="text/javascript" src="https://www.intel.com/content/dam/www/global/wap/performance-config.js" ></script>
|
||||
<script type="text/javascript">
|
||||
// Configure TMS settings
|
||||
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);
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
+4
-4
@@ -25,7 +25,7 @@ BUILD_TYPE = os.getenv("BUILD_TYPE")
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
if BUILD_TYPE == 'oneapi' or BUILD_TYPE == 'dita':
|
||||
if BUILD_TYPE == 'oneapi':
|
||||
project = u'Intel® oneAPI Threading Building Blocks (oneTBB)'
|
||||
else:
|
||||
project = u'oneAPI Threading Building Blocks (oneTBB)'
|
||||
@@ -90,7 +90,7 @@ pygments_style = None
|
||||
# Syntax highlighting for the :: directive
|
||||
highlight_language = 'cpp'
|
||||
|
||||
if BUILD_TYPE == 'oneapi' or BUILD_TYPE == 'dita':
|
||||
if BUILD_TYPE == 'oneapi':
|
||||
rst_prolog = """
|
||||
.. |full_name| replace:: Intel\ |reg|\ oneAPI Threading Building Blocks (oneTBB)
|
||||
.. |short_name| replace:: oneTBB
|
||||
@@ -120,7 +120,7 @@ else:
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
if BUILD_TYPE == 'oneapi' or BUILD_TYPE == 'dita':
|
||||
if BUILD_TYPE == 'oneapi':
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
else:
|
||||
html_theme = 'sphinx_book_theme'
|
||||
@@ -140,7 +140,7 @@ else:
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
if BUILD_TYPE == 'oneapi' or BUILD_TYPE == 'dita':
|
||||
if BUILD_TYPE == 'oneapi':
|
||||
html_context = {
|
||||
'css_files': [
|
||||
'_static/theme_overrides.css', # override wide tables in RTD theme
|
||||
|
||||
+1
-35
@@ -1,40 +1,6 @@
|
||||
|full_name|
|
||||
===========
|
||||
|
||||
This document contains information about |full_name|.
|
||||
|short_name| is a flexible performance library that can be found in the |base_tk|
|
||||
or as a stand-alone product. More information and specifications can be found on the
|
||||
|full_name| main page.
|
||||
|
||||
Documentation for older versions of |short_name| is available for download only.
|
||||
For a list of available documentation downloads by product version, see these pages:
|
||||
|
||||
* `Download Documentation for Intel Parallel Studio XE <https://software.intel.com/content/www/us/en/develop/articles/download-documentation-intel-parallel-studio-xe-current-previous.html>`_
|
||||
* `Download Documentation for Intel System Studio <https://software.intel.com/content/www/us/en/develop/articles/download-documentation-intel-system-studio-current-previous.html>`_
|
||||
|
||||
The following are some important topics for the ``novice user``:
|
||||
|
||||
**Get Started with oneAPI Threading Building Blocks (oneTBB)**
|
||||
|
||||
`Get Started with oneTBB <https://software.intel.com/content/www/us/en/develop/documentation/get-started-with-onetbb/top.html>`_ gives you a brief explanation of what oneTBB is.
|
||||
|
||||
**oneTBB Benefits**
|
||||
|
||||
:ref:`Benefits` describes how |short_name| differs from typical threading packages.
|
||||
|
||||
**Package Contents**
|
||||
|
||||
|short_name| includes dynamic library files and header files for Windows*, Linux*, and macOS*
|
||||
operating systems as described in :ref:`Package_Contents`.
|
||||
|
||||
|
||||
The following is important topic for the ``experienced user``:
|
||||
|
||||
**Migrating from Threading Building Blocks (TBB)**
|
||||
|
||||
Learn how to migrate from TBB to oneTBB with :ref:`Migration_Guide`.
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
@@ -44,4 +10,4 @@ Learn how to migrate from TBB to oneTBB with :ref:`Migration_Guide`.
|
||||
intro/Benefits
|
||||
tbb_userguide/title
|
||||
reference/reference
|
||||
intro/notices_and_disclaimers
|
||||
intro/notices_and_disclaimers
|
||||
@@ -1,72 +0,0 @@
|
||||
.. _parallel_sort_ranges_extension:
|
||||
|
||||
parallel_sort ranges interface extension
|
||||
========================================
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 1
|
||||
|
||||
Description
|
||||
***********
|
||||
|
||||
|full_name| implementation extends the `oneapi::tbb::parallel_sort specification <https://spec.oneapi.io/versions/latest/elements/oneTBB/source/algorithms/functions/parallel_sort_func.html>`_
|
||||
with overloads that takes the container by forwarding reference.
|
||||
|
||||
|
||||
API
|
||||
***
|
||||
|
||||
Header
|
||||
------
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#include <oneapi/tbb/parallel_sort.h>
|
||||
|
||||
Syntax
|
||||
------
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
namespace oneapi {
|
||||
namespace tbb {
|
||||
|
||||
template <typename Container>
|
||||
void parallel_sort( Container&& c );
|
||||
template <typename Container, typename Compare>
|
||||
void parallel_sort( Container&& c, const Compare& comp );
|
||||
|
||||
} // namespace tbb
|
||||
} // namespace oneapi
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. cpp:function:: template <typename Container> void parallel_sort( Container&& c );
|
||||
|
||||
Equivalent to ``parallel_sort( std::begin(c), std::end(c), comp )``, where `comp` uses `operator<` to determine relative orderings.
|
||||
|
||||
.. cpp:function:: template <typename Container, typename Compare> void parallel_sort( Container&& c, const Compare& comp );
|
||||
|
||||
Equivalent to ``parallel_sort( std::begin(c), std::end(c), comp )``.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
This interface may be used for sorting rvalue or constant views:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#include <array>
|
||||
#include <span> // requires C++20
|
||||
#include <oneapi/tbb/parallel_sort.h>
|
||||
|
||||
std::span<int> get_span() {
|
||||
static std::array<int, 3> arr = {3, 2, 1};
|
||||
return std::span<int>(arr);
|
||||
}
|
||||
|
||||
int main() {
|
||||
tbb::parallel_sort(get_span());
|
||||
}
|
||||
@@ -18,7 +18,6 @@ It also describes features that are not included in the oneTBB specification.
|
||||
|
||||
info_namespace
|
||||
parallel_for_each_semantics
|
||||
parallel_sort_ranges_extension
|
||||
|
||||
Preview features
|
||||
****************
|
||||
|
||||
@@ -191,7 +191,8 @@ This final implementation has all of the nodes and edges from the
|
||||
much advantage in using an ``input_node`` over an explicit loop. But,
|
||||
because an ``input_node`` is able to react to the behavior of downstream
|
||||
nodes, it can limit memory use in more complex graphs. For more
|
||||
information, see:ref:`create_token_based_system` .
|
||||
information, see `Creating a Token-Based
|
||||
System <create_token_based_system.html#create_token_based_system>`__
|
||||
|
||||
|
||||
.. |image0| image:: Images/flow_graph.jpg
|
||||
|
||||
@@ -325,131 +325,3 @@ task:
|
||||
}
|
||||
tg.wait();
|
||||
}
|
||||
|
||||
|
||||
Scheduler Bypass
|
||||
----------------
|
||||
|
||||
TBB ``task::execute()`` method can return a pointer to a task that can be executed next by the current thread.
|
||||
This might reduce scheduling overheads compared to direct ``spawn``. Similar to ``spawn``, the returned task
|
||||
is not guaranteed to be executed next by the current thread.
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#include <tbb/task.h>
|
||||
|
||||
// Assuming OtherTask is defined.
|
||||
|
||||
struct Task : tbb::task {
|
||||
task* execute(){
|
||||
// some work to do ...
|
||||
|
||||
auto* other_p = new(this->parent().allocate_child()) OtherTask{};
|
||||
this->parent().add_ref_count();
|
||||
|
||||
return other_p;
|
||||
}
|
||||
};
|
||||
|
||||
int main(){
|
||||
// Assuming RootTask is defined.
|
||||
RootTask& root = *new(tbb::task::allocate_root()) RootTask{};
|
||||
|
||||
Task& child = *new(root.allocate_child()) Task{/*params*/};
|
||||
|
||||
root.add_ref_count();
|
||||
|
||||
tbb::task_spawn(child);
|
||||
|
||||
root.wait_for_all();;
|
||||
}
|
||||
|
||||
In oneTBB this can be done using the preview feature of ``oneapi::tbb::task_group``.
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#define TBB_PREVIEW_TASK_GROUP_EXTENSIONS 1
|
||||
#include <oneapi/tbb/task_group.h>
|
||||
|
||||
// Assuming OtherTask is defined.
|
||||
|
||||
int main(){
|
||||
oneapi::tbb::task_group tg;
|
||||
|
||||
tg.run([&tg](){
|
||||
//some work to do ...
|
||||
|
||||
return tg.defer(OtherTask{});
|
||||
});
|
||||
|
||||
tg.wait();
|
||||
}
|
||||
|
||||
Here ``oneapi::tbb::task_group::defer`` adds a new task into the ``tg``. However, the task is not put into a
|
||||
queue of tasks ready for execution via ``oneapi::tbb::task_group::run``, but bypassed to the executing thread directly
|
||||
via function return value.
|
||||
|
||||
Deferred task creation
|
||||
----------------------
|
||||
The TBB low-level task API separates the task creation from the actual spawning. This separation allows to
|
||||
postpone the task spawning, while the parent task and final result production are blocked from premature leave.
|
||||
For example, ``RootTask``, ``ChildTask``, and ``CallBackTask`` are the user-side functors that
|
||||
inherit ``tbb::task`` and implement its interface. Then, blocking the ``RootTask`` from leaving prematurely
|
||||
and waiting on it is implemented as follows:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#include <tbb/task.h>
|
||||
|
||||
int main() {
|
||||
// Assuming RootTask, ChildTask, and CallBackTask are defined.
|
||||
RootTask& root = *new(tbb::task::allocate_root()) RootTask{};
|
||||
|
||||
ChildTask& child = *new(root.allocate_child()) ChildTask{/*params*/};
|
||||
CallBackTask& cb_task = *new(root.allocate_child()) CallBackTask{/*params*/};
|
||||
|
||||
root.set_ref_count(3);
|
||||
|
||||
tbb::task::spawn(child);
|
||||
|
||||
register_callback([cb_task&](){
|
||||
tbb::task::enqueue(cb_task);
|
||||
});
|
||||
|
||||
root.wait_for_all();
|
||||
// Control flow will reach here only after both ChildTask and CallBackTask are executed,
|
||||
// i.e. after the callback is called
|
||||
}
|
||||
|
||||
In oneTBB this can be done using the preview feature of ``oneapi::tbb::task_group``.
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#define TBB_PREVIEW_TASK_GROUP_EXTENSIONS 1
|
||||
#include <oneapi/tbb/task_group.h>
|
||||
|
||||
int main(){
|
||||
oneapi::tbb::task_group tg;
|
||||
oneapi::tbb::task_arena arena;
|
||||
// Assuming ChildTask and CallBackTask are defined.
|
||||
|
||||
auto cb = tg.defer(CallBackTask{/*params*/});
|
||||
|
||||
register_callback([&tg, c = std::move(cb), &arena]{
|
||||
arena.enqueue(c);
|
||||
});
|
||||
|
||||
tg.run(ChildTask{/*params*/});
|
||||
|
||||
|
||||
tg.wait();
|
||||
// Control flow gets here once both ChildTask and CallBackTask are executed
|
||||
// i.e. after the callback is called
|
||||
}
|
||||
|
||||
Here ``oneapi::tbb::task_group::defer`` adds a new task into the ``tg``. However, the task is not spawned until
|
||||
``oneapi::tbb::task_arena::enqueue`` is called.
|
||||
|
||||
.. note::
|
||||
The call to ``oneapi::tbb::task_group::wait`` will not return control until both ``ChildTask`` and
|
||||
``CallBackTask`` are executed.
|
||||
|
||||
@@ -9,7 +9,8 @@ You may not always want to block the main application thread by calling
|
||||
wait_for_all(). However, it is safest to call wait_for_all on a graph
|
||||
before destroying it. A common solution is to enqueue a task to build
|
||||
and wait for the graph to complete. For example, assume you really do
|
||||
not want to call a wait_for_all in the example from :ref:`always_use_wait_for_all`,
|
||||
not want to call a wait_for_all in the example from `Always Use
|
||||
wait_for_all() <always_use_wait_for_all.html#always_use_wait4all>`__,
|
||||
Instead you can enqueue a task that creates the graph and waits for it:
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ Use graph::reset() to Reset a Canceled Graph
|
||||
When a graph execution is canceled either because of an unhandled
|
||||
exception or because its task_group_context is canceled explicitly, the
|
||||
graph and its nodes may be left in an indeterminate state. For example,
|
||||
in the code samples shown in :ref:`cancel_a_graph` the input 2 may be
|
||||
in the code samples shown in `Cancel a Graph
|
||||
Explicitly <cancel_a_graph.html#cancel_a_graph>`__ the input 2 may be
|
||||
left in a buffer. But even beyond remnants in the buffers, there are
|
||||
other optimizations performed during the execution of a flow graph that
|
||||
can leave its nodes and edges in an indeterminate state. If you want to
|
||||
|
||||
@@ -29,7 +29,8 @@ All ``input_node`` objects are constructed in the inactive state and usually
|
||||
activated after the entire flow graph is constructed.
|
||||
|
||||
|
||||
For example, you can use the code in :ref:`Data_Flow_Graph`. In that implementation,
|
||||
For example, you can use the code in `Data Flow
|
||||
Graph <Data_Flow_Graph.html#Data_Flow_Graph>`__. In that implementation,
|
||||
the ``input_node`` is constructed in the inactive state and activated after
|
||||
all other edges are made:
|
||||
|
||||
|
||||
@@ -121,7 +121,6 @@ if (NOT _find_index EQUAL -1)
|
||||
elseif ("${EXAMPLES_UI_MODE}" STREQUAL "x")
|
||||
set_x_ui_project_settings()
|
||||
endif()
|
||||
target_compile_options(UI_LIB_${PROJECT_NAME} PRIVATE ${TBB_CXX_STD_FLAG})
|
||||
endif()
|
||||
|
||||
unset(_available_ui_modes)
|
||||
|
||||
@@ -89,9 +89,10 @@ void video::terminate() {
|
||||
#endif
|
||||
g_video = 0;
|
||||
running = false;
|
||||
|
||||
delete[] g_pImg;
|
||||
g_pImg = nullptr;
|
||||
if (g_pImg) {
|
||||
delete[] g_pImg;
|
||||
g_pImg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
video::~video() {
|
||||
|
||||
@@ -164,9 +164,10 @@ void video::terminate() {
|
||||
m_pD2DFactory->Release();
|
||||
g_video = 0;
|
||||
running = false;
|
||||
|
||||
delete[] g_pImg;
|
||||
g_pImg = 0;
|
||||
if (g_pImg) {
|
||||
delete[] g_pImg;
|
||||
g_pImg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//////////// drawing area constructor & destructor /////////////
|
||||
|
||||
@@ -123,15 +123,17 @@ bool video::init_window(int sizex, int sizey) {
|
||||
}
|
||||
|
||||
void video::terminate() {
|
||||
delete g_pBitmap;
|
||||
g_pBitmap = 0;
|
||||
|
||||
if (g_pBitmap) {
|
||||
delete g_pBitmap;
|
||||
g_pBitmap = 0;
|
||||
}
|
||||
Gdiplus::GdiplusShutdown(gdiplusToken);
|
||||
g_video = 0;
|
||||
running = false;
|
||||
|
||||
delete[] g_pImg;
|
||||
g_pImg = 0;
|
||||
if (g_pImg) {
|
||||
delete[] g_pImg;
|
||||
g_pImg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//////////// drawing area constructor & destructor /////////////
|
||||
|
||||
@@ -87,9 +87,10 @@ void video::terminate() {
|
||||
}
|
||||
g_video = 0;
|
||||
running = false;
|
||||
|
||||
delete[] g_pImg;
|
||||
g_pImg = 0;
|
||||
if (g_pImg) {
|
||||
delete[] g_pImg;
|
||||
g_pImg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
video::~video() {
|
||||
|
||||
@@ -125,8 +125,8 @@ void ParallelEvolution::Run(double execution_time, int nthread) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete pGlobControl;
|
||||
pGlobControl = nullptr;
|
||||
if (pGlobControl)
|
||||
delete pGlobControl;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -124,8 +124,8 @@ public:
|
||||
|
||||
~ParallelEvolution() {
|
||||
//! delete global_control object
|
||||
delete m_pGlobControl;
|
||||
m_pGlobControl = nullptr;
|
||||
if (m_pGlobControl != nullptr)
|
||||
delete m_pGlobControl;
|
||||
}
|
||||
virtual void Run(double execution_time, int nthread);
|
||||
virtual void Step();
|
||||
|
||||
@@ -39,6 +39,7 @@ unsigned short init_values[BOARD_SIZE] = { 1, 0, 0, 9, 0, 0, 0, 8, 0, 0, 8, 0, 2
|
||||
0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 7, 4, 0, 0, 7, 0, 0,
|
||||
0, 3, 0, 0, 3, 0, 0, 0, 2, 0, 0, 5, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 0 };
|
||||
oneapi::tbb::task_group *g;
|
||||
double solve_time;
|
||||
|
||||
typedef struct {
|
||||
@@ -46,8 +47,8 @@ typedef struct {
|
||||
unsigned potential_set;
|
||||
} board_element;
|
||||
|
||||
void read_board(const char* filename) {
|
||||
FILE* fp;
|
||||
void read_board(const char *filename) {
|
||||
FILE *fp;
|
||||
int input;
|
||||
fp = fopen(filename, "r");
|
||||
if (!fp) {
|
||||
@@ -65,7 +66,7 @@ void read_board(const char* filename) {
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void print_board(const std::vector<board_element>& b) {
|
||||
void print_board(board_element *b) {
|
||||
for (unsigned row = 0; row < BOARD_DIM; ++row) {
|
||||
for (unsigned col = 0; col < BOARD_DIM; ++col) {
|
||||
printf(" %d", b[row * BOARD_DIM + col].solved_element);
|
||||
@@ -78,7 +79,7 @@ void print_board(const std::vector<board_element>& b) {
|
||||
}
|
||||
}
|
||||
|
||||
void print_potential_board(const std::vector<board_element>& b) {
|
||||
void print_potential_board(board_element *b) {
|
||||
for (unsigned row = 0; row < BOARD_DIM; ++row) {
|
||||
for (unsigned col = 0; col < BOARD_DIM; ++col) {
|
||||
if (b[row * BOARD_DIM + col].solved_element)
|
||||
@@ -94,45 +95,50 @@ void print_potential_board(const std::vector<board_element>& b) {
|
||||
}
|
||||
}
|
||||
|
||||
void init_board(std::vector<board_element>& b) {
|
||||
void init_board(board_element *b) {
|
||||
for (unsigned i = 0; i < BOARD_SIZE; ++i)
|
||||
b[i].solved_element = b[i].potential_set = 0;
|
||||
}
|
||||
|
||||
void init_board(std::vector<board_element>& b, unsigned short arr[BOARD_SIZE]) {
|
||||
void init_board(board_element *b, unsigned short arr[81]) {
|
||||
for (unsigned i = 0; i < BOARD_SIZE; ++i) {
|
||||
b[i].solved_element = arr[i];
|
||||
b[i].potential_set = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void init_potentials(std::vector<board_element>& b) {
|
||||
void init_potentials(board_element *b) {
|
||||
for (unsigned i = 0; i < BOARD_SIZE; ++i)
|
||||
b[i].potential_set = 0;
|
||||
}
|
||||
|
||||
bool fixed_board(const std::vector<board_element>& b) {
|
||||
void copy_board(board_element *src, board_element *dst) {
|
||||
for (unsigned i = 0; i < BOARD_SIZE; ++i)
|
||||
dst[i].solved_element = src[i].solved_element;
|
||||
}
|
||||
|
||||
bool fixed_board(board_element *b) {
|
||||
for (int i = BOARD_SIZE - 1; i >= 0; --i)
|
||||
if (b[i].solved_element == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool in_row(const std::vector<board_element>& b, unsigned row, unsigned col, unsigned short p) {
|
||||
bool in_row(board_element *b, unsigned row, unsigned col, unsigned short p) {
|
||||
for (unsigned c = 0; c < BOARD_DIM; ++c)
|
||||
if (c != col && b[row * BOARD_DIM + c].solved_element == p)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool in_col(const std::vector<board_element>& b, unsigned row, unsigned col, unsigned short p) {
|
||||
bool in_col(board_element *b, unsigned row, unsigned col, unsigned short p) {
|
||||
for (unsigned r = 0; r < BOARD_DIM; ++r)
|
||||
if (r != row && b[r * BOARD_DIM + col].solved_element == p)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool in_block(const std::vector<board_element>& b, unsigned row, unsigned col, unsigned short p) {
|
||||
bool in_block(board_element *b, unsigned row, unsigned col, unsigned short p) {
|
||||
unsigned b_row = row / 3 * 3, b_col = col / 3 * 3;
|
||||
for (unsigned i = b_row; i < b_row + 3; ++i)
|
||||
for (unsigned j = b_col; j < b_col + 3; ++j)
|
||||
@@ -141,7 +147,7 @@ bool in_block(const std::vector<board_element>& b, unsigned row, unsigned col, u
|
||||
return false;
|
||||
}
|
||||
|
||||
void calculate_potentials(std::vector<board_element>& b) {
|
||||
void calculate_potentials(board_element *b) {
|
||||
for (unsigned i = 0; i < BOARD_SIZE; ++i) {
|
||||
b[i].potential_set = 0;
|
||||
if (!b[i].solved_element) { // element is not yet fixed
|
||||
@@ -155,7 +161,7 @@ void calculate_potentials(std::vector<board_element>& b) {
|
||||
}
|
||||
}
|
||||
|
||||
bool valid_board(const std::vector<board_element>& b) {
|
||||
bool valid_board(board_element *b) {
|
||||
bool success = true;
|
||||
for (unsigned i = 0; i < BOARD_SIZE; ++i) {
|
||||
if (success && b[i].solved_element) { // element is fixed
|
||||
@@ -169,7 +175,7 @@ bool valid_board(const std::vector<board_element>& b) {
|
||||
return success;
|
||||
}
|
||||
|
||||
bool examine_potentials(std::vector<board_element>& b, bool& progress) {
|
||||
bool examine_potentials(board_element *b, bool *progress) {
|
||||
bool singletons = false;
|
||||
for (unsigned i = 0; i < BOARD_SIZE; ++i) {
|
||||
if (b[i].solved_element == 0 && b[i].potential_set == 0) // empty set
|
||||
@@ -222,58 +228,62 @@ bool examine_potentials(std::vector<board_element>& b, bool& progress) {
|
||||
}
|
||||
}
|
||||
}
|
||||
progress = singletons;
|
||||
*progress = singletons;
|
||||
return valid_board(b);
|
||||
}
|
||||
|
||||
void partial_solve(oneapi::tbb::task_group& g,
|
||||
std::vector<board_element>& b,
|
||||
unsigned first_potential_set) {
|
||||
void partial_solve(board_element *b, unsigned first_potential_set) {
|
||||
if (fixed_board(b)) {
|
||||
if (find_one)
|
||||
g.cancel();
|
||||
g->cancel();
|
||||
if (++nSols == 1 && verbose) {
|
||||
print_board(b);
|
||||
}
|
||||
free(b);
|
||||
return;
|
||||
}
|
||||
calculate_potentials(b);
|
||||
bool progress = true;
|
||||
bool success = examine_potentials(b, progress);
|
||||
bool success = examine_potentials(b, &progress);
|
||||
if (success && progress) {
|
||||
partial_solve(g, b, first_potential_set);
|
||||
partial_solve(b, first_potential_set);
|
||||
}
|
||||
else if (success && !progress) {
|
||||
board_element *new_board;
|
||||
while (b[first_potential_set].solved_element != 0)
|
||||
++first_potential_set;
|
||||
for (unsigned short potential = 1; potential <= BOARD_DIM; ++potential) {
|
||||
if (1 << (potential - 1) & b[first_potential_set].potential_set) {
|
||||
g.run([&g, b /*make a copy of the board*/, first_potential_set, potential]() {
|
||||
//as task_group treat passed in functor as const - const_cast is needed
|
||||
//to allow modification of the copy
|
||||
auto& new_board = const_cast<std::vector<board_element>&>(b);
|
||||
new_board[first_potential_set].solved_element = potential;
|
||||
partial_solve(g, new_board, first_potential_set);
|
||||
new_board = (board_element *)malloc(BOARD_SIZE * sizeof(board_element));
|
||||
copy_board(b, new_board);
|
||||
new_board[first_potential_set].solved_element = potential;
|
||||
g->run([=] {
|
||||
partial_solve(new_board, first_potential_set);
|
||||
});
|
||||
}
|
||||
}
|
||||
free(b);
|
||||
}
|
||||
else {
|
||||
free(b);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned solve(int p) {
|
||||
oneapi::tbb::global_control c(oneapi::tbb::global_control::max_allowed_parallelism, p);
|
||||
nSols = 0;
|
||||
std::vector<board_element> start_board(BOARD_SIZE);
|
||||
board_element *start_board = (board_element *)malloc(BOARD_SIZE * sizeof(board_element));
|
||||
init_board(start_board, init_values);
|
||||
oneapi::tbb::task_group g;
|
||||
g = new oneapi::tbb::task_group;
|
||||
oneapi::tbb::tick_count t0 = oneapi::tbb::tick_count::now();
|
||||
partial_solve(g, start_board, 0);
|
||||
g.wait();
|
||||
partial_solve(start_board, 0);
|
||||
g->wait();
|
||||
solve_time = (oneapi::tbb::tick_count::now() - t0).seconds();
|
||||
delete g;
|
||||
return nSols;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int main(int argc, char *argv[]) {
|
||||
oneapi::tbb::tick_count mainStartTime = oneapi::tbb::tick_count::now();
|
||||
|
||||
utility::thread_number_range threads(utility::get_default_num_threads);
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
#if __TBB_PREVIEW_COLLABORATIVE_CALL_ONCE
|
||||
|
||||
#include "task_arena.h"
|
||||
#include "task_group.h"
|
||||
#include "task.h"
|
||||
#include "tbb/task_arena.h"
|
||||
#include "tbb/task_group.h"
|
||||
#include "tbb/task.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
|
||||
@@ -329,8 +329,7 @@
|
||||
|
||||
#define __TBB_TSX_INTRINSICS_PRESENT (__RTM__ || __INTEL_COMPILER || (_MSC_VER>=1700 && (__TBB_x86_64 || __TBB_x86_32)))
|
||||
|
||||
#define __TBB_WAITPKG_INTRINSICS_PRESENT ((__INTEL_COMPILER >= 1900 || __TBB_GCC_VERSION >= 110000 || __TBB_CLANG_VERSION >= 120000) \
|
||||
&& (_WIN32 || _WIN64 || __unix__ || __APPLE__) && (__TBB_x86_32 || __TBB_x86_64) && !__ANDROID__)
|
||||
#define __TBB_WAITPKG_INTRINSICS_PRESENT ((__INTEL_COMPILER >= 1900 || __TBB_GCC_VERSION >= 110000 || __TBB_CLANG_VERSION >= 120000) && !__ANDROID__)
|
||||
|
||||
/** Internal TBB features & modes **/
|
||||
|
||||
|
||||
@@ -82,8 +82,7 @@ public:
|
||||
// TODO: pass the graph_buffer_policy to the base so it can allocate the queue instead.
|
||||
// This would be an interface-breaking change.
|
||||
virtual ~function_input_base() {
|
||||
delete my_queue;
|
||||
my_queue = nullptr;
|
||||
if ( my_queue ) delete my_queue;
|
||||
}
|
||||
|
||||
graph_task* try_put_task( const input_type& t) override {
|
||||
|
||||
@@ -180,8 +180,7 @@ public:
|
||||
|
||||
~hash_buffer() {
|
||||
internal_free_buffer(pointer_array, elements_array, my_size, nelements);
|
||||
delete my_key;
|
||||
my_key = nullptr;
|
||||
if(my_key) delete my_key;
|
||||
}
|
||||
hash_buffer(const hash_buffer&) = delete;
|
||||
hash_buffer& operator=(const hash_buffer&) = delete;
|
||||
|
||||
@@ -29,9 +29,7 @@
|
||||
#include <intrin.h>
|
||||
#ifdef __TBBMALLOC_BUILD
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h> // SwitchToThread()
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
|
||||
@@ -79,10 +79,10 @@ class rw_scoped_lock {
|
||||
public:
|
||||
//! Construct lock that has not acquired a mutex.
|
||||
/** Equivalent to zero-initialization of *this. */
|
||||
constexpr rw_scoped_lock() noexcept {}
|
||||
constexpr rw_scoped_lock() noexcept : m_mutex(nullptr), m_is_writer(false) {}
|
||||
|
||||
//! Acquire lock on given mutex.
|
||||
rw_scoped_lock(Mutex& m, bool write = true) {
|
||||
rw_scoped_lock(Mutex& m, bool write = true) : m_mutex(nullptr) {
|
||||
acquire(m, write);
|
||||
}
|
||||
|
||||
@@ -160,11 +160,11 @@ public:
|
||||
|
||||
protected:
|
||||
//! The pointer to the current mutex that is held, or nullptr if no mutex is held.
|
||||
Mutex* m_mutex {nullptr};
|
||||
Mutex* m_mutex{};
|
||||
|
||||
//! If mutex != nullptr, then is_writer is true if holding a writer lock, false if holding a reader lock.
|
||||
/** Not defined if not holding a lock. */
|
||||
bool m_is_writer {false};
|
||||
bool m_is_writer{};
|
||||
};
|
||||
|
||||
} // namespace d1
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
suppress_unused_warning(m_version_and_traits);
|
||||
}
|
||||
|
||||
~task_handle_task() override {
|
||||
~task_handle_task(){
|
||||
m_wait_ctx.release();
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ public:
|
||||
task_scheduler_handle& operator=(const task_scheduler_handle& other) = delete;
|
||||
|
||||
//! Move only
|
||||
task_scheduler_handle(task_scheduler_handle&& other) noexcept {
|
||||
task_scheduler_handle(task_scheduler_handle&& other) noexcept : m_ctl{nullptr} {
|
||||
std::swap(m_ctl, other.m_ctl);
|
||||
}
|
||||
task_scheduler_handle& operator=(task_scheduler_handle&& other) noexcept {
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
#if __TBB_ARENA_BINDING
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
namespace tbb {
|
||||
namespace detail {
|
||||
@@ -38,6 +37,10 @@ struct constraints {
|
||||
constraints(numa_node_id id = -1, int maximal_concurrency = -1)
|
||||
: numa_id(id)
|
||||
, max_concurrency(maximal_concurrency)
|
||||
#if __TBB_PREVIEW_TASK_ARENA_CONSTRAINTS_EXTENSION_PRESENT
|
||||
, core_type(-1)
|
||||
, max_threads_per_core(-1)
|
||||
#endif
|
||||
{}
|
||||
#endif /*!__TBB_CPP20_PRESENT*/
|
||||
|
||||
|
||||
@@ -236,7 +236,7 @@ void parallel_sort( RandomAccessIterator begin, RandomAccessIterator end, const
|
||||
}
|
||||
}
|
||||
|
||||
//! Sorts the data in [begin,end) with a default comparator \c std::less
|
||||
//! Sorts the data in [begin,end) with a default comparator \c std::less<RandomAccessIterator>
|
||||
/** @ingroup algorithms **/
|
||||
template<typename RandomAccessIterator>
|
||||
__TBB_requires(std::random_access_iterator<RandomAccessIterator> &&
|
||||
@@ -250,16 +250,16 @@ void parallel_sort( RandomAccessIterator begin, RandomAccessIterator end ) {
|
||||
template<typename Range, typename Compare>
|
||||
__TBB_requires(container_based_sequence<Range, std::random_access_iterator_tag> &&
|
||||
compare<Compare, range_iterator_type<Range>>)
|
||||
void parallel_sort( Range&& rng, const Compare& comp ) {
|
||||
void parallel_sort( Range& rng, const Compare& comp ) {
|
||||
parallel_sort(std::begin(rng), std::end(rng), comp);
|
||||
}
|
||||
|
||||
//! Sorts the data in rng with a default comparator \c std::less
|
||||
//! Sorts the data in rng with a default comparator \c std::less<RandomAccessIterator>
|
||||
/** @ingroup algorithms **/
|
||||
template<typename Range>
|
||||
__TBB_requires(container_based_sequence<Range, std::random_access_iterator_tag> &&
|
||||
less_than_comparable<typename std::iterator_traits<range_iterator_type<Range>>::value_type>)
|
||||
void parallel_sort( Range&& rng ) {
|
||||
void parallel_sort( Range& rng ) {
|
||||
parallel_sort(std::begin(rng), std::end(rng));
|
||||
}
|
||||
//@}
|
||||
|
||||
@@ -486,7 +486,8 @@ struct dynamic_grainsize_mode : Mode {
|
||||
|
||||
class auto_partition_type: public dynamic_grainsize_mode<adaptive_mode<auto_partition_type> > {
|
||||
public:
|
||||
auto_partition_type( const auto_partitioner& ) {
|
||||
auto_partition_type( const auto_partitioner& )
|
||||
: dynamic_grainsize_mode<adaptive_mode<auto_partition_type> >() {
|
||||
my_divisor *= __TBB_INITIAL_CHUNKS;
|
||||
}
|
||||
auto_partition_type( auto_partition_type& src, split)
|
||||
@@ -532,7 +533,8 @@ public:
|
||||
class static_partition_type : public linear_affinity_mode<static_partition_type> {
|
||||
public:
|
||||
typedef detail::proportional_split split_type;
|
||||
static_partition_type( const static_partitioner& ) {}
|
||||
static_partition_type( const static_partitioner& )
|
||||
: linear_affinity_mode<static_partition_type>() {}
|
||||
static_partition_type( static_partition_type& p, const proportional_split& split_obj )
|
||||
: linear_affinity_mode<static_partition_type>(p, split_obj) {}
|
||||
};
|
||||
@@ -543,7 +545,8 @@ class affinity_partition_type : public dynamic_grainsize_mode<linear_affinity_mo
|
||||
public:
|
||||
static const unsigned factor = 1 << factor_power; // number of slots in affinity array per task
|
||||
typedef detail::proportional_split split_type;
|
||||
affinity_partition_type( affinity_partitioner_base& ap ) {
|
||||
affinity_partition_type( affinity_partitioner_base& ap )
|
||||
: dynamic_grainsize_mode<linear_affinity_mode<affinity_partition_type> >() {
|
||||
__TBB_ASSERT( (factor&(factor-1))==0, "factor must be power of two" );
|
||||
ap.resize(factor);
|
||||
my_array = ap.my_array;
|
||||
|
||||
@@ -524,28 +524,6 @@ protected:
|
||||
return cancellation_status ? canceled : complete;
|
||||
}
|
||||
|
||||
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
|
||||
task_group_status internal_run_and_wait(d2::task_handle&& h) {
|
||||
if (h == nullptr) {
|
||||
throw_exception(exception_id::bad_task_handle);
|
||||
}
|
||||
|
||||
using acs = d2::task_handle_accessor;
|
||||
if (&acs::ctx_of(h) != &context()) {
|
||||
throw_exception(exception_id::bad_task_handle_wrong_task_group);
|
||||
}
|
||||
|
||||
bool cancellation_status = false;
|
||||
try_call([&] {
|
||||
execute_and_wait(*acs::release(h), context(), m_wait_ctx, context());
|
||||
}).on_completion([&] {
|
||||
// TODO: the reset method is not thread-safe. Ensure the correct behavior.
|
||||
cancellation_status = context().is_group_execution_cancelled();
|
||||
context().reset();
|
||||
});
|
||||
return cancellation_status ? canceled : complete;
|
||||
}
|
||||
#endif
|
||||
template<typename F>
|
||||
task* prepare_task(F&& f) {
|
||||
m_wait_ctx.reserve();
|
||||
@@ -654,12 +632,6 @@ public:
|
||||
task_group_status run_and_wait(const F& f) {
|
||||
return internal_run_and_wait(f);
|
||||
}
|
||||
|
||||
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
|
||||
task_group_status run_and_wait(d2::task_handle&& h) {
|
||||
return internal_run_and_wait(std::move(h));
|
||||
}
|
||||
#endif
|
||||
}; // class task_group
|
||||
|
||||
#if TBB_PREVIEW_ISOLATED_TASK_GROUP
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
// Product version
|
||||
#define TBB_VERSION_MAJOR 2021
|
||||
// Update version
|
||||
#define TBB_VERSION_MINOR 6
|
||||
#define TBB_VERSION_MINOR 4
|
||||
// "Patch" version for custom releases
|
||||
#define TBB_VERSION_PATCH 0
|
||||
// Suffix string
|
||||
@@ -34,7 +34,7 @@
|
||||
// OneAPI oneTBB specification version
|
||||
#define ONETBB_SPEC_VERSION "1.0"
|
||||
// Full interface version
|
||||
#define TBB_INTERFACE_VERSION 12060
|
||||
#define TBB_INTERFACE_VERSION 12040
|
||||
// Major interface version
|
||||
#define TBB_INTERFACE_VERSION_MAJOR (TBB_INTERFACE_VERSION/1000)
|
||||
// Minor interface version
|
||||
|
||||
Vendored
+2
-4
@@ -48,14 +48,12 @@ if /i "%1"=="all" (set TBB_TARGET_VS=vc_mt) & shift & goto ParseAr
|
||||
|
||||
:SetEnv
|
||||
if exist "%TBBROOT%\redist\%TBB_TARGET_ARCH%\%TBB_TARGET_VS%\tbb12.dll" (
|
||||
set "TBB_DLL_PATH=%TBBROOT%\redist\%TBB_TARGET_ARCH%\%TBB_TARGET_VS%"
|
||||
set "PATH=%TBBROOT%\redist\%TBB_TARGET_ARCH%\%TBB_TARGET_VS%;%PATH%"
|
||||
)
|
||||
if exist "%TBBROOT%\..\redist\%TBB_TARGET_ARCH%\tbb\%TBB_TARGET_VS%\tbb12.dll" (
|
||||
set "TBB_DLL_PATH=%TBBROOT%\..\redist\%TBB_TARGET_ARCH%\tbb\%TBB_TARGET_VS%"
|
||||
set "PATH=%TBBROOT%\..\redist\%TBB_TARGET_ARCH%\tbb\%TBB_TARGET_VS%;%PATH%"
|
||||
)
|
||||
|
||||
set "PATH=%TBB_DLL_PATH%;%PATH%"
|
||||
|
||||
set "LIB=%TBBROOT%\lib\%TBB_TARGET_ARCH%\%TBB_TARGET_VS%;%LIB%"
|
||||
set "INCLUDE=%TBBROOT%\include;%INCLUDE%"
|
||||
set "CPATH=%TBBROOT%\include;%CPATH%"
|
||||
|
||||
Vendored
-1
@@ -18,7 +18,6 @@ REM
|
||||
@echo off
|
||||
|
||||
set "TBBROOT=@TBBROOT_REPLACEMENT@"
|
||||
set "TBB_DLL_PATH=@BINARY_PATH_REPLACEMENT@"
|
||||
|
||||
set "INCLUDE=%TBBROOT%\include;%INCLUDE%"
|
||||
set "CPATH=%TBBROOT%\include;%CPATH%"
|
||||
|
||||
@@ -28,25 +28,25 @@
|
||||
<ItemDefinitionGroup Condition="$(Configuration.ToLower().Contains('release')) AND '$(Platform)' == 'Win32'">
|
||||
<Link>
|
||||
<AdditionalLibraryDirectories>$(MSBuildThisFileDirectory)..\..\lib\native\win-x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>tbb12.lib;tbbmalloc.lib;tbbmalloc_proxy.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>tbb12.lib;tbbmalloc.lib;tbbmalloc_proxy.lib;tbbproxy.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="$(Configuration.ToLower().Contains('release')) AND '$(Platform)' == 'x64'">
|
||||
<Link>
|
||||
<AdditionalLibraryDirectories>$(MSBuildThisFileDirectory)..\..\lib\native\win-x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>tbb12.lib;tbbmalloc.lib;tbbmalloc_proxy.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>tbb12.lib;tbbmalloc.lib;tbbmalloc_proxy.lib;tbbproxy.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="$(Configuration.ToLower().Contains('debug')) AND '$(Platform)' == 'Win32'">
|
||||
<Link>
|
||||
<AdditionalLibraryDirectories>$(MSBuildThisFileDirectory)..\..\lib\native\win-x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>tbb12_debug.lib;tbbmalloc_debug.lib;tbbmalloc_proxy_debug.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>tbb12_debug.lib;tbbmalloc_debug.lib;tbbmalloc_proxy_debug.lib;tbbproxy_debug.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="$(Configuration.ToLower().Contains('debug')) AND '$(Platform)' == 'x64'">
|
||||
<Link>
|
||||
<AdditionalLibraryDirectories>$(MSBuildThisFileDirectory)..\..\lib\native\win-x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>tbb12_debug.lib;tbbmalloc_debug.lib;tbbmalloc_proxy_debug.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>tbb12_debug.lib;tbbmalloc_debug.lib;tbbmalloc_proxy_debug.lib;tbbproxy_debug.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ string(STRIP "${TBB4PY_INCLUDE_STRING}" TBB4PY_INCLUDE_STRING)
|
||||
|
||||
add_custom_target(
|
||||
python_build
|
||||
ALL
|
||||
DEPENDS tbb python_copy
|
||||
COMMAND
|
||||
${PYTHON_EXECUTABLE} ${PYTHON_BUILD_WORK_DIR}/setup.py
|
||||
|
||||
@@ -79,6 +79,7 @@ target_compile_options(tbb
|
||||
${TBB_WARNING_SUPPRESS}
|
||||
${TBB_LIB_COMPILE_FLAGS}
|
||||
${TBB_COMMON_COMPILE_FLAGS}
|
||||
${TBB_IPO_COMPILE_FLAGS}
|
||||
)
|
||||
|
||||
# Avoid use of target_link_libraries here as it changes /DEF option to \DEF on Windows.
|
||||
@@ -88,8 +89,6 @@ set_target_properties(tbb PROPERTIES
|
||||
SOVERSION ${TBB_BINARY_VERSION}
|
||||
)
|
||||
|
||||
tbb_handle_ipo(tbb)
|
||||
|
||||
if (TBB_DEF_FILE_PREFIX) # If there's no prefix, assume we're using export directives
|
||||
set_target_properties(tbb PROPERTIES
|
||||
LINK_FLAGS ${TBB_LINK_DEF_FILE_FLAG}${CMAKE_CURRENT_SOURCE_DIR}/def/${TBB_DEF_FILE_PREFIX}-tbb.def
|
||||
@@ -104,12 +103,14 @@ if (COMMAND target_link_options)
|
||||
PRIVATE
|
||||
${TBB_LIB_LINK_FLAGS}
|
||||
${TBB_COMMON_LINK_FLAGS}
|
||||
${TBB_IPO_LINK_FLAGS}
|
||||
)
|
||||
else()
|
||||
target_link_libraries(tbb
|
||||
PRIVATE
|
||||
${TBB_LIB_LINK_FLAGS}
|
||||
${TBB_COMMON_LINK_FLAGS}
|
||||
${TBB_IPO_LINK_FLAGS}
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -28,12 +28,12 @@ namespace r1 {
|
||||
struct address_context {
|
||||
address_context() = default;
|
||||
|
||||
address_context(void* address, std::uintptr_t context) :
|
||||
my_address(address), my_context(context)
|
||||
address_context(void* address, std::uintptr_t contex) :
|
||||
my_address(address), my_contex(contex)
|
||||
{}
|
||||
|
||||
void* my_address{nullptr};
|
||||
std::uintptr_t my_context{0};
|
||||
std::uintptr_t my_contex{0};
|
||||
};
|
||||
|
||||
class address_waiter : public concurrent_monitor_base<address_context> {
|
||||
@@ -75,7 +75,7 @@ void notify_by_address(void* address, std::uintptr_t target_context) {
|
||||
address_waiter& waiter = get_address_waiter(address);
|
||||
|
||||
auto predicate = [address, target_context] (address_context ctx) {
|
||||
return ctx.my_address == address && ctx.my_context == target_context;
|
||||
return ctx.my_address == address && ctx.my_contex == target_context;
|
||||
};
|
||||
|
||||
waiter.notify_relaxed(predicate);
|
||||
|
||||
@@ -27,11 +27,11 @@
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#if _WIN32 || _WIN64
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#endif /* _WIN32||_WIN64 */
|
||||
|
||||
#if __TBB_WEAK_SYMBOLS_PRESENT
|
||||
|
||||
|
||||
+2
-2
@@ -49,7 +49,7 @@ public:
|
||||
restore_affinity_mask(my_binding_handler, this_task_arena::current_thread_index());
|
||||
}
|
||||
|
||||
~numa_binding_observer() override{
|
||||
~numa_binding_observer(){
|
||||
destroy_binding_handler(my_binding_handler);
|
||||
}
|
||||
};
|
||||
@@ -631,7 +631,7 @@ class delegated_task : public d1::task {
|
||||
public:
|
||||
delegated_task(d1::delegate_base& d, concurrent_monitor& s, d1::wait_context& wo)
|
||||
: m_delegate(d), m_monitor(s), m_wait_ctx(wo), m_completed{ false }{}
|
||||
~delegated_task() override {
|
||||
~delegated_task() {
|
||||
// The destructor can be called earlier than the m_monitor is notified
|
||||
// because the waiting thread can be released after m_wait_ctx.release_wait.
|
||||
// To close that race we wait for the m_completed signal.
|
||||
|
||||
+12
-15
@@ -217,6 +217,9 @@ struct arena_base : padded<intrusive_list_node> {
|
||||
task_stream<back_nonnull_accessor> my_critical_task_stream;
|
||||
#endif
|
||||
|
||||
//! The number of workers requested by the external thread owning the arena.
|
||||
unsigned my_max_num_workers;
|
||||
|
||||
//! The total number of workers that are requested from the resource manager.
|
||||
int my_total_num_workers_requested;
|
||||
|
||||
@@ -251,9 +254,18 @@ struct arena_base : padded<intrusive_list_node> {
|
||||
//! The market that owns this arena.
|
||||
market* my_market;
|
||||
|
||||
//! ABA prevention marker.
|
||||
std::uintptr_t my_aba_epoch;
|
||||
|
||||
//! Default task group context.
|
||||
d1::task_group_context* my_default_ctx;
|
||||
|
||||
//! The number of slots in the arena.
|
||||
unsigned my_num_slots;
|
||||
|
||||
//! The number of reserved slots (can be occupied only by external threads).
|
||||
unsigned my_num_reserved_slots;
|
||||
|
||||
#if __TBB_ENQUEUE_ENFORCED_CONCURRENCY
|
||||
// arena needs an extra worker despite a global limit
|
||||
std::atomic<bool> my_global_concurrency_mode;
|
||||
@@ -272,21 +284,6 @@ struct arena_base : padded<intrusive_list_node> {
|
||||
int my_local_concurrency_requests;
|
||||
#endif /* __TBB_ENQUEUE_ENFORCED_CONCURRENCY*/
|
||||
|
||||
//! ABA prevention marker.
|
||||
std::uintptr_t my_aba_epoch;
|
||||
//! The number of slots in the arena.
|
||||
unsigned my_num_slots;
|
||||
//! The number of reserved slots (can be occupied only by external threads).
|
||||
unsigned my_num_reserved_slots;
|
||||
//! The number of workers requested by the external thread owning the arena.
|
||||
unsigned my_max_num_workers;
|
||||
|
||||
//! The target serialization epoch for callers of adjust_job_count_estimate
|
||||
int my_adjust_demand_target_epoch;
|
||||
|
||||
//! The current serialization epoch for callers of adjust_job_count_estimate
|
||||
d1::waitable_atomic<int> my_adjust_demand_current_epoch;
|
||||
|
||||
#if TBB_USE_ASSERT
|
||||
//! Used to trap accesses to the object after its destruction.
|
||||
std::uintptr_t my_guard;
|
||||
|
||||
@@ -148,7 +148,8 @@ class sleep_node : public wait_node<Context> {
|
||||
public:
|
||||
using base_type::base_type;
|
||||
|
||||
~sleep_node() override {
|
||||
// Make it virtual due to Intel Compiler warning
|
||||
virtual ~sleep_node() {
|
||||
if (this->my_initialized) {
|
||||
if (this->my_skipped_wakeup) semaphore().P();
|
||||
semaphore().~binary_semaphore();
|
||||
|
||||
@@ -281,13 +281,13 @@ namespace r1 {
|
||||
}
|
||||
|
||||
if ( fname_len>0 ) {
|
||||
ap_data._len += fname_len;
|
||||
if ( ap_data._len>PATH_MAX ) {
|
||||
DYNAMIC_LINK_WARNING( dl_buff_too_small );
|
||||
ap_data._len=0;
|
||||
return;
|
||||
}
|
||||
std::strncpy( ap_data._path+rc, dlinfo.dli_fname, fname_len );
|
||||
ap_data._len += fname_len;
|
||||
ap_data._path[ap_data._len]=0;
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
and CLOSE_INTERNAL_NAMESPACE to override the following default definitions. **/
|
||||
|
||||
#include <cstddef>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#if _WIN32
|
||||
#include <Windows.h>
|
||||
#endif /* _WIN32 */
|
||||
|
||||
namespace tbb {
|
||||
|
||||
+10
-10
@@ -59,19 +59,19 @@ public:
|
||||
};
|
||||
|
||||
class alignas(max_nfs_size) allowed_parallelism_control : public control_storage {
|
||||
std::size_t default_value() const override {
|
||||
virtual std::size_t default_value() const override {
|
||||
return max(1U, governor::default_num_threads());
|
||||
}
|
||||
bool is_first_arg_preferred(std::size_t a, std::size_t b) const override {
|
||||
virtual bool is_first_arg_preferred(std::size_t a, std::size_t b) const override {
|
||||
return a<b; // prefer min allowed parallelism
|
||||
}
|
||||
void apply_active(std::size_t new_active) override {
|
||||
virtual void apply_active(std::size_t new_active) override {
|
||||
control_storage::apply_active(new_active);
|
||||
__TBB_ASSERT( my_active_value>=1, NULL );
|
||||
// -1 to take external thread into account
|
||||
market::set_active_num_workers( my_active_value-1 );
|
||||
}
|
||||
std::size_t active_value() override {
|
||||
virtual std::size_t active_value() override {
|
||||
spin_mutex::scoped_lock lock(my_list_mutex); // protect my_list.empty() call
|
||||
if (my_list.empty())
|
||||
return default_value();
|
||||
@@ -88,10 +88,10 @@ public:
|
||||
};
|
||||
|
||||
class alignas(max_nfs_size) stack_size_control : public control_storage {
|
||||
std::size_t default_value() const override {
|
||||
virtual std::size_t default_value() const override {
|
||||
return ThreadStackSize;
|
||||
}
|
||||
void apply_active(std::size_t new_active) override {
|
||||
virtual void apply_active(std::size_t new_active) override {
|
||||
control_storage::apply_active(new_active);
|
||||
#if __TBB_WIN8UI_SUPPORT && (_WIN32_WINNT < 0x0A00)
|
||||
__TBB_ASSERT( false, "For Windows 8 Store* apps we must not set stack size" );
|
||||
@@ -100,20 +100,20 @@ class alignas(max_nfs_size) stack_size_control : public control_storage {
|
||||
};
|
||||
|
||||
class alignas(max_nfs_size) terminate_on_exception_control : public control_storage {
|
||||
std::size_t default_value() const override {
|
||||
virtual std::size_t default_value() const override {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#if __TBB_SUPPORTS_WORKERS_WAITING_IN_TERMINATE
|
||||
class alignas(max_nfs_size) lifetime_control : public control_storage {
|
||||
bool is_first_arg_preferred(std::size_t, std::size_t) const override {
|
||||
virtual bool is_first_arg_preferred(std::size_t, std::size_t) const override {
|
||||
return false; // not interested
|
||||
}
|
||||
std::size_t default_value() const override {
|
||||
virtual std::size_t default_value() const override {
|
||||
return 0;
|
||||
}
|
||||
void apply_active(std::size_t new_active) override {
|
||||
virtual void apply_active(std::size_t new_active) override {
|
||||
if (new_active == 1) {
|
||||
// reserve the market reference
|
||||
market::global_market_mutex_type::scoped_lock lock( market::theMarketMutex );
|
||||
|
||||
+2
-2
@@ -82,11 +82,11 @@ struct task_proxy : public d1::task {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task* execute(d1::execution_data&) override {
|
||||
virtual task* execute(d1::execution_data&) {
|
||||
__TBB_ASSERT_RELEASE(false, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
task* cancel(d1::execution_data&) override {
|
||||
virtual task* cancel(d1::execution_data&) {
|
||||
__TBB_ASSERT_RELEASE(false, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
+4
-4
@@ -578,14 +578,14 @@ void market::adjust_demand ( arena& a, int delta, bool mandatory ) {
|
||||
my_num_workers_requested += delta;
|
||||
__TBB_ASSERT(my_num_workers_requested <= (int)effective_soft_limit, NULL);
|
||||
|
||||
target_epoch = a.my_adjust_demand_target_epoch++;
|
||||
target_epoch = my_adjust_demand_target_epoch++;
|
||||
}
|
||||
|
||||
a.my_adjust_demand_current_epoch.wait_until(target_epoch, /* context = */ target_epoch, std::memory_order_relaxed);
|
||||
my_adjust_demand_current_epoch.wait_until(target_epoch, /* context = */ target_epoch, std::memory_order_acquire);
|
||||
// Must be called outside of any locks
|
||||
my_server->adjust_job_count_estimate( delta );
|
||||
a.my_adjust_demand_current_epoch.exchange(target_epoch + 1);
|
||||
a.my_adjust_demand_current_epoch.notify_relaxed(target_epoch + 1);
|
||||
my_adjust_demand_current_epoch.exchange(target_epoch + 1);
|
||||
my_adjust_demand_current_epoch.notify_relaxed(target_epoch + 1);
|
||||
}
|
||||
|
||||
void market::process( job& j ) {
|
||||
|
||||
+7
-1
@@ -105,6 +105,12 @@ private:
|
||||
//! Number of workers currently requested from RML
|
||||
int my_num_workers_requested;
|
||||
|
||||
//! The target serialization epoch for callers of adjust_job_count_estimate
|
||||
int my_adjust_demand_target_epoch;
|
||||
|
||||
//! The current serialization epoch for callers of adjust_job_count_estimate
|
||||
d1::waitable_atomic<int> my_adjust_demand_current_epoch;
|
||||
|
||||
//! First unused index of worker
|
||||
/** Used to assign indices to the new workers coming from RML, and busy part
|
||||
of my_workers array. **/
|
||||
@@ -228,7 +234,7 @@ public:
|
||||
unsigned arena_index, std::size_t stack_size );
|
||||
|
||||
//! Removes the arena from the market's list
|
||||
void try_destroy_arena ( arena*, uintptr_t aba_epoch, unsigned priority_level );
|
||||
void try_destroy_arena ( arena*, uintptr_t aba_epoch, unsigned pririty_level );
|
||||
|
||||
//! Removes the arena from the market's list
|
||||
void detach_arena ( arena& );
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
, my_suspend_point(my_curr_dispatcher->get_suspend_point())
|
||||
{}
|
||||
|
||||
~resume_node() override {
|
||||
virtual ~resume_node() {
|
||||
if (this->my_skipped_wakeup) {
|
||||
spin_wait_until_eq(this->my_notify_calls, 1);
|
||||
}
|
||||
|
||||
+7
-4
@@ -90,8 +90,9 @@ static basic_mask_t* process_mask;
|
||||
static int num_masks;
|
||||
|
||||
void destroy_process_mask() {
|
||||
delete [] process_mask;
|
||||
process_mask = nullptr;
|
||||
if( process_mask ) {
|
||||
delete [] process_mask;
|
||||
}
|
||||
}
|
||||
|
||||
#define curMaskSize sizeof(basic_mask_t) * num_masks
|
||||
@@ -120,8 +121,10 @@ void affinity_helper::protect_affinity_mask( bool restore_process_mask ) {
|
||||
}
|
||||
}
|
||||
void affinity_helper::dismiss() {
|
||||
delete [] threadMask;
|
||||
threadMask = NULL;
|
||||
if( threadMask ) {
|
||||
delete [] threadMask;
|
||||
threadMask = NULL;
|
||||
}
|
||||
is_changed = 0;
|
||||
}
|
||||
#undef curMaskSize
|
||||
|
||||
@@ -331,7 +331,7 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
~stage_task() override {
|
||||
~stage_task() {
|
||||
if ( my_filter && my_object ) {
|
||||
my_filter->finalize(my_object);
|
||||
my_object = nullptr;
|
||||
|
||||
@@ -96,7 +96,7 @@ private:
|
||||
protected:
|
||||
private_worker( private_server& server, tbb_client& client, const std::size_t i ) :
|
||||
my_state(st_init), my_server(server), my_client(client), my_index(i),
|
||||
my_handle(), my_next()
|
||||
my_thread_monitor(), my_handle(), my_next()
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -165,7 +165,7 @@ private:
|
||||
//! Equivalent of adding additional_slack to my_slack and waking up to 2 threads if my_slack permits.
|
||||
void wake_some( int additional_slack );
|
||||
|
||||
~private_server() override;
|
||||
virtual ~private_server();
|
||||
|
||||
void remove_server_ref() {
|
||||
if( --my_ref_count==0 ) {
|
||||
|
||||
+55
-109
@@ -168,11 +168,7 @@ struct queuing_rw_mutex_impl {
|
||||
s.my_state.store(d1::queuing_rw_mutex::scoped_lock::state_t(write ? STATE_WRITER : STATE_READER), std::memory_order_relaxed);
|
||||
s.my_internal_lock.store(RELEASED, std::memory_order_relaxed);
|
||||
|
||||
|
||||
// The CAS must have release semantics, because we are
|
||||
// "sending" the fields initialized above to other actors.
|
||||
// We need acquire semantics, because we are acquiring the predecessor (or mutex if no predecessor)
|
||||
queuing_rw_mutex::scoped_lock* predecessor = m.q_tail.exchange(&s, std::memory_order_acq_rel);
|
||||
queuing_rw_mutex::scoped_lock* predecessor = m.q_tail.exchange(&s, std::memory_order_release);
|
||||
|
||||
if( write ) { // Acquiring for write
|
||||
|
||||
@@ -181,8 +177,7 @@ struct queuing_rw_mutex_impl {
|
||||
predecessor = tricky_pointer(predecessor) & ~FLAG;
|
||||
__TBB_ASSERT( !predecessor->my_next, "the predecessor has another successor!");
|
||||
tricky_pointer::store(predecessor->my_next, &s, std::memory_order_release);
|
||||
// We are acquiring the mutex
|
||||
spin_wait_until_eq(s.my_going, 1U, std::memory_order_acquire);
|
||||
spin_wait_until_eq(s.my_going, 1U);
|
||||
}
|
||||
|
||||
} else { // Acquiring for read
|
||||
@@ -199,18 +194,10 @@ struct queuing_rw_mutex_impl {
|
||||
} else {
|
||||
// Load predecessor->my_state now, because once predecessor->my_next becomes
|
||||
// non-NULL, we must assume that *predecessor might be destroyed.
|
||||
pred_state = predecessor->my_state.load(std::memory_order_relaxed);
|
||||
if (pred_state == STATE_READER) {
|
||||
// Notify the previous reader to unblock us.
|
||||
predecessor->my_state.compare_exchange_strong(pred_state, STATE_READER_UNBLOCKNEXT, std::memory_order_relaxed);
|
||||
}
|
||||
if (pred_state == STATE_ACTIVEREADER) { // either we initially read it or CAS failed
|
||||
// Active reader means that the predecessor already acquired the mutex and cannot notify us.
|
||||
// Therefore, we need to acquire the mutex ourselves by re-reading predecessor state.
|
||||
(void)predecessor->my_state.load(std::memory_order_acquire);
|
||||
}
|
||||
pred_state = STATE_READER;
|
||||
predecessor->my_state.compare_exchange_strong(pred_state, STATE_READER_UNBLOCKNEXT, std::memory_order_acq_rel);
|
||||
}
|
||||
tricky_pointer::store(s.my_prev, predecessor, std::memory_order_relaxed);
|
||||
tricky_pointer::store(s.my_prev, predecessor, std::memory_order_relaxed); // TODO: order?
|
||||
__TBB_ASSERT( !( tricky_pointer(predecessor) & FLAG ), "use of corrupted pointer!" );
|
||||
__TBB_ASSERT( !predecessor->my_next.load(std::memory_order_relaxed), "the predecessor has another successor!");
|
||||
tricky_pointer::store(predecessor->my_next, &s, std::memory_order_release);
|
||||
@@ -219,18 +206,13 @@ struct queuing_rw_mutex_impl {
|
||||
sync_prepare_done = true;
|
||||
ITT_NOTIFY(sync_prepare, s.my_mutex);
|
||||
#endif
|
||||
// We are acquiring the mutex
|
||||
spin_wait_until_eq(s.my_going, 1U, std::memory_order_acquire);
|
||||
}
|
||||
}
|
||||
|
||||
// The protected state must have been acquired here before it can be further released to any other reader(s):
|
||||
unsigned char old_state = STATE_READER;
|
||||
// When this reader is signaled by previous actor it acquires the mutex.
|
||||
// We need to build happens-before relation with all other coming readers that will read our ACTIVEREADER
|
||||
// without blocking on my_going. Therefore, we need to publish ACTIVEREADER with release semantics.
|
||||
// On fail it is relaxed, because we will build happens-before on my_going.
|
||||
s.my_state.compare_exchange_strong(old_state, STATE_ACTIVEREADER, std::memory_order_release, std::memory_order_relaxed);
|
||||
s.my_state.compare_exchange_strong(old_state, STATE_ACTIVEREADER, std::memory_order_acq_rel);
|
||||
if( old_state!=STATE_READER ) {
|
||||
#if __TBB_USE_ITT_NOTIFY
|
||||
if( !sync_prepare_done )
|
||||
@@ -238,16 +220,20 @@ struct queuing_rw_mutex_impl {
|
||||
#endif
|
||||
// Failed to become active reader -> need to unblock the next waiting reader first
|
||||
__TBB_ASSERT( s.my_state.load(std::memory_order_relaxed)==STATE_READER_UNBLOCKNEXT, "unexpected state" );
|
||||
spin_wait_while_eq(s.my_next, 0U, std::memory_order_acquire);
|
||||
spin_wait_while_eq(s.my_next, 0U);
|
||||
/* my_state should be changed before unblocking the next otherwise it might finish
|
||||
and another thread can get our old state and left blocked */
|
||||
s.my_state.store(STATE_ACTIVEREADER, std::memory_order_relaxed);
|
||||
tricky_pointer::load(s.my_next, std::memory_order_relaxed)->my_going.store(1U, std::memory_order_release);
|
||||
}
|
||||
__TBB_ASSERT(s.my_state.load(std::memory_order_relaxed) == STATE_ACTIVEREADER, "unlocked reader is active reader");
|
||||
__TBB_ASSERT( s.my_state.load(std::memory_order_relaxed) ==STATE_ACTIVEREADER, "unlocked reader is active reader" );
|
||||
}
|
||||
|
||||
ITT_NOTIFY(sync_acquired, s.my_mutex);
|
||||
|
||||
// Force acquire so that user's critical section receives correct values
|
||||
// from processor that was previously in the user's critical section.
|
||||
atomic_fence(std::memory_order_acquire); // TODO: consider exchange on line 171
|
||||
}
|
||||
|
||||
//! A method to acquire queuing_rw_mutex if it is free
|
||||
@@ -267,11 +253,13 @@ struct queuing_rw_mutex_impl {
|
||||
s.my_internal_lock.store(RELEASED, std::memory_order_relaxed);
|
||||
|
||||
// The CAS must have release semantics, because we are
|
||||
// "sending" the fields initialized above to other actors.
|
||||
// We need acquire semantics, because we are acquiring the mutex
|
||||
// "sending" the fields initialized above to other processors.
|
||||
d1::queuing_rw_mutex::scoped_lock* expected = nullptr;
|
||||
if (!m.q_tail.compare_exchange_strong(expected, &s, std::memory_order_acq_rel))
|
||||
if (!m.q_tail.compare_exchange_strong(expected, &s, std::memory_order_release))
|
||||
return false; // Someone already took the lock
|
||||
// Force acquire so that user's critical section receives correct values
|
||||
// from processor that was previously in the user's critical section.
|
||||
atomic_fence(std::memory_order_acquire);
|
||||
s.my_mutex = &m;
|
||||
ITT_NOTIFY(sync_acquired, s.my_mutex);
|
||||
return true;
|
||||
@@ -292,50 +280,32 @@ struct queuing_rw_mutex_impl {
|
||||
d1::queuing_rw_mutex::scoped_lock* next = tricky_pointer::load(s.my_next, std::memory_order_acquire);
|
||||
if( !next ) {
|
||||
d1::queuing_rw_mutex::scoped_lock* expected = &s;
|
||||
// Release mutex on success otherwise wait for successor publication
|
||||
if( s.my_mutex->q_tail.compare_exchange_strong(expected, nullptr,
|
||||
std::memory_order_release, std::memory_order_relaxed) )
|
||||
{
|
||||
if( s.my_mutex->q_tail.compare_exchange_strong(expected, nullptr, std::memory_order_release) ) {
|
||||
// this was the only item in the queue, and the queue is now empty.
|
||||
goto done;
|
||||
}
|
||||
spin_wait_while_eq(s.my_next, 0U, std::memory_order_relaxed);
|
||||
spin_wait_while_eq(s.my_next, 0U);
|
||||
next = tricky_pointer::load(s.my_next, std::memory_order_acquire);
|
||||
}
|
||||
next->my_going.store(2U, std::memory_order_relaxed); // protect next queue node from being destroyed too early
|
||||
// If the next is STATE_UPGRADE_WAITING, it is expected to acquire all other released readers via release
|
||||
// sequence in next->my_state. In that case, we need to preserve release sequence in next->my_state
|
||||
// contributed by other reader. So, there are two approaches not to break the release sequence:
|
||||
// 1. Use read-modify-write (exchange) operation to store with release the UPGRADE_LOSER state;
|
||||
// 2. Acquire the release sequence and store the sequence and UPGRADE_LOSER state.
|
||||
// The second approach seems better on x86 because it does not involve interlocked operations.
|
||||
// Therefore, we read next->my_state with acquire while it is not required for else branch to get the
|
||||
// release sequence.
|
||||
if( next->my_state.load(std::memory_order_acquire)==STATE_UPGRADE_WAITING ) {
|
||||
if( next->my_state.load()==STATE_UPGRADE_WAITING ) {
|
||||
// the next waiting for upgrade means this writer was upgraded before.
|
||||
acquire_internal_lock(s);
|
||||
// Responsibility transition, the one who reads uncorrupted my_prev will do release.
|
||||
// Guarantee that above store of 2 into next->my_going happens-before resetting of next->my_prev
|
||||
d1::queuing_rw_mutex::scoped_lock* tmp = tricky_pointer::exchange(next->my_prev, nullptr, std::memory_order_release);
|
||||
// Pass the release sequence that we acquired with the above load of next->my_state.
|
||||
next->my_state.store(STATE_UPGRADE_LOSER, std::memory_order_release);
|
||||
// We are releasing the mutex
|
||||
next->my_state.store(STATE_UPGRADE_LOSER, std::memory_order_relaxed);
|
||||
next->my_going.store(1U, std::memory_order_release);
|
||||
unblock_or_wait_on_internal_lock(s, get_flag(tmp));
|
||||
} else {
|
||||
// next->state cannot be STATE_UPGRADE_REQUESTED
|
||||
__TBB_ASSERT( next->my_state.load(std::memory_order_relaxed) & (STATE_COMBINED_WAITINGREADER | STATE_WRITER), "unexpected state" );
|
||||
__TBB_ASSERT( !( next->my_prev.load(std::memory_order_relaxed) & FLAG ), "use of corrupted pointer!" );
|
||||
// Guarantee that above store of 2 into next->my_going happens-before resetting of next->my_prev
|
||||
tricky_pointer::store(next->my_prev, nullptr, std::memory_order_release);
|
||||
// We are releasing the mutex
|
||||
tricky_pointer::store(next->my_prev, nullptr, std::memory_order_relaxed);
|
||||
next->my_going.store(1U, std::memory_order_release);
|
||||
}
|
||||
|
||||
} else { // Acquired for read
|
||||
// The basic idea it to build happens-before relation with left and right readers via prev and next. In addition,
|
||||
// the first reader should acquire the left (prev) signal and propagate to right (next). To simplify, we always
|
||||
// build happens-before relation between left and right (left is happened before right).
|
||||
|
||||
queuing_rw_mutex::scoped_lock *tmp = nullptr;
|
||||
retry:
|
||||
// Addition to the original paper: Mark my_prev as in use
|
||||
@@ -347,9 +317,12 @@ struct queuing_rw_mutex_impl {
|
||||
// Failed to acquire the lock on predecessor. The predecessor either unlinks or upgrades.
|
||||
// In the second case, it could or could not know my "in use" flag - need to check
|
||||
// Responsibility transition, the one who reads uncorrupted my_prev will do release.
|
||||
tmp = tricky_pointer::compare_exchange_strong(s.my_prev, tricky_pointer(predecessor) | FLAG, predecessor, std::memory_order_acquire);
|
||||
tmp = tricky_pointer::compare_exchange_strong(s.my_prev, tricky_pointer(predecessor) | FLAG, predecessor, std::memory_order_release);
|
||||
if( !(tricky_pointer(tmp) & FLAG) ) {
|
||||
// Wait for the predecessor to change my_prev (e.g. during unlink)
|
||||
// TODO: spin_wait condition seems never reachable
|
||||
__TBB_ASSERT(tricky_pointer::load(s.my_prev, std::memory_order_relaxed) != (tricky_pointer(predecessor) | FLAG), nullptr);
|
||||
tricky_pointer::spin_wait_while_eq( s.my_prev, tricky_pointer(predecessor)|FLAG );
|
||||
// Now owner of predecessor is waiting for _us_ to release its lock
|
||||
release_internal_lock(*predecessor);
|
||||
}
|
||||
@@ -365,13 +338,13 @@ struct queuing_rw_mutex_impl {
|
||||
tricky_pointer::store(predecessor->my_next, nullptr, std::memory_order_release);
|
||||
|
||||
d1::queuing_rw_mutex::scoped_lock* expected = &s;
|
||||
if( !tricky_pointer::load(s.my_next, std::memory_order_acquire) && !s.my_mutex->q_tail.compare_exchange_strong(expected, predecessor, std::memory_order_release) ) {
|
||||
if( !tricky_pointer::load(s.my_next, std::memory_order_relaxed) && !s.my_mutex->q_tail.compare_exchange_strong(expected, predecessor, std::memory_order_release) ) {
|
||||
spin_wait_while_eq( s.my_next, 0U, std::memory_order_acquire );
|
||||
}
|
||||
__TBB_ASSERT( !(s.my_next.load(std::memory_order_relaxed) & FLAG), "use of corrupted pointer" );
|
||||
|
||||
// my_next is acquired either with load or spin_wait.
|
||||
if(d1::queuing_rw_mutex::scoped_lock *const l_next = tricky_pointer::load(s.my_next, std::memory_order_relaxed) ) { // I->next != nil, TODO: rename to next after clearing up and adapting the n in the comment two lines below
|
||||
// ensure acquire semantics of reading 'my_next'
|
||||
if(d1::queuing_rw_mutex::scoped_lock *const l_next = tricky_pointer::load(s.my_next, std::memory_order_acquire) ) { // I->next != nil, TODO: rename to next after clearing up and adapting the n in the comment two lines below
|
||||
// Equivalent to I->next->prev = I->prev but protected against (prev[n]&FLAG)!=0
|
||||
tmp = tricky_pointer::exchange(l_next->my_prev, predecessor, std::memory_order_release);
|
||||
// I->prev->next = I->next;
|
||||
@@ -386,12 +359,9 @@ struct queuing_rw_mutex_impl {
|
||||
d1::queuing_rw_mutex::scoped_lock* next = tricky_pointer::load(s.my_next, std::memory_order_acquire);
|
||||
if( !next ) {
|
||||
d1::queuing_rw_mutex::scoped_lock* expected = &s;
|
||||
// Release mutex on success otherwise wait for successor publication
|
||||
if( !s.my_mutex->q_tail.compare_exchange_strong(expected, nullptr,
|
||||
std::memory_order_release, std::memory_order_relaxed) )
|
||||
{
|
||||
spin_wait_while_eq( s.my_next, 0U, std::memory_order_relaxed );
|
||||
next = tricky_pointer::load(s.my_next, std::memory_order_acquire);
|
||||
if( !s.my_mutex->q_tail.compare_exchange_strong(expected, nullptr, std::memory_order_release) ) {
|
||||
spin_wait_while_eq( s.my_next, 0U );
|
||||
next = tricky_pointer::load(s.my_next, std::memory_order_relaxed);
|
||||
} else {
|
||||
goto unlock_self;
|
||||
}
|
||||
@@ -405,8 +375,7 @@ struct queuing_rw_mutex_impl {
|
||||
unblock_or_wait_on_internal_lock(s, get_flag(tmp));
|
||||
}
|
||||
done:
|
||||
// Lifetime synchronization, no need to build happens-before relation
|
||||
spin_wait_while_eq( s.my_going, 2U, std::memory_order_relaxed );
|
||||
spin_wait_while_eq( s.my_going, 2U );
|
||||
|
||||
s.initialize();
|
||||
}
|
||||
@@ -415,41 +384,26 @@ struct queuing_rw_mutex_impl {
|
||||
if ( s.my_state.load(std::memory_order_relaxed) == STATE_ACTIVEREADER ) return true; // Already a reader
|
||||
|
||||
ITT_NOTIFY(sync_releasing, s.my_mutex);
|
||||
d1::queuing_rw_mutex::scoped_lock* next = tricky_pointer::load(s.my_next, std::memory_order_acquire);
|
||||
if( !next ) {
|
||||
s.my_state.store(STATE_READER, std::memory_order_seq_cst);
|
||||
s.my_state.store(STATE_READER, std::memory_order_relaxed);
|
||||
if( ! tricky_pointer::load(s.my_next, std::memory_order_relaxed)) {
|
||||
// the following load of q_tail must not be reordered with setting STATE_READER above
|
||||
if( &s == s.my_mutex->q_tail.load(std::memory_order_seq_cst) ) {
|
||||
if( &s==s.my_mutex->q_tail.load() ) {
|
||||
unsigned char old_state = STATE_READER;
|
||||
// When this reader is signaled by previous actor it acquires the mutex.
|
||||
// We need to build happens-before relation with all other coming readers that will read our ACTIVEREADER
|
||||
// without blocking on my_going. Therefore, we need to publish ACTIVEREADER with release semantics.
|
||||
// On fail it is relaxed, because we will build happens-before on my_going.
|
||||
s.my_state.compare_exchange_strong(old_state, STATE_ACTIVEREADER, std::memory_order_release, std::memory_order_relaxed);
|
||||
s.my_state.compare_exchange_strong(old_state, STATE_ACTIVEREADER, std::memory_order_release);
|
||||
if( old_state==STATE_READER )
|
||||
return true; // Downgrade completed
|
||||
}
|
||||
/* wait for the next to register */
|
||||
spin_wait_while_eq(s.my_next, 0U, std::memory_order_relaxed);
|
||||
next = tricky_pointer::load(s.my_next, std::memory_order_acquire);
|
||||
spin_wait_while_eq( s.my_next, 0U );
|
||||
}
|
||||
|
||||
d1::queuing_rw_mutex::scoped_lock *const next = tricky_pointer::load(s.my_next, std::memory_order_acquire);
|
||||
__TBB_ASSERT( next, "still no successor at this point!" );
|
||||
if( next->my_state.load(std::memory_order_relaxed) & STATE_COMBINED_WAITINGREADER )
|
||||
if( next->my_state & STATE_COMBINED_WAITINGREADER )
|
||||
next->my_going.store(1U, std::memory_order_release);
|
||||
// If the next is STATE_UPGRADE_WAITING, it is expected to acquire all other released readers via release
|
||||
// sequence in next->my_state. In that case, we need to preserve release sequence in next->my_state
|
||||
// contributed by other reader. So, there are two approaches not to break the release sequence:
|
||||
// 1. Use read-modify-write (exchange) operation to store with release the UPGRADE_LOSER state;
|
||||
// 2. Acquire the release sequence and store the sequence and UPGRADE_LOSER state.
|
||||
// The second approach seems better on x86 because it does not involve interlocked operations.
|
||||
// Therefore, we read next->my_state with acquire while it is not required for else branch to get the
|
||||
// release sequence.
|
||||
else if( next->my_state.load(std::memory_order_acquire)==STATE_UPGRADE_WAITING )
|
||||
else if( next->my_state==STATE_UPGRADE_WAITING )
|
||||
// the next waiting for upgrade means this writer was upgraded before.
|
||||
// To safe release sequence on next->my_state read it with acquire
|
||||
next->my_state.store(STATE_UPGRADE_LOSER, std::memory_order_release);
|
||||
s.my_state.store(STATE_ACTIVEREADER, std::memory_order_release);
|
||||
next->my_state.store(STATE_UPGRADE_LOSER, std::memory_order_relaxed);
|
||||
s.my_state.store(STATE_ACTIVEREADER, std::memory_order_relaxed);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -465,20 +419,16 @@ struct queuing_rw_mutex_impl {
|
||||
queuing_rw_mutex::scoped_lock* me = &s;
|
||||
|
||||
ITT_NOTIFY(sync_releasing, s.my_mutex);
|
||||
// Publish ourselves into my_state that other UPGRADE_WAITING actors can acquire our state.
|
||||
s.my_state.store(STATE_UPGRADE_REQUESTED, std::memory_order_release);
|
||||
s.my_state.store(STATE_UPGRADE_REQUESTED, std::memory_order_relaxed);
|
||||
requested:
|
||||
__TBB_ASSERT( !(s.my_next.load(std::memory_order_relaxed) & FLAG), "use of corrupted pointer!" );
|
||||
acquire_internal_lock(s);
|
||||
d1::queuing_rw_mutex::scoped_lock* expected = &s;
|
||||
if( !s.my_mutex->q_tail.compare_exchange_strong(expected, tricky_pointer(me)|FLAG, std::memory_order_acq_rel) ) {
|
||||
spin_wait_while_eq( s.my_next, 0U, std::memory_order_relaxed );
|
||||
if( !s.my_mutex->q_tail.compare_exchange_strong(expected, tricky_pointer(me)|FLAG, std::memory_order_release) ) {
|
||||
spin_wait_while_eq( s.my_next, 0U );
|
||||
queuing_rw_mutex::scoped_lock * next;
|
||||
next = tricky_pointer::fetch_add(s.my_next, FLAG, std::memory_order_acquire);
|
||||
// While we were READER the next READER might reach STATE_UPGRADE_WAITING state.
|
||||
// Therefore, it did not build happens before relation with us and we need to acquire the
|
||||
// next->my_state to build the happens before relation ourselves
|
||||
unsigned short n_state = next->my_state.load(std::memory_order_acquire);
|
||||
unsigned short n_state = next->my_state;
|
||||
/* the next reader can be blocked by our state. the best thing to do is to unblock it */
|
||||
if( n_state & STATE_COMBINED_WAITINGREADER )
|
||||
next->my_going.store(1U, std::memory_order_release);
|
||||
@@ -489,7 +439,7 @@ struct queuing_rw_mutex_impl {
|
||||
// save next|FLAG for simplicity of following comparisons
|
||||
tmp = tricky_pointer(next)|FLAG;
|
||||
for( atomic_backoff b; tricky_pointer::load(s.my_next, std::memory_order_relaxed)==tmp; b.pause() ) {
|
||||
if( s.my_state.load(std::memory_order_acquire) & STATE_COMBINED_UPGRADING ) {
|
||||
if( s.my_state & STATE_COMBINED_UPGRADING ) {
|
||||
if( tricky_pointer::load(s.my_next, std::memory_order_acquire)==tmp )
|
||||
tricky_pointer::store(s.my_next, next, std::memory_order_relaxed);
|
||||
goto waiting;
|
||||
@@ -508,11 +458,7 @@ struct queuing_rw_mutex_impl {
|
||||
} // if( this != my_mutex->q_tail... )
|
||||
{
|
||||
unsigned char old_state = STATE_UPGRADE_REQUESTED;
|
||||
// If we reach STATE_UPGRADE_WAITING state we do not build happens-before relation with READER on
|
||||
// left. We delegate this responsibility to READER on left when it try upgrading. Therefore, we are releasing
|
||||
// on success.
|
||||
// Otherwise, on fail, we already acquired the next->my_state.
|
||||
s.my_state.compare_exchange_strong(old_state, STATE_UPGRADE_WAITING, std::memory_order_release, std::memory_order_relaxed);
|
||||
s.my_state.compare_exchange_strong(old_state, STATE_UPGRADE_WAITING, std::memory_order_acquire);
|
||||
}
|
||||
waiting:
|
||||
__TBB_ASSERT( !( s.my_next.load(std::memory_order_relaxed) & FLAG ), "use of corrupted pointer!" );
|
||||
@@ -531,14 +477,11 @@ struct queuing_rw_mutex_impl {
|
||||
// While the predecessor pointer (my_prev) is in use (FLAG is set), we can safely update the node`s state.
|
||||
// Corrupted pointer transitions responsibility to release the predecessor`s node on us.
|
||||
unsigned char old_state = STATE_UPGRADE_REQUESTED;
|
||||
// Try to build happens before with the upgrading READER on left. If fail, the predecessor state is not
|
||||
// important for us because it will acquire our state.
|
||||
predecessor->my_state.compare_exchange_strong(old_state, STATE_UPGRADE_WAITING, std::memory_order_release,
|
||||
std::memory_order_relaxed);
|
||||
predecessor->my_state.compare_exchange_strong(old_state, STATE_UPGRADE_WAITING, std::memory_order_release);
|
||||
}
|
||||
if( !success ) {
|
||||
// Responsibility transition, the one who reads uncorrupted my_prev will do release.
|
||||
tmp = tricky_pointer::compare_exchange_strong(s.my_prev, tricky_pointer(predecessor)|FLAG, predecessor, std::memory_order_acquire);
|
||||
tmp = tricky_pointer::compare_exchange_strong(s.my_prev, tricky_pointer(predecessor)|FLAG, predecessor, std::memory_order_release);
|
||||
if( tricky_pointer(tmp) & FLAG ) {
|
||||
tricky_pointer::spin_wait_while_eq(s.my_prev, predecessor);
|
||||
predecessor = tricky_pointer::load(s.my_prev, std::memory_order_relaxed);
|
||||
@@ -566,6 +509,9 @@ struct queuing_rw_mutex_impl {
|
||||
// now wait for the predecessor to finish working with my fields
|
||||
spin_wait_while_eq( s.my_going, 2U );
|
||||
|
||||
// Acquire critical section indirectly from previous owner or directly from predecessor (TODO: not clear).
|
||||
atomic_fence(std::memory_order_acquire); // on either "my_mutex->q_tail" or "my_going" (TODO: not clear)
|
||||
|
||||
bool result = ( s.my_state != STATE_UPGRADE_LOSER );
|
||||
s.my_state.store(STATE_WRITER, std::memory_order_relaxed);
|
||||
s.my_going.store(1U, std::memory_order_relaxed);
|
||||
|
||||
@@ -82,7 +82,7 @@ public:
|
||||
friend class thread_monitor;
|
||||
std::atomic<std::size_t> my_epoch{0};
|
||||
};
|
||||
thread_monitor() {
|
||||
thread_monitor() : skipped_wakeup(false), my_sema() {
|
||||
ITT_SYNC_CREATE(&my_sema, SyncType_RML, SyncObj_ThreadMonitor);
|
||||
}
|
||||
~thread_monitor() {}
|
||||
@@ -129,7 +129,7 @@ public:
|
||||
private:
|
||||
cookie my_cookie; // epoch counter
|
||||
std::atomic<bool> in_wait{false};
|
||||
bool skipped_wakeup{false};
|
||||
bool skipped_wakeup;
|
||||
binary_semaphore my_sema;
|
||||
#if __TBB_USE_POSIX
|
||||
static void check( int error_code, const char* routine );
|
||||
@@ -238,14 +238,9 @@ inline void thread_monitor::prepare_wait( cookie& c ) {
|
||||
}
|
||||
|
||||
inline void thread_monitor::commit_wait( cookie& c ) {
|
||||
bool do_it = ( c.my_epoch.load(std::memory_order_relaxed) == my_cookie.my_epoch.load(std::memory_order_acquire) );
|
||||
if( do_it ) {
|
||||
my_sema.P();
|
||||
} else {
|
||||
tbb::detail::atomic_backoff backoff;
|
||||
while (in_wait.load(std::memory_order_relaxed)) { backoff.pause(); }
|
||||
skipped_wakeup = true;
|
||||
}
|
||||
bool do_it = ( c.my_epoch.load(std::memory_order_relaxed) == my_cookie.my_epoch.load(std::memory_order_relaxed) );
|
||||
if( do_it ) my_sema.P();
|
||||
else cancel_wait();
|
||||
}
|
||||
|
||||
inline void thread_monitor::cancel_wait() {
|
||||
|
||||
@@ -86,6 +86,7 @@ struct rtm_mutex_impl {
|
||||
s.m_mutex = &m;
|
||||
s.m_mutex->lock();
|
||||
s.m_transaction_state = d1::rtm_mutex::rtm_state::rtm_real;
|
||||
return;
|
||||
}
|
||||
|
||||
//! Try to acquire lock on the given mutex.
|
||||
|
||||
@@ -97,6 +97,7 @@ struct rtm_rw_mutex_impl {
|
||||
__TBB_ASSERT(!m.write_flag.load(std::memory_order_relaxed), "After acquire for write, write_flag already true");
|
||||
m.write_flag.store(true, std::memory_order_relaxed); // kill transactional readers
|
||||
s.m_transaction_state = d1::rtm_rw_mutex::rtm_type::rtm_real_writer;
|
||||
return;
|
||||
}
|
||||
|
||||
//! Acquire read lock on given mutex.
|
||||
|
||||
@@ -175,7 +175,7 @@ public:
|
||||
#endif // _WIN64
|
||||
};
|
||||
|
||||
#if (_WIN32 || _WIN64 || __unix__ || __APPLE__) && (__TBB_x86_32 || __TBB_x86_64)
|
||||
#if (_WIN32 || _WIN64 || __unix__) && (__TBB_x86_32 || __TBB_x86_64)
|
||||
#if _MSC_VER
|
||||
#pragma intrinsic(__rdtsc)
|
||||
#endif
|
||||
@@ -220,7 +220,7 @@ inline void prolonged_pause_impl() {
|
||||
#endif
|
||||
|
||||
inline void prolonged_pause() {
|
||||
#if __TBB_WAITPKG_INTRINSICS_PRESENT
|
||||
#if __TBB_WAITPKG_INTRINSICS_PRESENT && (_WIN32 || _WIN64 || __unix__) && (__TBB_x86_32 || __TBB_x86_64)
|
||||
if (governor::wait_package_enabled()) {
|
||||
std::uint64_t time_stamp = machine_time_stamp();
|
||||
// _tpause function directs the processor to enter an implementation-dependent optimized state
|
||||
|
||||
@@ -102,6 +102,7 @@ public:
|
||||
, my_task_dispatcher{ nullptr }
|
||||
, my_arena{}
|
||||
, my_arena_slot{}
|
||||
, my_inbox{}
|
||||
, my_random{ this }
|
||||
, my_last_observer{ nullptr }
|
||||
, my_small_object_pool{new (cache_aligned_allocate(sizeof(small_object_pool_impl))) small_object_pool_impl{}}
|
||||
|
||||
@@ -147,10 +147,6 @@
|
||||
# define ITT_ARCH_IA32E 2
|
||||
#endif /* ITT_ARCH_IA32E */
|
||||
|
||||
#ifndef ITT_ARCH_IA64
|
||||
# define ITT_ARCH_IA64 3
|
||||
#endif /* ITT_ARCH_IA64 */
|
||||
|
||||
#ifndef ITT_ARCH_ARM
|
||||
# define ITT_ARCH_ARM 4
|
||||
#endif /* ITT_ARCH_ARM */
|
||||
|
||||
@@ -46,6 +46,7 @@ function(tbbbind_build TBBBIND_NAME REQUIRED_HWLOC_TARGET)
|
||||
${TBB_WARNING_LEVEL}
|
||||
${TBB_LIB_COMPILE_FLAGS}
|
||||
${TBB_COMMON_COMPILE_FLAGS}
|
||||
${TBB_IPO_COMPILE_FLAGS}
|
||||
)
|
||||
|
||||
# Avoid use of target_link_libraries here as it changes /DEF option to \DEF on Windows.
|
||||
@@ -54,9 +55,6 @@ function(tbbbind_build TBBBIND_NAME REQUIRED_HWLOC_TARGET)
|
||||
VERSION ${TBBBIND_BINARY_VERSION}.${TBB_BINARY_MINOR_VERSION}
|
||||
SOVERSION ${TBBBIND_BINARY_VERSION}
|
||||
)
|
||||
|
||||
tbb_handle_ipo(${TBBBIND_NAME})
|
||||
|
||||
if (TBB_DEF_FILE_PREFIX) # If there's no prefix, assume we're using export directives
|
||||
set_target_properties(${TBBBIND_NAME} PROPERTIES
|
||||
LINK_FLAGS ${TBB_LINK_DEF_FILE_FLAG}${CMAKE_CURRENT_SOURCE_DIR}/def/${TBB_DEF_FILE_PREFIX}-tbbbind.def
|
||||
@@ -71,12 +69,14 @@ function(tbbbind_build TBBBIND_NAME REQUIRED_HWLOC_TARGET)
|
||||
PRIVATE
|
||||
${TBB_LIB_LINK_FLAGS}
|
||||
${TBB_COMMON_LINK_FLAGS}
|
||||
${TBB_IPO_LINK_FLAGS}
|
||||
)
|
||||
else()
|
||||
target_link_libraries(${TBBBIND_NAME}
|
||||
PRIVATE
|
||||
${TBB_LIB_LINK_FLAGS}
|
||||
${TBB_COMMON_LINK_FLAGS}
|
||||
${TBB_IPO_LINK_FLAGS}
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
EXPORTS
|
||||
|
||||
global
|
||||
__TBB_internal_initialize_system_topology
|
||||
__TBB_internal_apply_affinity
|
||||
__TBB_internal_restore_affinity
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
EXPORTS
|
||||
|
||||
global
|
||||
__TBB_internal_initialize_system_topology
|
||||
__TBB_internal_apply_affinity
|
||||
__TBB_internal_restore_affinity
|
||||
|
||||
@@ -405,7 +405,7 @@ class binding_handler {
|
||||
affinity_masks_container affinity_backup;
|
||||
system_topology::affinity_mask handler_affinity_mask;
|
||||
|
||||
#ifdef _WIN32
|
||||
#if WIN32
|
||||
affinity_masks_container affinity_buffer;
|
||||
int my_numa_node_id;
|
||||
int my_core_type_id;
|
||||
@@ -415,7 +415,7 @@ class binding_handler {
|
||||
public:
|
||||
binding_handler( std::size_t size, int numa_node_id, int core_type_id, int max_threads_per_core )
|
||||
: affinity_backup(size)
|
||||
#ifdef _WIN32
|
||||
#if WIN32
|
||||
, affinity_buffer(size)
|
||||
, my_numa_node_id(numa_node_id)
|
||||
, my_core_type_id(core_type_id)
|
||||
@@ -424,7 +424,7 @@ public:
|
||||
{
|
||||
for (std::size_t i = 0; i < size; ++i) {
|
||||
affinity_backup[i] = system_topology::instance().allocate_process_affinity_mask();
|
||||
#ifdef _WIN32
|
||||
#if WIN32
|
||||
affinity_buffer[i] = system_topology::instance().allocate_process_affinity_mask();
|
||||
#endif
|
||||
}
|
||||
@@ -436,7 +436,7 @@ public:
|
||||
~binding_handler() {
|
||||
for (std::size_t i = 0; i < affinity_backup.size(); ++i) {
|
||||
system_topology::instance().free_affinity_mask(affinity_backup[i]);
|
||||
#ifdef _WIN32
|
||||
#if WIN32
|
||||
system_topology::instance().free_affinity_mask(affinity_buffer[i]);
|
||||
#endif
|
||||
}
|
||||
@@ -452,7 +452,7 @@ public:
|
||||
|
||||
topology.store_current_affinity_mask(affinity_backup[slot_num]);
|
||||
|
||||
#ifdef _WIN32
|
||||
#if WIN32
|
||||
// TBBBind supports only systems where NUMA nodes and core types do not cross the border
|
||||
// between several processor groups. So if a certain NUMA node or core type constraint
|
||||
// specified, then the constraints affinity mask will not cross the processor groups' border.
|
||||
|
||||
@@ -59,6 +59,7 @@ target_compile_options(tbbmalloc
|
||||
${TBB_LIB_COMPILE_FLAGS}
|
||||
${TBBMALLOC_LIB_COMPILE_FLAGS}
|
||||
${TBB_COMMON_COMPILE_FLAGS}
|
||||
${TBB_IPO_COMPILE_FLAGS}
|
||||
)
|
||||
|
||||
enable_language(C)
|
||||
@@ -71,8 +72,6 @@ set_target_properties(tbbmalloc PROPERTIES
|
||||
LINKER_LANGUAGE C
|
||||
)
|
||||
|
||||
tbb_handle_ipo(tbbmalloc)
|
||||
|
||||
if (TBB_DEF_FILE_PREFIX) # If there's no prefix, assume we're using export directives
|
||||
set_target_properties(tbbmalloc PROPERTIES
|
||||
LINK_FLAGS ${TBB_LINK_DEF_FILE_FLAG}${CMAKE_CURRENT_SOURCE_DIR}/def/${TBB_DEF_FILE_PREFIX}-tbbmalloc.def
|
||||
@@ -89,12 +88,14 @@ if (COMMAND target_link_options)
|
||||
PRIVATE
|
||||
${TBB_LIB_LINK_FLAGS}
|
||||
${TBB_COMMON_LINK_FLAGS}
|
||||
${TBB_IPO_LINK_FLAGS}
|
||||
)
|
||||
else()
|
||||
target_link_libraries(tbbmalloc
|
||||
PRIVATE
|
||||
${TBB_LIB_LINK_FLAGS}
|
||||
${TBB_COMMON_LINK_FLAGS}
|
||||
${TBB_IPO_LINK_FLAGS}
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -61,10 +61,6 @@ static inline bool isPowerOfTwoAtLeast(uintptr_t arg, uintptr_t power2) {
|
||||
return arg && tbb::detail::is_power_of_two_at_least(arg,power2);
|
||||
}
|
||||
|
||||
inline void do_yield() {
|
||||
tbb::detail::yield();
|
||||
}
|
||||
|
||||
#define USE_DEFAULT_MEMORY_MAPPING 1
|
||||
|
||||
// To support malloc replacement
|
||||
|
||||
@@ -162,7 +162,7 @@ bool BackRefMain::requestNewSpace()
|
||||
static_assert(!(blockSpaceSize % BackRefBlock::bytes),
|
||||
"Must request space for whole number of blocks.");
|
||||
|
||||
if (BackRefMain::dataSz <= lastUsed + 1) // no space in main
|
||||
if (backRefMain.load(std::memory_order_relaxed)->dataSz <= lastUsed + 1) // no space in main
|
||||
return false;
|
||||
|
||||
// only one thread at a time may add blocks
|
||||
@@ -181,7 +181,7 @@ bool BackRefMain::requestNewSpace()
|
||||
|
||||
MallocMutex::scoped_lock lock(mainMutex); // ... and share under lock
|
||||
|
||||
const size_t numOfUnusedIdxs = BackRefMain::dataSz - lastUsed - 1;
|
||||
const size_t numOfUnusedIdxs = backRefMain.load(std::memory_order_relaxed)->dataSz - lastUsed - 1;
|
||||
if (numOfUnusedIdxs <= 0) { // no space in main under lock, roll back
|
||||
backend->putBackRefSpace(newBl, blockSpaceSize, isRawMemUsed);
|
||||
return false;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#define TlsGetValue_func pthread_getspecific
|
||||
#define GetMyTID() pthread_self()
|
||||
#include <sched.h>
|
||||
inline void do_yield() {sched_yield();}
|
||||
extern "C" { static void mallocThreadShutdownNotification(void*); }
|
||||
#if __sun || __SUNPRO_CC
|
||||
#define __asm__ asm
|
||||
@@ -42,10 +43,12 @@
|
||||
#define TlsAlloc() FlsAlloc(NULL)
|
||||
#define TLS_ALLOC_FAILURE FLS_OUT_OF_INDEXES
|
||||
#define TlsFree FlsFree
|
||||
inline void do_yield() {std::this_thread::yield();}
|
||||
#else
|
||||
#define TlsSetValue_func TlsSetValue
|
||||
#define TlsGetValue_func TlsGetValue
|
||||
#define TLS_ALLOC_FAILURE TLS_OUT_OF_INDEXES
|
||||
inline void do_yield() {SwitchToThread();}
|
||||
#endif
|
||||
#else
|
||||
#error Must define USE_PTHREAD or USE_WINTHREAD
|
||||
@@ -260,7 +263,7 @@ class MemoryPool {
|
||||
// and set reasonable low granularity
|
||||
static const size_t defaultGranularity = estimatedCacheLineSize;
|
||||
|
||||
MemoryPool() = delete; // deny
|
||||
MemoryPool(); // deny
|
||||
public:
|
||||
static MallocMutex memPoolListLock;
|
||||
|
||||
@@ -543,7 +546,7 @@ public:
|
||||
static const int POOL_LOW_MARK = 8;
|
||||
|
||||
class ResOfGet {
|
||||
ResOfGet() = delete;
|
||||
ResOfGet();
|
||||
public:
|
||||
Block* block;
|
||||
bool lastAccMiss;
|
||||
|
||||
@@ -90,7 +90,7 @@ T min ( const T& val1, const T& val2 ) {
|
||||
// TODO: add a constructor to remove warnings suppression
|
||||
struct parseFileItem {
|
||||
const char* format;
|
||||
long long& value;
|
||||
unsigned long long& value;
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER<1900) && !defined(__INTEL_COMPILER)
|
||||
|
||||
@@ -447,31 +447,31 @@ private:
|
||||
void parseSystemMemInfo() {
|
||||
bool hpAvailable = false;
|
||||
bool thpAvailable = false;
|
||||
long long hugePageSize = -1;
|
||||
unsigned long long hugePageSize = 0;
|
||||
|
||||
#if __unix__
|
||||
// Check huge pages existence
|
||||
long long meminfoHugePagesTotal = 0;
|
||||
unsigned long long meminfoHugePagesTotal = 0;
|
||||
|
||||
parseFileItem meminfoItems[] = {
|
||||
// Parse system huge page size
|
||||
{ "Hugepagesize: %lld kB", hugePageSize },
|
||||
{ "Hugepagesize: %llu kB", hugePageSize },
|
||||
// Check if there are preallocated huge pages on the system
|
||||
// https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt
|
||||
{ "HugePages_Total: %lld", meminfoHugePagesTotal } };
|
||||
{ "HugePages_Total: %llu", meminfoHugePagesTotal } };
|
||||
|
||||
parseFile</*BUFF_SIZE=*/100>("/proc/meminfo", meminfoItems);
|
||||
|
||||
// Double check another system information regarding preallocated
|
||||
// huge pages if there are no information in /proc/meminfo
|
||||
long long vmHugePagesTotal = 0;
|
||||
unsigned long long vmHugePagesTotal = 0;
|
||||
|
||||
parseFileItem vmItem[] = { { "%lld", vmHugePagesTotal } };
|
||||
parseFileItem vmItem[] = { { "%llu", vmHugePagesTotal } };
|
||||
|
||||
// We parse a counter number, it can't be huge
|
||||
parseFile</*BUFF_SIZE=*/100>("/proc/sys/vm/nr_hugepages", vmItem);
|
||||
|
||||
if (hugePageSize > -1 && (meminfoHugePagesTotal > 0 || vmHugePagesTotal > 0)) {
|
||||
if (meminfoHugePagesTotal > 0 || vmHugePagesTotal > 0) {
|
||||
MALLOC_ASSERT(hugePageSize != 0, "Huge Page size can't be zero if we found preallocated.");
|
||||
|
||||
// Any non zero value clearly states that there are preallocated
|
||||
@@ -480,11 +480,11 @@ private:
|
||||
}
|
||||
|
||||
// Check if there is transparent huge pages support on the system
|
||||
long long thpPresent = 'n';
|
||||
unsigned long long thpPresent = 'n';
|
||||
parseFileItem thpItem[] = { { "[alwa%cs] madvise never\n", thpPresent } };
|
||||
parseFile</*BUFF_SIZE=*/100>("/sys/kernel/mm/transparent_hugepage/enabled", thpItem);
|
||||
|
||||
if (hugePageSize > -1 && thpPresent == 'y') {
|
||||
if (thpPresent == 'y') {
|
||||
MALLOC_ASSERT(hugePageSize != 0, "Huge Page size can't be zero if we found thp existence.");
|
||||
thpAvailable = true;
|
||||
}
|
||||
|
||||
+1
-1
@@ -602,7 +602,7 @@ if (TARGET TBB::tbbmalloc)
|
||||
endif()
|
||||
|
||||
# Thread Sanitizer overloads memory management routines that conflicts with tbbmalloc_proxy.
|
||||
if (BUILD_SHARED_LIBS AND NOT TBB_SANITIZE MATCHES "thread" AND NOT MSVC_CXX_ARCHITECTURE_ID MATCHES "ARM64")
|
||||
if (BUILD_SHARED_LIBS AND NOT TBB_SANITIZE MATCHES "thread")
|
||||
# Define TBB malloc proxy tests
|
||||
tbb_add_lib_test(SUBDIR tbbmalloc NAME test_malloc_atexit DEPENDENCIES TBB::tbbmalloc_proxy TBB::tbbmalloc)
|
||||
tbb_add_test(SUBDIR tbbmalloc NAME test_malloc_atexit DEPENDENCIES TBB::tbbmalloc_proxy TBB::tbbmalloc _test_malloc_atexit)
|
||||
|
||||
@@ -391,8 +391,8 @@ public:
|
||||
};
|
||||
|
||||
StaticSharedCountingAllocator() = default;
|
||||
|
||||
StaticSharedCountingAllocator( const StaticSharedCountingAllocator& ) = default;
|
||||
StaticSharedCountingAllocator& operator=( const StaticSharedCountingAllocator& ) = default;
|
||||
|
||||
template <typename U>
|
||||
StaticSharedCountingAllocator( const StaticSharedCountingAllocator<U>& other) : alloc_base_type(other) {}
|
||||
|
||||
@@ -310,15 +310,14 @@ struct harness_mapped_receiver : public tbb::flow::receiver<T> {
|
||||
virtual
|
||||
#endif
|
||||
~harness_mapped_receiver() {
|
||||
delete my_multiset;
|
||||
my_multiset = nullptr;
|
||||
if ( my_multiset ) delete my_multiset;
|
||||
}
|
||||
|
||||
void initialize_map( const T& m, size_t c ) {
|
||||
my_count = 0;
|
||||
max_value = m;
|
||||
num_copies = c;
|
||||
delete my_multiset;
|
||||
if ( my_multiset ) delete my_multiset;
|
||||
my_multiset = new multiset_type;
|
||||
}
|
||||
|
||||
|
||||
@@ -141,32 +141,27 @@ namespace utils {
|
||||
#if __unix__
|
||||
|
||||
inline bool isTHPEnabledOnMachine() {
|
||||
long long thpPresent = 'n';
|
||||
long long hugePageSize = -1;
|
||||
|
||||
unsigned long long thpPresent = 'n';
|
||||
parseFileItem thpItem[] = { { "[alwa%cs] madvise never\n", thpPresent } };
|
||||
parseFileItem hpSizeItem[] = { { "Hugepagesize: %lld kB", hugePageSize } };
|
||||
|
||||
parseFile</*BUFF_SIZE=*/100>("/sys/kernel/mm/transparent_hugepage/enabled", thpItem);
|
||||
parseFile</*BUFF_SIZE=*/100>("/proc/meminfo", hpSizeItem);
|
||||
|
||||
if (hugePageSize > -1 && thpPresent == 'y') {
|
||||
if (thpPresent == 'y') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
inline long long getSystemTHPAllocatedSize() {
|
||||
long long anonHugePagesSize = 0;
|
||||
inline unsigned long long getSystemTHPAllocatedSize() {
|
||||
unsigned long long anonHugePagesSize = 0;
|
||||
parseFileItem meminfoItems[] = {
|
||||
{ "AnonHugePages: %lld kB", anonHugePagesSize } };
|
||||
{ "AnonHugePages: %llu kB", anonHugePagesSize } };
|
||||
parseFile</*BUFF_SIZE=*/100>("/proc/meminfo", meminfoItems);
|
||||
return anonHugePagesSize;
|
||||
}
|
||||
inline long long getSystemTHPCount() {
|
||||
long long anonHugePages = 0;
|
||||
inline unsigned long long getSystemTHPCount() {
|
||||
unsigned long long anonHugePages = 0;
|
||||
parseFileItem vmstatItems[] = {
|
||||
{ "nr_anon_transparent_hugepages %lld", anonHugePages } };
|
||||
{ "nr_anon_transparent_hugepages %llu", anonHugePages } };
|
||||
parseFile</*BUFF_SIZE=*/100>("/proc/vmstat", vmstatItems);
|
||||
return anonHugePages;
|
||||
}
|
||||
|
||||
@@ -37,12 +37,13 @@
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <sched.h>
|
||||
#if __FreeBSD__
|
||||
#elif __FreeBSD__
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/cpuset.h>
|
||||
#endif
|
||||
#endif
|
||||
#include <thread>
|
||||
|
||||
namespace utils {
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
|
||||
#if __TBB_DYNAMIC_LOAD_ENABLED
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#if _WIN32 || _WIN64
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
@@ -53,10 +53,6 @@
|
||||
// Suppress "typedef ignored ... when no variable is declared" warning by vc14
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4091)
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
#pragma warning (pop)
|
||||
#pragma comment (lib, "dbghelp.lib")
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user