Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4fbacf34a3 | ||
|
|
0bfcf0f669 | ||
|
|
a85e2d6fa7 |
@@ -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
|
||||
@@ -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
|
||||
@@ -1,5 +1,5 @@
|
||||
# oneAPI Threading Building Blocks
|
||||
[](LICENSE.txt) [](https://github.com/oneapi-src/oneTBB/actions/workflows/ci.yml?query=branch%3Amaster)
|
||||
[](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
@@ -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
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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; }
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "detail/_config.h"
|
||||
#include "detail/_namespace_injection.h"
|
||||
#include "detail/_mutex_common.h"
|
||||
|
||||
namespace tbb {
|
||||
namespace detail {
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "detail/_config.h"
|
||||
#include "detail/_namespace_injection.h"
|
||||
#include "detail/_mutex_common.h"
|
||||
|
||||
namespace tbb {
|
||||
namespace detail {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#define __TBB_spin_mutex_H
|
||||
|
||||
#include "detail/_namespace_injection.h"
|
||||
#include "detail/_mutex_common.h"
|
||||
|
||||
#include "profiling.h"
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#define __TBB_spin_rw_mutex_H
|
||||
|
||||
#include "detail/_namespace_injection.h"
|
||||
#include "detail/_mutex_common.h"
|
||||
|
||||
#include "profiling.h"
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
Vendored
+59
-28
@@ -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
|
||||
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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
|
||||
Vendored
+23
-8
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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) */
|
||||
|
||||
@@ -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) */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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" );
|
||||
}
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user