Compare commits

..
Author SHA1 Message Date
Aleksei Fedotov 4fbacf34a3 Merge pull request #368 from anton-potapov/task_group_extensions_fixup
Fixup for POC: Extend tbb::task_group to support new use cases
2021-04-01 12:28:15 +03:00
Anton Potapov 0bfcf0f669 POC:
- changed newly added version of run to accept task_handle argument as
a rvalue ref
2021-03-29 15:32:07 +03:00
Fedotov, Aleksei a85e2d6fa7 POC: Extend tbb::task_group to support new use cases
The use cases include:
- Instantiation of the tbb::task_group with arbitrary tbb::task_group_context.
- Bypassing a functor using tbb::task_group interfaces.
- Deferring a task to be run later as part of the current tbb::task_group execution.
2021-03-26 20:44:03 +03:00
248 changed files with 2370 additions and 8526 deletions
-60
View File
@@ -1,60 +0,0 @@
#!/bin/bash
#
# Copyright (c) 2021 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
SCAN_TARGET=$1
SKIP_PATTERN='*/.github/*'
# Ignored cases
IGNORE_COMMAND="sed -e /.*\\sOd\\s*=.*/d \
-e /.*\\sOt\\s*=.*/d \
-e /.*\\siff\\s*=.*/d \
-e /.*\\sith\\s*=.*/d \
-e /.*\\scas\\s*=.*/d \
-e /.*\\sCAS\\s*=.*/d \
-e /.*\\ssom\\s*=.*/d \
-e /.*\\sSOM\\s*=.*/d \
-e /.*\\suint\\s*=.*/d \
-e /.*\\sUINT\\s*=.*/d \
-e /.*\\scopyable\\s*=.*/d \
-e /.*\\sCopyable\\s*=.*/d \
-e /.*\\sFo\\s*=.*/d \
-e /.*pipeline_filters.h.*nd\\s*=.*/d \
-e /.*ittnotify.h.*unx\\s*=.*/d \
-e /.*bzlib.cpp.*MSDOS\\s*=.*/d \
-e /.*test_task.cpp.*tE\\s*=.*/d \
-e /.*backend.cpp.*resSize\\s*=.*/d \
-e /.*test_join_node.h.*Ned\\s*=.*/d \
-e /.*test_indexer_node.cpp.*OT\\s*=.*/d \
-e /.*allocator_stl_test_common.h.*Aci*\\s*=.*/d \
-e /.*seismic_video.cpp.*DialogBox\\s*=.*/d \
-e /.*test_composite_node.cpp.*que\\s*=.*/d \
-e /.*blocksort.cpp.*hiSt\\s*=.*/d \
-e /.*compress.cpp.*fave\\s*=.*/d \
-e /.*count_strings.cpp.*ue\\s*=.*/d \
-e /.*count_strings.cpp.*nd\\s*=.*/d \
-e /.*count_strings.cpp.*ths\\s*=.*/d \
-e /.*polygon_overlay\/README.md.*ist\\s*=.*/d \
-e /.*_pipeline_filters.h.*nd\\s*=.*/d \
-e /.*sub_string_finder\/README.md.*ba\\s*=.*/d"
SCAN_RESULT=`codespell --quiet-level=2 --skip "${SKIP_PATTERN}" ${SCAN_TARGET}`
SCAN_RESULT=`echo -e "${SCAN_RESULT}" | ${IGNORE_COMMAND}`
echo "${SCAN_RESULT}"
if [[ ! -z ${SCAN_RESULT} ]]; then
exit 1
fi
-264
View File
@@ -1,264 +0,0 @@
# Copyright (c) 2021 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
name: oneTBB CI
on:
push:
branches: [master]
pull_request:
branches: [master]
types:
- opened
- synchronize
- reopened
env:
BUILD_CONCURRENCY: 2
MACOS_BUILD_CONCURRENCY: 3
TEST_TIMEOUT: 180
jobs:
codespell:
runs-on: [ubuntu-20.04]
timeout-minutes: 10
steps:
- uses: actions/checkout@v2
- name: Run scan
run: |
sudo apt update && sudo apt install -y codespell
${GITHUB_WORKSPACE}/.github/scripts/codespell.sh `pwd`
examples_clang-format:
runs-on: [ubuntu-20.04]
timeout-minutes: 10
steps:
- uses: actions/checkout@v2
- name: Run scan
run: |
cp -r examples examples_formatted
find examples_formatted -regex '.*\.\(cpp\|hpp\)' -exec clang-format-9 -style=file -i {} \;
diff -r examples examples_formatted
python_module_test_ubuntu18-04:
runs-on: [ubuntu-18.04]
timeout-minutes: 15
steps:
- uses: actions/checkout@v2
- name: Run testing
run: |
mkdir build && cd build
cmake -DTBB4PY_BUILD=ON -DCMAKE_CXX_COMPILER=g++ -DCMAKE_C_COMPILER=gcc ..
make VERBOSE=1 -j${BUILD_CONCURRENCY} python_build
ctest -R python_test --output-on-failure --timeout ${TEST_TIMEOUT}
linux-testing:
name: ${{ matrix.os }}_${{ matrix.cxx_compiler }}_cxx${{ matrix.std }}_${{ matrix.build_type }}_preview=${{ matrix.preview }}
runs-on: ['${{ matrix.os }}']
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
c_compiler: gcc
cxx_compiler: g++
std: 14
build_type: relwithdebinfo
preview: 'OFF'
- os: ubuntu-20.04
c_compiler: gcc
cxx_compiler: g++
std: 17
build_type: release
preview: 'ON'
- os: ubuntu-20.04
c_compiler: gcc-10
cxx_compiler: g++-10
std: 20
build_type: debug
preview: 'ON'
steps:
- uses: actions/checkout@v2
- name: Run testing
shell: bash
run: |
set -x
mkdir build && cd build
cmake -DCMAKE_CXX_STANDARD=${{ matrix.std }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
-DCMAKE_CXX_COMPILER=${{ matrix.cxx_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DTBB_CPF=${{ matrix.preview }} ..
make VERBOSE=1 -j${BUILD_CONCURRENCY}
ctest --timeout ${TEST_TIMEOUT} --output-on-failure
macos-testing:
name: ${{ matrix.os }}_${{ matrix.cxx_compiler }}_cxx${{ matrix.std }}_${{ matrix.build_type }}_preview=${{ matrix.preview }}
runs-on: ['${{ matrix.os }}']
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
include:
- os: macos-10.15
c_compiler: clang
cxx_compiler: clang++
std: 14
build_type: relwithdebinfo
preview: 'ON'
steps:
- uses: actions/checkout@v2
- name: Run testing
shell: bash
run: |
set -x
mkdir build && cd build
cmake -DCMAKE_CXX_STANDARD=${{ matrix.std }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
-DCMAKE_CXX_COMPILER=${{ matrix.cxx_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DTBB_CPF=${{ matrix.preview }} ..
make VERBOSE=1 -j${MACOS_BUILD_CONCURRENCY}
ctest --timeout ${TEST_TIMEOUT} --output-on-failure
windows-testing:
name: ${{ matrix.job_name }}
runs-on: ['${{ matrix.os }}']
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
include:
- os: windows-2016
generator: Visual Studio 15 2017
c_compiler: cl
cxx_compiler: cl
std: 14
build_type: relwithdebinfo
preview: 'ON'
job_name: windows_cl2017_cxx14_relwithdebinfo_preview=ON
- os: windows-2019
generator: Visual Studio 16 2019
c_compiler: cl
cxx_compiler: cl
std: 17
build_type: relwithdebinfo
preview: 'OFF'
job_name: windows_cl2019_cxx17_relwithdebinfo_preview=OFF
steps:
- uses: actions/checkout@v2
- name: Run testing
run: |
mkdir build
cd build
cmake -G "${{ matrix.generator }}" -A x64 -DCMAKE_CXX_STANDARD=${{ matrix.std }} `
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCMAKE_CXX_COMPILER=${{ matrix.cxx_compiler }} `
-DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DTBB_CPF=${{ matrix.preview }} ..
cmake --build . --config ${{ matrix.build_type }} -j -v
ctest -C ${{ matrix.build_type }} --timeout ${env:TEST_TIMEOUT} --output-on-failure
linux-examples-testing:
name: examples_${{ matrix.os }}_${{ matrix.cxx_compiler }}_cxx${{ matrix.std }}_${{ matrix.build_type }}_preview=${{ matrix.preview }}
runs-on: ['${{ matrix.os }}']
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
c_compiler: gcc
cxx_compiler: g++
std: 14
build_type: relwithdebinfo
preview: 'OFF'
- os: ubuntu-20.04
c_compiler: gcc
cxx_compiler: g++
std: 17
build_type: release
preview: 'ON'
- os: ubuntu-20.04
c_compiler: gcc-10
cxx_compiler: g++-10
std: 20
build_type: debug
preview: 'ON'
steps:
- uses: actions/checkout@v2
- name: Run testing
shell: bash
run: |
set -x
mkdir build && cd build
cmake -DCMAKE_CXX_STANDARD=${{ matrix.std }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
-DCMAKE_CXX_COMPILER=${{ matrix.cxx_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} \
-DTBB_CPF=${{ matrix.preview }} -DTBB_TEST=OFF -DTBB_EXAMPLES=ON ..
cmake --build . -v --target light_test_examples
macos-examples-testing:
name: examples_${{ matrix.os }}_${{ matrix.cxx_compiler }}_cxx${{ matrix.std }}_${{ matrix.build_type }}_preview=${{ matrix.preview }}
runs-on: ['${{ matrix.os }}']
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
include:
- os: macos-10.15
c_compiler: clang
cxx_compiler: clang++
std: 14
build_type: relwithdebinfo
preview: 'ON'
steps:
- uses: actions/checkout@v2
- name: Run testing
shell: bash
run: |
set -x
mkdir build && cd build
cmake -DCMAKE_CXX_STANDARD=${{ matrix.std }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
-DCMAKE_CXX_COMPILER=${{ matrix.cxx_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} \
-DTBB_CPF=${{ matrix.preview }} -DTBB_TEST=OFF -DTBB_EXAMPLES=ON ..
cmake --build . -v --target light_test_examples
windows-examples-testing:
name: ${{ matrix.job_name }}
runs-on: ['${{ matrix.os }}']
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
include:
- os: windows-2016
generator: Visual Studio 15 2017
c_compiler: cl
cxx_compiler: cl
std: 14
build_type: relwithdebinfo
preview: 'ON'
job_name: examples_windows_cl2017_cxx14_relwithdebinfo_preview=ON
- os: windows-2019
generator: Visual Studio 16 2019
c_compiler: cl
cxx_compiler: cl
std: 17
build_type: relwithdebinfo
preview: 'OFF'
job_name: examples_windows_cl2019_cxx17_relwithdebinfo_preview=OFF
steps:
- uses: actions/checkout@v2
- name: Run testing
run: |
mkdir build
cd build
cmake -G "${{ matrix.generator }}" -A x64 -DCMAKE_CXX_STANDARD=${{ matrix.std }} `
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCMAKE_CXX_COMPILER=${{ matrix.cxx_compiler }} `
-DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DTBB_CPF=${{ matrix.preview }} -DTBB_TEST=OFF -DTBB_EXAMPLES=ON ..
cmake --build . -v --target light_test_examples
+2 -4
View File
@@ -1,5 +1,5 @@
# oneAPI Threading Building Blocks
[![Apache License Version 2.0](https://img.shields.io/badge/license-Apache_2.0-green.svg)](LICENSE.txt) [![oneTBB CI](https://github.com/oneapi-src/oneTBB/actions/workflows/ci.yml/badge.svg)](https://github.com/oneapi-src/oneTBB/actions/workflows/ci.yml?query=branch%3Amaster)
[![Apache License Version 2.0](https://img.shields.io/badge/license-Apache_2.0-green.svg)](LICENSE.txt)
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.
@@ -9,9 +9,7 @@ Here are [Release Notes]( https://software.intel.com/en-us/articles/intel-oneapi
[System Requirements](https://software.intel.com/en-us/articles/intel-oneapi-threading-building-blocks-system-requirements).
## Documentation
* [oneTBB Specification](https://spec.oneapi.com/versions/latest/elements/oneTBB/source/nested-index.html)
* [oneTBB Developer Guide and Reference](https://software.intel.com/en-us/oneapi-tbb-documentation)
* [Migrating from TBB to oneTBB](https://software.intel.com/content/www/us/en/develop/documentation/onetbb-documentation/top/onetbb-developer-guide/migrating-from-threading-building-blocks-tbb.html)
* [oneTBB documentation](https://software.intel.com/en-us/oneapi-tbb-documentation)
* README for build system: [cmake/README.md](cmake/README.md)
## Support
+1 -1
View File
@@ -38,7 +38,7 @@ cmake <options> <repo_root>
Some useful options:
- `-G <generator>` - specify particular project generator, see `cmake --help` for details.
- `-DCMAKE_BUILD_TYPE=Debug` - specify for Debug build, it isn't applicable for multi-config generators, e.g. for Visual Studio generator).
- `-DCMAKE_BUILD_TYPE=Debug` - specify for Debug build, it doesn't applicable for multi-config generators, e.g. for Visual Studio generator).
#### TBBBind library configuration
+1 -2
View File
@@ -31,8 +31,7 @@ if (NOT TBB_STRICT AND COMMAND tbb_remove_compile_flag)
tbb_remove_compile_flag(-Werror)
endif()
# 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
if (NOT "${CMAKE_OSX_ARCHITECTURES}" MATCHES "^arm64$" AND CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64)
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -mrtm)
endif()
+2 -10
View File
@@ -37,9 +37,8 @@ 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 (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>)
if (CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64)
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -mrtm)
endif()
set(TBB_COMMON_LINK_LIBS dl)
@@ -48,12 +47,5 @@ if (ANDROID_PLATFORM)
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} $<$<NOT:$<CONFIG:Debug>>:-D_FORTIFY_SOURCE=2>)
endif()
# Enabling LTO on Android causes the NDK bug.
# NDK throws the warning: "argument unused during compilation: '-Wa,--noexecstack'"
if (NOT ANDROID_PLATFORM)
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)
+4 -8
View File
@@ -32,9 +32,8 @@ if (NOT CMAKE_GENERATOR MATCHES "Ninja" AND NOT CMAKE_CXX_DEPENDS_USE_COMPILER)
set(TBB_MMD_FLAG -MMD)
endif()
# Enable Intel(R) Transactional Synchronization Extensions (-mrtm) and WAITPKG instructions support (-mwaitpkg) on relevant processors
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>)
if (CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64)
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -mrtm)
endif()
set(TBB_COMMON_LINK_LIBS dl)
@@ -49,14 +48,11 @@ if (NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL Intel)
set(TBB_DSE_FLAG $<$<NOT:$<VERSION_LESS:${CMAKE_CXX_COMPILER_VERSION},6.0>>:-flifetime-dse=1>)
endif()
# Workaround for heavy tests and too many symbols in debug (rellocation truncated to fit: R_MIPS_CALL16)
# Workaround for heavy tests
if ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "mips")
set(TBB_TEST_COMPILE_FLAGS ${TBB_TEST_COMPILE_FLAGS} -DTBB_TEST_LOW_WORKLOAD $<$<CONFIG:DEBUG>:-mxgot>)
set(TBB_TEST_COMPILE_FLAGS ${TBB_TEST_COMPILE_FLAGS} -DTBB_TEST_LOW_WORKLOAD)
endif()
set(TBB_IPO_COMPILE_FLAGS $<$<NOT:$<CONFIG:Debug>>:-flto>)
set(TBB_IPO_LINK_FLAGS $<$<NOT:$<CONFIG:Debug>>:-flto>)
# TBB malloc settings
set(TBBMALLOC_LIB_COMPILE_FLAGS -fno-rtti -fno-exceptions)
set(TBB_OPENMP_FLAG -fopenmp)
-5
View File
@@ -16,14 +16,11 @@ if (MSVC)
include(${CMAKE_CURRENT_LIST_DIR}/MSVC.cmake)
set(TBB_WARNING_LEVEL ${TBB_WARNING_LEVEL} /W3)
set(TBB_OPENMP_FLAG /Qopenmp)
set(TBB_IPO_COMPILE_FLAGS $<$<NOT:$<CONFIG:Debug>>:/Qipo>)
set(TBB_IPO_LINK_FLAGS $<$<NOT:$<CONFIG:Debug>>:/INCREMENTAL:NO>)
elseif (APPLE)
include(${CMAKE_CURRENT_LIST_DIR}/AppleClang.cmake)
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -fstack-protector -Wformat -Wformat-security
$<$<NOT:$<CONFIG:Debug>>:-fno-omit-frame-pointer -qno-opt-report-embed -D_FORTIFY_SOURCE=2>)
set(TBB_OPENMP_FLAG -qopenmp)
set(TBB_IPO_COMPILE_FLAGS $<$<NOT:$<CONFIG:Debug>>:-ipo>)
else()
include(${CMAKE_CURRENT_LIST_DIR}/GNU.cmake)
set(TBB_LIB_LINK_FLAGS ${TBB_LIB_LINK_FLAGS} -static-intel -Wl,-z,relro,-z,now,)
@@ -31,6 +28,4 @@ else()
$<$<NOT:$<CONFIG:Debug>>:-qno-opt-report-embed -D_FORTIFY_SOURCE=2>
$<$<EQUAL:${TBB_ARCH},32>:-falign-stack=maintain-16-byte>)
set(TBB_OPENMP_FLAG -qopenmp)
set(TBB_IPO_COMPILE_FLAGS $<$<NOT:$<CONFIG:Debug>>:-ipo>)
endif()
set(TBB_IPO_LINK_FLAGS ${TBB_IPO_LINK_FLAGS} ${TBB_IPO_COMPILE_FLAGS})
-27
View File
@@ -1,27 +0,0 @@
# Copyright (c) 2020-2021 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
if (WIN32)
include(${CMAKE_CURRENT_LIST_DIR}/MSVC.cmake)
set(TBB_IPO_COMPILE_FLAGS $<$<NOT:$<CONFIG:Debug>>:/Qipo>)
set(TBB_IPO_LINK_FLAGS $<$<NOT:$<CONFIG:Debug>>:/INCREMENTAL:NO>)
else()
include(${CMAKE_CURRENT_LIST_DIR}/Clang.cmake)
set(TBB_IPO_COMPILE_FLAGS $<$<NOT:$<CONFIG:Debug>>:-ipo>)
endif()
set(TBB_IPO_LINK_FLAGS ${TBB_IPO_LINK_FLAGS} ${TBB_IPO_COMPILE_FLAGS})
if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86|AMD64)")
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -mrtm -mwaitpkg)
endif()
-3
View File
@@ -69,7 +69,4 @@ if (TBB_WINDOWS_DRIVER)
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} /D _UNICODE /DUNICODE /DWINAPI_FAMILY=WINAPI_FAMILY_APP /D__WRL_NO_DEFAULT_LIB__)
endif()
set(TBB_IPO_COMPILE_FLAGS $<$<NOT:$<CONFIG:Debug>>:/GL>)
set(TBB_IPO_LINK_FLAGS $<$<NOT:$<CONFIG:Debug>>:/LTCG /INCREMENTAL:NO>)
set(TBB_OPENMP_FLAG /openmp)
+1 -4
View File
@@ -45,10 +45,7 @@ endforeach()
unset(HWLOC_TARGET_NAME)
if (NOT HWLOC_TARGET_EXPLICITLY_DEFINED AND
# No hwloc auto detection for cross compilation
NOT CMAKE_CROSSCOMPILING
)
if (NOT HWLOC_TARGET_EXPLICITLY_DEFINED)
find_package(PkgConfig QUIET)
if (PKG_CONFIG_FOUND)
pkg_search_module(HWLOC hwloc)
+6 -2
View File
@@ -26,18 +26,22 @@ set(DLL_REL_PATH "redist")
file(READ ${CMAKE_CURRENT_LIST_DIR}/../../include/oneapi/tbb/version.h _tbb_version_info)
string(REGEX REPLACE ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1" _tbb_ver_major "${_tbb_version_info}")
string(REGEX REPLACE ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1" _tbb_ver_minor "${_tbb_version_info}")
string(REGEX REPLACE ".*#define TBB_VERSION_PATCH ([0-9]+).*" "\\1" _tbb_ver_patch "${_tbb_version_info}")
string(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" _tbb_interface_ver "${_tbb_version_info}")
string(REGEX REPLACE ".*#define __TBB_BINARY_VERSION ([0-9]+).*" "\\1" TBB_BINARY_VERSION "${_tbb_version_info}")
file(READ ${CMAKE_CURRENT_LIST_DIR}/../../CMakeLists.txt _tbb_cmakelist)
string(REGEX REPLACE ".*TBBMALLOC_BINARY_VERSION ([0-9]+).*" "\\1" TBBMALLOC_BINARY_VERSION "${_tbb_cmakelist}")
set(TBBMALLOC_PROXY_BINARY_VERSION ${TBBMALLOC_BINARY_VERSION})
string(REGEX REPLACE ".*TBBBIND_BINARY_VERSION ([0-9]+).*" "\\1" TBBBIND_BINARY_VERSION "${_tbb_cmakelist}")
# Parse patch and tweak versions from interface version: e.g. 12014 --> 01 - patch version, 4 - tweak version.
math(EXPR _tbb_ver_patch "${_tbb_interface_ver} % 1000 / 10")
math(EXPR _tbb_ver_tweak "${_tbb_interface_ver} % 10")
set(COMMON_ARGS
TBB_ROOT_REL_PATH ${TBB_ROOT_REL_PATH}
INC_REL_PATH ${INC_REL_PATH}
LIB_REL_PATH ${LIB_REL_PATH}
VERSION ${_tbb_ver_major}.${_tbb_ver_minor}.${_tbb_ver_patch}
VERSION ${_tbb_ver_major}.${_tbb_ver_minor}.${_tbb_ver_patch}.${_tbb_ver_tweak}
TBB_BINARY_VERSION ${TBB_BINARY_VERSION}
TBBMALLOC_BINARY_VERSION ${TBBMALLOC_BINARY_VERSION}
TBBMALLOC_PROXY_BINARY_VERSION ${TBBMALLOC_PROXY_BINARY_VERSION}
@@ -114,7 +114,7 @@ static void CountOccurrences(int nthreads) {
if (!silent && count_collisions) {
for (auto i = hashes.begin(); i != hashes.end(); ++i)
c += i->second - 1;
printf("hashes = %d collisions = %d ", static_cast<int>(hashes.size()), c);
printf("hashes = %d collisions = %d ", hashes.size(), c);
c = 0;
hashes.clear();
}
-4
View File
@@ -34,10 +34,6 @@ add_executable(fgbzip2
target_link_libraries(fgbzip2 TBB::tbb Threads::Threads)
target_compile_options(fgbzip2 PRIVATE ${TBB_CXX_STD_FLAG})
if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL IntelLLVM)
target_compile_options(fgbzip2 PRIVATE -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE)
endif()
if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL Intel)
if (COMMAND target_link_options)
target_link_options(fgbzip2 PRIVATE /FORCE:MULTIPLE /INCREMENTAL:NO)
+6 -11
View File
@@ -38,12 +38,6 @@
// for each part of map within radius of BMU W
// update vector: W(t+1) = W(t) + w(dist)*L*(V - W(t))
#ifndef NOMINMAX
#define NOMINMAX
#endif // NOMINMAX
#include <algorithm>
#define _MAIN_C_ 1
#include "som.hpp"
@@ -51,7 +45,6 @@
#include "oneapi/tbb/blocked_range2d.h"
#include "oneapi/tbb/tick_count.h"
#include "oneapi/tbb/task_arena.h"
#include "oneapi/tbb/global_control.h"
#include "common/utility/utility.hpp"
#include "common/utility/get_default_num_threads.hpp"
@@ -190,6 +183,10 @@ void wait_for_all_graphs(int cIndex) { // cIndex ranges over [0 .. SPECULATION_C
for (int x = 0; x < xranges; ++x) {
for (int y = 0; y < yranges; ++y) {
(*g_array[cIndex])[x][y]->wait_for_all();
#if EXTRA_DEBUG
__TBB_ASSERT(!(*g_array[cIndex])[x][y]->is_cancelled(),
"wait_for_all() did not reset graph cancel");
#endif
}
}
}
@@ -375,7 +372,7 @@ void graph_teach(SOMap &map1, teaching_vector_type &in, oneapi::tbb::task_arena
extra_count.reserve(xRangeMax * yRangeMax + 1);
missing_count.reserve(xRangeMax * yRangeMax + 1);
canceled_before.reserve(xRangeMax * yRangeMax + 1);
for (int i = 0; i < xRangeMax * yRangeMax + 1; ++i) {
for (int = 0; i < xRangeMax * yRangeMax + 1; ++i) {
cancel_count.push_back(0);
extra_count.push_back(0);
missing_count.push_back(0);
@@ -539,10 +536,8 @@ int main(int argc, char *argv[]) {
std::vector<int> single_yval;
single_yval.reserve(my_teaching.size());
#endif
//TODO: Investigate how to not require mandatory concurrency
for (int p = std::max(threads.first, 2); p <= std::max(threads.last, 2); ++p) {
for (int p = threads.first; p <= threads.last; ++p) {
// Restrict max concurrency level via task_arena interface
oneapi::tbb::global_control limit(oneapi::tbb::global_control::max_allowed_parallelism, p);
oneapi::tbb::task_arena ta(p);
if (extra_debug)
printf(" -------------- Running with %d threads. ------------\n", p);
@@ -26,9 +26,6 @@ add_subdirectory(../../common/gui gui)
target_link_libraries(polygon_overlay TBB::tbb TBB::tbbmalloc Threads::Threads UI_LIB_polygon_overlay)
target_compile_options(polygon_overlay PRIVATE ${TBB_CXX_STD_FLAG})
if (MSVC)
target_compile_options(polygon_overlay PRIVATE -DNOMINMAX)
endif()
set(EXECUTABLE "$<TARGET_FILE:polygon_overlay>")
set(ARGS "")
@@ -36,4 +33,3 @@ set(LIGHT_ARGS --polys 10 --size 5x5)
add_execution_target(run_polygon_overlay polygon_overlay ${EXECUTABLE} "${ARGS}")
add_execution_target(light_test_polygon_overlay polygon_overlay ${EXECUTABLE} "${LIGHT_ARGS}")
@@ -14,6 +14,10 @@
limitations under the License.
*/
#ifndef NOMINMAX
#define NOMINMAX
#endif // NOMINMAX
// Polygon overlay
//
#include <cstdlib>
@@ -16,6 +16,10 @@
// Support for GUI display for Polygon overlay demo
#ifndef NOMINMAX
#define NOMINMAX
#endif // NOMINMAX
#define VIDEO_WINMAIN_ARGS
#include <iostream>
@@ -65,10 +65,6 @@ add_subdirectory(../../common/gui gui)
target_link_libraries(tachyon TBB::tbb Threads::Threads UI_LIB_tachyon)
target_compile_options(tachyon PRIVATE ${TBB_CXX_STD_FLAG})
if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL IntelLLVM)
target_compile_options(tachyon PRIVATE -D_CRT_SECURE_NO_WARNINGS)
endif()
set(EXECUTABLE "$<TARGET_FILE:tachyon>")
set(ARGS ${CMAKE_CURRENT_SOURCE_DIR}/dat/balls.dat)
set(PERF_ARGS silent ${CMAKE_CURRENT_SOURCE_DIR}/dat/balls3.dat)
@@ -25,10 +25,6 @@ add_executable(square gen_input.cpp square.cpp)
target_link_libraries(square TBB::tbb Threads::Threads)
target_compile_options(square PRIVATE ${TBB_CXX_STD_FLAG})
if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL IntelLLVM)
target_compile_options(square PRIVATE -D_CRT_SECURE_NO_WARNINGS)
endif()
set(EXECUTABLE "$<TARGET_FILE:square>")
set(ARGS 0 input.txt output.txt)
set(PERF_ARGS auto input.txt output.txt silent)
@@ -18,7 +18,6 @@
// Example program that reads a file of decimal integers in text format
// and changes each to its square.
//
#include <cstring>
#include <cstdlib>
#include <cstdio>
@@ -15,7 +15,7 @@
*/
/*
This file contains the TBB-based implementation of convex hull algorithm.
This file contains the TBB-based implementation of convex hull algortihm.
It corresponds to the following settings in convex_hull_bench.cpp:
- USETBB defined to 1
- USECONCVEC defined to 1
@@ -25,10 +25,6 @@ add_executable(sudoku sudoku.cpp)
target_link_libraries(sudoku TBB::tbb Threads::Threads)
target_compile_options(sudoku PRIVATE ${TBB_CXX_STD_FLAG})
if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL IntelLLVM)
target_compile_options(sudoku PRIVATE -D_CRT_SECURE_NO_WARNINGS)
endif()
set(EXECUTABLE "$<TARGET_FILE:sudoku>")
set(ARGS 4 ${CMAKE_CURRENT_SOURCE_DIR}/input1 verbose)
set(PERF_ARGS auto ${CMAKE_CURRENT_SOURCE_DIR}/input1 silent)
-3
View File
@@ -37,9 +37,6 @@
#if TBB_PREVIEW_CONCURRENT_LRU_CACHE
#include "tbb/concurrent_lru_cache.h"
#endif
#if TBB_PREVIEW_COLLABORATIVE_CALL_ONCE
#include "oneapi/tbb/collaborative_call_once.h"
#endif
#include "oneapi/tbb/concurrent_priority_queue.h"
#include "oneapi/tbb/concurrent_queue.h"
#include "oneapi/tbb/concurrent_unordered_map.h"
-7
View File
@@ -40,7 +40,6 @@ namespace d1 {
//! A range over which to iterate.
/** @ingroup algorithms */
template<typename Value>
__TBB_requires(blocked_range_value<Value>)
class blocked_range {
public:
//! Type of a value
@@ -140,18 +139,12 @@ private:
}
template<typename RowValue, typename ColValue>
__TBB_requires(blocked_range_value<RowValue> &&
blocked_range_value<ColValue>)
friend class blocked_range2d;
template<typename RowValue, typename ColValue, typename PageValue>
__TBB_requires(blocked_range_value<RowValue> &&
blocked_range_value<ColValue> &&
blocked_range_value<PageValue>)
friend class blocked_range3d;
template<typename DimValue, unsigned int N, typename>
__TBB_requires(blocked_range_value<DimValue>)
friend class blocked_rangeNd_impl;
};
-3
View File
@@ -21,7 +21,6 @@
#include "detail/_config.h"
#include "detail/_namespace_injection.h"
#include "detail/_range_common.h"
#include "blocked_range.h"
@@ -32,8 +31,6 @@ namespace d1 {
//! A 2-dimensional range that models the Range concept.
/** @ingroup algorithms */
template<typename RowValue, typename ColValue = RowValue>
__TBB_requires(blocked_range_value<RowValue> &&
blocked_range_value<ColValue>)
class blocked_range2d {
public:
//! Type for size of an iteration range
-3
View File
@@ -31,9 +31,6 @@ namespace d1 {
//! A 3-dimensional range that models the Range concept.
/** @ingroup algorithms */
template<typename PageValue, typename RowValue = PageValue, typename ColValue = RowValue>
__TBB_requires(blocked_range_value<PageValue> &&
blocked_range_value<RowValue> &&
blocked_range_value<ColValue>)
class blocked_range3d {
public:
//! Type for size of an iteration range
-3
View File
@@ -28,7 +28,6 @@
#include "detail/_config.h"
#include "detail/_template_helpers.h" // index_sequence, make_index_sequence
#include "detail/_range_common.h"
#include "blocked_range.h"
@@ -50,11 +49,9 @@ namespace d1 {
*/
template<typename Value, unsigned int N, typename = detail::make_index_sequence<N>>
__TBB_requires(blocked_range_value<Value>)
class blocked_rangeNd_impl;
template<typename Value, unsigned int N, std::size_t... Is>
__TBB_requires(blocked_range_value<Value>)
class blocked_rangeNd_impl<Value, N, detail::index_sequence<Is...>> {
public:
//! Type of a value.
@@ -1,222 +0,0 @@
/*
Copyright (c) 2021 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef __TBB_collaborative_call_once_H
#define __TBB_collaborative_call_once_H
#if __TBB_PREVIEW_COLLABORATIVE_CALL_ONCE
#include "tbb/task_arena.h"
#include "tbb/task_group.h"
#include "tbb/task.h"
#include <atomic>
namespace tbb {
namespace detail {
namespace d1 {
#if _MSC_VER && !defined(__INTEL_COMPILER)
// Suppress warning: structure was padded due to alignment specifier
#pragma warning (push)
#pragma warning (disable: 4324)
#endif
constexpr std::uintptr_t collaborative_once_max_references = max_nfs_size;
constexpr std::uintptr_t collaborative_once_references_mask = collaborative_once_max_references-1;
class alignas(max_nfs_size) collaborative_once_runner : no_copy {
struct storage_t {
task_arena m_arena{ task_arena::attach{} };
wait_context m_wait_context{1};
};
std::atomic<std::int64_t> m_ref_count{0};
std::atomic<bool> m_is_ready{false};
// Storage with task_arena and wait_context must be initialized only by winner thread
union {
storage_t m_storage;
};
template<typename Fn>
void isolated_execute(Fn f) {
auto func = [f] {
f();
// delegate_base requires bool returning functor while isolate_within_arena ignores the result
return true;
};
delegated_function<decltype(func)> delegate(func);
r1::isolate_within_arena(delegate, reinterpret_cast<std::intptr_t>(this));
}
public:
class lifetime_guard : no_copy {
collaborative_once_runner& m_runner;
public:
lifetime_guard(collaborative_once_runner& r) : m_runner(r) {
m_runner.m_ref_count++;
}
~lifetime_guard() {
m_runner.m_ref_count--;
}
};
collaborative_once_runner() {}
~collaborative_once_runner() {
spin_wait_until_eq(m_ref_count, 0, std::memory_order_acquire);
if (m_is_ready.load(std::memory_order_relaxed)) {
m_storage.~storage_t();
}
}
std::uintptr_t to_bits() {
return reinterpret_cast<std::uintptr_t>(this);
}
static collaborative_once_runner* from_bits(std::uintptr_t bits) {
__TBB_ASSERT( (bits & collaborative_once_references_mask) == 0, "invalid pointer, last log2(max_nfs_size) bits must be zero" );
return reinterpret_cast<collaborative_once_runner*>(bits);
}
template <typename F>
void run_once(F&& f) {
__TBB_ASSERT(!m_is_ready.load(std::memory_order_relaxed), "storage with task_arena and wait_context is already initialized");
// Initialize internal state
new(&m_storage) storage_t();
m_storage.m_arena.execute([&] {
isolated_execute([&] {
task_group_context context{ task_group_context::bound,
task_group_context::default_traits | task_group_context::concurrent_wait };
function_stack_task<F> t{ std::forward<F>(f), m_storage.m_wait_context };
// Set the ready flag after entering the execute body to prevent
// moonlighting threads from occupying all slots inside the arena.
m_is_ready.store(true, std::memory_order_release);
execute_and_wait(t, context, m_storage.m_wait_context, context);
});
});
}
void assist() noexcept {
// Do not join the arena until the winner thread takes the slot
spin_wait_while_eq(m_is_ready, false);
m_storage.m_arena.execute([&] {
isolated_execute([&] {
// We do not want to get an exception from user functor on moonlighting threads.
// The exception is handled with the winner thread
task_group_context stub_context;
wait(m_storage.m_wait_context, stub_context);
});
});
}
};
class collaborative_once_flag : no_copy {
enum state : std::uintptr_t { uninitialized, done };
std::atomic<std::uintptr_t> m_state{ state::uninitialized };
template <typename Fn, typename... Args>
friend void collaborative_call_once(collaborative_once_flag& flag, Fn&& f, Args&&... args);
void set_completion_state(std::uintptr_t runner_bits, std::uintptr_t desired) {
std::uintptr_t expected = runner_bits;
do {
expected = runner_bits;
// Possible inefficiency: when we start waiting,
// some moonlighting threads might continue coming that will prolong our waiting.
// Fortunately, there are limited number of threads on the system so wait time is limited.
spin_wait_until_eq(m_state, expected);
} while (!m_state.compare_exchange_strong(expected, desired));
}
template <typename Fn>
void do_collaborative_call_once(Fn&& f) {
std::uintptr_t expected = m_state.load(std::memory_order_acquire);
collaborative_once_runner runner;
do {
if (expected == state::uninitialized && m_state.compare_exchange_strong(expected, runner.to_bits())) {
// Winner thread
runner.run_once([&] {
try_call([&] {
std::forward<Fn>(f)();
}).on_exception([&] {
// Reset the state to uninitialized to allow other threads to try initialization again
set_completion_state(runner.to_bits(), state::uninitialized);
});
// We successfully executed functor
set_completion_state(runner.to_bits(), state::done);
});
break;
} else {
// Moonlighting thread: we need to add a reference to the state to prolong runner lifetime.
// However, the maximum number of references are limited with runner alignment.
// So, we use CAS loop and spin_wait to guarantee that references never exceed "max_value".
do {
auto max_value = expected | collaborative_once_references_mask;
expected = spin_wait_while_eq(m_state, max_value);
// "expected > state::done" prevents storing values, when state is uninitialized or done
} while (expected > state::done && !m_state.compare_exchange_strong(expected, expected + 1));
if (auto shared_runner = collaborative_once_runner::from_bits(expected & ~collaborative_once_references_mask)) {
collaborative_once_runner::lifetime_guard guard{*shared_runner};
m_state.fetch_sub(1);
// The moonlighting threads are not expected to handle exceptions from user functor.
// Therefore, no exception is expected from assist().
shared_runner->assist();
}
}
} while (expected != state::done);
}
};
template <typename Fn, typename... Args>
void collaborative_call_once(collaborative_once_flag& flag, Fn&& fn, Args&&... args) {
if (flag.m_state.load(std::memory_order_acquire) != collaborative_once_flag::done) {
#if __TBB_GCC_PARAMETER_PACK_IN_LAMBDAS_BROKEN
// Using stored_pack to suppress bug in GCC 4.8
// with parameter pack expansion in lambda
auto stored_pack = save_pack(std::forward<Args>(args)...);
auto func = [&] { call(std::forward<Fn>(fn), std::move(stored_pack)); };
#else
auto func = [&] { fn(std::forward<Args>(args)...); };
#endif
flag.do_collaborative_call_once(func);
}
}
#if _MSC_VER && !defined(__INTEL_COMPILER)
#pragma warning (pop) // 4324 warning
#endif
} // namespace d1
} // namespace detail
using detail::d1::collaborative_call_once;
using detail::d1::collaborative_once_flag;
} // namespace tbb
#endif // __TBB_PREVIEW_COLLABORATIVE_CALL_ONCE
#endif // __TBB_collaborative_call_once_H
+4 -17
View File
@@ -489,7 +489,7 @@ public:
using iterator = Iterator;
// True if range is empty.
bool empty() const { return my_begin == my_end; }
bool empty() const {return my_begin == my_end;}
// True if range can be partitioned into two subranges.
bool is_divisible() const {
@@ -518,8 +518,8 @@ public:
set_midpoint();
}
Iterator begin() const { return my_begin; }
Iterator end() const { return my_end; }
const Iterator begin() const { return my_begin; }
const Iterator end() const { return my_end; }
// The grain size for this range.
size_type grainsize() const { return my_grainsize; }
@@ -552,26 +552,13 @@ void hash_map_range<Iterator>::set_midpoint() const {
"[my_begin, my_midpoint) range should not be empty" );
}
#if __TBB_PREVIEW_CONCURRENT_HASH_MAP_EXTENSIONS && __TBB_CPP20_CONCEPTS_PRESENT
template <typename Mutex>
concept ch_map_rw_scoped_lockable = rw_scoped_lockable<Mutex> &&
requires (const typename Mutex::scoped_lock& sl) {
{ sl.is_writer() } -> std::convertible_to<bool>;
};
#endif
template <typename Key, typename T,
typename HashCompare = d1::tbb_hash_compare<Key>,
typename Allocator = tbb_allocator<std::pair<const Key, T>>
#if __TBB_PREVIEW_CONCURRENT_HASH_MAP_EXTENSIONS
, typename MutexType = spin_rw_mutex
>
__TBB_requires(tbb::detail::hash_compare<HashCompare, Key> &&
ch_map_rw_scoped_lockable<MutexType>)
#else
>
__TBB_requires(tbb::detail::hash_compare<HashCompare, Key>)
#endif
>
class concurrent_hash_map
#if __TBB_PREVIEW_CONCURRENT_HASH_MAP_EXTENSIONS
: protected hash_map_base<Allocator, MutexType>
+2 -4
View File
@@ -236,8 +236,7 @@ public:
: my_lru_cache_ptr(other.my_lru_cache_ptr), my_map_record_ptr(other.my_map_record_ptr) {
__TBB_ASSERT(
(other.my_lru_cache_ptr != nullptr && other.my_map_record_ptr != nullptr) ||
(other.my_lru_cache_ptr == nullptr && other.my_map_record_ptr == nullptr),
bool(other.my_lru_cache_ptr) == bool(other.my_map_record_ptr),
"invalid state of moving object?");
other.my_lru_cache_ptr = nullptr;
@@ -246,8 +245,7 @@ public:
handle_object& operator=(handle_object&& other) {
__TBB_ASSERT(
(other.my_lru_cache_ptr != nullptr && other.my_map_record_ptr != nullptr) ||
(other.my_lru_cache_ptr == nullptr && other.my_map_record_ptr == nullptr),
bool(other.my_lru_cache_ptr) == bool(other.my_map_record_ptr),
"invalid state of moving object?");
if (my_lru_cache_ptr)
+4 -4
View File
@@ -26,7 +26,7 @@
namespace tbb {
namespace detail {
namespace d2 {
namespace d1 {
template<typename Key, typename Value, typename KeyCompare, typename RandomGenerator,
typename Allocator, bool AllowMultimapping>
@@ -327,13 +327,13 @@ void swap( concurrent_multimap<Key, Value, Compare, Allocator>& lhs,
lhs.swap(rhs);
}
} // namespace d2
} // namespace d1
} // namespace detail
inline namespace v1 {
using detail::d2::concurrent_map;
using detail::d2::concurrent_multimap;
using detail::d1::concurrent_map;
using detail::d1::concurrent_multimap;
using detail::split;
} // inline namespace v1
+24 -24
View File
@@ -26,7 +26,7 @@
namespace tbb {
namespace detail {
namespace d2 {
namespace d1 {
// A high-performance thread-safe non-blocking concurrent queue.
// Multiple threads may each push and pop concurrently.
@@ -57,7 +57,7 @@ public:
my_allocator(a), my_queue_representation(nullptr)
{
my_queue_representation = static_cast<queue_representation_type*>(r1::cache_aligned_allocate(sizeof(queue_representation_type)));
queue_allocator_traits::construct(my_allocator, my_queue_representation);
queue_allocator_traits::construct(my_allocator, my_queue_representation, my_allocator);
__TBB_ASSERT(is_aligned(my_queue_representation, max_nfs_size), "alignment error" );
__TBB_ASSERT(is_aligned(&my_queue_representation->head_counter, max_nfs_size), "alignment error" );
@@ -76,13 +76,13 @@ public:
concurrent_queue(const concurrent_queue& src, const allocator_type& a) :
concurrent_queue(a)
{
my_queue_representation->assign(*src.my_queue_representation, my_allocator, copy_construct_item);
my_queue_representation->assign(*src.my_queue_representation, copy_construct_item);
}
concurrent_queue(const concurrent_queue& src) :
concurrent_queue(queue_allocator_traits::select_on_container_copy_construction(src.get_allocator()))
{
my_queue_representation->assign(*src.my_queue_representation, my_allocator, copy_construct_item);
my_queue_representation->assign(*src.my_queue_representation, copy_construct_item);
}
// Move constructors
@@ -101,7 +101,7 @@ public:
internal_swap(src);
} else {
// allocators are different => performing per-element move
my_queue_representation->assign(*src.my_queue_representation, my_allocator, move_construct_item);
my_queue_representation->assign(*src.my_queue_representation, move_construct_item);
src.clear();
}
}
@@ -109,7 +109,7 @@ public:
// Destroy queue
~concurrent_queue() {
clear();
my_queue_representation->clear(my_allocator);
my_queue_representation->clear();
queue_allocator_traits::destroy(my_allocator, my_queue_representation);
r1::cache_aligned_deallocate(my_queue_representation);
}
@@ -177,7 +177,7 @@ private:
template <typename... Args>
void internal_push( Args&&... args ) {
ticket_type k = my_queue_representation->tail_counter++;
my_queue_representation->choose(k).push(k, *my_queue_representation, my_allocator, std::forward<Args>(args)...);
my_queue_representation->choose(k).push(k, *my_queue_representation, std::forward<Args>(args)...);
}
bool internal_try_pop( void* dst ) {
@@ -193,7 +193,7 @@ private:
// Queue had item with ticket k when we looked. Attempt to get that item.
// Another thread snatched the item, retry.
} while (!my_queue_representation->head_counter.compare_exchange_strong(k, k + 1));
} while (!my_queue_representation->choose(k).pop(dst, k, *my_queue_representation, my_allocator));
} while (!my_queue_representation->choose(k).pop(dst, k, *my_queue_representation));
return true;
}
@@ -230,7 +230,7 @@ class concurrent_monitor;
// The concurrent monitor tags for concurrent_bounded_queue.
static constexpr std::size_t cbq_slots_avail_tag = 0;
static constexpr std::size_t cbq_items_avail_tag = 1;
} // namespace d2
} // namespace d1
namespace r1 {
@@ -246,7 +246,7 @@ namespace r1 {
} // namespace r1
namespace d2 {
namespace d1 {
// A high-performance thread-safe blocking concurrent bounded queue.
// Supports boundedness and blocking semantics.
// Multiple threads may each push and pop concurrently.
@@ -260,7 +260,7 @@ class concurrent_bounded_queue {
template <typename FuncType>
void internal_wait(r1::concurrent_monitor* monitors, std::size_t monitor_tag, std::ptrdiff_t target, FuncType pred) {
d1::delegated_function<FuncType> func(pred);
delegated_function<FuncType> func(pred);
r1::wait_bounded_queue_monitor(monitors, monitor_tag, target, func);
}
public:
@@ -285,7 +285,7 @@ public:
my_queue_representation = reinterpret_cast<queue_representation_type*>(
r1::allocate_bounded_queue_rep(sizeof(queue_representation_type)));
my_monitors = reinterpret_cast<r1::concurrent_monitor*>(my_queue_representation + 1);
queue_allocator_traits::construct(my_allocator, my_queue_representation);
queue_allocator_traits::construct(my_allocator, my_queue_representation, my_allocator);
my_capacity = std::size_t(-1) / (queue_representation_type::item_size > 1 ? queue_representation_type::item_size : 2);
__TBB_ASSERT(is_aligned(my_queue_representation, max_nfs_size), "alignment error" );
@@ -305,13 +305,13 @@ public:
concurrent_bounded_queue( const concurrent_bounded_queue& src, const allocator_type& a ) :
concurrent_bounded_queue(a)
{
my_queue_representation->assign(*src.my_queue_representation, my_allocator, copy_construct_item);
my_queue_representation->assign(*src.my_queue_representation, copy_construct_item);
}
concurrent_bounded_queue( const concurrent_bounded_queue& src ) :
concurrent_bounded_queue(queue_allocator_traits::select_on_container_copy_construction(src.get_allocator()))
{
my_queue_representation->assign(*src.my_queue_representation, my_allocator, copy_construct_item);
my_queue_representation->assign(*src.my_queue_representation, copy_construct_item);
}
// Move constructors
@@ -330,7 +330,7 @@ public:
internal_swap(src);
} else {
// allocators are different => performing per-element move
my_queue_representation->assign(*src.my_queue_representation, my_allocator, move_construct_item);
my_queue_representation->assign(*src.my_queue_representation, move_construct_item);
src.clear();
}
}
@@ -338,7 +338,7 @@ public:
// Destroy queue
~concurrent_bounded_queue() {
clear();
my_queue_representation->clear(my_allocator);
my_queue_representation->clear();
queue_allocator_traits::destroy(my_allocator, my_queue_representation);
r1::deallocate_bounded_queue_rep(reinterpret_cast<std::uint8_t*>(my_queue_representation),
sizeof(queue_representation_type));
@@ -456,12 +456,12 @@ private:
try_call( [&] {
internal_wait(my_monitors, cbq_slots_avail_tag, target, pred);
}).on_exception( [&] {
my_queue_representation->choose(ticket).abort_push(ticket, *my_queue_representation, my_allocator);
my_queue_representation->choose(ticket).abort_push(ticket, *my_queue_representation);
});
}
__TBB_ASSERT((static_cast<std::ptrdiff_t>(my_queue_representation->head_counter.load(std::memory_order_relaxed)) > target), nullptr);
my_queue_representation->choose(ticket).push(ticket, *my_queue_representation, my_allocator, std::forward<Args>(args)...);
my_queue_representation->choose(ticket).push(ticket, *my_queue_representation, std::forward<Args>(args)...);
r1::notify_bounded_queue_monitor(my_monitors, cbq_items_avail_tag, ticket);
}
@@ -477,7 +477,7 @@ private:
// Another thread claimed the slot, so retry.
} while (!my_queue_representation->tail_counter.compare_exchange_strong(ticket, ticket + 1));
my_queue_representation->choose(ticket).push(ticket, *my_queue_representation, my_allocator, std::forward<Args>(args)...);
my_queue_representation->choose(ticket).push(ticket, *my_queue_representation, std::forward<Args>(args)...);
r1::notify_bounded_queue_monitor(my_monitors, cbq_items_avail_tag, ticket);
return true;
}
@@ -505,7 +505,7 @@ private:
});
}
__TBB_ASSERT(static_cast<std::ptrdiff_t>(my_queue_representation->tail_counter.load(std::memory_order_relaxed)) > target, nullptr);
} while (!my_queue_representation->choose(target).pop(dst, target, *my_queue_representation, my_allocator));
} while (!my_queue_representation->choose(target).pop(dst, target, *my_queue_representation));
r1::notify_bounded_queue_monitor(my_monitors, cbq_slots_avail_tag, target);
return true;
@@ -523,7 +523,7 @@ private:
// Queue had item with ticket k when we looked. Attempt to get that item.
// Another thread snatched the item, retry.
} while (!my_queue_representation->head_counter.compare_exchange_strong(ticket, ticket + 1));
} while (!my_queue_representation->choose(ticket).pop(dst, ticket, *my_queue_representation, my_allocator));
} while (!my_queue_representation->choose(ticket).pop(dst, ticket, *my_queue_representation));
r1::notify_bounded_queue_monitor(my_monitors, cbq_slots_avail_tag, ticket);
return true;
@@ -563,13 +563,13 @@ concurrent_bounded_queue( It, It, Alloc = Alloc() )
#endif /* __TBB_CPP17_DEDUCTION_GUIDES_PRESENT */
} //namespace d2
} //namespace d1
} // namesapce detail
inline namespace v1 {
using detail::d2::concurrent_queue;
using detail::d2::concurrent_bounded_queue;
using detail::d1::concurrent_queue;
using detail::d1::concurrent_bounded_queue;
using detail::r1::user_abort;
using detail::r1::bad_last_alloc;
+4 -4
View File
@@ -25,7 +25,7 @@
namespace tbb {
namespace detail {
namespace d2 {
namespace d1 {
template<typename Key, typename KeyCompare, typename RandomGenerator, typename Allocator, bool AllowMultimapping>
struct set_traits {
@@ -244,13 +244,13 @@ void swap( concurrent_multiset<Key, Compare, Allocator>& lhs,
lhs.swap(rhs);
}
} // namespace d2
} // namespace d1
} // namespace detail
inline namespace v1 {
using detail::d2::concurrent_set;
using detail::d2::concurrent_multiset;
using detail::d1::concurrent_set;
using detail::d1::concurrent_multiset;
using detail::split;
} // inline namespace v1
+6 -2
View File
@@ -26,13 +26,17 @@ namespace r1 {
/** Normally called from __TBB_ASSERT macro.
If assertion handler is null, print message for assertion failure and abort.
Otherwise call the assertion handler. */
void __TBB_EXPORTED_FUNC assertion_failure(const char* location, int line, const char* expression, const char* comment);
void __TBB_EXPORTED_FUNC assertion_failure(const char* filename, int line, const char* expression, const char* comment);
} // namespace r1
} // namespace detail
} // namespace tbb
//! Release version of assertions
#define __TBB_ASSERT_RELEASE(predicate,message) ((predicate)?((void)0) : tbb::detail::r1::assertion_failure(__func__,__LINE__,#predicate,message))
#if __TBB_BUILD
#define __TBB_ASSERT_RELEASE(predicate,message) ((predicate)?((void)0) : tbb::detail::r1::assertion_failure(__FILE__,__LINE__,#predicate,message))
#else
#define __TBB_ASSERT_RELEASE(predicate,message) ((predicate)?((void)0) : tbb::detail::r1::assertion_failure(__func__,0,#predicate,message))
#endif
#if TBB_USE_ASSERT
//! Assert that predicate is true.
@@ -30,7 +30,7 @@
namespace tbb {
namespace detail {
namespace d2 {
namespace d1 {
using ticket_type = std::size_t;
@@ -67,7 +67,6 @@ public:
using allocator_type = Allocator;
using allocator_traits_type = tbb::detail::allocator_traits<allocator_type>;
using queue_allocator_type = typename allocator_traits_type::template rebind_alloc<queue_rep_type>;
static constexpr size_type item_size = sizeof(T);
static constexpr size_type items_per_page = item_size <= 8 ? 32 :
@@ -124,7 +123,7 @@ public:
}
if (tail_counter.load(std::memory_order_relaxed) != k) spin_wait_until_my_turn(tail_counter, k, base);
d1::call_itt_notify(d1::acquired, &tail_counter);
call_itt_notify(acquired, &tail_counter);
if (p) {
spin_mutex::scoped_lock lock( page_mutex );
@@ -134,7 +133,7 @@ public:
} else {
head_page.store(p, std::memory_order_relaxed);
}
tail_page.store(p, std::memory_order_release);
tail_page.store(p, std::memory_order_relaxed);;
} else {
p = tail_page.load(std::memory_order_acquire); // TODO may be relaxed ?
}
@@ -142,10 +141,10 @@ public:
}
template<typename... Args>
void push( ticket_type k, queue_rep_type& base, queue_allocator_type& allocator, Args&&... args )
void push( ticket_type k, queue_rep_type& base, Args&&... args )
{
padded_page* p = nullptr;
page_allocator_type page_allocator(allocator);
page_allocator_type page_allocator(base.get_allocator());
size_type index = prepare_page(k, base, page_allocator, p);
__TBB_ASSERT(p != nullptr, "Page was not prepared");
@@ -153,38 +152,38 @@ public:
// variadic capture on GCC 4.8.5
auto value_guard = make_raii_guard([&] {
++base.n_invalid_entries;
d1::call_itt_notify(d1::releasing, &tail_counter);
call_itt_notify(releasing, &tail_counter);
tail_counter.fetch_add(queue_rep_type::n_queue);
});
page_allocator_traits::construct(page_allocator, &(*p)[index], std::forward<Args>(args)...);
// If no exception was thrown, mark item as present.
p->mask.store(p->mask.load(std::memory_order_relaxed) | uintptr_t(1) << index, std::memory_order_relaxed);
d1::call_itt_notify(d1::releasing, &tail_counter);
call_itt_notify(releasing, &tail_counter);
value_guard.dismiss();
tail_counter.fetch_add(queue_rep_type::n_queue);
}
void abort_push( ticket_type k, queue_rep_type& base, queue_allocator_type& allocator ) {
void abort_push( ticket_type k, queue_rep_type& base) {
padded_page* p = nullptr;
prepare_page(k, base, allocator, p);
prepare_page(k, base, base.get_allocator(), p);
++base.n_invalid_entries;
tail_counter.fetch_add(queue_rep_type::n_queue);
}
bool pop( void* dst, ticket_type k, queue_rep_type& base, queue_allocator_type& allocator) {
bool pop( void* dst, ticket_type k, queue_rep_type& base ) {
k &= -queue_rep_type::n_queue;
spin_wait_until_eq(head_counter, k);
d1::call_itt_notify(d1::acquired, &head_counter);
spin_wait_while_eq(tail_counter, k);
d1::call_itt_notify(d1::acquired, &tail_counter);
if (head_counter.load(std::memory_order_relaxed) != k) spin_wait_until_eq(head_counter, k);
call_itt_notify(acquired, &head_counter);
if (tail_counter.load(std::memory_order_relaxed) == k) spin_wait_while_eq(tail_counter, k);
call_itt_notify(acquired, &tail_counter);
padded_page *p = head_page.load(std::memory_order_acquire);
__TBB_ASSERT( p, nullptr );
size_type index = modulo_power_of_two( k/queue_rep_type::n_queue, items_per_page );
bool success = false;
{
page_allocator_type page_allocator(allocator);
page_allocator_type page_allocator(base.get_allocator());
micro_queue_pop_finalizer<self_type, value_type, page_allocator_type> finalizer(*this, page_allocator,
k + queue_rep_type::n_queue, index == items_per_page - 1 ? p : nullptr );
if (p->mask.load(std::memory_order_relaxed) & (std::uintptr_t(1) << index)) {
@@ -197,7 +196,7 @@ public:
return success;
}
micro_queue& assign( const micro_queue& src, queue_allocator_type& allocator,
micro_queue& assign( const micro_queue& src, queue_rep_type& base,
item_constructor_type construct_item )
{
head_counter.store(src.head_counter.load(std::memory_order_relaxed), std::memory_order_relaxed);
@@ -212,7 +211,7 @@ public:
size_type end_in_first_page = (index+n_items < items_per_page) ? (index + n_items) : items_per_page;
try_call( [&] {
head_page.store(make_copy(allocator, srcp, index, end_in_first_page, g_index, construct_item), std::memory_order_relaxed);
head_page.store(make_copy(base, srcp, index, end_in_first_page, g_index, construct_item), std::memory_order_relaxed);
}).on_exception( [&] {
head_counter.store(0, std::memory_order_relaxed);
tail_counter.store(0, std::memory_order_relaxed);
@@ -222,7 +221,7 @@ public:
try_call( [&] {
if (srcp != src.tail_page.load(std::memory_order_relaxed)) {
for (srcp = srcp->next; srcp != src.tail_page.load(std::memory_order_relaxed); srcp=srcp->next ) {
cur_page->next = make_copy( allocator, srcp, 0, items_per_page, g_index, construct_item );
cur_page->next = make_copy( base, srcp, 0, items_per_page, g_index, construct_item );
cur_page = cur_page->next;
}
@@ -230,7 +229,7 @@ public:
size_type last_index = modulo_power_of_two(tail_counter.load(std::memory_order_relaxed) / queue_rep_type::n_queue, items_per_page);
if( last_index==0 ) last_index = items_per_page;
cur_page->next = make_copy( allocator, srcp, 0, last_index, g_index, construct_item );
cur_page->next = make_copy( base, srcp, 0, last_index, g_index, construct_item );
cur_page = cur_page->next;
}
tail_page.store(cur_page, std::memory_order_relaxed);
@@ -245,10 +244,10 @@ public:
return *this;
}
padded_page* make_copy( queue_allocator_type& allocator, const padded_page* src_page, size_type begin_in_page,
padded_page* make_copy( queue_rep_type& base, const padded_page* src_page, size_type begin_in_page,
size_type end_in_page, ticket_type& g_index, item_constructor_type construct_item )
{
page_allocator_type page_allocator(allocator);
page_allocator_type page_allocator(base.get_allocator());
padded_page* new_page = page_allocator_traits::allocate(page_allocator, 1);
new_page->next = nullptr;
new_page->mask.store(src_page->mask.load(std::memory_order_relaxed), std::memory_order_relaxed);
@@ -288,10 +287,10 @@ public:
tail_page.store(pg, std::memory_order_relaxed);
}
void clear(queue_allocator_type& allocator ) {
void clear(queue_rep_type& base) {
padded_page* curr_page = head_page.load(std::memory_order_relaxed);
std::size_t index = head_counter.load(std::memory_order_relaxed);
page_allocator_type page_allocator(allocator);
page_allocator_type page_allocator(base.get_allocator());
while (curr_page) {
for (; index != items_per_page - 1; ++index) {
@@ -378,12 +377,12 @@ public:
if( is_valid_page(p) ) {
spin_mutex::scoped_lock lock( my_queue.page_mutex );
padded_page* q = p->next;
my_queue.head_page.store(q, std::memory_order_release);
my_queue.head_page.store(q, std::memory_order_relaxed);
if( !is_valid_page(q) ) {
my_queue.tail_page.store(nullptr, std::memory_order_release);
my_queue.tail_page.store(nullptr, std::memory_order_relaxed);
}
}
my_queue.head_counter.store(my_ticket_type, std::memory_order_release);
my_queue.head_counter.store(my_ticket_type, std::memory_order_relaxed);
if ( is_valid_page(p) ) {
allocator_traits_type::destroy(allocator, static_cast<padded_page*>(p));
allocator_traits_type::deallocate(allocator, static_cast<padded_page*>(p), 1);
@@ -424,13 +423,14 @@ public:
static constexpr size_type item_size = micro_queue_type::item_size;
static constexpr size_type items_per_page = micro_queue_type::items_per_page;
concurrent_queue_rep() {}
concurrent_queue_rep( queue_allocator_type& alloc ) : my_queue_allocator(alloc)
{}
concurrent_queue_rep( const concurrent_queue_rep& ) = delete;
concurrent_queue_rep& operator=( const concurrent_queue_rep& ) = delete;
void clear( queue_allocator_type& alloc ) {
page_allocator_type page_allocator(alloc);
void clear() {
page_allocator_type page_allocator(my_queue_allocator);
for (size_type i = 0; i < n_queue; ++i) {
padded_page* tail_page = array[i].get_tail_page();
if( is_valid_page(tail_page) ) {
@@ -444,7 +444,7 @@ public:
}
}
void assign( const concurrent_queue_rep& src, queue_allocator_type& alloc, item_constructor_type construct_item ) {
void assign( const concurrent_queue_rep& src, item_constructor_type construct_item ) {
head_counter.store(src.head_counter.load(std::memory_order_relaxed), std::memory_order_relaxed);
tail_counter.store(src.tail_counter.load(std::memory_order_relaxed), std::memory_order_relaxed);
n_invalid_entries.store(src.n_invalid_entries.load(std::memory_order_relaxed), std::memory_order_relaxed);
@@ -453,11 +453,11 @@ public:
size_type queue_idx = 0;
try_call( [&] {
for (; queue_idx < n_queue; ++queue_idx) {
array[queue_idx].assign(src.array[queue_idx], alloc, construct_item);
array[queue_idx].assign(src.array[queue_idx], *this, construct_item);
}
}).on_exception( [&] {
for (size_type i = 0; i < queue_idx + 1; ++i) {
array[i].clear(alloc);
array[i].clear(*this);
}
head_counter.store(0, std::memory_order_relaxed);
tail_counter.store(0, std::memory_order_relaxed);
@@ -486,6 +486,10 @@ public:
return tc - hc - nie;
}
queue_allocator_type& get_allocator() {
return my_queue_allocator;
}
friend class micro_queue<T, Allocator>;
// Map ticket_type to an array index
@@ -503,6 +507,7 @@ public:
alignas(max_nfs_size) std::atomic<ticket_type> head_counter{};
alignas(max_nfs_size) std::atomic<ticket_type> tail_counter{};
alignas(max_nfs_size) std::atomic<size_type> n_invalid_entries{};
queue_allocator_type& my_queue_allocator;
}; // class concurrent_queue_rep
#if _MSC_VER && !defined(__INTEL_COMPILER)
@@ -583,7 +588,7 @@ protected:
Value* my_item{ nullptr };
queue_rep_type* my_queue_rep{ nullptr };
ticket_type my_head_counter{};
padded_page* my_array[queue_rep_type::n_queue]{};
padded_page* my_array[queue_rep_type::n_queue];
}; // class concurrent_queue_iterator_base
struct concurrent_queue_iterator_provider {
@@ -647,7 +652,7 @@ private:
friend struct concurrent_queue_iterator_provider;
}; // class concurrent_queue_iterator
} // namespace d2
} // namespace d1
} // namespace detail
} // tbb
@@ -49,7 +49,7 @@
namespace tbb {
namespace detail {
namespace d2 {
namespace d1 {
template <typename Value, typename Allocator>
class skip_list_node {
@@ -72,52 +72,25 @@ public:
using pointer = typename value_allocator_traits::pointer;
using const_pointer = typename value_allocator_traits::const_pointer;
//In perfect world these constructor and destructor would have been private,
//however this seems technically impractical due to use of allocator_traits.
skip_list_node( size_type levels, container_allocator_type& alloc )
: my_container_allocator(alloc), my_height(levels), my_index_number(0)
{
for (size_type l = 0; l < my_height; ++l) {
allocator_traits::construct(my_container_allocator, &get_atomic_next(l), nullptr);
}
}
//Should not be called directly, instead use create method
skip_list_node( size_type levels )
: my_height(levels), my_index_number(0)
{}
//Should not be called directly, instead use destroy method
~skip_list_node() {}
~skip_list_node() {
for (size_type l = 0; l < my_height; ++l) {
allocator_traits::destroy(my_container_allocator, &get_atomic_next(l));
}
}
skip_list_node( const skip_list_node& ) = delete;
skip_list_node( skip_list_node&& ) = delete;
skip_list_node& operator=( const skip_list_node& ) = delete;
skip_list_node& operator=( skip_list_node&& ) = delete;
static skip_list_node* create( container_allocator_type& alloc, size_type height ) {
size_type sz = calc_node_size(height);
static_assert(std::is_same<typename allocator_traits::value_type, std::uint8_t>::value, "skip_list_node assumes that passed in allocator operates on bytes");
auto* node = reinterpret_cast<skip_list_node*>(allocator_traits::allocate(alloc, sz));
//Construct the node itself
allocator_traits::construct(alloc, node, height);
//Construct the level pointers
for (size_type l = 0; l < height; ++l) {
allocator_traits::construct(alloc, &node->get_atomic_next(l), nullptr);
}
return node;
}
static void destroy( container_allocator_type& alloc, skip_list_node* node ) {
//Destroy the level pointers
for (size_type l = 0; l < node->height(); ++l) {
allocator_traits::destroy(alloc, &node->atomic_next(l));
}
size_type sz = calc_node_size(node->height());
// Destroy the node itself
allocator_traits::destroy(alloc, node);
// Deallocate the node
allocator_traits::deallocate(alloc, reinterpret_cast<std::uint8_t*>(node), sz);
}
pointer storage() {
return &my_value;
}
@@ -159,11 +132,6 @@ public:
}
private:
static size_type calc_node_size( size_type height ) {
static_assert(alignof(skip_list_node) >= alignof(atomic_node_ptr), "Incorrect alignment");
return sizeof(skip_list_node) + height * sizeof(atomic_node_ptr);
}
atomic_node_ptr& get_atomic_next( size_type level ) {
atomic_node_ptr* arr = reinterpret_cast<atomic_node_ptr*>(this + 1);
return arr[level];
@@ -174,6 +142,7 @@ private:
return arr[level];
}
container_allocator_type& my_container_allocator;
union {
value_type my_value;
};
@@ -264,7 +233,7 @@ protected:
using node_allocator_traits = tbb::detail::allocator_traits<node_allocator_type>;
using list_node_type = skip_list_node<value_type, node_allocator_type>;
using node_type = d1::node_handle<key_type, value_type, list_node_type, allocator_type>;
using node_type = node_handle<key_type, value_type, list_node_type, allocator_type>;
using iterator = skip_list_iterator<list_node_type, value_type>;
using const_iterator = skip_list_iterator<list_node_type, const value_type>;
@@ -346,7 +315,10 @@ public:
~concurrent_skip_list() {
clear();
delete_head();
node_ptr head = my_head_ptr.load(std::memory_order_relaxed);
if (head != nullptr) {
delete_node(head);
}
}
concurrent_skip_list& operator=( const concurrent_skip_list& other ) {
@@ -363,8 +335,6 @@ public:
concurrent_skip_list& operator=( concurrent_skip_list&& other ) {
if (this != &other) {
clear();
delete_head();
my_compare = std::move(other.my_compare);
my_rng = std::move(other.my_rng);
@@ -415,10 +385,10 @@ public:
std::pair<iterator, bool> insert( node_type&& nh ) {
if (!nh.empty()) {
auto insert_node = d1::node_handle_accessor::get_node_ptr(nh);
auto insert_node = node_handle_accessor::get_node_ptr(nh);
std::pair<iterator, bool> insert_result = internal_insert_node(insert_node);
if (insert_result.second) {
d1::node_handle_accessor::deactivate(nh);
node_handle_accessor::deactivate(nh);
}
return insert_result;
}
@@ -477,7 +447,7 @@ public:
node_type unsafe_extract( const_iterator pos ) {
std::pair<node_ptr, node_ptr> extract_result = internal_extract(pos);
return extract_result.first ? d1::node_handle_accessor::construct<node_type>(extract_result.first) : node_type();
return extract_result.first ? node_handle_accessor::construct<node_type>(extract_result.first) : node_type();
}
node_type unsafe_extract( iterator pos ) {
@@ -665,10 +635,8 @@ public:
class const_range_type {
public:
using size_type = typename concurrent_skip_list::size_type;
using difference_type = typename concurrent_skip_list::difference_type;
using value_type = typename concurrent_skip_list::value_type;
using iterator = typename concurrent_skip_list::const_iterator;
using value_type = typename iterator::value_type;
using reference = typename iterator::reference;
bool empty() const {
return my_begin.my_node_ptr->next(0) == my_end.my_node_ptr;
@@ -703,8 +671,6 @@ public:
class range_type : public const_range_type {
public:
using iterator = typename concurrent_skip_list::iterator;
using value_type = typename iterator::value_type;
using reference = typename iterator::reference;
range_type(range_type& r, split) : const_range_type(r, split()) {}
range_type(const concurrent_skip_list& l) : const_range_type(l) {}
@@ -1079,12 +1045,23 @@ private:
}
}).on_exception([&] {
clear();
delete_head();
node_ptr head = my_head_ptr.load(std::memory_order_relaxed);
if (head != nullptr) {
delete_node(head);
}
});
}
static size_type calc_node_size( size_type height ) {
static_assert(alignof(list_node_type) >= alignof(typename list_node_type::atomic_node_ptr), "Incorrect alignment");
return sizeof(list_node_type) + height * sizeof(typename list_node_type::atomic_node_ptr);
}
node_ptr create_node( size_type height ) {
return list_node_type::create(my_node_allocator, height);
size_type sz = calc_node_size(height);
node_ptr node = reinterpret_cast<node_ptr>(node_allocator_traits::allocate(my_node_allocator, sz));
node_allocator_traits::construct(my_node_allocator, node, height, my_node_allocator);
return node;
}
template <typename... Args>
@@ -1107,16 +1084,13 @@ private:
return create_node(max_level);
}
void delete_head() {
node_ptr head = my_head_ptr.load(std::memory_order_relaxed);
if (head != nullptr) {
delete_node(head);
my_head_ptr.store(nullptr, std::memory_order_relaxed);
}
}
void delete_node( node_ptr node ) {
list_node_type::destroy(my_node_allocator, node);
size_type sz = calc_node_size(node->height());
// Destroy the node
node_allocator_traits::destroy(my_node_allocator, node);
// Deallocate the node
node_allocator_traits::deallocate(my_node_allocator, reinterpret_cast<std::uint8_t*>(node), sz);
}
void delete_value_node( node_ptr node ) {
@@ -1267,8 +1241,7 @@ private:
tbb::enumerable_thread_specific<std::minstd_rand> engines;
};
} // namespace d2
} // namespace d1
} // namespace detail
} // namespace tbb
@@ -910,10 +910,6 @@ private:
// Deallocate the memory
node_allocator_traits::deallocate(dummy_node_allocator, node, 1);
} else {
// GCC 11.1 issues a warning here that incorrect destructor might be called for dummy_nodes
#if (__TBB_GCC_VERSION >= 110100 && __TBB_GCC_VERSION < 120000 ) && !__clang__ && !__INTEL_COMPILER
volatile
#endif
value_node_ptr val_node = static_cast<value_node_ptr>(node);
value_node_allocator_type value_node_allocator(my_segments.get_allocator());
// Destroy the value
+5 -43
View File
@@ -44,7 +44,7 @@
#define __TBB_CPP14_PRESENT (__TBB_LANG >= 201402L)
#define __TBB_CPP17_PRESENT (__TBB_LANG >= 201703L)
#define __TBB_CPP20_PRESENT (__TBB_LANG >= 202002L)
#define __TBB_CPP20_PRESENT (__TBB_LANG >= 201709L)
#if __INTEL_COMPILER || _MSC_VER
#define __TBB_NOINLINE(decl) __declspec(noinline) decl
@@ -209,7 +209,7 @@
/** Library features presence macros **/
#define __TBB_CPP14_INTEGER_SEQUENCE_PRESENT (__TBB_LANG >= 201402L)
#define __TBB_CPP17_INVOKE_PRESENT (__TBB_LANG >= 201703L)
#define __TBB_CPP17_INVOKE_RESULT_PRESENT (__TBB_LANG >= 201703L)
// TODO: Remove the condition(__INTEL_COMPILER > 2021) from the __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
// macro when this feature start working correctly on this compiler.
@@ -250,12 +250,7 @@
#define __TBB_CPP17_LOGICAL_OPERATIONS_PRESENT (__TBB_LANG >= 201703L)
#define __TBB_CPP17_ALLOCATOR_IS_ALWAYS_EQUAL_PRESENT (__TBB_LANG >= 201703L)
#define __TBB_CPP17_IS_SWAPPABLE_PRESENT (__TBB_LANG >= 201703L)
#if defined(__cpp_impl_three_way_comparison) && defined(__cpp_lib_three_way_comparison)
#define __TBB_CPP20_COMPARISONS_PRESENT ((__cpp_impl_three_way_comparison >= 201907L) && (__cpp_lib_three_way_comparison >= 201907L))
#else
#define __TBB_CPP20_COMPARISONS_PRESENT __TBB_CPP20_PRESENT
#endif
#define __TBB_CPP20_COMPARISONS_PRESENT __TBB_CPP20_PRESENT
#define __TBB_RESUMABLE_TASKS (!__TBB_WIN8UI_SUPPORT && !__ANDROID__)
@@ -289,10 +284,6 @@
#define __TBB_GCC_WARNING_IGNORED_ATTRIBUTES_PRESENT (__TBB_GCC_VERSION >= 60100)
#endif
#if __GNUC__ && !__INTEL_COMPILER && !__clang__
#define __TBB_GCC_PARAMETER_PACK_IN_LAMBDAS_BROKEN (__TBB_GCC_VERSION <= 40805)
#endif
#define __TBB_CPP17_FALLTHROUGH_PRESENT (__TBB_LANG >= 201703L)
#define __TBB_CPP17_NODISCARD_PRESENT (__TBB_LANG >= 201703L)
#define __TBB_FALLTHROUGH_PRESENT (__TBB_GCC_VERSION >= 70000 && !__INTEL_COMPILER)
@@ -316,6 +307,7 @@
#define __TBB_CPP17_UNCAUGHT_EXCEPTIONS_PRESENT (_MSC_VER >= 1900 || __GLIBCXX__ && __cpp_lib_uncaught_exceptions \
|| _LIBCPP_VERSION >= 3700 && (!__TBB_MACOS_TARGET_VERSION || __TBB_MACOS_TARGET_VERSION >= 101200))
#define __TBB_TSX_INTRINSICS_PRESENT ((__RTM__ || _MSC_VER>=1700 || __INTEL_COMPILER) && !__ANDROID__)
#define __TBB_WAITPKG_INTRINSICS_PRESENT ((__INTEL_COMPILER >= 1900 || __TBB_GCC_VERSION >= 110000 || __TBB_CLANG_VERSION >= 120000) && !__ANDROID__)
@@ -395,7 +387,7 @@
// instantiation site, which is too late for suppression of the corresponding messages for internal
// stuff.
#if !defined(__INTEL_COMPILER) && (!defined(TBB_SUPPRESS_DEPRECATED_MESSAGES) || (TBB_SUPPRESS_DEPRECATED_MESSAGES == 0))
#if (__TBB_LANG >= 201402L && (!defined(_MSC_VER) || _MSC_VER >= 1920))
#if (__TBB_LANG >= 201402L)
#define __TBB_DEPRECATED [[deprecated]]
#define __TBB_DEPRECATED_MSG(msg) [[deprecated(msg)]]
#elif _MSC_VER
@@ -439,28 +431,6 @@
#endif
#endif
#if __SANITIZE_THREAD__
#define __TBB_USE_THREAD_SANITIZER 1
#elif defined(__has_feature)
#if __has_feature(thread_sanitizer)
#define __TBB_USE_THREAD_SANITIZER 1
#endif
#endif
#ifndef __TBB_USE_CONSTRAINTS
#define __TBB_USE_CONSTRAINTS 1
#endif
#ifndef __TBB_STRICT_CONSTRAINTS
#define __TBB_STRICT_CONSTRAINTS 1
#endif
#if __TBB_CPP20_CONCEPTS_PRESENT && __TBB_USE_CONSTRAINTS
#define __TBB_requires(...) requires __VA_ARGS__
#else // __TBB_CPP20_CONCEPTS_PRESENT
#define __TBB_requires(...)
#endif // __TBB_CPP20_CONCEPTS_PRESENT
/** Macros of the form __TBB_XXX_BROKEN denote known issues that are caused by
the bugs in compilers, standard or OS specific libraries. They should be
removed as soon as the corresponding bugs are fixed or the buggy OS/compiler
@@ -508,12 +478,4 @@
#define __TBB_PREVIEW_CONCURRENT_HASH_MAP_EXTENSIONS 1
#endif
#if TBB_PREVIEW_TASK_GROUP_EXTENSIONS || __TBB_BUILD
#define __TBB_PREVIEW_TASK_GROUP_EXTENSIONS 1
#endif
#if TBB_PREVIEW_COLLABORATIVE_CALL_ONCE || __TBB_BUILD
#define __TBB_PREVIEW_COLLABORATIVE_CALL_ONCE 1
#endif
#endif // __TBB_detail__config_H
-4
View File
@@ -40,10 +40,6 @@ enum class exception_id {
invalid_key,
bad_tagged_msg_cast,
unsafe_wait,
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
bad_task_handle,
bad_task_handle_wrong_task_group,
#endif // __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
last_entry
};
} // namespace d0
@@ -54,7 +54,6 @@ namespace graph_policy_namespace {
// functor that, given an object accepted by the port, will return the
/// field of type K being used for matching.
template<typename K, typename KHash=tbb_hash_compare<typename std::decay<K>::type > >
__TBB_requires(tbb::detail::hash_compare<KHash, K>)
struct key_matching {
typedef K key_type;
typedef typename std::decay<K>::type base_key_type;
@@ -109,10 +108,7 @@ template <typename Input, typename Output, typename B>
class function_body_leaf : public function_body< Input, Output > {
public:
function_body_leaf( const B &_body ) : body(_body) { }
Output operator()(const Input &i) override {
return tbb::detail::invoke(body, i);
// return body(i);
}
Output operator()(const Input &i) override { return body(i); }
B get_body() { return body; }
function_body_leaf* clone() override {
return new function_body_leaf< Input, Output, B >(body);
@@ -127,8 +123,7 @@ class function_body_leaf< continue_msg, continue_msg, B> : public function_body<
public:
function_body_leaf( const B &_body ) : body(_body) { }
continue_msg operator()( const continue_msg &i ) override {
tbb::detail::invoke(body, i);
// body(i);
body(i);
return i;
}
B get_body() { return body; }
@@ -152,66 +152,67 @@ public:
typedef receiver<T> successor_type;
reservable_predecessor_cache( successor_type* owner )
: predecessor_cache<T,M>(owner), reserved_src(nullptr)
: predecessor_cache<T,M>(owner), reserved_src(NULL)
{
// Do not work with the passed pointer here as it may not be fully initialized yet
}
bool try_reserve( output_type &v ) {
bool
try_reserve( output_type &v ) {
bool msg = false;
do {
predecessor_type* pred = nullptr;
{
typename mutex_type::scoped_lock lock(this->my_mutex);
if ( reserved_src.load(std::memory_order_relaxed) || this->internal_empty() )
if ( reserved_src || this->internal_empty() )
return false;
pred = &this->internal_pop();
reserved_src.store(pred, std::memory_order_relaxed);
reserved_src = &this->internal_pop();
}
// Try to get from this sender
msg = pred->try_reserve( v );
msg = reserved_src->try_reserve( v );
if (msg == false) {
typename mutex_type::scoped_lock lock(this->my_mutex);
// Relinquish ownership of the edge
register_successor( *pred, *this->my_owner );
reserved_src.store(nullptr, std::memory_order_relaxed);
register_successor( *reserved_src, *this->my_owner );
reserved_src = NULL;
} else {
// Retain ownership of the edge
this->add( *pred);
this->add( *reserved_src );
}
} while ( msg == false );
return msg;
}
bool try_release() {
reserved_src.load(std::memory_order_relaxed)->try_release();
reserved_src.store(nullptr, std::memory_order_relaxed);
bool
try_release( ) {
reserved_src->try_release( );
reserved_src = NULL;
return true;
}
bool try_consume() {
reserved_src.load(std::memory_order_relaxed)->try_consume();
reserved_src.store(nullptr, std::memory_order_relaxed);
bool
try_consume( ) {
reserved_src->try_consume( );
reserved_src = NULL;
return true;
}
void reset() {
reserved_src.store(nullptr, std::memory_order_relaxed);
predecessor_cache<T, M>::reset();
void reset( ) {
reserved_src = NULL;
predecessor_cache<T,M>::reset( );
}
void clear() {
reserved_src.store(nullptr, std::memory_order_relaxed);
predecessor_cache<T, M>::clear();
reserved_src = NULL;
predecessor_cache<T,M>::clear();
}
private:
std::atomic<predecessor_type*> reserved_src;
predecessor_type *reserved_src;
};
+11 -1
View File
@@ -19,7 +19,7 @@
// #include "../config.h"
#include "_task.h"
#include "../task_group.h"
#include "tbb/task_group.h"
#include "../task_arena.h"
#include "../flow_graph_abstractions.h"
@@ -296,6 +296,16 @@ public:
}
}
#if TODO_REVAMP
#error Decide on ref_count() presence.
Its only use is in the template<typename T, typename BufferType> void test_resets()
#endif
#if __TBB_EXTRA_DEBUG
unsigned ref_count() const { return my_wait_context.reference_count(); }
#endif
// TODO revamp: consider adding getter for task_group_context.
// ITERATORS
@@ -169,7 +169,7 @@ private:
// default-initialized and then copied to in some fashion, resulting in two
// constructions and one destruction per element. If the type is char[ ], we
// placement new into each element, resulting in one construction per element.
static const size_t space_size = sizeof(ArrayType);
static const size_t space_size = sizeof(ArrayType) / sizeof(char);
char value_space[space_size];
-20
View File
@@ -72,33 +72,13 @@ template <typename Key>
class tbb_hash_compare {
public:
std::size_t hash( const Key& a ) const { return my_hash_func(a); }
#if defined(_MSC_VER) && _MSC_VER <= 1900
#pragma warning (push)
// MSVC 2015 throws a strange warning: 'std::size_t': forcing value to bool 'true' or 'false'
#pragma warning (disable: 4800)
#endif
bool equal( const Key& a, const Key& b ) const { return my_key_equal(a, b); }
#if defined(_MSC_VER) && _MSC_VER <= 1900
#pragma warning (pop)
#endif
private:
std::hash<Key> my_hash_func;
std::equal_to<Key> my_key_equal;
};
} // namespace d1
#if __TBB_CPP20_CONCEPTS_PRESENT
inline namespace d0 {
template <typename HashCompare, typename Key>
concept hash_compare = std::copy_constructible<HashCompare> &&
requires( const std::remove_reference_t<HashCompare>& hc, const Key& key1, const Key& key2 ) {
{ hc.hash(key1) } -> std::same_as<std::size_t>;
{ hc.equal(key1, key2) } -> std::convertible_to<bool>;
};
} // namespace d0
#endif // __TBB_CPP20_CONCEPTS_PRESENT
} // namespace detail
} // namespace tbb
-61
View File
@@ -1,61 +0,0 @@
/*
Copyright (c) 2021 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef __TBB_detail__mutex_common_H
#define __TBB_detail__mutex_common_H
#include "_config.h"
#include "_utils.h"
#if __TBB_CPP20_CONCEPTS_PRESENT
#include <concepts>
namespace tbb {
namespace detail {
inline namespace d0 {
template <typename Lock, typename Mutex>
concept mutex_scoped_lock = std::default_initializable<Lock> &&
std::constructible_from<Lock, Mutex&> &&
requires( Lock& lock, Mutex& mutex ) {
lock.acquire(mutex);
{ lock.try_acquire(mutex) } -> adaptive_same_as<bool>;
lock.release();
};
template <typename Lock, typename Mutex>
concept rw_mutex_scoped_lock = mutex_scoped_lock<Lock, Mutex> &&
std::constructible_from<Lock, Mutex&, bool> &&
requires( Lock& lock, Mutex& mutex ) {
lock.acquire(mutex, false);
{ lock.try_acquire(mutex, false) } -> adaptive_same_as<bool>;
{ lock.upgrade_to_writer() } -> adaptive_same_as<bool>;
{ lock.downgrade_to_reader() } -> adaptive_same_as<bool>;
};
template <typename Mutex>
concept scoped_lockable = mutex_scoped_lock<typename Mutex::scoped_lock, Mutex>;
template <typename Mutex>
concept rw_scoped_lockable = scoped_lockable<Mutex> &&
rw_mutex_scoped_lock<typename Mutex::scoped_lock, Mutex>;
} // namespace d0
} // namespace detail
} // namespace tbb
#endif // __TBB_CPP20_CONCEPTS_PRESENT
#endif // __TBB_detail__mutex_common_H
@@ -129,9 +129,7 @@ class flow_control {
bool is_pipeline_stopped = false;
flow_control() = default;
template<typename Body, typename InputType, typename OutputType > friend class concrete_filter;
template<typename Output>
__TBB_requires(std::copyable<Output>)
friend class input_node;
template<typename Output> friend class input_node;
public:
void stop() { is_pipeline_stopped = true; }
};
-57
View File
@@ -19,10 +19,6 @@
#include "_config.h"
#include "_utils.h"
#if __TBB_CPP20_CONCEPTS_PRESENT
#include <concepts>
#include <iterator>
#endif
namespace tbb {
namespace detail {
@@ -73,59 +69,6 @@ auto get_range_split_object( PartitionerSplitType& split_obj )
return range_split_object_provider<Range>::get(split_obj);
}
#if __TBB_CPP20_CONCEPTS_PRESENT
template <typename Range>
using range_iterator_type = decltype(std::begin(std::declval<Range&>()));
template <typename Iterator>
using iterator_reference_type = typename std::iterator_traits<Iterator>::reference;
template <typename Range>
using range_reference_type = iterator_reference_type<range_iterator_type<Range>>;
// template <typename Value>
// concept blocked_range_value = std::copyable<Value> &&
// requires( const std::remove_reference_t<Value>& lhs, const std::remove_reference_t<Value>& rhs ) {
// // { lhs < rhs } -> relaxed_convertible_to<bool>;
// // { lhs - rhs } -> std::convertible_to<std::size_t>;
// // { lhs + (rhs - lhs) } -> std::convertible_to<Value>;
// };
template <typename Value>
concept blocked_range_value = true;
template <typename T>
concept splittable = std::constructible_from<T, T&, tbb::detail::split>;
template <typename Range>
concept range = std::copy_constructible<Range> &&
splittable<Range> &&
requires( const std::remove_reference_t<Range>& range ) {
{ range.empty() } -> relaxed_convertible_to<bool>;
{ range.is_divisible() } -> relaxed_convertible_to<bool>;
};
template <typename Iterator>
constexpr bool iterator_concept_helper( std::input_iterator_tag ) {
return std::input_iterator<Iterator>;
}
template <typename Iterator>
constexpr bool iterator_concept_helper( std::random_access_iterator_tag ) {
return std::random_access_iterator<Iterator>;
}
template <typename Iterator, typename IteratorTag>
concept iterator_satisfies = requires (IteratorTag tag) {
requires iterator_concept_helper<Iterator>(tag);
};
template <typename Sequence, typename IteratorTag>
concept container_based_sequence = requires( Sequence& seq ) {
{ std::begin(seq) } -> iterator_satisfies<IteratorTag>;
{ std::end(seq) } -> iterator_satisfies<IteratorTag>;
};
#endif // __TBB_CPP20_CONCEPTS_PRESENT
} // namespace d0
} // namespace detail
} // namespace tbb
@@ -66,7 +66,7 @@ public:
template <typename Type>
void delete_object(Type* object, const execution_data& ed) {
// Copy this since it can be a member of the passed object and
// Copy this since the it can be the member of the passed object and
// unintentionally destroyed when Type destructor is called below
small_object_allocator alloc = *this;
object->~Type();
@@ -75,7 +75,7 @@ public:
template <typename Type>
void delete_object(Type* object) {
// Copy this since it can be a member of the passed object and
// Copy this since the it can be the member of the passed object and
// unintentionally destroyed when Type destructor is called below
small_object_allocator alloc = *this;
object->~Type();
+4
View File
@@ -30,6 +30,7 @@
#include <utility>
#include <atomic>
#include <mutex>
#include <functional>
namespace tbb {
namespace detail {
@@ -230,6 +231,9 @@ private:
};
static_assert(sizeof(task) == task_alignment, "task size is broken");
using task_handle = std::unique_ptr<task, std::function<void(task*)>>;
} // namespace d1
} // namespace detail
} // namespace tbb
-124
View File
@@ -1,124 +0,0 @@
/*
Copyright (c) 2020-2021 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef __TBB_task_handle_H
#define __TBB_task_handle_H
#include "_config.h"
#include "_task.h"
#include "_small_object_pool.h"
#include "_utils.h"
#include <memory>
namespace tbb {
namespace detail {
namespace d1 { class task_group_context; class wait_context; struct execution_data; }
namespace d2 {
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
class task_handle;
class task_handle_task : public d1::task {
std::uint64_t m_version_and_traits{};
d1::wait_context& m_wait_ctx;
d1::task_group_context& m_ctx;
d1::small_object_allocator m_allocator;
public:
void finalize(const d1::execution_data* ed = nullptr) {
if (ed) {
m_allocator.delete_object(this, *ed);
} else {
m_allocator.delete_object(this);
}
}
task_handle_task(d1::wait_context& wo, d1::task_group_context& ctx, d1::small_object_allocator& alloc)
: m_wait_ctx(wo)
, m_ctx(ctx)
, m_allocator(alloc) {
suppress_unused_warning(m_version_and_traits);
}
~task_handle_task(){
m_wait_ctx.release();
}
d1::task_group_context& ctx() const { return m_ctx; }
};
class task_handle {
struct task_handle_task_finalizer_t{
void operator()(task_handle_task* p){ p->finalize(); }
};
using handle_impl_t = std::unique_ptr<task_handle_task, task_handle_task_finalizer_t>;
handle_impl_t m_handle = {nullptr};
public:
task_handle() = default;
task_handle(task_handle&&) = default;
task_handle& operator=(task_handle&&) = default;
explicit operator bool() const noexcept { return static_cast<bool>(m_handle); }
friend bool operator==(task_handle const& th, std::nullptr_t) noexcept;
friend bool operator==(std::nullptr_t, task_handle const& th) noexcept;
friend bool operator!=(task_handle const& th, std::nullptr_t) noexcept;
friend bool operator!=(std::nullptr_t, task_handle const& th) noexcept;
private:
friend struct task_handle_accessor;
task_handle(task_handle_task* t) : m_handle {t}{};
d1::task* release() {
return m_handle.release();
}
};
struct task_handle_accessor {
static task_handle construct(task_handle_task* t) { return {t}; }
static d1::task* release(task_handle& th) { return th.release(); }
static d1::task_group_context& ctx_of(task_handle& th) {
__TBB_ASSERT(th.m_handle, "ctx_of does not expect empty task_handle.");
return th.m_handle->ctx();
}
};
inline bool operator==(task_handle const& th, std::nullptr_t) noexcept {
return th.m_handle == nullptr;
}
inline bool operator==(std::nullptr_t, task_handle const& th) noexcept {
return th.m_handle == nullptr;
}
inline bool operator!=(task_handle const& th, std::nullptr_t) noexcept {
return th.m_handle != nullptr;
}
inline bool operator!=(std::nullptr_t, task_handle const& th) noexcept {
return th.m_handle != nullptr;
}
#endif // __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
} // namespace d2
} // namespace detail
} // namespace tbb
#endif /* __TBB_task_handle_H */
+2 -12
View File
@@ -22,7 +22,7 @@
#include <cstddef>
#include <cstdint>
#include <utility>
#include <type_traits>
#include <memory>
#include <iterator>
@@ -182,17 +182,7 @@ using pack_element_t = typename pack_element<N, Args...>::type;
template <typename Func>
class raii_guard {
public:
static_assert(
std::is_nothrow_copy_constructible<Func>::value &&
std::is_nothrow_move_constructible<Func>::value,
"Throwing an exception during the Func copy or move construction cause an unexpected behavior."
);
raii_guard( Func f ) noexcept : my_func(f), is_active(true) {}
raii_guard( raii_guard&& g ) noexcept : my_func(std::move(g.my_func)), is_active(g.is_active) {
g.is_active = false;
}
raii_guard( Func f ) : my_func(f), is_active(true) {}
~raii_guard() {
if (is_active) {
+6 -39
View File
@@ -20,7 +20,6 @@
#include <type_traits>
#include <cstdint>
#include <atomic>
#include <functional>
#include "_config.h"
#include "_assert.h"
@@ -38,8 +37,6 @@ template<typename... T> void suppress_unused_warning(T&&...) {}
bound is more useful than a run-time exact answer.
@ingroup memory_allocation */
constexpr size_t max_nfs_size = 128;
constexpr std::size_t max_nfs_size_exp = 7;
static_assert(1 << max_nfs_size_exp == max_nfs_size, "max_nfs_size_exp must be a log2(max_nfs_size)");
//! Class that implements exponential backoff.
class atomic_backoff {
@@ -93,28 +90,25 @@ public:
//! Spin WHILE the condition is true.
/** T and U should be comparable types. */
template <typename T, typename C>
T spin_wait_while(const std::atomic<T>& location, C comp, std::memory_order order) {
void spin_wait_while(const std::atomic<T>& location, C comp) {
atomic_backoff backoff;
T snapshot = location.load(order);
while (comp(snapshot)) {
while (comp(location.load(std::memory_order_acquire))) {
backoff.pause();
snapshot = location.load(order);
}
return snapshot;
}
//! Spin WHILE the value of the variable is equal to a given value
/** T and U should be comparable types. */
template <typename T, typename U>
T spin_wait_while_eq(const std::atomic<T>& location, const U value, std::memory_order order = std::memory_order_acquire) {
return spin_wait_while(location, [&value](T t) { return t == value; }, order);
void spin_wait_while_eq(const std::atomic<T>& location, const U value) {
spin_wait_while(location, [&value](T t) { return t == value; });
}
//! Spin UNTIL the value of the variable is equal to a given value
/** T and U should be comparable types. */
template<typename T, typename U>
T spin_wait_until_eq(const std::atomic<T>& location, const U value, std::memory_order order = std::memory_order_acquire) {
return spin_wait_while(location, [&value](T t) { return t != value; }, order);
void spin_wait_until_eq(const std::atomic<T>& location, const U value) {
spin_wait_while(location, [&value](T t) { return t != value; });
}
//! Spin UNTIL the condition returns true or spinning time is up.
@@ -330,35 +324,8 @@ using synthesized_three_way_result = decltype(synthesized_three_way_comparator{}
std::declval<T2&>()));
#endif // __TBB_CPP20_COMPARISONS_PRESENT
// Check if the type T is implicitly OR explicitly convertible to U
template <typename T, typename U>
concept relaxed_convertible_to = std::constructible_from<U, T>;
template <typename T, typename U>
concept adaptive_same_as =
#if __TBB_STRICT_CONSTRAINTS
std::same_as<T, U>;
#else
std::convertible_to<T, U>;
#endif
#endif // __TBB_CPP20_CONCEPTS_PRESENT
template <typename F, typename... Args>
auto invoke(F&& f, Args&&... args)
#if __TBB_CPP17_INVOKE_PRESENT
-> std::invoke_result_t<F, Args...>
#else
-> decltype(std::forward<F>(f)(std::forward<Args>(args)...))
#endif
{
#if __TBB_CPP17_INVOKE_PRESENT
return std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
#else
return std::forward<F>(f)(std::forward<Args>(args)...);
#endif
}
} // namespace d0
namespace d1 {
+5 -129
View File
@@ -35,7 +35,6 @@
#include "detail/_template_helpers.h"
#include "detail/_aggregator.h"
#include "detail/_allocator_traits.h"
#include "detail/_utils.h"
#include "profiling.h"
#include "task_arena.h"
@@ -53,9 +52,6 @@
#include <tuple>
#include <list>
#include <queue>
#if __TBB_CPP20_CONCEPTS_PRESENT
#include <concepts>
#endif
/** @file
\brief The graph related classes and functions
@@ -81,63 +77,6 @@ struct null_type {};
//! An empty class used for messages that mean "I'm done"
class continue_msg {};
} // namespace d1
#if __TBB_CPP20_CONCEPTS_PRESENT
namespace d0 {
template <typename ReturnType, typename OutputType>
concept node_body_return_type = std::same_as<OutputType, tbb::detail::d1::continue_msg> ||
std::same_as<OutputType, ReturnType>;
template <typename Body, typename Output>
concept continue_node_body = std::copy_constructible<Body> &&
requires( Body& body, const tbb::detail::d1::continue_msg& v ) {
{ body(v) } -> node_body_return_type<Output>;
};
template <typename Body, typename Input, typename Output>
concept function_node_body = std::copy_constructible<Body> &&
std::invocable<Body&, const Input&>;
// requires( Body& body, const Input& v ) {
// { body(v) } -> node_body_return_type<Output>;
// };
template <typename FunctionObject, typename Input, typename Key>
concept join_node_function_object = std::copy_constructible<FunctionObject> &&
requires( FunctionObject& func, const Input& v ) {
{ func(v) } -> adaptive_same_as<Key>;
};
template <typename Body, typename Output>
concept input_node_body = std::copy_constructible<Body> &&
requires( Body& body, tbb::detail::d1::flow_control& fc ) {
{ body(fc) } -> adaptive_same_as<Output>;
};
template <typename Body, typename Input, typename OutputPortsType>
concept multifunction_node_body = std::copy_constructible<Body> &&
requires( Body& body, const Input& v, OutputPortsType& p ) {
body(v, p);
};
template <typename Sequencer, typename Value>
concept sequencer = std::copy_constructible<Sequencer> &&
requires( Sequencer& seq, const Value& value ) {
{ seq(value) } -> adaptive_same_as<std::size_t>;
};
template <typename Body, typename Input, typename GatewayType>
concept async_node_body = std::copy_constructible<Body> &&
requires( Body& body, const Input& v, GatewayType& gateway ) {
body(v, gateway);
};
} // namespace d0
#endif // __TBB_CPP20_CONCEPTS_PRESENT
namespace d1 {
//! Forward declaration section
template< typename T > class sender;
template< typename T > class receiver;
@@ -541,7 +480,6 @@ inline graph_node::~graph_node() {
//! An executable node that acts as a source, i.e. it has no predecessors
template < typename Output >
__TBB_requires(std::copyable<Output>)
class input_node : public graph_node, public sender< Output > {
public:
//! The type of the output message, which is complete
@@ -555,7 +493,6 @@ public:
//! Constructor for a node with a successor
template< typename Body >
__TBB_requires(input_node_body<Body, Output>)
__TBB_NOINLINE_SYM input_node( graph &g, Body body )
: graph_node(g), my_active(false)
, my_body( new input_body_leaf< output_type, Body>(body) )
@@ -568,7 +505,6 @@ public:
#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
template <typename Body, typename... Successors>
__TBB_requires(input_node_body<Body, Output>)
input_node( const node_set<order::preceding, Successors...>& successors, Body body )
: input_node(successors.graph_reference(), body)
{
@@ -761,9 +697,6 @@ private:
//! Implements a function node that supports Input -> Output
template<typename Input, typename Output = continue_msg, typename Policy = queueing>
__TBB_requires(std::default_initializable<Input> &&
std::copy_constructible<Input> &&
std::copy_constructible<Output>)
class function_node
: public graph_node
, public function_input< Input, Output, Policy, cache_aligned_allocator<Input> >
@@ -787,7 +720,6 @@ public:
// TODO: pass the graph_buffer_policy to the function_input_base so it can all
// be done in one place. This would be an interface-breaking change.
template< typename Body >
__TBB_requires(function_node_body<Body, Input, Output>)
__TBB_NOINLINE_SYM function_node( graph &g, size_t concurrency,
Body body, Policy = Policy(), node_priority_t a_priority = no_priority )
: graph_node(g), input_impl_type(g, concurrency, body, a_priority),
@@ -797,13 +729,11 @@ public:
}
template <typename Body>
__TBB_requires(function_node_body<Body, Input, Output>)
function_node( graph& g, size_t concurrency, Body body, node_priority_t a_priority )
: function_node(g, concurrency, body, Policy(), a_priority) {}
#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
template <typename Body, typename... Args>
__TBB_requires(function_node_body<Body, Input, Output>)
function_node( const node_set<Args...>& nodes, size_t concurrency, Body body,
Policy p = Policy(), node_priority_t a_priority = no_priority )
: function_node(nodes.graph_reference(), concurrency, body, p, a_priority) {
@@ -811,7 +741,6 @@ public:
}
template <typename Body, typename... Args>
__TBB_requires(function_node_body<Body, Input, Output>)
function_node( const node_set<Args...>& nodes, size_t concurrency, Body body, node_priority_t a_priority )
: function_node(nodes, concurrency, body, Policy(), a_priority) {}
#endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
@@ -849,8 +778,6 @@ protected:
//! implements a function node that supports Input -> (set of outputs)
// Output is a tuple of output types.
template<typename Input, typename Output, typename Policy = queueing>
__TBB_requires(std::default_initializable<Input> &&
std::copy_constructible<Input>)
class multifunction_node :
public graph_node,
public multifunction_input
@@ -880,7 +807,6 @@ private:
using input_impl_type::my_predecessors;
public:
template<typename Body>
__TBB_requires(multifunction_node_body<Body, Input, output_ports_type>)
__TBB_NOINLINE_SYM multifunction_node(
graph &g, size_t concurrency,
Body body, Policy = Policy(), node_priority_t a_priority = no_priority
@@ -893,13 +819,11 @@ public:
}
template <typename Body>
__TBB_requires(multifunction_node_body<Body, Input, output_ports_type>)
__TBB_NOINLINE_SYM multifunction_node(graph& g, size_t concurrency, Body body, node_priority_t a_priority)
: multifunction_node(g, concurrency, body, Policy(), a_priority) {}
#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
template <typename Body, typename... Args>
__TBB_requires(multifunction_node_body<Body, Input, output_ports_type>)
__TBB_NOINLINE_SYM multifunction_node(const node_set<Args...>& nodes, size_t concurrency, Body body,
Policy p = Policy(), node_priority_t a_priority = no_priority)
: multifunction_node(nodes.graph_reference(), concurrency, body, p, a_priority) {
@@ -907,7 +831,6 @@ public:
}
template <typename Body, typename... Args>
__TBB_requires(multifunction_node_body<Body, Input, output_ports_type>)
__TBB_NOINLINE_SYM multifunction_node(const node_set<Args...>& nodes, size_t concurrency, Body body, node_priority_t a_priority)
: multifunction_node(nodes, concurrency, body, Policy(), a_priority) {}
#endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
@@ -985,7 +908,6 @@ private:
//! Implements an executable node that supports continue_msg -> Output
template <typename Output, typename Policy = Policy<void> >
__TBB_requires(std::copy_constructible<Output>)
class continue_node : public graph_node, public continue_input<Output, Policy>,
public function_output<Output> {
public:
@@ -998,7 +920,6 @@ public:
//! Constructor for executable node with continue_msg -> Output
template <typename Body >
__TBB_requires(continue_node_body<Body, Output>)
__TBB_NOINLINE_SYM continue_node(
graph &g,
Body body, Policy = Policy(), node_priority_t a_priority = no_priority
@@ -1011,27 +932,23 @@ public:
}
template <typename Body>
__TBB_requires(continue_node_body<Body, Output>)
continue_node( graph& g, Body body, node_priority_t a_priority )
: continue_node(g, body, Policy(), a_priority) {}
#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
template <typename Body, typename... Args>
__TBB_requires(continue_node_body<Body, Output>)
continue_node( const node_set<Args...>& nodes, Body body,
Policy p = Policy(), node_priority_t a_priority = no_priority )
: continue_node(nodes.graph_reference(), body, p, a_priority ) {
make_edges_in_order(nodes, *this);
}
template <typename Body, typename... Args>
__TBB_requires(continue_node_body<Body, Output>)
continue_node( const node_set<Args...>& nodes, Body body, node_priority_t a_priority)
: continue_node(nodes, body, Policy(), a_priority) {}
#endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
//! Constructor for executable node with continue_msg -> Output
template <typename Body >
__TBB_requires(continue_node_body<Body, Output>)
__TBB_NOINLINE_SYM continue_node(
graph &g, int number_of_predecessors,
Body body, Policy = Policy(), node_priority_t a_priority = no_priority
@@ -1044,13 +961,11 @@ public:
}
template <typename Body>
__TBB_requires(continue_node_body<Body, Output>)
continue_node( graph& g, int number_of_predecessors, Body body, node_priority_t a_priority)
: continue_node(g, number_of_predecessors, body, Policy(), a_priority) {}
#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
template <typename Body, typename... Args>
__TBB_requires(continue_node_body<Body, Output>)
continue_node( const node_set<Args...>& nodes, int number_of_predecessors,
Body body, Policy p = Policy(), node_priority_t a_priority = no_priority )
: continue_node(nodes.graph_reference(), number_of_predecessors, body, p, a_priority) {
@@ -1058,7 +973,6 @@ public:
}
template <typename Body, typename... Args>
__TBB_requires(continue_node_body<Body, Output>)
continue_node( const node_set<Args...>& nodes, int number_of_predecessors,
Body body, node_priority_t a_priority )
: continue_node(nodes, number_of_predecessors, body, Policy(), a_priority) {}
@@ -1585,7 +1499,6 @@ protected:
//! Forwards messages in sequence order
template <typename T>
__TBB_requires(std::copyable<T>)
class sequencer_node : public queue_node<T> {
function_body< T, size_t > *my_sequencer;
// my_sequencer should be a benign function and must be callable
@@ -1598,7 +1511,6 @@ public:
//! Constructor
template< typename Sequencer >
__TBB_requires(sequencer<Sequencer, T>)
__TBB_NOINLINE_SYM sequencer_node( graph &g, const Sequencer& s ) : queue_node<T>(g),
my_sequencer(new function_body_leaf< T, size_t, Sequencer>(s) ) {
fgt_node( CODEPTR(), FLOW_SEQUENCER_NODE, &(this->my_graph),
@@ -1608,7 +1520,6 @@ public:
#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
template <typename Sequencer, typename... Args>
__TBB_requires(sequencer<Sequencer, T>)
sequencer_node( const node_set<Args...>& nodes, const Sequencer& s)
: sequencer_node(nodes.graph_reference(), s) {
make_edges_in_order(nodes, *this);
@@ -1897,16 +1808,12 @@ private:
graph_task* decrement_counter( long long delta ) {
{
spin_mutex::scoped_lock lock(my_mutex);
if( delta > 0 && size_t(delta) > my_count ) {
if( delta > 0 && size_t(delta) > my_count )
my_count = 0;
}
else if( delta < 0 && size_t(-delta) > my_threshold - my_count ) {
else if( delta < 0 && size_t(delta) > my_threshold - my_count )
my_count = my_threshold;
}
else {
else
my_count -= size_t(delta); // absolute value of delta is sufficiently small
}
__TBB_ASSERT(my_count <= my_threshold, "counter values are truncated to be inside the [0, threshold] interval");
}
return forward_task();
}
@@ -2165,22 +2072,6 @@ public:
};
#if __TBB_CPP20_CONCEPTS_PRESENT
// Helper function which is well-formed only if all of the elements in OutputTuple
// satisfies join_node_function_object<body[i], tuple[i], K>
template <typename OutputTuple, typename K,
typename... Functions, std::size_t... Idx>
void join_node_function_objects_helper( std::index_sequence<Idx...> )
requires (std::tuple_size_v<OutputTuple> == sizeof...(Functions)) &&
(... && join_node_function_object<Functions, std::tuple_element_t<Idx, OutputTuple>, K>);
template <typename OutputTuple, typename K, typename... Functions>
concept join_node_functions = requires {
join_node_function_objects_helper<OutputTuple, K, Functions...>(std::make_index_sequence<sizeof...(Functions)>{});
};
#endif
// template for key_matching join_node
// tag_matching join_node is a specialization of key_matching, and is source-compatible.
template<typename OutputTuple, typename K, typename KHash>
@@ -2198,25 +2089,21 @@ public:
#endif /* __TBB_PREVIEW_MESSAGE_BASED_KEY_MATCHING */
template<typename __TBB_B0, typename __TBB_B1>
__TBB_requires(join_node_functions<OutputTuple, K, __TBB_B0, __TBB_B1>)
__TBB_NOINLINE_SYM join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1) : unfolded_type(g, b0, b1) {
fgt_multiinput_node<N>( CODEPTR(), FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
this->input_ports(), static_cast< sender< output_type > *>(this) );
}
template<typename __TBB_B0, typename __TBB_B1, typename __TBB_B2>
__TBB_requires(join_node_functions<OutputTuple, K, __TBB_B0, __TBB_B1, __TBB_B2>)
__TBB_NOINLINE_SYM join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2) : unfolded_type(g, b0, b1, b2) {
fgt_multiinput_node<N>( CODEPTR(), FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
this->input_ports(), static_cast< sender< output_type > *>(this) );
}
template<typename __TBB_B0, typename __TBB_B1, typename __TBB_B2, typename __TBB_B3>
__TBB_requires(join_node_functions<OutputTuple, K, __TBB_B0, __TBB_B1, __TBB_B2, __TBB_B3>)
__TBB_NOINLINE_SYM join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3) : unfolded_type(g, b0, b1, b2, b3) {
fgt_multiinput_node<N>( CODEPTR(), FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
this->input_ports(), static_cast< sender< output_type > *>(this) );
}
template<typename __TBB_B0, typename __TBB_B1, typename __TBB_B2, typename __TBB_B3, typename __TBB_B4>
__TBB_requires(join_node_functions<OutputTuple, K, __TBB_B0, __TBB_B1, __TBB_B2, __TBB_B3, __TBB_B4>)
__TBB_NOINLINE_SYM join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3, __TBB_B4 b4) :
unfolded_type(g, b0, b1, b2, b3, b4) {
fgt_multiinput_node<N>( CODEPTR(), FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
@@ -2225,7 +2112,6 @@ public:
#if __TBB_VARIADIC_MAX >= 6
template<typename __TBB_B0, typename __TBB_B1, typename __TBB_B2, typename __TBB_B3, typename __TBB_B4,
typename __TBB_B5>
__TBB_requires(join_node_functions<OutputTuple, K, __TBB_B0, __TBB_B1, __TBB_B2, __TBB_B3, __TBB_B4, __TBB_B5>)
__TBB_NOINLINE_SYM join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3, __TBB_B4 b4, __TBB_B5 b5) :
unfolded_type(g, b0, b1, b2, b3, b4, b5) {
fgt_multiinput_node<N>( CODEPTR(), FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
@@ -2235,7 +2121,6 @@ public:
#if __TBB_VARIADIC_MAX >= 7
template<typename __TBB_B0, typename __TBB_B1, typename __TBB_B2, typename __TBB_B3, typename __TBB_B4,
typename __TBB_B5, typename __TBB_B6>
__TBB_requires(join_node_functions<OutputTuple, K, __TBB_B0, __TBB_B1, __TBB_B2, __TBB_B3, __TBB_B4, __TBB_B5, __TBB_B6>)
__TBB_NOINLINE_SYM join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3, __TBB_B4 b4, __TBB_B5 b5, __TBB_B6 b6) :
unfolded_type(g, b0, b1, b2, b3, b4, b5, b6) {
fgt_multiinput_node<N>( CODEPTR(), FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
@@ -2245,7 +2130,6 @@ public:
#if __TBB_VARIADIC_MAX >= 8
template<typename __TBB_B0, typename __TBB_B1, typename __TBB_B2, typename __TBB_B3, typename __TBB_B4,
typename __TBB_B5, typename __TBB_B6, typename __TBB_B7>
__TBB_requires(join_node_functions<OutputTuple, K, __TBB_B0, __TBB_B1, __TBB_B2, __TBB_B3, __TBB_B4, __TBB_B5, __TBB_B6, __TBB_B7>)
__TBB_NOINLINE_SYM join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3, __TBB_B4 b4, __TBB_B5 b5, __TBB_B6 b6,
__TBB_B7 b7) : unfolded_type(g, b0, b1, b2, b3, b4, b5, b6, b7) {
fgt_multiinput_node<N>( CODEPTR(), FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
@@ -2255,7 +2139,6 @@ public:
#if __TBB_VARIADIC_MAX >= 9
template<typename __TBB_B0, typename __TBB_B1, typename __TBB_B2, typename __TBB_B3, typename __TBB_B4,
typename __TBB_B5, typename __TBB_B6, typename __TBB_B7, typename __TBB_B8>
__TBB_requires(join_node_functions<OutputTuple, K, __TBB_B0, __TBB_B1, __TBB_B2, __TBB_B3, __TBB_B4, __TBB_B5, __TBB_B6, __TBB_B7, __TBB_B8>)
__TBB_NOINLINE_SYM join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3, __TBB_B4 b4, __TBB_B5 b5, __TBB_B6 b6,
__TBB_B7 b7, __TBB_B8 b8) : unfolded_type(g, b0, b1, b2, b3, b4, b5, b6, b7, b8) {
fgt_multiinput_node<N>( CODEPTR(), FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
@@ -2265,7 +2148,6 @@ public:
#if __TBB_VARIADIC_MAX >= 10
template<typename __TBB_B0, typename __TBB_B1, typename __TBB_B2, typename __TBB_B3, typename __TBB_B4,
typename __TBB_B5, typename __TBB_B6, typename __TBB_B7, typename __TBB_B8, typename __TBB_B9>
__TBB_requires(join_node_functions<OutputTuple, K, __TBB_B0, __TBB_B1, __TBB_B2, __TBB_B3, __TBB_B4, __TBB_B5, __TBB_B6, __TBB_B7, __TBB_B8, __TBB_B9>)
__TBB_NOINLINE_SYM join_node(graph &g, __TBB_B0 b0, __TBB_B1 b1, __TBB_B2 b2, __TBB_B3 b3, __TBB_B4 b4, __TBB_B5 b5, __TBB_B6 b6,
__TBB_B7 b7, __TBB_B8 b8, __TBB_B9 b9) : unfolded_type(g, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9) {
fgt_multiinput_node<N>( CODEPTR(), FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
@@ -2281,12 +2163,11 @@ public:
#endif
typename... Args, typename... Bodies
>
__TBB_requires((sizeof...(Bodies) == 0) || join_node_functions<OutputTuple, K, Bodies...>)
__TBB_NOINLINE_SYM join_node(const node_set<Args...>& nodes, Bodies... bodies)
: join_node(nodes.graph_reference(), bodies...) {
make_edges_in_order(nodes, *this);
}
#endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
#endif
__TBB_NOINLINE_SYM join_node(const join_node &other) : unfolded_type(other) {
fgt_multiinput_node<N>( CODEPTR(), FLOW_JOIN_NODE_TAG_MATCHING, &this->my_graph,
@@ -2841,7 +2722,6 @@ private:
//! Implements async node
template < typename Input, typename Output,
typename Policy = queueing_lightweight >
__TBB_requires(std::default_initializable<Input> && std::copy_constructible<Input>)
class async_node
: public multifunction_node< Input, std::tuple< Output >, Policy >, public sender< Output >
{
@@ -2907,7 +2787,6 @@ private:
public:
template<typename Body>
__TBB_requires(async_node_body<Body, input_type, gateway_type>)
__TBB_NOINLINE_SYM async_node(
graph &g, size_t concurrency,
Body body, Policy = Policy(), node_priority_t a_priority = no_priority
@@ -2922,14 +2801,12 @@ public:
);
}
template <typename Body>
__TBB_requires(async_node_body<Body, input_type, gateway_type>)
template <typename Body, typename... Args>
__TBB_NOINLINE_SYM async_node(graph& g, size_t concurrency, Body body, node_priority_t a_priority)
: async_node(g, concurrency, body, Policy(), a_priority) {}
#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
template <typename Body, typename... Args>
__TBB_requires(async_node_body<Body, input_type, gateway_type>)
__TBB_NOINLINE_SYM async_node(
const node_set<Args...>& nodes, size_t concurrency, Body body,
Policy = Policy(), node_priority_t a_priority = no_priority )
@@ -2938,7 +2815,6 @@ public:
}
template <typename Body, typename... Args>
__TBB_requires(async_node_body<Body, input_type, gateway_type>)
__TBB_NOINLINE_SYM async_node(const node_set<Args...>& nodes, size_t concurrency, Body body, node_priority_t a_priority)
: async_node(nodes, concurrency, body, Policy(), a_priority) {}
#endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
-4
View File
@@ -137,10 +137,6 @@ public:
return *this;
};
explicit operator bool() const noexcept {
return m_ctl != nullptr;
}
//! Get and active instance of task_scheduler_handle
static task_scheduler_handle get() {
task_scheduler_handle handle;
+1 -2
View File
@@ -23,7 +23,6 @@
#include "detail/_utils.h"
#include "detail/_scoped_lock.h"
#include "detail/_waitable_atomic.h"
#include "detail/_mutex_common.h"
#include "profiling.h"
namespace tbb {
@@ -65,7 +64,7 @@ public:
//! Try acquiring lock (non-blocking)
/** Return true if lock acquired; false otherwise. */
bool try_lock() {
bool result = !my_flag.load(std::memory_order_relaxed) && !my_flag.exchange(true);
bool result = !my_flag.exchange(true);
if (result) {
call_itt_notify(acquired, this);
}
-1
View File
@@ -19,7 +19,6 @@
#include "detail/_config.h"
#include "detail/_namespace_injection.h"
#include "detail/_mutex_common.h"
namespace tbb {
namespace detail {
-1
View File
@@ -19,7 +19,6 @@
#include "detail/_config.h"
#include "detail/_namespace_injection.h"
#include "detail/_mutex_common.h"
namespace tbb {
namespace detail {
+9 -63
View File
@@ -22,7 +22,6 @@
#include "detail/_exception.h"
#include "detail/_task.h"
#include "detail/_small_object_pool.h"
#include "detail/_utils.h"
#include "profiling.h"
#include "partitioner.h"
@@ -34,27 +33,6 @@
namespace tbb {
namespace detail {
#if __TBB_CPP20_CONCEPTS_PRESENT
inline namespace d0 {
template <typename Body, typename Range>
concept parallel_for_body = std::copy_constructible<Body> &&
std::invocable<const std::remove_reference_t<Body>&, Range&>;
template <typename Index>
concept parallel_for_index = std::constructible_from<Index, int> &&
std::copyable<Index> &&
requires( const std::remove_reference_t<Index>& lhs, const std::remove_reference_t<Index>& rhs ) {
{ lhs < rhs } -> adaptive_same_as<bool>;
{ lhs - rhs } -> std::convertible_to<Index>;
{ lhs + rhs } -> std::convertible_to<Index>;
};
template <typename Function, typename Index>
concept parallel_for_function = std::invocable<const std::remove_reference_t<Function>&, Index>;
} // namespace d0
#endif // __TBB_CPP20_CONCEPTS_PRESENT
namespace d1 {
//! Task type used in parallel_for
@@ -113,7 +91,7 @@ struct start_for : public task {
}
//! Run body for range, serves as callback for partitioner
void run_body( Range &r ) {
tbb::detail::invoke(my_body, r);
my_body( r );
}
//! spawn right task, serves as callback for partitioner
@@ -180,12 +158,12 @@ task* start_for<Range, Body, Partitioner>::cancel(execution_data& ed) {
//! Calls the function with values from range [begin, end) with a step provided
template<typename Function, typename Index>
class parallel_for_body_wrapper : detail::no_assign {
class parallel_for_body : detail::no_assign {
const Function &my_func;
const Index my_begin;
const Index my_step;
public:
parallel_for_body_wrapper( const Function& _func, Index& _begin, Index& _step )
parallel_for_body( const Function& _func, Index& _begin, Index& _step )
: my_func(_func), my_begin(_begin), my_step(_step) {}
void operator()( const blocked_range<Index>& r ) const {
@@ -202,7 +180,7 @@ public:
#endif
#endif
for ( Index i = b; i < e; ++i, k += ms ) {
tbb::detail::invoke(my_func, k);
my_func( k );
}
}
};
@@ -223,7 +201,6 @@ public:
//! Parallel iteration over range with default partitioner.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_for_body<Body, Range>)
void parallel_for( const Range& range, const Body& body ) {
start_for<Range,Body,const __TBB_DEFAULT_PARTITIONER>::run(range,body,__TBB_DEFAULT_PARTITIONER());
}
@@ -231,7 +208,6 @@ void parallel_for( const Range& range, const Body& body ) {
//! Parallel iteration over range with simple partitioner.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_for_body<Body, Range>)
void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner ) {
start_for<Range,Body,const simple_partitioner>::run(range,body,partitioner);
}
@@ -239,7 +215,6 @@ void parallel_for( const Range& range, const Body& body, const simple_partitione
//! Parallel iteration over range with auto_partitioner.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_for_body<Body, Range>)
void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner ) {
start_for<Range,Body,const auto_partitioner>::run(range,body,partitioner);
}
@@ -247,7 +222,6 @@ void parallel_for( const Range& range, const Body& body, const auto_partitioner&
//! Parallel iteration over range with static_partitioner.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_for_body<Body, Range>)
void parallel_for( const Range& range, const Body& body, const static_partitioner& partitioner ) {
start_for<Range,Body,const static_partitioner>::run(range,body,partitioner);
}
@@ -255,7 +229,6 @@ void parallel_for( const Range& range, const Body& body, const static_partitione
//! Parallel iteration over range with affinity_partitioner.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_for_body<Body, Range>)
void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner ) {
start_for<Range,Body,affinity_partitioner>::run(range,body,partitioner);
}
@@ -263,7 +236,6 @@ void parallel_for( const Range& range, const Body& body, affinity_partitioner& p
//! Parallel iteration over range with default partitioner and user-supplied context.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_for_body<Body, Range>)
void parallel_for( const Range& range, const Body& body, task_group_context& context ) {
start_for<Range,Body,const __TBB_DEFAULT_PARTITIONER>::run(range, body, __TBB_DEFAULT_PARTITIONER(), context);
}
@@ -271,7 +243,6 @@ void parallel_for( const Range& range, const Body& body, task_group_context& con
//! Parallel iteration over range with simple partitioner and user-supplied context.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_for_body<Body, Range>)
void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner, task_group_context& context ) {
start_for<Range,Body,const simple_partitioner>::run(range, body, partitioner, context);
}
@@ -279,7 +250,6 @@ void parallel_for( const Range& range, const Body& body, const simple_partitione
//! Parallel iteration over range with auto_partitioner and user-supplied context.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_for_body<Body, Range>)
void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner, task_group_context& context ) {
start_for<Range,Body,const auto_partitioner>::run(range, body, partitioner, context);
}
@@ -287,7 +257,6 @@ void parallel_for( const Range& range, const Body& body, const auto_partitioner&
//! Parallel iteration over range with static_partitioner and user-supplied context.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_for_body<Body, Range>)
void parallel_for( const Range& range, const Body& body, const static_partitioner& partitioner, task_group_context& context ) {
start_for<Range,Body,const static_partitioner>::run(range, body, partitioner, context);
}
@@ -295,7 +264,6 @@ void parallel_for( const Range& range, const Body& body, const static_partitione
//! Parallel iteration over range with affinity_partitioner and user-supplied context.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_for_body<Body, Range>)
void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner, task_group_context& context ) {
start_for<Range,Body,affinity_partitioner>::run(range,body,partitioner, context);
}
@@ -305,75 +273,63 @@ template <typename Index, typename Function, typename Partitioner>
void parallel_for_impl(Index first, Index last, Index step, const Function& f, Partitioner& partitioner) {
if (step <= 0 )
throw_exception(exception_id::nonpositive_step); // throws std::invalid_argument
else if (first < last) {
else if (last > first) {
// Above "else" avoids "potential divide by zero" warning on some platforms
// Index end = (last - first - Index(1)) / step + Index(1);
// Index end = (Index(-1) + (last - first)) / step + Index(1);
Index end = Index(1) + (last - first - 1) / step;
Index end = (last - first - Index(1)) / step + Index(1);
blocked_range<Index> range(static_cast<Index>(0), end);
parallel_for_body_wrapper<Function, Index> body(f, first, step);
parallel_for_body<Function, Index> body(f, first, step);
parallel_for(range, body, partitioner);
}
}
//! Parallel iteration over a range of integers with a step provided and default partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, Index step, const Function& f) {
parallel_for_impl<Index,Function,const auto_partitioner>(first, last, step, f, auto_partitioner());
}
//! Parallel iteration over a range of integers with a step provided and simple partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, Index step, const Function& f, const simple_partitioner& partitioner) {
parallel_for_impl<Index,Function,const simple_partitioner>(first, last, step, f, partitioner);
}
//! Parallel iteration over a range of integers with a step provided and auto partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, Index step, const Function& f, const auto_partitioner& partitioner) {
parallel_for_impl<Index,Function,const auto_partitioner>(first, last, step, f, partitioner);
}
//! Parallel iteration over a range of integers with a step provided and static partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, Index step, const Function& f, const static_partitioner& partitioner) {
parallel_for_impl<Index,Function,const static_partitioner>(first, last, step, f, partitioner);
}
//! Parallel iteration over a range of integers with a step provided and affinity partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, Index step, const Function& f, affinity_partitioner& partitioner) {
parallel_for_impl(first, last, step, f, partitioner);
}
//! Parallel iteration over a range of integers with a default step value and default partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, const Function& f) {
parallel_for_impl<Index,Function,const auto_partitioner>(first, last, static_cast<Index>(1), f, auto_partitioner());
}
//! Parallel iteration over a range of integers with a default step value and simple partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, const Function& f, const simple_partitioner& partitioner) {
parallel_for_impl<Index,Function,const simple_partitioner>(first, last, static_cast<Index>(1), f, partitioner);
}
//! Parallel iteration over a range of integers with a default step value and auto partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, const Function& f, const auto_partitioner& partitioner) {
parallel_for_impl<Index,Function,const auto_partitioner>(first, last, static_cast<Index>(1), f, partitioner);
}
//! Parallel iteration over a range of integers with a default step value and static partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, const Function& f, const static_partitioner& partitioner) {
parallel_for_impl<Index,Function,const static_partitioner>(first, last, static_cast<Index>(1), f, partitioner);
}
//! Parallel iteration over a range of integers with a default step value and affinity partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, const Function& f, affinity_partitioner& partitioner) {
parallel_for_impl(first, last, static_cast<Index>(1), f, partitioner);
}
@@ -383,73 +339,63 @@ template <typename Index, typename Function, typename Partitioner>
void parallel_for_impl(Index first, Index last, Index step, const Function& f, Partitioner& partitioner, task_group_context &context) {
if (step <= 0 )
throw_exception(exception_id::nonpositive_step); // throws std::invalid_argument
else if (first < last) {
else if (last > first) {
// Above "else" avoids "potential divide by zero" warning on some platforms
Index end = (last - first - Index(1)) / step + Index(1);
blocked_range<Index> range(static_cast<Index>(0), end);
parallel_for_body_wrapper<Function, Index> body(f, first, step);
parallel_for_body<Function, Index> body(f, first, step);
parallel_for(range, body, partitioner, context);
}
}
//! Parallel iteration over a range of integers with explicit step, task group context, and default partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, Index step, const Function& f, task_group_context &context) {
parallel_for_impl<Index,Function,const auto_partitioner>(first, last, step, f, auto_partitioner(), context);
}
//! Parallel iteration over a range of integers with explicit step, task group context, and simple partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, Index step, const Function& f, const simple_partitioner& partitioner, task_group_context &context) {
parallel_for_impl<Index,Function,const simple_partitioner>(first, last, step, f, partitioner, context);
}
//! Parallel iteration over a range of integers with explicit step, task group context, and auto partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, Index step, const Function& f, const auto_partitioner& partitioner, task_group_context &context) {
parallel_for_impl<Index,Function,const auto_partitioner>(first, last, step, f, partitioner, context);
}
//! Parallel iteration over a range of integers with explicit step, task group context, and static partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, Index step, const Function& f, const static_partitioner& partitioner, task_group_context &context) {
parallel_for_impl<Index,Function,const static_partitioner>(first, last, step, f, partitioner, context);
}
//! Parallel iteration over a range of integers with explicit step, task group context, and affinity partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, Index step, const Function& f, affinity_partitioner& partitioner, task_group_context &context) {
parallel_for_impl(first, last, step, f, partitioner, context);
}
//! Parallel iteration over a range of integers with a default step value, explicit task group context, and default partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, const Function& f, task_group_context &context) {
parallel_for_impl<Index,Function,const auto_partitioner>(first, last, static_cast<Index>(1), f, auto_partitioner(), context);
}
//! Parallel iteration over a range of integers with a default step value, explicit task group context, and simple partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, const Function& f, const simple_partitioner& partitioner, task_group_context &context) {
parallel_for_impl<Index,Function,const simple_partitioner>(first, last, static_cast<Index>(1), f, partitioner, context);
}
//! Parallel iteration over a range of integers with a default step value, explicit task group context, and auto partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, const Function& f, const auto_partitioner& partitioner, task_group_context &context) {
parallel_for_impl<Index,Function,const auto_partitioner>(first, last, static_cast<Index>(1), f, partitioner, context);
}
//! Parallel iteration over a range of integers with a default step value, explicit task group context, and static partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, const Function& f, const static_partitioner& partitioner, task_group_context &context) {
parallel_for_impl<Index,Function,const static_partitioner>(first, last, static_cast<Index>(1), f, partitioner, context);
}
//! Parallel iteration over a range of integers with a default step value, explicit task group context, and affinity_partitioner
template <typename Index, typename Function>
__TBB_requires(parallel_for_index<Index> && parallel_for_function<Function, Index>)
void parallel_for(Index first, Index last, const Function& f, affinity_partitioner& partitioner, task_group_context &context) {
parallel_for_impl(first, last, static_cast<Index>(1), f, partitioner, context);
}
+1 -39
View File
@@ -32,25 +32,6 @@
namespace tbb {
namespace detail {
#if __TBB_CPP20_CONCEPTS_PRESENT
namespace d1 {
template <typename Item>
class feeder;
} // namespace d1
inline namespace d0 {
template <typename Body, typename ItemType, typename FeederItemType>
concept parallel_for_each_body = requires( const std::remove_reference_t<Body>& body, ItemType&& item ) {
body(std::forward<ItemType>(item));
} ||
requires( const std::remove_reference_t<Body>& body, ItemType&& item,
tbb::detail::d1::feeder<FeederItemType>& feeder ) {
body(std::forward<ItemType>(item), feeder);
};
} // namespace d0
#endif // __TBB_CPP20_CONCEPTS_PRESENT
namespace d2 {
template<typename Body, typename Item> class feeder_impl;
} // namespace d2
@@ -67,7 +48,7 @@ class feeder {
virtual void internal_add_copy(const Item& item) = 0;
virtual void internal_add_move(Item&& item) = 0;
template<typename Body_, typename Item_> friend class d2::feeder_impl;
template<typename Body_, typename Item_> friend class detail::d2::feeder_impl;
public:
//! Add a work item to a running parallel_for_each.
void add(const Item& item) {internal_add_copy(item);}
@@ -576,19 +557,6 @@ template<typename Body, typename Item> Item get_item_type_impl(...); // stub
template <typename Body, typename Item>
using get_item_type = decltype(get_item_type_impl<Body, Item>(0));
#if __TBB_CPP20_CONCEPTS_PRESENT
template <typename Body, typename ItemType>
using feeder_item_type = std::remove_cvref_t<get_item_type<Body, ItemType>>;
template <typename Body, typename Iterator>
concept parallel_for_each_iterator_body =
parallel_for_each_body<Body, iterator_reference_type<Iterator>, feeder_item_type<Body, iterator_reference_type<Iterator>>>;
template <typename Body, typename Range>
concept parallel_for_each_range_body =
parallel_for_each_body<Body, range_reference_type<Range>, feeder_item_type<Body, range_reference_type<Range>>>;
#endif
/** Implements parallel iteration over a range.
@ingroup algorithms */
template<typename Iterator, typename Body>
@@ -629,20 +597,17 @@ void run_parallel_for_each( Iterator first, Iterator last, const Body& body, tas
//! Parallel iteration over a range, with optional addition of more work.
/** @ingroup algorithms */
template<typename Iterator, typename Body>
__TBB_requires(std::input_iterator<Iterator> && parallel_for_each_iterator_body<Body, Iterator>)
void parallel_for_each(Iterator first, Iterator last, const Body& body) {
task_group_context context(PARALLEL_FOR_EACH);
run_parallel_for_each<Iterator, Body>(first, last, body, context);
}
template<typename Range, typename Body>
__TBB_requires(container_based_sequence<Range, std::input_iterator_tag> && parallel_for_each_range_body<Body, Range>)
void parallel_for_each(Range& rng, const Body& body) {
parallel_for_each(std::begin(rng), std::end(rng), body);
}
template<typename Range, typename Body>
__TBB_requires(container_based_sequence<Range, std::input_iterator_tag> && parallel_for_each_range_body<Body, Range>)
void parallel_for_each(const Range& rng, const Body& body) {
parallel_for_each(std::begin(rng), std::end(rng), body);
}
@@ -650,19 +615,16 @@ void parallel_for_each(const Range& rng, const Body& body) {
//! Parallel iteration over a range, with optional addition of more work and user-supplied context
/** @ingroup algorithms */
template<typename Iterator, typename Body>
__TBB_requires(std::input_iterator<Iterator> && parallel_for_each_iterator_body<Body, Iterator>)
void parallel_for_each(Iterator first, Iterator last, const Body& body, task_group_context& context) {
run_parallel_for_each<Iterator, Body>(first, last, body, context);
}
template<typename Range, typename Body>
__TBB_requires(container_based_sequence<Range, std::input_iterator_tag> && parallel_for_each_range_body<Body, Range>)
void parallel_for_each(Range& rng, const Body& body, task_group_context& context) {
parallel_for_each(std::begin(rng), std::end(rng), body, context);
}
template<typename Range, typename Body>
__TBB_requires(container_based_sequence<Range, std::input_iterator_tag> && parallel_for_each_range_body<Body, Range>)
void parallel_for_each(const Range& rng, const Body& body, task_group_context& context) {
parallel_for_each(std::begin(rng), std::end(rng), body, context);
}
-74
View File
@@ -22,7 +22,6 @@
#include "detail/_task.h"
#include "detail/_aligned_space.h"
#include "detail/_small_object_pool.h"
#include "detail/_range_common.h"
#include "task_group.h" // task_group_context
#include "partitioner.h"
@@ -30,31 +29,6 @@
namespace tbb {
namespace detail {
#if __TBB_CPP20_CONCEPTS_PRESENT
inline namespace d0 {
template <typename Body, typename Range>
concept parallel_reduce_body = splittable<Body> &&
requires( Body& body, const Range& range, Body& rhs ) {
body(range);
body.join(rhs);
};
template <typename Function, typename Range, typename Value>
concept parallel_reduce_function = requires( const std::remove_reference_t<Function>& func,
const Range& range,
const Value& value ) {
{ func(range, value) } -> std::convertible_to<Value>;
};
template <typename Combine, typename Value>
concept parallel_reduce_combine = requires( const std::remove_reference_t<Combine>& combine,
const Value& lhs, const Value& rhs ) {
{ combine(lhs, rhs) } -> std::convertible_to<Value>;
};
} // namespace d0
#endif // __TBB_CPP20_CONCEPTS_PRESENT
namespace d1 {
//! Tree node type for parallel_reduce.
@@ -418,7 +392,6 @@ public:
//! Parallel iteration with reduction and default partitioner.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_reduce_body<Body, Range>)
void parallel_reduce( const Range& range, Body& body ) {
start_reduce<Range,Body, const __TBB_DEFAULT_PARTITIONER>::run( range, body, __TBB_DEFAULT_PARTITIONER() );
}
@@ -426,7 +399,6 @@ void parallel_reduce( const Range& range, Body& body ) {
//! Parallel iteration with reduction and simple_partitioner
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_reduce_body<Body, Range>)
void parallel_reduce( const Range& range, Body& body, const simple_partitioner& partitioner ) {
start_reduce<Range,Body,const simple_partitioner>::run( range, body, partitioner );
}
@@ -434,7 +406,6 @@ void parallel_reduce( const Range& range, Body& body, const simple_partitioner&
//! Parallel iteration with reduction and auto_partitioner
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_reduce_body<Body, Range>)
void parallel_reduce( const Range& range, Body& body, const auto_partitioner& partitioner ) {
start_reduce<Range,Body,const auto_partitioner>::run( range, body, partitioner );
}
@@ -442,7 +413,6 @@ void parallel_reduce( const Range& range, Body& body, const auto_partitioner& pa
//! Parallel iteration with reduction and static_partitioner
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_reduce_body<Body, Range>)
void parallel_reduce( const Range& range, Body& body, const static_partitioner& partitioner ) {
start_reduce<Range,Body,const static_partitioner>::run( range, body, partitioner );
}
@@ -450,7 +420,6 @@ void parallel_reduce( const Range& range, Body& body, const static_partitioner&
//! Parallel iteration with reduction and affinity_partitioner
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_reduce_body<Body, Range>)
void parallel_reduce( const Range& range, Body& body, affinity_partitioner& partitioner ) {
start_reduce<Range,Body,affinity_partitioner>::run( range, body, partitioner );
}
@@ -458,7 +427,6 @@ void parallel_reduce( const Range& range, Body& body, affinity_partitioner& part
//! Parallel iteration with reduction, default partitioner and user-supplied context.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_reduce_body<Body, Range>)
void parallel_reduce( const Range& range, Body& body, task_group_context& context ) {
start_reduce<Range,Body,const __TBB_DEFAULT_PARTITIONER>::run( range, body, __TBB_DEFAULT_PARTITIONER(), context );
}
@@ -466,7 +434,6 @@ void parallel_reduce( const Range& range, Body& body, task_group_context& contex
//! Parallel iteration with reduction, simple partitioner and user-supplied context.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_reduce_body<Body, Range>)
void parallel_reduce( const Range& range, Body& body, const simple_partitioner& partitioner, task_group_context& context ) {
start_reduce<Range,Body,const simple_partitioner>::run( range, body, partitioner, context );
}
@@ -474,7 +441,6 @@ void parallel_reduce( const Range& range, Body& body, const simple_partitioner&
//! Parallel iteration with reduction, auto_partitioner and user-supplied context
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_reduce_body<Body, Range>)
void parallel_reduce( const Range& range, Body& body, const auto_partitioner& partitioner, task_group_context& context ) {
start_reduce<Range,Body,const auto_partitioner>::run( range, body, partitioner, context );
}
@@ -482,7 +448,6 @@ void parallel_reduce( const Range& range, Body& body, const auto_partitioner& pa
//! Parallel iteration with reduction, static_partitioner and user-supplied context
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_reduce_body<Body, Range>)
void parallel_reduce( const Range& range, Body& body, const static_partitioner& partitioner, task_group_context& context ) {
start_reduce<Range,Body,const static_partitioner>::run( range, body, partitioner, context );
}
@@ -490,7 +455,6 @@ void parallel_reduce( const Range& range, Body& body, const static_partitioner&
//! Parallel iteration with reduction, affinity_partitioner and user-supplied context
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_reduce_body<Body, Range>)
void parallel_reduce( const Range& range, Body& body, affinity_partitioner& partitioner, task_group_context& context ) {
start_reduce<Range,Body,affinity_partitioner>::run( range, body, partitioner, context );
}
@@ -500,8 +464,6 @@ void parallel_reduce( const Range& range, Body& body, affinity_partitioner& part
//! Parallel iteration with reduction and default partitioner.
/** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
parallel_reduce_combine<Reduction, Value>)
Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction ) {
lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
start_reduce<Range,lambda_reduce_body<Range,Value,RealBody,Reduction>,const __TBB_DEFAULT_PARTITIONER>
@@ -512,8 +474,6 @@ Value parallel_reduce( const Range& range, const Value& identity, const RealBody
//! Parallel iteration with reduction and simple_partitioner.
/** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
parallel_reduce_combine<Reduction, Value>)
Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
const simple_partitioner& partitioner ) {
lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
@@ -525,8 +485,6 @@ Value parallel_reduce( const Range& range, const Value& identity, const RealBody
//! Parallel iteration with reduction and auto_partitioner
/** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
parallel_reduce_combine<Reduction, Value>)
Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
const auto_partitioner& partitioner ) {
lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
@@ -538,8 +496,6 @@ Value parallel_reduce( const Range& range, const Value& identity, const RealBody
//! Parallel iteration with reduction and static_partitioner
/** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
parallel_reduce_combine<Reduction, Value>)
Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
const static_partitioner& partitioner ) {
lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
@@ -551,8 +507,6 @@ Value parallel_reduce( const Range& range, const Value& identity, const RealBody
//! Parallel iteration with reduction and affinity_partitioner
/** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
parallel_reduce_combine<Reduction, Value>)
Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
affinity_partitioner& partitioner ) {
lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
@@ -564,8 +518,6 @@ Value parallel_reduce( const Range& range, const Value& identity, const RealBody
//! Parallel iteration with reduction, default partitioner and user-supplied context.
/** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
parallel_reduce_combine<Reduction, Value>)
Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
task_group_context& context ) {
lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
@@ -577,8 +529,6 @@ Value parallel_reduce( const Range& range, const Value& identity, const RealBody
//! Parallel iteration with reduction, simple partitioner and user-supplied context.
/** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
parallel_reduce_combine<Reduction, Value>)
Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
const simple_partitioner& partitioner, task_group_context& context ) {
lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
@@ -590,8 +540,6 @@ Value parallel_reduce( const Range& range, const Value& identity, const RealBody
//! Parallel iteration with reduction, auto_partitioner and user-supplied context
/** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
parallel_reduce_combine<Reduction, Value>)
Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
const auto_partitioner& partitioner, task_group_context& context ) {
lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
@@ -603,8 +551,6 @@ Value parallel_reduce( const Range& range, const Value& identity, const RealBody
//! Parallel iteration with reduction, static_partitioner and user-supplied context
/** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
parallel_reduce_combine<Reduction, Value>)
Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
const static_partitioner& partitioner, task_group_context& context ) {
lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
@@ -616,8 +562,6 @@ Value parallel_reduce( const Range& range, const Value& identity, const RealBody
//! Parallel iteration with reduction, affinity_partitioner and user-supplied context
/** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
parallel_reduce_combine<Reduction, Value>)
Value parallel_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
affinity_partitioner& partitioner, task_group_context& context ) {
lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
@@ -629,7 +573,6 @@ Value parallel_reduce( const Range& range, const Value& identity, const RealBody
//! Parallel iteration with deterministic reduction and default simple partitioner.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_reduce_body<Body, Range>)
void parallel_deterministic_reduce( const Range& range, Body& body ) {
start_deterministic_reduce<Range, Body, const simple_partitioner>::run(range, body, simple_partitioner());
}
@@ -637,7 +580,6 @@ void parallel_deterministic_reduce( const Range& range, Body& body ) {
//! Parallel iteration with deterministic reduction and simple partitioner.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_reduce_body<Body, Range>)
void parallel_deterministic_reduce( const Range& range, Body& body, const simple_partitioner& partitioner ) {
start_deterministic_reduce<Range, Body, const simple_partitioner>::run(range, body, partitioner);
}
@@ -645,7 +587,6 @@ void parallel_deterministic_reduce( const Range& range, Body& body, const simple
//! Parallel iteration with deterministic reduction and static partitioner.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_reduce_body<Body, Range>)
void parallel_deterministic_reduce( const Range& range, Body& body, const static_partitioner& partitioner ) {
start_deterministic_reduce<Range, Body, const static_partitioner>::run(range, body, partitioner);
}
@@ -653,7 +594,6 @@ void parallel_deterministic_reduce( const Range& range, Body& body, const static
//! Parallel iteration with deterministic reduction, default simple partitioner and user-supplied context.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_reduce_body<Body, Range>)
void parallel_deterministic_reduce( const Range& range, Body& body, task_group_context& context ) {
start_deterministic_reduce<Range,Body, const simple_partitioner>::run( range, body, simple_partitioner(), context );
}
@@ -661,7 +601,6 @@ void parallel_deterministic_reduce( const Range& range, Body& body, task_group_c
//! Parallel iteration with deterministic reduction, simple partitioner and user-supplied context.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_reduce_body<Body, Range>)
void parallel_deterministic_reduce( const Range& range, Body& body, const simple_partitioner& partitioner, task_group_context& context ) {
start_deterministic_reduce<Range, Body, const simple_partitioner>::run(range, body, partitioner, context);
}
@@ -669,7 +608,6 @@ void parallel_deterministic_reduce( const Range& range, Body& body, const simple
//! Parallel iteration with deterministic reduction, static partitioner and user-supplied context.
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_reduce_body<Body, Range>)
void parallel_deterministic_reduce( const Range& range, Body& body, const static_partitioner& partitioner, task_group_context& context ) {
start_deterministic_reduce<Range, Body, const static_partitioner>::run(range, body, partitioner, context);
}
@@ -681,8 +619,6 @@ void parallel_deterministic_reduce( const Range& range, Body& body, const static
// TODO: consider making static_partitioner the default
/** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
parallel_reduce_combine<Reduction, Value>)
Value parallel_deterministic_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction ) {
return parallel_deterministic_reduce(range, identity, real_body, reduction, simple_partitioner());
}
@@ -690,8 +626,6 @@ Value parallel_deterministic_reduce( const Range& range, const Value& identity,
//! Parallel iteration with deterministic reduction and simple partitioner.
/** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
parallel_reduce_combine<Reduction, Value>)
Value parallel_deterministic_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction, const simple_partitioner& partitioner ) {
lambda_reduce_body<Range,Value,RealBody,Reduction> body(identity, real_body, reduction);
start_deterministic_reduce<Range,lambda_reduce_body<Range,Value,RealBody,Reduction>, const simple_partitioner>
@@ -702,8 +636,6 @@ Value parallel_deterministic_reduce( const Range& range, const Value& identity,
//! Parallel iteration with deterministic reduction and static partitioner.
/** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
parallel_reduce_combine<Reduction, Value>)
Value parallel_deterministic_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction, const static_partitioner& partitioner ) {
lambda_reduce_body<Range, Value, RealBody, Reduction> body(identity, real_body, reduction);
start_deterministic_reduce<Range, lambda_reduce_body<Range, Value, RealBody, Reduction>, const static_partitioner>
@@ -714,8 +646,6 @@ Value parallel_deterministic_reduce( const Range& range, const Value& identity,
//! Parallel iteration with deterministic reduction, default simple partitioner and user-supplied context.
/** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
parallel_reduce_combine<Reduction, Value>)
Value parallel_deterministic_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
task_group_context& context ) {
return parallel_deterministic_reduce(range, identity, real_body, reduction, simple_partitioner(), context);
@@ -724,8 +654,6 @@ Value parallel_deterministic_reduce( const Range& range, const Value& identity,
//! Parallel iteration with deterministic reduction, simple partitioner and user-supplied context.
/** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
parallel_reduce_combine<Reduction, Value>)
Value parallel_deterministic_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
const simple_partitioner& partitioner, task_group_context& context ) {
lambda_reduce_body<Range, Value, RealBody, Reduction> body(identity, real_body, reduction);
@@ -737,8 +665,6 @@ Value parallel_deterministic_reduce( const Range& range, const Value& identity,
//! Parallel iteration with deterministic reduction, static partitioner and user-supplied context.
/** @ingroup algorithms **/
template<typename Range, typename Value, typename RealBody, typename Reduction>
__TBB_requires(range<Range> && parallel_reduce_function<RealBody, Range, Value> &&
parallel_reduce_combine<Reduction, Value>)
Value parallel_deterministic_reduce( const Range& range, const Value& identity, const RealBody& real_body, const Reduction& reduction,
const static_partitioner& partitioner, task_group_context& context ) {
lambda_reduce_body<Range, Value, RealBody, Reduction> body(identity, real_body, reduction);
+15 -54
View File
@@ -50,35 +50,6 @@ struct final_scan_tag {
template<typename Range, typename Body>
struct sum_node;
#if __TBB_CPP20_CONCEPTS_PRESENT
} // namespace d1
namespace d0 {
template <typename Body, typename Range>
concept parallel_scan_body = splittable<Body> &&
requires( Body& body, const Range& range, Body& other ) {
body(range, tbb::detail::d1::pre_scan_tag{});
body(range, tbb::detail::d1::final_scan_tag{});
body.reverse_join(other);
body.assign(other);
};
template <typename Function, typename Range, typename Value>
concept parallel_scan_function = requires( const std::remove_reference_t<Function>& func,
const Range& range, const Value& value ) {
{ func(range, value, true) } -> std::convertible_to<Value>;
};
template <typename Combine, typename Value>
concept parallel_scan_combine = requires( const std::remove_reference_t<Combine>& combine,
const Value& lhs, const Value& rhs ) {
{ combine(lhs, rhs) } -> std::convertible_to<Value>;
};
} // namespace d0
namespace d1 {
#endif // __TBB_CPP20_CONCEPTS_PRESENT
//! Performs final scan for a leaf
/** @ingroup algorithms */
template<typename Range, typename Body>
@@ -119,7 +90,7 @@ private:
if (m_parent) {
auto parent = m_parent;
m_parent = nullptr;
if (parent->ref_count.fetch_sub(1) == 1) {
if (parent->ref_count.fetch_sub(1, std::memory_order_relaxed) == 1) {
return parent;
}
}
@@ -195,7 +166,7 @@ public:
m_allocator(alloc)
{
if( m_parent )
m_parent->ref_count.fetch_add(1);
m_parent->ref_count.fetch_add(1, std::memory_order_relaxed);
// Poison fields that will be set by second pass.
poison_pointer(m_body);
poison_pointer(m_incoming);
@@ -203,7 +174,7 @@ public:
~sum_node() {
if (m_parent)
m_parent->ref_count.fetch_sub(1);
m_parent->ref_count.fetch_sub(1, std::memory_order_relaxed);
}
private:
sum_node* release_parent() {
@@ -211,7 +182,7 @@ private:
if (m_parent) {
auto parent = m_parent;
m_parent = nullptr;
if (parent->ref_count.fetch_sub(1) == 1) {
if (parent->ref_count.fetch_sub(1, std::memory_order_relaxed) == 1) {
return parent;
}
}
@@ -284,7 +255,7 @@ private:
sum_node_type*& m_return_slot;
small_object_allocator m_allocator;
public:
std::atomic<final_sum_type*> m_right_zombie;
final_sum_type* m_right_zombie;
sum_node_type& m_result;
std::atomic<unsigned int> ref_count{2};
finish_scan* m_parent;
@@ -293,18 +264,17 @@ public:
__TBB_ASSERT( m_result.ref_count.load() == static_cast<unsigned int>((m_result.m_left!=nullptr)+(m_result.m_right!=nullptr)), nullptr );
if( m_result.m_left )
m_result.m_left_is_final = false;
final_sum_type* right_zombie = m_right_zombie.load(std::memory_order_acquire);
if( right_zombie && m_sum_slot )
if( m_right_zombie && m_sum_slot )
(*m_sum_slot)->reverse_join(*m_result.m_left_sum);
__TBB_ASSERT( !m_return_slot, nullptr );
if( right_zombie || m_result.m_right ) {
if( m_right_zombie || m_result.m_right ) {
m_return_slot = &m_result;
} else {
m_result.self_destroy(ed);
}
if( right_zombie && !m_sum_slot && !m_result.m_right ) {
right_zombie->self_destroy(ed);
m_right_zombie.store(nullptr, std::memory_order_relaxed);
if( m_right_zombie && !m_sum_slot && !m_result.m_right ) {
m_right_zombie->self_destroy(ed);
m_right_zombie = nullptr;
}
return finalize(ed);
}
@@ -328,7 +298,7 @@ private:
if (m_parent) {
auto parent = m_parent;
m_parent = nullptr;
if (parent->ref_count.fetch_sub(1) == 1) {
if (parent->ref_count.fetch_sub(1, std::memory_order_relaxed) == 1) {
return parent;
}
}
@@ -369,7 +339,7 @@ private:
if (m_parent) {
auto parent = m_parent;
m_parent = nullptr;
if (parent->ref_count.fetch_sub(1) == 1) {
if (parent->ref_count.fetch_sub(1, std::memory_order_relaxed) == 1) {
return parent;
}
}
@@ -458,9 +428,8 @@ task* start_scan<Range,Body,Partitioner>::execute( execution_data& ed ) {
if( treat_as_stolen ) {
// Invocation is for right child that has been really stolen or needs to be virtually stolen
small_object_allocator alloc{};
final_sum_type* right_zombie = alloc.new_object<final_sum_type>(m_body, alloc);
m_parent->m_right_zombie.store(right_zombie, std::memory_order_release);
m_body = *right_zombie;
m_parent->m_right_zombie = alloc.new_object<final_sum_type>(m_body, alloc);
m_body = *m_parent->m_right_zombie;
m_is_final = false;
}
task* next_task = nullptr;
@@ -558,7 +527,6 @@ public:
//! Parallel prefix with default partitioner
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_scan_body<Body, Range>)
void parallel_scan( const Range& range, Body& body ) {
start_scan<Range, Body, auto_partitioner>::run(range,body,__TBB_DEFAULT_PARTITIONER());
}
@@ -566,7 +534,6 @@ void parallel_scan( const Range& range, Body& body ) {
//! Parallel prefix with simple_partitioner
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_scan_body<Body, Range>)
void parallel_scan( const Range& range, Body& body, const simple_partitioner& partitioner ) {
start_scan<Range, Body, simple_partitioner>::run(range, body, partitioner);
}
@@ -574,7 +541,6 @@ void parallel_scan( const Range& range, Body& body, const simple_partitioner& pa
//! Parallel prefix with auto_partitioner
/** @ingroup algorithms **/
template<typename Range, typename Body>
__TBB_requires(range<Range> && parallel_scan_body<Body, Range>)
void parallel_scan( const Range& range, Body& body, const auto_partitioner& partitioner ) {
start_scan<Range,Body,auto_partitioner>::run(range, body, partitioner);
}
@@ -582,8 +548,6 @@ void parallel_scan( const Range& range, Body& body, const auto_partitioner& part
//! Parallel prefix with default partitioner
/** @ingroup algorithms **/
template<typename Range, typename Value, typename Scan, typename ReverseJoin>
__TBB_requires(range<Range> && parallel_scan_function<Scan, Range, Value> &&
parallel_scan_combine<ReverseJoin, Value>)
Value parallel_scan( const Range& range, const Value& identity, const Scan& scan, const ReverseJoin& reverse_join ) {
lambda_scan_body<Range, Value, Scan, ReverseJoin> body(identity, scan, reverse_join);
parallel_scan(range, body, __TBB_DEFAULT_PARTITIONER());
@@ -593,8 +557,6 @@ Value parallel_scan( const Range& range, const Value& identity, const Scan& scan
//! Parallel prefix with simple_partitioner
/** @ingroup algorithms **/
template<typename Range, typename Value, typename Scan, typename ReverseJoin>
__TBB_requires(range<Range> && parallel_scan_function<Scan, Range, Value> &&
parallel_scan_combine<ReverseJoin, Value>)
Value parallel_scan( const Range& range, const Value& identity, const Scan& scan, const ReverseJoin& reverse_join,
const simple_partitioner& partitioner ) {
lambda_scan_body<Range, Value, Scan, ReverseJoin> body(identity, scan, reverse_join);
@@ -605,8 +567,6 @@ Value parallel_scan( const Range& range, const Value& identity, const Scan& scan
//! Parallel prefix with auto_partitioner
/** @ingroup algorithms **/
template<typename Range, typename Value, typename Scan, typename ReverseJoin>
__TBB_requires(range<Range> && parallel_scan_function<Scan, Range, Value> &&
parallel_scan_combine<ReverseJoin, Value>)
Value parallel_scan( const Range& range, const Value& identity, const Scan& scan, const ReverseJoin& reverse_join,
const auto_partitioner& partitioner ) {
lambda_scan_body<Range, Value, Scan, ReverseJoin> body(identity, scan, reverse_join);
@@ -621,6 +581,7 @@ inline namespace v1 {
using detail::d1::parallel_scan;
using detail::d1::pre_scan_tag;
using detail::d1::final_scan_tag;
} // namespace v1
} // namespace tbb
-28
View File
@@ -29,26 +29,6 @@
namespace tbb {
namespace detail {
#if __TBB_CPP20_CONCEPTS_PRESENT
inline namespace d0 {
// TODO: consider using std::strict_weak_order concept
template <typename Compare, typename Iterator>
concept compare = requires( const std::remove_reference_t<Compare>& comp, typename std::iterator_traits<Iterator>::reference value ) {
// Forward via iterator_traits::reference
{ comp(typename std::iterator_traits<Iterator>::reference(value),
typename std::iterator_traits<Iterator>::reference(value)) } -> std::convertible_to<bool>;
};
// Inspired by std::__PartiallyOrderedWith exposition only concept
template <typename T>
concept less_than_comparable = requires( const std::remove_reference_t<T>& lhs,
const std::remove_reference_t<T>& rhs ) {
{ lhs < rhs } -> boolean_testable;
};
} // namespace d0
#endif // __TBB_CPP20_CONCEPTS_PRESENT
namespace d1 {
//! Range used in quicksort to split elements into subranges based on a value.
@@ -223,8 +203,6 @@ void parallel_quick_sort( RandomAccessIterator begin, RandomAccessIterator end,
The compare object must define a bool operator() function.
@ingroup algorithms **/
template<typename RandomAccessIterator, typename Compare>
__TBB_requires(std::random_access_iterator<RandomAccessIterator> &&
compare<Compare, RandomAccessIterator>)
void parallel_sort( RandomAccessIterator begin, RandomAccessIterator end, const Compare& comp ) {
constexpr int min_parallel_size = 500;
if( end > begin ) {
@@ -239,8 +217,6 @@ void parallel_sort( RandomAccessIterator begin, RandomAccessIterator end, const
//! 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> &&
less_than_comparable<typename std::iterator_traits<RandomAccessIterator>::value_type>)
void parallel_sort( RandomAccessIterator begin, RandomAccessIterator end ) {
parallel_sort(begin, end, std::less<typename std::iterator_traits<RandomAccessIterator>::value_type>());
}
@@ -248,8 +224,6 @@ void parallel_sort( RandomAccessIterator begin, RandomAccessIterator end ) {
//! Sorts the data in rng using the given comparator
/** @ingroup algorithms **/
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 ) {
parallel_sort(std::begin(rng), std::end(rng), comp);
}
@@ -257,8 +231,6 @@ void parallel_sort( Range& rng, const Compare& comp ) {
//! 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 ) {
parallel_sort(std::begin(rng), std::end(rng));
}
+3 -11
View File
@@ -265,7 +265,7 @@ struct partition_type_base {
template<typename StartType, typename Range>
void work_balance(StartType &start, Range &range, const execution_data&) {
start.run_body( range ); // static partitioner goes here
start.run_body( range ); // simple partitioner goes always here
}
template<typename StartType, typename Range>
@@ -301,10 +301,6 @@ struct adaptive_mode : partition_type_base<Partition> {
static const unsigned factor = 1;
adaptive_mode() : my_divisor(get_initial_auto_partitioner_divisor() / 4 * my_partition::factor) {}
adaptive_mode(adaptive_mode &src, split) : my_divisor(do_split(src, split())) {}
adaptive_mode(adaptive_mode&, const proportional_split&) : my_divisor(0)
{
// left blank as my_divisor gets overridden in the successors' constructors
}
/*! Override do_split methods in order to specify splitting strategy */
std::size_t do_split(adaptive_mode &src, split) {
return src.my_divisor /= 2u;
@@ -341,11 +337,7 @@ struct proportional_mode : adaptive_mode<Partition> {
proportional_mode() : adaptive_mode<Partition>() {}
proportional_mode(proportional_mode &src, split) : adaptive_mode<Partition>(src, split()) {}
proportional_mode(proportional_mode &src, const proportional_split& split_obj)
: adaptive_mode<Partition>(src, split_obj)
{
self().my_divisor = do_split(src, split_obj);
}
proportional_mode(proportional_mode &src, const proportional_split& split_obj) { self().my_divisor = do_split(src, split_obj); }
std::size_t do_split(proportional_mode &src, const proportional_split& split_obj) {
std::size_t portion = split_obj.right() * my_partition::factor;
portion = (portion + my_partition::factor/2) & (0ul - my_partition::factor);
@@ -444,7 +436,7 @@ struct dynamic_grainsize_mode : Mode {
template<typename StartType, typename Range>
void work_balance(StartType &start, Range &range, execution_data& ed) {
if( !range.is_divisible() || !self().max_depth() ) {
start.run_body( range );
start.run_body( range ); // simple partitioner goes always here
}
else { // do range pool
range_vector<Range, range_pool_size> range_pool(range);
+9 -4
View File
@@ -20,7 +20,6 @@
#include "detail/_namespace_injection.h"
#include "detail/_assert.h"
#include "detail/_utils.h"
#include "detail/_mutex_common.h"
#include "profiling.h"
@@ -87,11 +86,14 @@ public:
call_itt_notify(prepare, &m);
__TBB_ASSERT(pred->m_next.load(std::memory_order_relaxed) == nullptr, "the predecessor has another successor!");
pred->m_next.store(this, std::memory_order_release);
pred->m_next.store(this, std::memory_order_relaxed);
spin_wait_while_eq(m_going, 0U);
}
call_itt_notify(acquired, &m);
// 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);
}
//! Acquire lock on given mutex if free (i.e. non-blocking)
@@ -107,11 +109,14 @@ public:
// The compare_exchange_strong must have release semantics, because we are
// "sending" the fields initialized above to other processors.
// x86 compare exchange operation always has a strong fence
if (!m.q_tail.compare_exchange_strong(expected, this, std::memory_order_acq_rel))
if (!m.q_tail.compare_exchange_strong(expected, this))
return false;
m_mutex = &m;
// 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);
call_itt_notify(acquired, &m);
return true;
}
@@ -133,7 +138,7 @@ public:
// Someone in the queue
spin_wait_while_eq(m_next, nullptr);
}
m_next.load(std::memory_order_acquire)->m_going.store(1U, std::memory_order_release);
m_next.load(std::memory_order_relaxed)->m_going.store(1U, std::memory_order_release);
reset();
}
-1
View File
@@ -20,7 +20,6 @@
#include "detail/_config.h"
#include "detail/_namespace_injection.h"
#include "detail/_assert.h"
#include "detail/_mutex_common.h"
#include "profiling.h"
-1
View File
@@ -23,7 +23,6 @@
#include "detail/_utils.h"
#include "detail/_waitable_atomic.h"
#include "detail/_scoped_lock.h"
#include "detail/_mutex_common.h"
#include "profiling.h"
namespace tbb {
-1
View File
@@ -18,7 +18,6 @@
#define __TBB_spin_mutex_H
#include "detail/_namespace_injection.h"
#include "detail/_mutex_common.h"
#include "profiling.h"
-1
View File
@@ -18,7 +18,6 @@
#define __TBB_spin_rw_mutex_H
#include "detail/_namespace_injection.h"
#include "detail/_mutex_common.h"
#include "profiling.h"
+42 -71
View File
@@ -23,10 +23,6 @@
#include "detail/_aligned_space.h"
#include "detail/_small_object_pool.h"
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
#include "detail/_task_handle.h"
#endif
#if __TBB_ARENA_BINDING
#include "info.h"
#endif /*__TBB_ARENA_BINDING*/
@@ -92,25 +88,9 @@ int __TBB_EXPORTED_FUNC max_concurrency(const d1::task_arena_base*);
void __TBB_EXPORTED_FUNC isolate_within_arena(d1::delegate_base& d, std::intptr_t);
void __TBB_EXPORTED_FUNC enqueue(d1::task&, d1::task_arena_base*);
void __TBB_EXPORTED_FUNC enqueue(d1::task&, d1::task_group_context&, d1::task_arena_base*);
void __TBB_EXPORTED_FUNC submit(d1::task&, d1::task_group_context&, arena*, std::uintptr_t);
} // namespace r1
namespace d2 {
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
inline void enqueue_impl(task_handle&& th, d1::task_arena_base* ta) {
if (th == nullptr) {
throw_exception(exception_id::bad_task_handle);
}
auto& ctx = task_handle_accessor::ctx_of(th);
// Do not access th after release
r1::enqueue(*task_handle_accessor::release(th), ctx, ta);
}
#endif// __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
}
namespace d1 {
static constexpr int priority_stride = INT_MAX / 4;
@@ -212,33 +192,6 @@ R isolate_impl(F& f) {
return func.consume_result();
}
template <typename F>
class enqueue_task : public task {
small_object_allocator m_allocator;
const F m_func;
void finalize(const execution_data& ed) {
m_allocator.delete_object(this, ed);
}
task* execute(execution_data& ed) override {
m_func();
finalize(ed);
return nullptr;
}
task* cancel(execution_data&) override {
__TBB_ASSERT_RELEASE(false, "Unhandled exception from enqueue task is caught");
return nullptr;
}
public:
enqueue_task(const F& f, small_object_allocator& alloc) : m_allocator(alloc), m_func(f) {}
enqueue_task(F&& f, small_object_allocator& alloc) : m_allocator(alloc), m_func(std::move(f)) {}
};
template<typename F>
void enqueue_impl(F&& f, task_arena_base* ta) {
small_object_allocator alloc{};
r1::enqueue(*alloc.new_object<enqueue_task<typename std::decay<F>::type>>(std::forward<F>(f), alloc), ta);
}
/** 1-to-1 proxy representation class of scheduler's arena
* Constructors set up settings only, real construction is deferred till the first method invocation
* Destructor only removes one of the references to the inner arena representation.
@@ -246,11 +199,45 @@ void enqueue_impl(F&& f, task_arena_base* ta) {
*/
class task_arena : public task_arena_base {
template <typename F>
class enqueue_task : public task {
small_object_allocator m_allocator;
const F m_func;
void finalize(const execution_data& ed) {
m_allocator.delete_object(this, ed);
}
task* execute(execution_data& ed) override {
m_func();
finalize(ed);
return nullptr;
}
task* cancel(execution_data&) override {
__TBB_ASSERT_RELEASE(false, "Unhandled exception from enqueue task is caught");
return nullptr;
}
public:
enqueue_task(const F& f, small_object_allocator& alloc) : m_allocator(alloc), m_func(f) {}
enqueue_task(F&& f, small_object_allocator& alloc) : m_allocator(alloc), m_func(std::move(f)) {}
};
void mark_initialized() {
__TBB_ASSERT( my_arena.load(std::memory_order_relaxed), "task_arena initialization is incomplete" );
my_initialization_state.store(do_once_state::initialized, std::memory_order_release);
}
template<typename F>
void enqueue_impl(F&& f) {
initialize();
small_object_allocator alloc{};
r1::enqueue(*alloc.new_object<enqueue_task<typename std::decay<F>::type>>(std::forward<F>(f), alloc), this);
}
void enqueue_impl(task_handle&& th) {
initialize();
r1::enqueue(*th.release(), this);
}
template<typename R, typename F>
R execute_impl(F& f) {
initialize();
@@ -385,18 +372,15 @@ public:
template<typename F>
void enqueue(F&& f) {
initialize();
enqueue_impl(std::forward<F>(f), this);
enqueue_impl(std::forward<F>(f));
}
//! Enqueues a task into the arena to process a functor wrapped in task_handle, and immediately returns.
//! Enqueues a task into the arena to process a functor, and immediately returns.
//! Does not require the calling thread to join the arena
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
void enqueue(d2::task_handle&& th) {
initialize();
d2::enqueue_impl(std::move(th), this);
void enqueue(task_handle&& th) {
enqueue_impl(std::move(th));
}
#endif //__TBB_PREVIEW_TASK_GROUP_EXTENSIONS
//! Joins the arena and executes a mutable functor, then returns
//! If not possible to join, wraps the functor into a task, enqueues it and waits for task completion
@@ -455,28 +439,20 @@ inline int current_thread_index() {
return idx == -1 ? task_arena_base::not_initialized : idx;
}
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
inline bool is_inside_task() {
return nullptr != current_context();
}
#endif //__TBB_PREVIEW_TASK_GROUP_EXTENSIONS
//! Returns the maximal number of threads that can work inside the arena
inline int max_concurrency() {
return r1::max_concurrency(nullptr);
}
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
inline void enqueue(d2::task_handle&& th) {
d2::enqueue_impl(std::move(th), nullptr);
inline void enqueue(task_handle&& th) {
task_arena arena( task_arena::attach {});
return arena.enqueue(std::move(th));
}
template<typename F>
inline void enqueue(F&& f) {
enqueue_impl(std::forward<F>(f), nullptr);
}
#endif //__TBB_PREVIEW_TASK_GROUP_EXTENSIONS
using r1::submit;
} // namespace d1
@@ -485,18 +461,13 @@ using r1::submit;
inline namespace v1 {
using detail::d1::task_arena;
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
using detail::d1::is_inside_task;
#endif
namespace this_task_arena {
using detail::d1::current_thread_index;
using detail::d1::max_concurrency;
using detail::d1::isolate;
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
using detail::d1::enqueue;
#endif
} // namespace this_task_arena
} // inline namespace v1
+98 -235
View File
@@ -19,19 +19,15 @@
#include "detail/_config.h"
#include "detail/_namespace_injection.h"
#include "detail/_assert.h"
#include "detail/_utils.h"
#include "detail/_template_helpers.h"
#include "detail/_utils.h"
#include "detail/_exception.h"
#include "detail/_task.h"
#include "detail/_small_object_pool.h"
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
#include "detail/_task_handle.h"
#endif
#include "profiling.h"
#include <memory>
#include <type_traits>
#if _MSC_VER && !defined(__INTEL_COMPILER)
@@ -47,7 +43,6 @@ namespace d1 {
class delegate_base;
class task_arena_base;
class task_group_context;
class task_group_base;
}
namespace r1 {
@@ -73,70 +68,6 @@ void __TBB_EXPORTED_FUNC capture_fp_settings(d1::task_group_context&);
struct task_group_context_impl;
}
namespace d2 {
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
namespace {
template<typename F>
d1::task* task_ptr_or_nullptr(F&& f);
}
template<typename F>
class function_task : public task_handle_task {
//TODO: apply empty base optimization here
const F m_func;
private:
d1::task* execute(d1::execution_data& ed) override {
__TBB_ASSERT(ed.context == &this->ctx(), "The task group context should be used for all tasks");
task* res = task_ptr_or_nullptr(m_func);
finalize(&ed);
return res;
}
d1::task* cancel(d1::execution_data& ed) override {
finalize(&ed);
return nullptr;
}
public:
template<typename FF>
function_task(FF&& f, d1::wait_context& wo, d1::task_group_context& ctx, d1::small_object_allocator& alloc)
: task_handle_task{wo, ctx, alloc},
m_func(std::forward<FF>(f)) {}
};
namespace {
template<typename F>
d1::task* task_ptr_or_nullptr_impl(std::false_type, F&& f){
task_handle th = std::forward<F>(f)();
return task_handle_accessor::release(th);
}
template<typename F>
d1::task* task_ptr_or_nullptr_impl(std::true_type, F&& f){
std::forward<F>(f)();
return nullptr;
}
template<typename F>
d1::task* task_ptr_or_nullptr(F&& f){
using is_void_t = std::is_void<
decltype(std::forward<F>(f)())
>;
return task_ptr_or_nullptr_impl(is_void_t{}, std::forward<F>(f));
}
}
#else
namespace {
template<typename F>
d1::task* task_ptr_or_nullptr(F&& f){
std::forward<F>(f)();
return nullptr;
}
} // namespace
#endif // __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
} // namespace d2
namespace d1 {
struct context_list_node {
@@ -188,23 +119,14 @@ private:
//! Specifies whether cancellation was requested for this task group.
std::atomic<std::uint32_t> my_cancellation_requested;
//! Versioning for run-time checks and behavioral traits of the context.
enum class task_group_context_version : std::uint8_t {
gold_2021U1 = 0, // version of task_group_context released in oneTBB 2021.1 GOLD
proxy_support = 1 // backward compatible support for 'this' context to act as a proxy
};
task_group_context_version my_version;
//! Version for run-time checks and behavioral traits of the context.
std::uint8_t my_version;
//! The context traits.
struct context_traits {
bool fp_settings : 1;
bool concurrent_wait : 1;
bool bound : 1;
bool proxy : 1; // true if 'this' acts as a proxy for user-specified context
bool reserved1 : 1;
bool reserved2 : 1;
bool reserved3 : 1;
bool reserved4 : 1;
} my_traits;
static_assert(sizeof(context_traits) == 1, "Traits shall fit into one byte.");
@@ -225,13 +147,8 @@ private:
//! The synchronization machine state to manage lifetime.
std::atomic<lifetime_state> my_lifetime_state;
union {
//! Pointer to the context of the parent cancellation group. NULL for isolated contexts.
task_group_context* my_parent;
//! Pointer to the actual context 'this' context represents a proxy of.
task_group_context* my_actual_context;
};
//! Pointer to the context of the parent cancellation group. NULL for isolated contexts.
task_group_context* my_parent;
//! Thread data instance that registered this context in its list.
std::atomic<r1::thread_data*> my_owner;
@@ -251,77 +168,34 @@ private:
string_resource_index my_name;
char padding[max_nfs_size
- sizeof(std::uint64_t) // my_cpu_ctl_env
- sizeof(std::atomic<std::uint32_t>) // my_cancellation_requested
- sizeof(std::uint8_t) // my_version
- sizeof(context_traits) // my_traits
- sizeof(std::atomic<std::uint8_t>) // my_state
- sizeof(std::atomic<lifetime_state>) // my_lifetime_state
- sizeof(task_group_context*) // my_parent
- sizeof(std::atomic<r1::thread_data*>) // my_owner
- sizeof(context_list_node) // my_node
- sizeof(r1::tbb_exception_ptr*) // my_exception
- sizeof(void*) // my_itt_caller
- sizeof(string_resource_index) // my_name
- sizeof(std::uint64_t) // my_cpu_ctl_env
- sizeof(std::atomic<std::uint32_t>) // my_cancellation_requested
- sizeof(std::uint8_t) // my_version
- sizeof(context_traits) // my_traits
- sizeof(std::atomic<std::uint8_t>) // my_state
- sizeof(std::atomic<lifetime_state>) // my_lifetime_state
- sizeof(task_group_context*) // my_parent
- sizeof(std::atomic<r1::thread_data*>) // my_owner
- sizeof(context_list_node) // my_node
- sizeof(r1::tbb_exception_ptr*) // my_exception
- sizeof(void*) // my_itt_caller
- sizeof(string_resource_index) // my_name
];
task_group_context(context_traits t, string_resource_index name)
: my_version{task_group_context_version::proxy_support}, my_name{name}
{
: my_version{}, my_name{ name } {
my_traits = t; // GCC4.8 issues warning list initialization for bitset (missing-field-initializers)
r1::initialize(*this);
}
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
task_group_context(task_group_context* actual_context)
: my_version{task_group_context_version::proxy_support}
, my_actual_context{actual_context}
{
__TBB_ASSERT(my_actual_context, "Passed pointer value points to nothing.");
my_traits.proxy = true;
my_name = actual_context->my_name;
// no need to initialize 'this' context as it acts as a proxy for my_actual_context, which
// initialization is a user-side responsibility.
}
#endif
static context_traits make_traits(kind_type relation_with_parent, std::uintptr_t user_traits) {
context_traits ct;
ct.bound = relation_with_parent == bound;
ct.fp_settings = (user_traits & fp_settings) == fp_settings;
ct.concurrent_wait = (user_traits & concurrent_wait) == concurrent_wait;
ct.bound = relation_with_parent == bound;
ct.proxy = false;
ct.reserved1 = ct.reserved2 = ct.reserved3 = ct.reserved4 = false;
return ct;
}
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
bool is_proxy() const {
return my_version >= task_group_context_version::proxy_support && my_traits.proxy;
}
#endif
task_group_context& actual_context() noexcept {
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
if (is_proxy()) {
__TBB_ASSERT(my_actual_context, "Actual task_group_context is not set.");
return *my_actual_context;
}
#endif
return *this;
}
const task_group_context& actual_context() const noexcept {
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
if (is_proxy()) {
__TBB_ASSERT(my_actual_context, "Actual task_group_context is not set.");
return *my_actual_context;
}
#endif
return *this;
}
public:
//! Default & binding constructor.
/** By default a bound context is created. That is this context will be bound
@@ -354,19 +228,12 @@ public:
: task_group_context(make_traits(relation_with_parent, t), CUSTOM_CTX) {}
// Custom constructor for instrumentation of oneTBB algorithm
task_group_context(string_resource_index name )
task_group_context (string_resource_index name )
: task_group_context(make_traits(bound, default_traits), name) {}
// Do not introduce any logic on user side since it might break state propagation assumptions
~task_group_context() {
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
// When 'this' serves as a proxy, the initialization does not happen - nor should the
// destruction.
if (!is_proxy())
#endif
{
r1::destroy(*this);
}
r1::destroy(*this);
}
//! Forcefully reinitializes the context after the task tree it was associated with is completed.
@@ -378,7 +245,7 @@ public:
The method does not change the context's parent if it is set. **/
void reset() {
r1::reset(actual_context());
r1::reset(*this);
}
//! Initiates cancellation of all tasks in this cancellation group and its subordinate groups.
@@ -390,12 +257,12 @@ public:
that when this method is concurrently called on the same not yet cancelled
context, true will be returned by one and only one invocation. **/
bool cancel_group_execution() {
return r1::cancel_group_execution(actual_context());
return r1::cancel_group_execution(*this);
}
//! Returns true if the context received cancellation request.
bool is_group_execution_cancelled() {
return r1::is_group_execution_cancelled(actual_context());
return r1::is_group_execution_cancelled(*this);
}
#if __TBB_FP_CONTEXT
@@ -408,16 +275,15 @@ public:
The method does not change the FPU control settings of the context's parent. **/
void capture_fp_settings() {
r1::capture_fp_settings(actual_context());
r1::capture_fp_settings(*this);
}
#endif
//! Returns the user visible context trait
std::uintptr_t traits() const {
std::uintptr_t t{};
const task_group_context& ctx = actual_context();
t |= ctx.my_traits.fp_settings ? fp_settings : 0;
t |= ctx.my_traits.concurrent_wait ? concurrent_wait : 0;
t |= my_traits.fp_settings ? fp_settings : 0;
t |= my_traits.concurrent_wait ? concurrent_wait : 0;
return t;
}
private:
@@ -429,7 +295,6 @@ private:
friend class r1::context_guard_helper;
friend struct r1::task_arena_impl;
friend struct r1::task_group_context_impl;
friend class task_group_base;
}; // class task_group_context
static_assert(sizeof(task_group_context) == 128, "Wrong size of task_group_context");
@@ -446,6 +311,28 @@ class structured_task_group;
class isolated_task_group;
#endif
namespace {
template <typename F>
struct is_void_return : std::is_void< typename std::result_of<F()>::type > {};
template<typename F>
task* return_value_or_nullptr_impl(std::false_type, F&& f){
task_handle th = std::forward<F>(f)();
return th.release();
}
template<typename F>
task* return_value_or_nullptr_impl(std::true_type, F&& f){
std::forward<F>(f)();
return nullptr;
}
template<typename F>
task* return_value_or_nullptr(F&& f){
return return_value_or_nullptr_impl(is_void_return<F>{}, std::forward<F>(f));
}
}
template<typename F>
class function_task : public task {
const F m_func;
@@ -463,8 +350,10 @@ class function_task : public task {
allocator.deallocate(this, ed);
}
private:
task* execute(execution_data& ed) override {
task* res = d2::task_ptr_or_nullptr(m_func);
task* res = return_value_or_nullptr(m_func);
finalize(ed);
return res;
}
@@ -493,7 +382,7 @@ class function_stack_task : public task {
m_wait_ctx.release();
}
task* execute(execution_data&) override {
task* res = d2::task_ptr_or_nullptr(m_func);
task* res = return_value_or_nullptr(m_func);
finalize();
return res;
}
@@ -508,58 +397,60 @@ public:
class task_group_base : no_copy {
protected:
wait_context m_wait_ctx;
task_group_context m_context;
task_group_context m_own_context;
task_group_context* m_context{nullptr};
template<typename F>
task_group_status internal_run_and_wait(const F& f) {
function_stack_task<F> t{ f, m_wait_ctx };
m_wait_ctx.reserve();
bool cancellation_status = false;
__TBB_ASSERT(m_context, nullptr);
try_call([&] {
execute_and_wait(t, context(), m_wait_ctx, context());
execute_and_wait(t, *m_context, m_wait_ctx, *m_context);
}).on_completion([&] {
// TODO: the reset method is not thread-safe. Ensure the correct behavior.
cancellation_status = context().is_group_execution_cancelled();
context().reset();
cancellation_status = m_context->is_group_execution_cancelled();
m_context->reset();
});
return cancellation_status ? canceled : complete;
}
template<typename F>
task* prepare_task(F&& f) {
auto prepare_task(F&& f) -> function_task<typename std::decay<F>::type>*{
m_wait_ctx.reserve();
small_object_allocator alloc{};
return alloc.new_object<function_task<typename std::decay<F>::type>>(std::forward<F>(f), m_wait_ctx, alloc);
}
task_group_context& context() noexcept {
return m_context.actual_context();
}
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
template<typename F>
d2::task_handle prepare_task_handle(F&& f) {
task_handle prepare_task_handle(F&& f) {
m_wait_ctx.reserve();
small_object_allocator alloc{};
using function_task_t = d2::function_task<typename std::decay<F>::type>;
d2::task_handle_task* function_task_p = alloc.new_object<function_task_t>(std::forward<F>(f), m_wait_ctx, context(), alloc);
using function_task_t = function_task<typename std::decay<F>::type>;
auto* function_task_p = alloc.new_object<function_task_t>(std::forward<F>(f), m_wait_ctx, alloc);
return d2::task_handle_accessor::construct(function_task_p);
return task_handle {function_task_p, [alloc, this](task* t) mutable {
alloc.delete_object(static_cast<function_task_t*>(t));
m_wait_ctx.release();
}};
}
#endif
public:
task_group_base(uintptr_t traits = 0)
: m_wait_ctx(0)
, m_context(task_group_context::bound, task_group_context::default_traits | traits)
{}
, m_own_context(task_group_context::bound, task_group_context::default_traits | traits)
, m_context(&m_own_context)
{
}
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
task_group_base(task_group_context& ctx)
: m_wait_ctx(0)
, m_own_context()
, m_context(&ctx)
{}
#endif
{
}
~task_group_base() noexcept(false) {
if (m_wait_ctx.continue_execution()) {
@@ -568,67 +459,60 @@ public:
#else
bool stack_unwinding_in_progress = std::uncaught_exception();
#endif
__TBB_ASSERT(m_context, nullptr);
// Always attempt to do proper cleanup to avoid inevitable memory corruption
// in case of missing wait (for the sake of better testability & debuggability)
if (!context().is_group_execution_cancelled())
if (!m_context->is_group_execution_cancelled())
cancel();
d1::wait(m_wait_ctx, context());
d1::wait(m_wait_ctx, *m_context);
if (!stack_unwinding_in_progress)
throw_exception(exception_id::missing_wait);
}
}
task_group_status wait() {
__TBB_ASSERT(m_context, nullptr);
bool cancellation_status = false;
try_call([&] {
d1::wait(m_wait_ctx, context());
d1::wait(m_wait_ctx, *m_context);
}).on_completion([&] {
// TODO: the reset method is not thread-safe. Ensure the correct behavior.
cancellation_status = m_context.is_group_execution_cancelled();
context().reset();
cancellation_status = m_context->is_group_execution_cancelled();
m_context->reset();
});
return cancellation_status ? canceled : complete;
}
void cancel() {
context().cancel_group_execution();
__TBB_ASSERT(m_context, nullptr);
m_context->cancel_group_execution();
}
}; // class task_group_base
class task_group : public task_group_base {
public:
task_group() : task_group_base(task_group_context::concurrent_wait) {}
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
task_group(task_group_context& ctx) : task_group_base(ctx) {}
#endif
template<typename F>
void run(F&& f) {
spawn(*prepare_task(std::forward<F>(f)), context());
__TBB_ASSERT(m_context, nullptr);
spawn(*prepare_task(std::forward<F>(f)), *m_context);
}
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
void run(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);
}
spawn(*acs::release(h), context());
void run(task_handle&& h) {
task* t = h.release();
__TBB_ASSERT(t, "Attempt running empty task_handle.");
__TBB_ASSERT(m_context, nullptr);
spawn(*t, *m_context);
}
template<typename F>
d2::task_handle defer(F&& f) {
task_handle defer(F&& f) {
return prepare_task_handle(std::forward<F>(f));
}
#endif //__TBB_PREVIEW_TASK_GROUP_EXTENSIONS
template<typename F>
task_group_status run_and_wait(const F& f) {
return internal_run_and_wait(f);
@@ -679,34 +563,15 @@ class isolated_task_group : public task_group {
return reinterpret_cast<intptr_t>(this);
}
public:
isolated_task_group() : task_group() {}
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
isolated_task_group(task_group_context& ctx) : task_group(ctx) {}
#endif
isolated_task_group () : task_group() {}
template<typename F>
void run(F&& f) {
spawn_delegate sd(prepare_task(std::forward<F>(f)), context());
__TBB_ASSERT(m_context, nullptr);
spawn_delegate sd(prepare_task(std::forward<F>(f)), *m_context);
r1::isolate_within_arena(sd, this_isolation());
}
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
void run(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);
}
spawn_delegate sd(acs::release(h), context());
r1::isolate_within_arena(sd, this_isolation());
}
#endif //__TBB_PREVIEW_TASK_GROUP_EXTENSIONS
template<typename F>
task_group_status run_and_wait( const F& f ) {
task_group_status result = not_complete;
@@ -749,9 +614,7 @@ using detail::d1::canceled;
using detail::d1::is_current_task_group_canceling;
using detail::r1::missing_wait;
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
using detail::d2::task_handle;
#endif
using detail::d1::task_handle;
}
} // namespace tbb
+2 -2
View File
@@ -23,7 +23,7 @@
// Product version
#define TBB_VERSION_MAJOR 2021
// Update version
#define TBB_VERSION_MINOR 3
#define TBB_VERSION_MINOR 2
// "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 12030
#define TBB_INTERFACE_VERSION 12020
// Major interface version
#define TBB_INTERFACE_VERSION_MAJOR (TBB_INTERFACE_VERSION/1000)
// Minor interface version
-17
View File
@@ -1,17 +0,0 @@
/*
Copyright (c) 2021 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "../oneapi/tbb/collaborative_call_once.h"
+59 -28
View File
@@ -19,19 +19,34 @@
# Supported arguments:
# intel64|ia32 - architecture, intel64 is default.
# Get absolute path to script. Gets a relative path as argument and outputs an absolute path.
# Get absolute path to script, when sourced from bash, zsh and ksh shells.
# Uses `readlink` to remove links and `pwd -P` to turn into an absolute path.
# Converted into a POSIX-compliant function.
# Usage:
# script_dir=$(get_script_path "$script_rel_path")
#
# Inputs:
# script/relative/pathname/scriptname
#
# Outputs:
# /script/absolute/pathname
# executing function in a *subshell* to localize vars and effects on `cd`
get_script_path() (
script_path="$1"
while [ -L "$script_path" ] ; do
script_dir=$(command dirname -- "$script_path")
script="$1"
while [ -L "$script" ] ; do
# combining next two lines fails in zsh shell
script_dir=$(command dirname -- "$script")
script_dir=$(cd "$script_dir" && command pwd -P)
script_path="$(readlink "$script_path")"
case $script_path in
script="$(readlink "$script")"
case $script in
(/*) ;;
(*) script_path="$script_dir/$script_path" ;;
(*) script="$script_dir/$script" ;;
esac
done
script_dir=$(command dirname -- "$script_path")
# combining next two lines fails in zsh shell
script_dir=$(command dirname -- "$script")
script_dir=$(cd "$script_dir" && command pwd -P)
printf "%s" "$script_dir"
)
@@ -140,33 +155,49 @@ TBBROOT=$(get_script_path "${vars_script_name:-}")/..
TBB_TARGET_ARCH="intel64"
if [ -n "${SETVARS_ARGS:-}" ]; then
tbb_arg_ia32="$(expr "${SETVARS_ARGS:-}" : '^.*\(ia32\)')"
if [ -n "${tbb_arg_ia32:-}" ]; then
TBB_TARGET_ARCH="ia32"
fi
if [ ! -z "$SETVARS_ARGS" ] && [ "$SETVARS_CALL" "==" "1" ]; then
for arg in "$SETVARS_ARGS"; do
case "$arg" in
(intel64|ia32)
TBB_TARGET_ARCH="${arg}"
;;
(*) ;;
esac
done
elif [ ! -z "$SETVARS_ARGS" ]; then
for arg in "$SETVARS_ARGS"; do
case "$arg" in
(intel64|ia32)
TBB_TARGET_ARCH="${arg}"
;;
(*)
>&2 echo "ERROR: Unknown argument $arg"
return 255 2>/dev/null || exit 255
;;
esac
done
else
for arg do
case "$arg" in
(intel64|ia32)
TBB_TARGET_ARCH="${arg}"
;;
(*) ;;
esac
done
for arg do
case "$arg" in
(intel64|ia32)
TBB_TARGET_ARCH="${arg}"
;;
(*) ;;
esac
done
fi
TBB_LIB_NAME="libtbb.so.12"
TBB_LIB_DIR="$TBB_TARGET_ARCH/gcc4.8"
if [ -e "$TBBROOT/lib/$TBB_LIB_DIR/$TBB_LIB_NAME" ]; then
export TBBROOT
export TBBROOT
LIBRARY_PATH=$(prepend_path "${TBBROOT}/lib/$TBB_LIB_DIR" "${LIBRARY_PATH:-}") ; export LIBRARY_PATH
LD_LIBRARY_PATH=$(prepend_path "${TBBROOT}/lib/$TBB_LIB_DIR" "${LD_LIBRARY_PATH:-}") ; export LD_LIBRARY_PATH
CPATH=$(prepend_path "${TBBROOT}/include" "${CPATH:-}") ; export CPATH
CMAKE_PREFIX_PATH=$(prepend_path "${TBBROOT}" "${CMAKE_PREFIX_PATH:-}") ; export CMAKE_PREFIX_PATH
LIBRARY_PATH=$(prepend_path "${TBBROOT}/lib"/$TBB_LIB_DIR "${LIBRARY_PATH:-}") ; export LIBRARY_PATH
LD_LIBRARY_PATH=$(prepend_path "${TBBROOT}/lib/$TBB_LIB_DIR" "${LD_LIBRARY_PATH:-}") ; export LD_LIBRARY_PATH
CPATH=$(prepend_path "${TBBROOT}/include" "${CPATH:-}") ; export CPATH
CMAKE_PREFIX_PATH=$(prepend_path "${TBBROOT}" "${CMAKE_PREFIX_PATH:-}") ; export CMAKE_PREFIX_PATH
else
>&2 echo "ERROR: $TBB_LIB_NAME library does not exist in $TBBROOT/lib/$TBB_LIB_DIR."
return 255 2>/dev/null || exit 255
>&2 echo "ERROR: $TBB_LIB_NAME library does not exist in $TBBROOT/lib/$TBB_LIB_DIR."
return 255 2>/dev/null || exit 255
fi
-104
View File
@@ -1,104 +0,0 @@
#%Module1.0###################################################################
#
# Copyright (c) 2020-2021 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Why all the directory and filename boilerplate code? It is needed in order
# to properly remove symbolic links used in assembly of the modulefiles
# folder as well as those found within the oneAPI installation folders.
# Without it many modulefiles will fail to work as expected.
# IMPORTANT: quotes around "$variables" and "[expressions]" are there
# to insure that paths/filenames which include spaces are handled properly.
# This modulefile requires Environment Modules 4.1 or later.
# Type `module --version` to determine the current installed version.
set min_tcl_ver 8.4
if { $tcl_version < $min_tcl_ver } {
puts stderr " "
puts stderr "ERROR: This modulefile requires tcl $min_tcl_ver or greater."
puts stderr "Your system reports that tclsh version $tcl_version is installed."
exit 1
}
# get full pathname for this script file
set scriptpath "${ModulesCurrentModulefile}"
# if modulefile script name is a symlink, resolve it
if { "[file type "$scriptpath"]" eq "link" } {
set scriptpath "[file readlink "$scriptpath"]"
}
# if fullpath contains links, resolve them
set scriptpath "[file normalize "$scriptpath"]"
# get directory holding this modulefile script and others
set modulefileroot "[file dirname "$scriptpath"]"
# get name of modulefile script we are loading
set modulefilename "[file tail "$scriptpath"]"
# determine modulefile script version
set modulefilever "[file dirname "$modulefileroot"]"
set modulefilever "[file tail "$modulefilever"]"
# point to component top-level root folder
set componentroot "[file dirname "$modulefileroot"]"
set componentroot "[file dirname "$componentroot"]"
# get component folder name
set componentname "[file tail "$componentroot"]"
# get oneAPI top-level root folder
set oneapiroot "[file dirname "$componentroot"]"
# disallow loading multiple versions of this modulefile
# disallow loading multiple architectures of this modulefile
# if only 64-bit architecture exists the test still works
set mname32 $modulefilename
set mname64 [string trimright $mname32 "32"]
if { [string equal "$mname32" "$mname64"] } {
append mname32 "32"
}
conflict $mname32
conflict $mname64
# On load print component name and version being loaded
if { [ module-info mode load ] } {
puts stderr "Loading $modulefilename version $modulefilever"
}
# On `module unload` print component module name and version being removed
# Include `module list` message only if this modulefile loads dependent modules
if { [ module-info mode ] == "unload" || [ module-info mode ] == "remove" } {
puts stderr "Removing $modulefilename version $modulefilever"
puts stderr "Use `module list` to view any remaining dependent modules."
}
# ###### Component Specific env vars setup ###################################
set tbbroot "$componentroot/$modulefilever"
set tbb_target_arch "intel64"
module-whatis "Intel(R) oneAPI Threading Building Blocks for $tbb_target_arch."
setenv TBBROOT "$tbbroot"
prepend-path CPATH "$tbbroot/include"
prepend-path LIBRARY_PATH "$tbbroot/lib/$tbb_target_arch/gcc4.8"
prepend-path LD_LIBRARY_PATH "$tbbroot/lib/$tbb_target_arch/gcc4.8"
prepend-path CMAKE_PREFIX_PATH "$tbbroot"
-104
View File
@@ -1,104 +0,0 @@
#%Module1.0###################################################################
#
# Copyright (c) 2020-2021 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Why all the directory and filename boilerplate code? It is needed in order
# to properly remove symbolic links used in assembly of the modulefiles
# folder as well as those found within the oneAPI installation folders.
# Without it many modulefiles will fail to work as expected.
# IMPORTANT: quotes around "$variables" and "[expressions]" are there
# to insure that paths/filenames which include spaces are handled properly.
# This modulefile requires Environment Modules 4.1 or later.
# Type `module --version` to determine the current installed version.
set min_tcl_ver 8.4
if { $tcl_version < $min_tcl_ver } {
puts stderr " "
puts stderr "ERROR: This modulefile requires tcl $min_tcl_ver or greater."
puts stderr "Your system reports that tclsh version $tcl_version is installed."
exit 1
}
# get full pathname for this script file
set scriptpath "${ModulesCurrentModulefile}"
# if modulefile script name is a symlink, resolve it
if { "[file type "$scriptpath"]" eq "link" } {
set scriptpath "[file readlink "$scriptpath"]"
}
# if fullpath contains links, resolve them
set scriptpath "[file normalize "$scriptpath"]"
# get directory holding this modulefile script and others
set modulefileroot "[file dirname "$scriptpath"]"
# get name of modulefile script we are loading
set modulefilename "[file tail "$scriptpath"]"
# determine modulefile script version
set modulefilever "[file dirname "$modulefileroot"]"
set modulefilever "[file tail "$modulefilever"]"
# point to component top-level root folder
set componentroot "[file dirname "$modulefileroot"]"
set componentroot "[file dirname "$componentroot"]"
# get component folder name
set componentname "[file tail "$componentroot"]"
# get oneAPI top-level root folder
set oneapiroot "[file dirname "$componentroot"]"
# disallow loading multiple versions of this modulefile
# disallow loading multiple architectures of this modulefile
# if only 64-bit architecture exists the test still works
set mname32 $modulefilename
set mname64 [string trimright $mname32 "32"]
if { [string equal "$mname32" "$mname64"] } {
append mname32 "32"
}
conflict $mname32
conflict $mname64
# On load print component name and version being loaded
if { [ module-info mode load ] } {
puts stderr "Loading $modulefilename version $modulefilever"
}
# On `module unload` print component module name and version being removed
# Include `module list` message only if this modulefile loads dependent modules
if { [ module-info mode ] == "unload" || [ module-info mode ] == "remove" } {
puts stderr "Removing $modulefilename version $modulefilever"
puts stderr "Use `module list` to view any remaining dependent modules."
}
# ###### Component Specific env vars setup ###################################
set tbbroot "$componentroot/$modulefilever"
set tbb_target_arch "ia32"
module-whatis "Intel(R) oneAPI Threading Building Blocks for $tbb_target_arch."
setenv TBBROOT "$tbbroot"
prepend-path CPATH "$tbbroot/include"
prepend-path LIBRARY_PATH "$tbbroot/lib/$tbb_target_arch/gcc4.8"
prepend-path LD_LIBRARY_PATH "$tbbroot/lib/$tbb_target_arch/gcc4.8"
prepend-path CMAKE_PREFIX_PATH "$tbbroot"
-21
View File
@@ -1,21 +0,0 @@
#!/bin/sh
#
# Copyright (c) 2019-2021 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
LOC=$(realpath $(dirname "${BASH_SOURCE[0]}"))
source $LOC/../../../common.sh $@
ERRORSTATE=0
return $ERRORSTATE
+23 -8
View File
@@ -15,19 +15,34 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# Get absolute path to script. Gets a relative path as argument and outputs an absolute path.
# Get absolute path to script, when sourced from bash, zsh and ksh shells.
# Uses `readlink` to remove links and `pwd -P` to turn into an absolute path.
# Converted into a POSIX-compliant function.
# Usage:
# script_dir=$(get_script_path "$script_rel_path")
#
# Inputs:
# script/relative/pathname/scriptname
#
# Outputs:
# /script/absolute/pathname
# executing function in a *subshell* to localize vars and effects on `cd`
get_script_path() (
script_path="$1"
while [ -L "$script_path" ] ; do
script_dir=$(command dirname -- "$script_path")
script="$1"
while [ -L "$script" ] ; do
# combining next two lines fails in zsh shell
script_dir=$(command dirname -- "$script")
script_dir=$(cd "$script_dir" && command pwd -P)
script_path="$(readlink "$script_path")"
case $script_path in
script="$(readlink "$script")"
case $script in
(/*) ;;
(*) script_path="$script_dir/$script_path" ;;
(*) script="$script_dir/$script" ;;
esac
done
script_dir=$(command dirname -- "$script_path")
# combining next two lines fails in zsh shell
script_dir=$(command dirname -- "$script")
script_dir=$(cd "$script_dir" && command pwd -P)
printf "%s" "$script_dir"
)
-25
View File
@@ -1,25 +0,0 @@
# Copyright (c) 2021 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=@_libdir_for_pc_file@
includedir=@_includedir_for_pc_file@
Name: oneAPI Threading Building Blocks (oneTBB)
Description: C++ library for parallel programming on multi-core processors.
URL: https://github.com/oneapi-src/oneTBB
Version: @TBB_VERSION@
Libs: -L${libdir} -l@TBB_LIB_NAME@
Cflags: -I${includedir}
@@ -1,64 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2019-2021 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- include files -->
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)..\..\lib\native\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)' == 'Debug'">TBB_USE_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<!-- .lib files -->
<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;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;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;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;tbbproxy_debug.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<!-- .dll files -->
<Target Name="TBBNuGet_CopyDebugDllsToOutDir" Condition="$(Configuration.ToLower().Contains('debug'))" BeforeTargets="PrepareForRun">
<ItemGroup Condition="(Exists('packages.config') OR
Exists('$(MSBuildProjectName).packages.config') OR
Exists('packages.$(MSBuildProjectName).config'))">
<FilesToCopy Include="$(MSBuildThisFileDirectory)\..\..\runtimes\win-x86\native\*.dll" Condition="'$(Platform)' == 'Win32'"/>
<FilesToCopy Include="$(MSBuildThisFileDirectory)\..\..\runtimes\win-x64\native\*.dll" Condition="'$(Platform)' == 'x64'"/>
</ItemGroup>
<Copy SourceFiles="@(FilesToCopy)" SkipUnchangedFiles="true" DestinationFolder="$(OutDir)"/>
</Target>
</Project>
@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2019-2021 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="TBBNuGet_CopyReleaseDllsToOutDir" BeforeTargets="PrepareForRun">
<ItemGroup Condition="(Exists('packages.config') OR
Exists('$(MSBuildProjectName).packages.config') OR
Exists('packages.$(MSBuildProjectName).config'))">
<FilesToCopy Include="$(MSBuildThisFileDirectory)\..\..\runtimes\win-x86\native\*.dll" Condition="'$(Platform)' == 'Win32'"/>
<FilesToCopy Include="$(MSBuildThisFileDirectory)\..\..\runtimes\win-x64\native\*.dll" Condition="'$(Platform)' == 'x64'"/>
</ItemGroup>
<Copy SourceFiles="@(FilesToCopy)" SkipUnchangedFiles="true" DestinationFolder="$(OutDir)"/>
</Target>
</Project>
@@ -1,18 +0,0 @@
@echo off
REM
REM Copyright (c) 2019-2021 Intel Corporation
REM
REM Licensed under the Apache License, Version 2.0 (the "License");
REM you may not use this file except in compliance with the License.
REM You may obtain a copy of the License at
REM
REM http://www.apache.org/licenses/LICENSE-2.0
REM
REM Unless required by applicable law or agreed to in writing, software
REM distributed under the License is distributed on an "AS IS" BASIS,
REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
REM See the License for the specific language governing permissions and
REM limitations under the License.
REM
exit /B 0
+1 -1
View File
@@ -28,7 +28,7 @@ set_target_properties(irml PROPERTIES VERSION 1)
target_include_directories(irml
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
$<INSTALL_INTERFACE:include>)
target_compile_options(irml
PRIVATE
+1 -24
View File
@@ -66,7 +66,7 @@ endif()
target_include_directories(tbb
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
$<INSTALL_INTERFACE:include>)
target_compile_options(tbb
PRIVATE
@@ -77,7 +77,6 @@ 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.
@@ -96,14 +95,12 @@ 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()
@@ -134,26 +131,6 @@ if (WIN32)
RENAME tbb_debug.lib
COMPONENT devel
)
else()
set(TBB_LIB_NAME tbb)
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILD_TYPE)
if (BUILD_TYPE STREQUAL "debug")
set(TBB_LIB_NAME ${TBB_LIB_NAME}${CMAKE_DEBUG_POSTFIX})
endif()
if (IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
set(_libdir_for_pc_file "${CMAKE_INSTALL_LIBDIR}")
else()
set(_libdir_for_pc_file "\${prefix}/${CMAKE_INSTALL_LIBDIR}")
endif()
if (IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
set(_includedir_for_pc_file "${CMAKE_INSTALL_INCLUDEDIR}")
else()
set(_includedir_for_pc_file "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
endif()
configure_file(${CMAKE_SOURCE_DIR}/integration/pkg-config/tbb.pc.in ${CMAKE_CURRENT_BINARY_DIR}/${TBB_LIB_NAME}.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${TBB_LIB_NAME}.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
endif()
if (COMMAND tbb_gen_vars)
+11 -31
View File
@@ -119,11 +119,6 @@ void arena::process(thread_data& tls) {
}
__TBB_ASSERT( index >= my_num_reserved_slots, "Workers cannot occupy reserved slots" );
tls.attach_arena(*this, index);
// worker thread enters the dispatch loop to look for a work
tls.my_inbox.set_is_idle(true);
if (tls.my_arena_slot->is_task_pool_published()) {
tls.my_inbox.set_is_idle(false);
}
task_dispatcher& task_disp = tls.my_arena_slot->default_task_dispatcher();
task_disp.set_stealing_threshold(calculate_stealing_threshold());
@@ -136,10 +131,6 @@ void arena::process(thread_data& tls) {
// Waiting on special object tied to this arena
outermost_worker_waiter waiter(*this);
d1::task* t = tls.my_task_dispatcher->local_wait_for_all(nullptr, waiter);
// For purposes of affinity support, the slot's mailbox is considered idle while no thread is
// attached to it.
tls.my_inbox.set_is_idle(true);
__TBB_ASSERT_EX(t == nullptr, "Outermost worker must not leave dispatch loop with a task");
__TBB_ASSERT(governor::is_thread_data_set(&tls), nullptr);
__TBB_ASSERT(tls.my_task_dispatcher == &task_disp, nullptr);
@@ -232,13 +223,14 @@ void arena::free_arena () {
__TBB_ASSERT( !my_global_concurrency_mode, NULL );
#endif
poison_value( my_guard );
std::intptr_t drained = 0;
for ( unsigned i = 0; i < my_num_slots; ++i ) {
// __TBB_ASSERT( !my_slots[i].my_scheduler, "arena slot is not empty" );
// TODO: understand the assertion and modify
// __TBB_ASSERT( my_slots[i].task_pool == EmptyTaskPool, NULL );
__TBB_ASSERT( my_slots[i].head == my_slots[i].tail, NULL ); // TODO: replace by is_quiescent_local_task_pool_empty
my_slots[i].free_task_pool();
mailbox(i).drain();
drained += mailbox(i).drain();
my_slots[i].my_default_task_dispatcher->~task_dispatcher();
}
__TBB_ASSERT(my_fifo_task_stream.empty(), "Not all enqueued tasks were executed");
@@ -395,7 +387,7 @@ struct task_arena_impl {
static void execute(d1::task_arena_base&, d1::delegate_base&);
static void wait(d1::task_arena_base&);
static int max_concurrency(const d1::task_arena_base*);
static void enqueue(d1::task&, d1::task_group_context*, d1::task_arena_base*);
static void enqueue(d1::task&, d1::task_arena_base*);
};
void __TBB_EXPORTED_FUNC initialize(d1::task_arena_base& ta) {
@@ -419,11 +411,7 @@ int __TBB_EXPORTED_FUNC max_concurrency(const d1::task_arena_base* ta) {
}
void __TBB_EXPORTED_FUNC enqueue(d1::task& t, d1::task_arena_base* ta) {
task_arena_impl::enqueue(t, nullptr, ta);
}
void __TBB_EXPORTED_FUNC enqueue(d1::task& t, d1::task_group_context& ctx, d1::task_arena_base* ta) {
task_arena_impl::enqueue(t, &ctx, ta);
task_arena_impl::enqueue(t, ta);
}
void task_arena_impl::initialize(d1::task_arena_base& ta) {
@@ -493,20 +481,14 @@ bool task_arena_impl::attach(d1::task_arena_base& ta) {
return false;
}
void task_arena_impl::enqueue(d1::task& t, d1::task_group_context* c, d1::task_arena_base* ta) {
void task_arena_impl::enqueue(d1::task& t, d1::task_arena_base* ta) {
thread_data* td = governor::get_thread_data(); // thread data is only needed for FastRandom instance
assert_pointer_valid(td, "thread_data pointer should not be null");
arena* a = ta ?
ta->my_arena.load(std::memory_order_relaxed)
: td->my_arena
;
assert_pointer_valid(a, "arena pointer should not be null");
auto* ctx = c ? c : a->my_default_ctx;
assert_pointer_valid(ctx, "context pointer should not be null");
// Is there a better place for checking the state of ctx?
arena* a = ta->my_arena.load(std::memory_order_relaxed);
assert_pointers_valid(ta, a, a->my_default_ctx, td);
// Is there a better place for checking the state of my_default_ctx?
__TBB_ASSERT(!a->my_default_ctx->is_group_execution_cancelled(),
"The task will not be executed because its task_group_context is cancelled.");
a->enqueue_task(t, *ctx, *td);
"The task will not be executed because default task_group_context of task_arena is cancelled. Has previously enqueued task thrown an exception?");
a->enqueue_task(t, *a->my_default_ctx, *td);
}
class nested_arena_context : no_copy {
@@ -521,8 +503,6 @@ public:
td.detach_task_dispatcher();
td.attach_arena(nested_arena, slot_index);
if (td.my_inbox.is_idle_state(true))
td.my_inbox.set_is_idle(false);
task_dispatcher& task_disp = td.my_arena_slot->default_task_dispatcher();
task_disp.set_stealing_threshold(m_orig_execute_data_ext.task_disp->m_stealing_threshold);
td.attach_task_dispatcher(task_disp);
@@ -576,7 +556,6 @@ public:
td.attach_arena(*m_orig_arena, m_orig_slot_index);
td.attach_task_dispatcher(*m_orig_execute_data_ext.task_disp);
__TBB_ASSERT(td.my_inbox.is_idle_state(false), nullptr);
}
td.my_task_dispatcher->m_execute_data_ext = m_orig_execute_data_ext;
}
@@ -775,3 +754,4 @@ void isolate_within_arena(d1::delegate_base& d, std::intptr_t isolation) {
} // namespace r1
} // namespace detail
} // namespace tbb
+2 -2
View File
@@ -576,10 +576,10 @@ inline d1::task* arena::steal_task(unsigned arena_index, FastRandom& frnd, execu
tp.allocator.delete_object(&tp, ed);
return nullptr;
}
// Note affinity is called for any stolen task (proxy or general)
// Note affinity is called for any stealed task (proxy or general)
ed.affinity_slot = slot;
} else {
// Note affinity is called for any stolen task (proxy or general)
// Note affinity is called for any stealed task (proxy or general)
ed.affinity_slot = d1::any_slot;
}
// Update task owner thread id to identify stealing
+7 -21
View File
@@ -18,7 +18,6 @@
#define __TBB_assert_impl_H
#include "oneapi/tbb/detail/_config.h"
#include "oneapi/tbb/detail/_utils.h"
#include <cstdio>
#include <cstdlib>
@@ -36,10 +35,11 @@ namespace r1 {
// TODO: consider extension for formatted error description string
static void assertion_failure_impl(const char* location, int line, const char* expression, const char* comment) {
std::fprintf(stderr, "Assertion %s failed (located in the %s function, line in file: %d)\n",
expression, location, line);
if (line != 0) {
std::fprintf(stderr, "Assertion %s failed on line %d of file %s\n", expression, line, location);
} else {
std::fprintf(stderr, "Assertion %s failed during the %s function execution\n", expression, location);
}
if (comment) {
std::fprintf(stderr, "Detailed description: %s\n", comment);
}
@@ -54,23 +54,9 @@ static void assertion_failure_impl(const char* location, int line, const char* e
}
}
// Do not move the definition into the assertion_failure function because it will require "magic statics".
// It will bring a dependency on C++ runtime on some platforms while assert_impl.h is reused in tbbmalloc
// that should not depend on C++ runtime
static std::atomic<do_once_state> assertion_state;
void __TBB_EXPORTED_FUNC assertion_failure(const char* location, int line, const char* expression, const char* comment) {
#if __TBB_MSVC_UNREACHABLE_CODE_IGNORED
// Workaround for erroneous "unreachable code" during assertion throwing using call_once
#pragma warning (push)
#pragma warning (disable: 4702)
#endif
// We cannot use std::call_once because it brings a dependency on C++ runtime on some platforms
// while assert_impl.h is reused in tbbmalloc that should not depend on C++ runtime
atomic_do_once([&](){ assertion_failure_impl(location, line, expression, comment); }, assertion_state);
#if __TBB_MSVC_UNREACHABLE_CODE_IGNORED
#pragma warning (pop)
#endif
static std::once_flag flag;
std::call_once(flag, [&](){ assertion_failure_impl(location, line, expression, comment); });
}
//! Report a runtime warning.
+2 -8
View File
@@ -121,7 +121,7 @@ public:
#if _WIN32 || _WIN64
/* [[noreturn]] */ void __stdcall co_local_wait_for_all(void* arg) noexcept;
#else
/* [[noreturn]] */ void co_local_wait_for_all(unsigned hi, unsigned lo) noexcept;
/* [[noreturn]] */ void co_local_wait_for_all(void* arg) noexcept;
#endif
#if _WIN32 || _WIN64
@@ -180,13 +180,7 @@ inline void create_coroutine(coroutine_type& c, std::size_t stack_size, void* ar
c.my_context.uc_stack.ss_flags = 0;
typedef void(*coroutine_func_t)();
std::uintptr_t addr = std::uintptr_t(arg);
unsigned lo = unsigned(addr);
unsigned hi = unsigned(std::uint64_t(addr) >> 32);
__TBB_ASSERT(sizeof(addr) == 8 || hi == 0, nullptr);
makecontext(&c.my_context, (coroutine_func_t)co_local_wait_for_all, 2, hi, lo);
makecontext(&c.my_context, (coroutine_func_t)co_local_wait_for_all, sizeof(arg) / sizeof(int), arg);
}
inline void current_coroutine(coroutine_type& c) {
+2 -2
View File
@@ -58,8 +58,8 @@ void __TBB_EXPORTED_FUNC wait_bounded_queue_monitor( concurrent_monitor* monitor
}
void __TBB_EXPORTED_FUNC abort_bounded_queue_monitors( concurrent_monitor* monitors ) {
concurrent_monitor& items_avail = monitors[d2::cbq_items_avail_tag];
concurrent_monitor& slots_avail = monitors[d2::cbq_slots_avail_tag];
concurrent_monitor& items_avail = monitors[d1::cbq_items_avail_tag];
concurrent_monitor& slots_avail = monitors[d1::cbq_slots_avail_tag];
items_avail.abort_all();
slots_avail.abort_all();
+2 -8
View File
@@ -31,7 +31,7 @@ namespace r1 {
//! Circular doubly-linked list with sentinel
/** head.next points to the front and head.prev points to the back */
class circular_doubly_linked_list_with_sentinel {
class circular_doubly_linked_list_with_sentinel : no_copy {
public:
struct base_node {
base_node* next;
@@ -44,9 +44,6 @@ public:
// ctor
constexpr circular_doubly_linked_list_with_sentinel() : count(0), head(&head, &head) {}
circular_doubly_linked_list_with_sentinel(const circular_doubly_linked_list_with_sentinel&) = delete;
circular_doubly_linked_list_with_sentinel& operator=(const circular_doubly_linked_list_with_sentinel&) = delete;
inline std::size_t size() const { return count.load(std::memory_order_relaxed); }
inline bool empty() const { return size() == 0; }
inline base_node* front() const { return head.next; }
@@ -190,16 +187,13 @@ private:
//! concurrent_monitor
/** fine-grained concurrent_monitor implementation */
template <typename Context>
class concurrent_monitor_base {
class concurrent_monitor_base : no_copy {
public:
//! ctor
constexpr concurrent_monitor_base() {}
//! dtor
~concurrent_monitor_base() = default;
concurrent_monitor_base(const concurrent_monitor_base&) = delete;
concurrent_monitor_base& operator=(const concurrent_monitor_base&) = delete;
//! prepare wait by inserting 'thr' into the wait queue
void prepare_wait( wait_node<Context>& node) {
// TODO: consider making even more lazy instantiation of the semaphore, that is only when it is actually needed, e.g. move it in node::wait()
-1
View File
@@ -103,7 +103,6 @@ _ZN3tbb6detail2r17executeERNS0_2d115task_arena_baseERNS2_13delegate_baseE;
_ZN3tbb6detail2r19terminateERNS0_2d115task_arena_baseE;
_ZN3tbb6detail2r120isolate_within_arenaERNS0_2d113delegate_baseEi;
_ZN3tbb6detail2r17enqueueERNS0_2d14taskEPNS2_15task_arena_baseE;
_ZN3tbb6detail2r17enqueueERNS0_2d14taskERNS2_18task_group_contextEPNS2_15task_arena_baseE;
_ZN3tbb6detail2r14waitERNS0_2d115task_arena_baseE;
/* System topology parsing and threads pinning (governor.cpp) */
-1
View File
@@ -103,7 +103,6 @@ _ZN3tbb6detail2r17executeERNS0_2d115task_arena_baseERNS2_13delegate_baseE;
_ZN3tbb6detail2r19terminateERNS0_2d115task_arena_baseE;
_ZN3tbb6detail2r120isolate_within_arenaERNS0_2d113delegate_baseEl;
_ZN3tbb6detail2r17enqueueERNS0_2d14taskEPNS2_15task_arena_baseE;
_ZN3tbb6detail2r17enqueueERNS0_2d14taskERNS2_18task_group_contextEPNS2_15task_arena_baseE;
_ZN3tbb6detail2r14waitERNS0_2d115task_arena_baseE;
/* System topology parsing and threads pinning (governor.cpp) */
-1
View File
@@ -105,7 +105,6 @@ __ZN3tbb6detail2r17executeERNS0_2d115task_arena_baseERNS2_13delegate_baseE
__ZN3tbb6detail2r19terminateERNS0_2d115task_arena_baseE
__ZN3tbb6detail2r120isolate_within_arenaERNS0_2d113delegate_baseEl
__ZN3tbb6detail2r17enqueueERNS0_2d14taskEPNS2_15task_arena_baseE
__ZN3tbb6detail2r17enqueueERNS0_2d14taskERNS2_18task_group_contextEPNS2_15task_arena_baseE
__ZN3tbb6detail2r14waitERNS0_2d115task_arena_baseE
# System topology parsing and threads pinning (governor.cpp)
-1
View File
@@ -98,7 +98,6 @@ EXPORTS
?max_concurrency@r1@detail@tbb@@YAHPBVtask_arena_base@d1@23@@Z
?terminate@r1@detail@tbb@@YAXAAVtask_arena_base@d1@23@@Z
?wait@r1@detail@tbb@@YAXAAVtask_arena_base@d1@23@@Z
?enqueue@r1@detail@tbb@@YAXAAVtask@d1@23@AAVtask_group_context@523@PAVtask_arena_base@523@@Z
; System topology parsing and threads pinning (governor.cpp)
?numa_node_count@r1@detail@tbb@@YAIXZ
-1
View File
@@ -98,7 +98,6 @@ EXPORTS
?attach@r1@detail@tbb@@YA_NAEAVtask_arena_base@d1@23@@Z
?isolate_within_arena@r1@detail@tbb@@YAXAEAVdelegate_base@d1@23@_J@Z
?enqueue@r1@detail@tbb@@YAXAEAVtask@d1@23@PEAVtask_arena_base@523@@Z
?enqueue@r1@detail@tbb@@YAXAEAVtask@d1@23@AEAVtask_group_context@523@PEAVtask_arena_base@523@@Z
; System topology parsing and threads pinning (governor.cpp)
?numa_node_count@r1@detail@tbb@@YAIXZ
+1 -1
View File
@@ -379,7 +379,7 @@ namespace r1 {
static dynamic_link_handle global_symbols_link( const char* library, const dynamic_link_descriptor descriptors[], std::size_t required ) {
dynamic_link_handle library_handle{};
#if _WIN32
auto res = GetModuleHandleEx(0, library, &library_handle);
bool res = GetModuleHandleEx(0, library, &library_handle);
__TBB_ASSERT_EX(res && library_handle || !res && !library_handle, nullptr);
#else /* _WIN32 */
#if !__TBB_DYNAMIC_LOAD_ENABLED /* only __TBB_WEAK_SYMBOLS_PRESENT is defined */
-10
View File
@@ -48,12 +48,6 @@ const char* missing_wait::what() const noexcept(true) { return "wait() was not c
/*[[noreturn]]*/ void do_throw_noexcept(void (*throw_func)()) noexcept {
throw_func();
#if __GNUC__ == 7
// In release, GCC 7 loses noexcept attribute during tail call optimization.
// The following statement prevents tail call optimization.
volatile bool reach_this_point = true;
suppress_unused_warning(reach_this_point);
#endif
}
bool terminate_on_exception(); // defined in global_control.cpp and ipc_server.cpp
@@ -90,10 +84,6 @@ void throw_exception ( exception_id eid ) {
case exception_id::bad_tagged_msg_cast: DO_THROW(std::runtime_error, ("Illegal tagged_msg cast")); break;
#if __TBB_SUPPORTS_WORKERS_WAITING_IN_TERMINATE
case exception_id::unsafe_wait: DO_THROW(unsafe_wait, ("Unsafe to wait further")); break;
#endif
#if __TBB_PREVIEW_TASK_GROUP_EXTENSIONS
case exception_id::bad_task_handle: DO_THROW(std::runtime_error, ("Attempt to schedule empty task_handle")); break;
case exception_id::bad_task_handle_wrong_task_group: DO_THROW(std::runtime_error, ("Attempt to schedule task_handle into different task_group")); break;
#endif
default: __TBB_ASSERT ( false, "Unknown exception ID" );
}
-2
View File
@@ -176,7 +176,6 @@ void governor::init_external_thread() {
// External thread always occupies the first slot
thread_data& td = *new(cache_aligned_allocate(sizeof(thread_data))) thread_data(0, false);
td.attach_arena(a, /*slot index*/ 0);
__TBB_ASSERT(td.my_inbox.is_idle_state(false), nullptr);
stack_size = a.my_market->worker_stack_size();
std::uintptr_t stack_base = get_stack_base(stack_size);
@@ -240,7 +239,6 @@ void release_impl(d1::task_scheduler_handle& handle) {
}
bool finalize_impl(d1::task_scheduler_handle& handle) {
__TBB_ASSERT_RELEASE(handle, "trying to finalize with null handle");
market::global_market_mutex_type::scoped_lock lock( market::theMarketMutex );
bool ok = true; // ok if theMarket does not exist yet
market* m = market::theMarket; // read the state of theMarket
+5 -2
View File
@@ -20,6 +20,7 @@
#include "oneapi/tbb/cache_aligned_allocator.h"
#include "oneapi/tbb/detail/_small_object_pool.h"
#include "arena_slot.h"
#include "scheduler_common.h"
#include <atomic>
@@ -186,12 +187,14 @@ public:
}
//! Drain the mailbox
void drain() {
intptr_t drain() {
intptr_t k = 0;
// No fences here because other threads have already quit.
for( ; task_proxy* t = my_first; ) {
for( ; task_proxy* t = my_first; ++k ) {
my_first.store(t->next_in_mailbox, std::memory_order_relaxed);
// cache_aligned_deallocate((char*)t - task_prefix_reservation_size);
}
return k;
}
//! True if thread that owns this mailbox is looking for work.
-1
View File
@@ -283,7 +283,6 @@ static const dynamic_link_descriptor ProcessorGroupsApiLinkTable[] = {
};
static void initialize_hardware_concurrency_info () {
suppress_unused_warning(TBB_ALL_PROCESSOR_GROUPS);
#if __TBB_WIN8UI_SUPPORT
// For these applications processor groups info is unavailable
// Setting up a number of processors for one processor group

Some files were not shown because too many files have changed in this diff Show More