diff --git a/CHANGES b/CHANGES index 5eae7dd..2acb3a1 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,27 @@ The list of most significant changes made over time in Intel(R) Threading Building Blocks (Intel(R) TBB). +Intel TBB 4.4 Update 5 +TBB_INTERFACE_VERSION == 9005 + +Changes (w.r.t. Intel TBB 4.4 Update 4): + +- Modified graph/fgbzip2 example to remove unnecessary data queuing. + +Preview Features: + +- Added a Python* module which is able to replace Python's thread pool + class with the implementation based on Intel TBB task scheduler. + +Bugs fixed: + +- Fixed the implementation of 64-bit tbb::atomic for IA-32 architecture + to work correctly with GCC 5.2 in C++11/14 mode. +- Fixed a possible crash when tasks with affinity (e.g. specified via + affinity_partitioner) are used simultaneously with task priority + changes. + +------------------------------------------------------------------------ Intel TBB 4.4 Update 4 TBB_INTERFACE_VERSION == 9004 diff --git a/Makefile b/Makefile index 38f1c3c..8198698 100644 --- a/Makefile +++ b/Makefile @@ -54,6 +54,10 @@ rml: mkdir examples: tbb tbbmalloc $(MAKE) -C examples -r -f Makefile tbb_root=.. release test +python: mkdir + $(MAKE) -C "$(work_dir)_release" -r -f $(tbb_root)/build/Makefile.tbb cfg=release + bash -c ". $(work_dir)_release$(SLASH)tbbvars.sh && $(MAKE) -rC '$(full_tbb_root)/python' CXX=$(compiler) install test-install" + .PHONY: clean clean_examples mkdir info clean: clean_examples diff --git a/README.md b/README.md index 9276d9d..f7d4110 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Build Status](https://travis-ci.org/wjakob/tbb.svg?branch=master)](https://travis-ci.org/wjakob/tbb) [![Build status](https://ci.appveyor.com/api/projects/status/fvepmk5nxekq27r8?svg=true)](https://ci.appveyor.com/project/wjakob/tbb/branch/master) -This is git repository is currently based on TBB 4.4 Update 4 and will be +This is git repository is currently based on TBB 4.4 Update 5 and will be updated from time to time to track the most recent release. The only modification is the addition of a CMake-based build system. diff --git a/build/index.html b/build/index.html index 32b34c5..e696580 100644 --- a/build/index.html +++ b/build/index.html @@ -45,6 +45,8 @@ To port Intel TBB to a new platform, operating system or architecture, see the <
  • GNU make utility. On Windows OS, if a UNIX* emulator is used to run GNU make, it should be able to run Windows OS utilities and commands. On Linux OS, OS X, etc., shell commands issued by GNU make should execute in a Bourne or BASH compatible shell. + In the following examples, replace make with the correct GNU make command for + your system (for example, gmake). GNU make version 3.80 and more recent are supported.

    @@ -57,7 +59,7 @@ On systems that support both 64-bit and 32-bit libraries, these steps build the

  • Change to the top-level directory of the installed software.
  • If using the Intel® C++ compiler, make sure the appropriate compiler is available in your PATH (e.g., by sourcing the appropriate iccvars script for the compiler to be used). -
  • Invoke GNU make using no arguments, for example, 'gmake'. +
  • Invoke GNU make using no arguments, for example, make.

    @@ -68,15 +70,15 @@ or related systems that support both 64-bit and 32-bit libraries), perform the f

  • Change to the top-level directory of the installed software.
  • If using the Intel® C++ compiler, make sure the appropriate compiler is available in your PATH (e.g., by sourcing the appropriate iccvars script for the compiler to be used). -
  • Invoke GNU make as follows, 'gmake arch=ia32'. +
  • Explicitly specify the architecture when invoking GNU make, e.g. make arch=ia32.

    The default make target will build the release and debug versions of the Intel TBB library.

    Other targets are available in the top-level Makefile. You might find the following targets useful:

    See also the list of other targets below.

    @@ -100,9 +102,9 @@ To perform different build and/or test operations, use the following steps.
  • Invoke GNU make by using one or more of the following commands.
    make -
    Default build. Equivalent to 'make tbb tbbmalloc'. +
    Default build. Equivalent to make tbb tbbmalloc.
    make all -
    Equivalent to 'make tbb tbbmalloc test examples'. +
    Equivalent to make tbb tbbmalloc test examples.
    cd src;make release
    Build and test release libraries only.
    cd src;make debug @@ -114,7 +116,9 @@ To perform different build and/or test operations, use the following steps.
    make test
    Compile and run unit-tests
    make examples -
    Build libraries and run all examples, like doing 'make debug clean release' from the general example Makefile. +
    Build libraries and run all examples, like doing make debug clean release from the general example Makefile. +
    make python +
    Build, install, and test Python* API for Intel TBB. See details here.
    make compiler={icl, icc, gcc, clang} [(above options or targets)]
    Build and run as above, but use specified compilers instead of default, native compilers
      @@ -137,7 +141,7 @@ To perform different build and/or test operations, use the following steps.
      Build and run as above, but build libraries for the selected ABI. Might be useful for cross-compilation; ensure proper environment is set before running this command.
      make tbb_root={(Intel TBB directory)} [(above options or targets)] -
      Build and run as above; for use when invoking 'make' from a directory other than the top-level directory. +
      Build and run as above; for use when invoking make from a directory other than the top-level directory.
      make tbb_build_dir={(build directory)} [(above options or targets)]
      Build and run as above, but place the built libraries in the specified directory, rather than in the default sub-directory within the build/ directory. This command might have troubles with the build in case the sources installed to the directory with spaces in the path.
      make tbb_build_prefix={(build sub-directory)} [(above options or targets)] @@ -229,8 +233,7 @@ See the Makefile infrastructure files for examples.

      Copyright © 2005-2016 Intel Corporation. All Rights Reserved.

      -Intel and Itanium are registered trademarks or trademarks of Intel Corporation or its -subsidiaries in the United States and other countries. +Intel, the Intel logo and Itanium are trademarks of Intel Corporation in the U.S. and/or other countries.

      * Other names and brands may be claimed as the property of others. diff --git a/build/ios.macos.inc b/build/ios.macos.inc index f03bd8c..95b3bad 100644 --- a/build/ios.macos.inc +++ b/build/ios.macos.inc @@ -20,7 +20,7 @@ ifneq ($(arch),$(filter $(arch),ia32 intel64 armv7 armv7s arm64)) $(error $(arch) is unknown architecture. Known arhitechtures are ia32 intel64 armv7 armv7s arm64) endif -# if target is ios but arch is ia32/intel64 then build for 32/64 simulator! +# If target is ios but arch is ia32/intel64 then build for 32/64 simulator! ifeq (,$(SDKROOT)) ifeq ($(arch),$(filter $(arch),ia32 intel64)) export SDKROOT:=$(shell xcodebuild -sdk -version | grep -o -E '/.*SDKs/iPhoneSimulator.*' 2>/dev/null) diff --git a/build/linux.icc.inc b/build/linux.icc.inc index 1bae169..593608d 100644 --- a/build/linux.icc.inc +++ b/build/linux.icc.inc @@ -70,7 +70,10 @@ ifeq (ia64,$(arch)) # strict-ansi does not work with on RHEL 4 AS CPLUS_FLAGS += $(PIC_KEY) $(if $(findstring cc3.,$(runtime)),-ansi,-strict-ansi) else - CPLUS_FLAGS += -strict-ansi +# For ICC 16 and older, -strict-ansi does not work with GNU C++ library headers +# in std=c++14 mode, use -ansi for them +# egrep returns 0 or 1, compare it in concatenation + CPLUS_FLAGS += $(if $(findstring c++14_1,$(stdver)_$(shell icc -dumpversion| egrep -c "^1[1-6]\.")),-ansi,-strict-ansi) endif ifneq (,$(codecov)) diff --git a/doc/Release_Notes.txt b/doc/Release_Notes.txt index a8870b4..511d1d0 100644 --- a/doc/Release_Notes.txt +++ b/doc/Release_Notes.txt @@ -169,9 +169,8 @@ Library Issues ------------------------------------------------------------------------ (C) 2016 Intel Corporation -Intel, Xeon and Pentium are registered trademarks or trademarks of -Intel Corporation or its subsidiaries in the United States and other -countries. +Intel, the Intel logo, Intel Core, Xeon, Xeon Phi and Pentium are +trademarks of Intel Corporation in the U.S. and/or other countries. * Other names and brands may be claimed as the property of others. diff --git a/examples/common/examples-common.inc b/examples/common/examples-common.inc index a0c1c9f..b0b0a37 100644 --- a/examples/common/examples-common.inc +++ b/examples/common/examples-common.inc @@ -17,7 +17,7 @@ # reasons why the executable file might be covered by the GNU General Public License. # detect if a compiler can support C++11 -# if CXX0XFLAGS already set, do not change it +# If CXX0XFLAGS already set, do not change it ifneq (,$(findstring $(CXX), icc icpc clang++)) # every supported icc or clang is OK CXX0XFLAGS ?= -std=c++0x diff --git a/examples/graph/fgbzip2/fgbzip2.cpp b/examples/graph/fgbzip2/fgbzip2.cpp index 513a640..e4b43d4 100644 --- a/examples/graph/fgbzip2/fgbzip2.cpp +++ b/examples/graph/fgbzip2/fgbzip2.cpp @@ -54,6 +54,10 @@ struct buffer_t { bool operator==( const buffer_t& other ) { return (this == &other) || (seq_id == other.seq_id && len == other.len && b == other.b); } + + bool operator!=(const buffer_t& other) { + return !(*this == other); + } }; buffer_t dummyBuffer = {0}; @@ -106,28 +110,13 @@ public: IOActivity( std::ifstream& inputStream, std::ofstream& output, size_t chunkSize ) : my_inputStream(inputStream), my_outputStream(output), my_chunkSize(chunkSize), my_fileWriter( [this]() { - std::priority_queue< buffer_t, std::vector, buffer_comp > my_outputQueue; - size_t my_nextOutputId = 0; - - while( true ) { - buffer_t buffer; - my_writeQueue.pop( buffer ); - if( buffer == dummyBuffer ) break; - if( buffer.seq_id == my_nextOutputId ) { - my_outputStream.write( buffer.b, buffer.len ); - delete[] buffer.b; - ++my_nextOutputId; - while( !my_outputQueue.empty() && my_outputQueue.top().seq_id == my_nextOutputId ) { - buffer = my_outputQueue.top(); - my_outputQueue.pop(); - my_outputStream.write( buffer.b, buffer.len ); - delete[] buffer.b; - ++my_nextOutputId; - } - } else { - my_outputQueue.push( buffer ); - } - } + buffer_t buffer; + my_writeQueue.pop(buffer); + while (buffer != dummyBuffer) { + my_outputStream.write(buffer.b, buffer.len); + delete[] buffer.b; + my_writeQueue.pop(buffer); + }; }) {} @@ -191,7 +180,8 @@ void fgCompressionAsyncIO( std::ifstream& inputStream, std::ofstream& outputStre return buffer.seq_id; }); - async_file_writer_node output_writer( g, tbb::flow::unlimited, [&ioActivity](const buffer_t& buffer, async_file_writer_node::async_gateway_type& asyncGateway ) { + // The node is serial to preserve the right order of buffers set by the preceding sequencer_node + async_file_writer_node output_writer( g, tbb::flow::serial, [&ioActivity](const buffer_t& buffer, async_file_writer_node::async_gateway_type& asyncGateway ) { ioActivity.write( buffer ); }); diff --git a/examples/parallel_for/game_of_life/msvs/resource.h b/examples/parallel_for/game_of_life/msvs/resource.h index d5ac7c4..031c527 100644 --- a/examples/parallel_for/game_of_life/msvs/resource.h +++ b/examples/parallel_for/game_of_life/msvs/resource.h @@ -1,3 +1,23 @@ +/* + Copyright 2005-2016 Intel Corporation. All Rights Reserved. + + This file is part of Threading Building Blocks. Threading Building Blocks is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. Threading Building Blocks is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. You should have received a copy of + the GNU General Public License along with Threading Building Blocks; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + As a special exception, you may use this file as part of a free software library without + restriction. Specifically, if other files instantiate templates or use macros or inline + functions from this file, or you compile this file and link it with other files to produce + an executable, this file does not by itself cause the resulting executable to be covered + by the GNU General Public License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General Public License. +*/ + //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by app.rc diff --git a/examples/parallel_for/polygon_overlay/msvs/resource.h b/examples/parallel_for/polygon_overlay/msvs/resource.h index e70b4ea..1ee7fd8 100644 --- a/examples/parallel_for/polygon_overlay/msvs/resource.h +++ b/examples/parallel_for/polygon_overlay/msvs/resource.h @@ -1,3 +1,23 @@ +/* + Copyright 2005-2016 Intel Corporation. All Rights Reserved. + + This file is part of Threading Building Blocks. Threading Building Blocks is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. Threading Building Blocks is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. You should have received a copy of + the GNU General Public License along with Threading Building Blocks; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + As a special exception, you may use this file as part of a free software library without + restriction. Specifically, if other files instantiate templates or use macros or inline + functions from this file, or you compile this file and link it with other files to produce + an executable, this file does not by itself cause the resulting executable to be covered + by the GNU General Public License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General Public License. +*/ + //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by pover.rc diff --git a/examples/parallel_for/seismic/msvs/resource.h b/examples/parallel_for/seismic/msvs/resource.h index 44453d7..c9e40b0 100644 --- a/examples/parallel_for/seismic/msvs/resource.h +++ b/examples/parallel_for/seismic/msvs/resource.h @@ -1,3 +1,23 @@ +/* + Copyright 2005-2016 Intel Corporation. All Rights Reserved. + + This file is part of Threading Building Blocks. Threading Building Blocks is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. Threading Building Blocks is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. You should have received a copy of + the GNU General Public License along with Threading Building Blocks; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + As a special exception, you may use this file as part of a free software library without + restriction. Specifically, if other files instantiate templates or use macros or inline + functions from this file, or you compile this file and link it with other files to produce + an executable, this file does not by itself cause the resulting executable to be covered + by the GNU General Public License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General Public License. +*/ + //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by SeismicSimulation.rc diff --git a/examples/parallel_for/tachyon/android/jni/Android.mk b/examples/parallel_for/tachyon/android/jni/Android.mk index 748fccf..9c30489 100644 --- a/examples/parallel_for/tachyon/android/jni/Android.mk +++ b/examples/parallel_for/tachyon/android/jni/Android.mk @@ -1,20 +1,20 @@ # Copyright 2005-2016 Intel Corporation. All Rights Reserved. # -# The source code contained or described herein and all documents related -# to the source code ("Material") are owned by Intel Corporation or its -# suppliers or licensors. Title to the Material remains with Intel -# Corporation or its suppliers and licensors. The Material is protected -# by worldwide copyright laws and treaty provisions. No part of the -# Material may be used, copied, reproduced, modified, published, uploaded, -# posted, transmitted, distributed, or disclosed in any way without -# Intel's prior express written permission. +# This file is part of Threading Building Blocks. Threading Building Blocks is free software; +# you can redistribute it and/or modify it under the terms of the GNU General Public License +# version 2 as published by the Free Software Foundation. Threading Building Blocks is +# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. You should have received a copy of +# the GNU General Public License along with Threading Building Blocks; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # -# No license under any patent, copyright, trade secret or other -# intellectual property right is granted to or conferred upon you by -# disclosure or delivery of the Materials, either expressly, by -# implication, inducement, estoppel or otherwise. Any license under such -# intellectual property rights must be express and approved by Intel in -# writing. +# As a special exception, you may use this file as part of a free software library without +# restriction. Specifically, if other files instantiate templates or use macros or inline +# functions from this file, or you compile this file and link it with other files to produce +# an executable, this file does not by itself cause the resulting executable to be covered +# by the GNU General Public License. This exception does not however invalidate any other +# reasons why the executable file might be covered by the GNU General Public License. # The original source for this example is diff --git a/examples/parallel_for/tachyon/android/jni/Application.mk b/examples/parallel_for/tachyon/android/jni/Application.mk index e697b2d..c55fdd4 100644 --- a/examples/parallel_for/tachyon/android/jni/Application.mk +++ b/examples/parallel_for/tachyon/android/jni/Application.mk @@ -1,20 +1,20 @@ # Copyright 2005-2016 Intel Corporation. All Rights Reserved. # -# The source code contained or described herein and all documents related -# to the source code ("Material") are owned by Intel Corporation or its -# suppliers or licensors. Title to the Material remains with Intel -# Corporation or its suppliers and licensors. The Material is protected -# by worldwide copyright laws and treaty provisions. No part of the -# Material may be used, copied, reproduced, modified, published, uploaded, -# posted, transmitted, distributed, or disclosed in any way without -# Intel's prior express written permission. +# This file is part of Threading Building Blocks. Threading Building Blocks is free software; +# you can redistribute it and/or modify it under the terms of the GNU General Public License +# version 2 as published by the Free Software Foundation. Threading Building Blocks is +# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. You should have received a copy of +# the GNU General Public License along with Threading Building Blocks; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # -# No license under any patent, copyright, trade secret or other -# intellectual property right is granted to or conferred upon you by -# disclosure or delivery of the Materials, either expressly, by -# implication, inducement, estoppel or otherwise. Any license under such -# intellectual property rights must be express and approved by Intel in -# writing. +# As a special exception, you may use this file as part of a free software library without +# restriction. Specifically, if other files instantiate templates or use macros or inline +# functions from this file, or you compile this file and link it with other files to produce +# an executable, this file does not by itself cause the resulting executable to be covered +# by the GNU General Public License. This exception does not however invalidate any other +# reasons why the executable file might be covered by the GNU General Public License. APP_ABI:= all APP_STL:=gnustl_shared diff --git a/examples/parallel_for/tachyon/android/jni/jni-engine.cpp b/examples/parallel_for/tachyon/android/jni/jni-engine.cpp index ce55c73..abad09a 100644 --- a/examples/parallel_for/tachyon/android/jni/jni-engine.cpp +++ b/examples/parallel_for/tachyon/android/jni/jni-engine.cpp @@ -1,21 +1,21 @@ /* Copyright 2005-2016 Intel Corporation. All Rights Reserved. - The source code contained or described herein and all documents related - to the source code ("Material") are owned by Intel Corporation or its - suppliers or licensors. Title to the Material remains with Intel - Corporation or its suppliers and licensors. The Material is protected - by worldwide copyright laws and treaty provisions. No part of the - Material may be used, copied, reproduced, modified, published, uploaded, - posted, transmitted, distributed, or disclosed in any way without - Intel's prior express written permission. + This file is part of Threading Building Blocks. Threading Building Blocks is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. Threading Building Blocks is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. You should have received a copy of + the GNU General Public License along with Threading Building Blocks; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - No license under any patent, copyright, trade secret or other - intellectual property right is granted to or conferred upon you by - disclosure or delivery of the Materials, either expressly, by - implication, inducement, estoppel or otherwise. Any license under such - intellectual property rights must be express and approved by Intel in - writing. + As a special exception, you may use this file as part of a free software library without + restriction. Specifically, if other files instantiate templates or use macros or inline + functions from this file, or you compile this file and link it with other files to produce + an executable, this file does not by itself cause the resulting executable to be covered + by the GNU General Public License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General Public License. */ /* diff --git a/examples/parallel_for/tachyon/android/src/com/intel/tbb/example/tachyon/tachyon.java b/examples/parallel_for/tachyon/android/src/com/intel/tbb/example/tachyon/tachyon.java index df6850b..070f9ba 100644 --- a/examples/parallel_for/tachyon/android/src/com/intel/tbb/example/tachyon/tachyon.java +++ b/examples/parallel_for/tachyon/android/src/com/intel/tbb/example/tachyon/tachyon.java @@ -1,21 +1,21 @@ /* Copyright 2005-2016 Intel Corporation. All Rights Reserved. - The source code contained or described herein and all documents related - to the source code ("Material") are owned by Intel Corporation or its - suppliers or licensors. Title to the Material remains with Intel - Corporation or its suppliers and licensors. The Material is protected - by worldwide copyright laws and treaty provisions. No part of the - Material may be used, copied, reproduced, modified, published, uploaded, - posted, transmitted, distributed, or disclosed in any way without - Intel's prior express written permission. + This file is part of Threading Building Blocks. Threading Building Blocks is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. Threading Building Blocks is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. You should have received a copy of + the GNU General Public License along with Threading Building Blocks; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - No license under any patent, copyright, trade secret or other - intellectual property right is granted to or conferred upon you by - disclosure or delivery of the Materials, either expressly, by - implication, inducement, estoppel or otherwise. Any license under such - intellectual property rights must be express and approved by Intel in - writing. + As a special exception, you may use this file as part of a free software library without + restriction. Specifically, if other files instantiate templates or use macros or inline + functions from this file, or you compile this file and link it with other files to produce + an executable, this file does not by itself cause the resulting executable to be covered + by the GNU General Public License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General Public License. */ /* diff --git a/examples/parallel_for/tachyon/msvs/resource.h b/examples/parallel_for/tachyon/msvs/resource.h index 5f70f0c..dd14356 100644 --- a/examples/parallel_for/tachyon/msvs/resource.h +++ b/examples/parallel_for/tachyon/msvs/resource.h @@ -1,3 +1,23 @@ +/* + Copyright 2005-2016 Intel Corporation. All Rights Reserved. + + This file is part of Threading Building Blocks. Threading Building Blocks is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. Threading Building Blocks is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. You should have received a copy of + the GNU General Public License along with Threading Building Blocks; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + As a special exception, you may use this file as part of a free software library without + restriction. Specifically, if other files instantiate templates or use macros or inline + functions from this file, or you compile this file and link it with other files to produce + an executable, this file does not by itself cause the resulting executable to be covered + by the GNU General Public License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General Public License. +*/ + #define IDC_MYICON 2 #define IDD_GUI 102 #define IDS_APP_TITLE 103 diff --git a/examples/parallel_for/tachyon/msvs/win8ui/App.xaml.cpp b/examples/parallel_for/tachyon/msvs/win8ui/App.xaml.cpp index 0450c3c..98fa60f 100644 --- a/examples/parallel_for/tachyon/msvs/win8ui/App.xaml.cpp +++ b/examples/parallel_for/tachyon/msvs/win8ui/App.xaml.cpp @@ -1,21 +1,21 @@ /* Copyright 2005-2016 Intel Corporation. All Rights Reserved. - The source code contained or described herein and all documents related - to the source code ("Material") are owned by Intel Corporation or its - suppliers or licensors. Title to the Material remains with Intel - Corporation or its suppliers and licensors. The Material is protected - by worldwide copyright laws and treaty provisions. No part of the - Material may be used, copied, reproduced, modified, published, uploaded, - posted, transmitted, distributed, or disclosed in any way without - Intel's prior express written permission. + This file is part of Threading Building Blocks. Threading Building Blocks is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. Threading Building Blocks is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. You should have received a copy of + the GNU General Public License along with Threading Building Blocks; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - No license under any patent, copyright, trade secret or other - intellectual property right is granted to or conferred upon you by - disclosure or delivery of the Materials, either expressly, by - implication, inducement, estoppel or otherwise. Any license under such - intellectual property rights must be express and approved by Intel in - writing. + As a special exception, you may use this file as part of a free software library without + restriction. Specifically, if other files instantiate templates or use macros or inline + functions from this file, or you compile this file and link it with other files to produce + an executable, this file does not by itself cause the resulting executable to be covered + by the GNU General Public License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General Public License. */ #include "DirectXPage.xaml.h" diff --git a/examples/parallel_for/tachyon/msvs/win8ui/App.xaml.h b/examples/parallel_for/tachyon/msvs/win8ui/App.xaml.h index 0d1352d..084062a 100644 --- a/examples/parallel_for/tachyon/msvs/win8ui/App.xaml.h +++ b/examples/parallel_for/tachyon/msvs/win8ui/App.xaml.h @@ -1,21 +1,21 @@ /* Copyright 2005-2016 Intel Corporation. All Rights Reserved. - The source code contained or described herein and all documents related - to the source code ("Material") are owned by Intel Corporation or its - suppliers or licensors. Title to the Material remains with Intel - Corporation or its suppliers and licensors. The Material is protected - by worldwide copyright laws and treaty provisions. No part of the - Material may be used, copied, reproduced, modified, published, uploaded, - posted, transmitted, distributed, or disclosed in any way without - Intel's prior express written permission. + This file is part of Threading Building Blocks. Threading Building Blocks is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. Threading Building Blocks is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. You should have received a copy of + the GNU General Public License along with Threading Building Blocks; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - No license under any patent, copyright, trade secret or other - intellectual property right is granted to or conferred upon you by - disclosure or delivery of the Materials, either expressly, by - implication, inducement, estoppel or otherwise. Any license under such - intellectual property rights must be express and approved by Intel in - writing. + As a special exception, you may use this file as part of a free software library without + restriction. Specifically, if other files instantiate templates or use macros or inline + functions from this file, or you compile this file and link it with other files to produce + an executable, this file does not by itself cause the resulting executable to be covered + by the GNU General Public License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General Public License. */ diff --git a/examples/parallel_for/tachyon/msvs/win8ui/DirectXBase.cpp b/examples/parallel_for/tachyon/msvs/win8ui/DirectXBase.cpp index 619db14..073beac 100644 --- a/examples/parallel_for/tachyon/msvs/win8ui/DirectXBase.cpp +++ b/examples/parallel_for/tachyon/msvs/win8ui/DirectXBase.cpp @@ -1,21 +1,21 @@ /* Copyright 2005-2016 Intel Corporation. All Rights Reserved. - The source code contained or described herein and all documents related - to the source code ("Material") are owned by Intel Corporation or its - suppliers or licensors. Title to the Material remains with Intel - Corporation or its suppliers and licensors. The Material is protected - by worldwide copyright laws and treaty provisions. No part of the - Material may be used, copied, reproduced, modified, published, uploaded, - posted, transmitted, distributed, or disclosed in any way without - Intel's prior express written permission. + This file is part of Threading Building Blocks. Threading Building Blocks is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. Threading Building Blocks is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. You should have received a copy of + the GNU General Public License along with Threading Building Blocks; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - No license under any patent, copyright, trade secret or other - intellectual property right is granted to or conferred upon you by - disclosure or delivery of the Materials, either expressly, by - implication, inducement, estoppel or otherwise. Any license under such - intellectual property rights must be express and approved by Intel in - writing. + As a special exception, you may use this file as part of a free software library without + restriction. Specifically, if other files instantiate templates or use macros or inline + functions from this file, or you compile this file and link it with other files to produce + an executable, this file does not by itself cause the resulting executable to be covered + by the GNU General Public License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General Public License. */ #include "pch.h" diff --git a/examples/parallel_for/tachyon/msvs/win8ui/DirectXBase.h b/examples/parallel_for/tachyon/msvs/win8ui/DirectXBase.h index 6cb0776..b9f4103 100644 --- a/examples/parallel_for/tachyon/msvs/win8ui/DirectXBase.h +++ b/examples/parallel_for/tachyon/msvs/win8ui/DirectXBase.h @@ -1,21 +1,21 @@ /* Copyright 2005-2016 Intel Corporation. All Rights Reserved. - The source code contained or described herein and all documents related - to the source code ("Material") are owned by Intel Corporation or its - suppliers or licensors. Title to the Material remains with Intel - Corporation or its suppliers and licensors. The Material is protected - by worldwide copyright laws and treaty provisions. No part of the - Material may be used, copied, reproduced, modified, published, uploaded, - posted, transmitted, distributed, or disclosed in any way without - Intel's prior express written permission. + This file is part of Threading Building Blocks. Threading Building Blocks is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. Threading Building Blocks is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. You should have received a copy of + the GNU General Public License along with Threading Building Blocks; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - No license under any patent, copyright, trade secret or other - intellectual property right is granted to or conferred upon you by - disclosure or delivery of the Materials, either expressly, by - implication, inducement, estoppel or otherwise. Any license under such - intellectual property rights must be express and approved by Intel in - writing. + As a special exception, you may use this file as part of a free software library without + restriction. Specifically, if other files instantiate templates or use macros or inline + functions from this file, or you compile this file and link it with other files to produce + an executable, this file does not by itself cause the resulting executable to be covered + by the GNU General Public License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General Public License. */ #pragma once diff --git a/examples/parallel_for/tachyon/msvs/win8ui/DirectXPage.xaml.cpp b/examples/parallel_for/tachyon/msvs/win8ui/DirectXPage.xaml.cpp index 3c08ffa..beb4880 100644 --- a/examples/parallel_for/tachyon/msvs/win8ui/DirectXPage.xaml.cpp +++ b/examples/parallel_for/tachyon/msvs/win8ui/DirectXPage.xaml.cpp @@ -1,21 +1,21 @@ /* Copyright 2005-2016 Intel Corporation. All Rights Reserved. - The source code contained or described herein and all documents related - to the source code ("Material") are owned by Intel Corporation or its - suppliers or licensors. Title to the Material remains with Intel - Corporation or its suppliers and licensors. The Material is protected - by worldwide copyright laws and treaty provisions. No part of the - Material may be used, copied, reproduced, modified, published, uploaded, - posted, transmitted, distributed, or disclosed in any way without - Intel's prior express written permission. + This file is part of Threading Building Blocks. Threading Building Blocks is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. Threading Building Blocks is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. You should have received a copy of + the GNU General Public License along with Threading Building Blocks; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - No license under any patent, copyright, trade secret or other - intellectual property right is granted to or conferred upon you by - disclosure or delivery of the Materials, either expressly, by - implication, inducement, estoppel or otherwise. Any license under such - intellectual property rights must be express and approved by Intel in - writing. + As a special exception, you may use this file as part of a free software library without + restriction. Specifically, if other files instantiate templates or use macros or inline + functions from this file, or you compile this file and link it with other files to produce + an executable, this file does not by itself cause the resulting executable to be covered + by the GNU General Public License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General Public License. */ diff --git a/examples/parallel_for/tachyon/msvs/win8ui/DirectXPage.xaml.h b/examples/parallel_for/tachyon/msvs/win8ui/DirectXPage.xaml.h index d16f164..3bf5f35 100644 --- a/examples/parallel_for/tachyon/msvs/win8ui/DirectXPage.xaml.h +++ b/examples/parallel_for/tachyon/msvs/win8ui/DirectXPage.xaml.h @@ -1,21 +1,21 @@ /* Copyright 2005-2016 Intel Corporation. All Rights Reserved. - The source code contained or described herein and all documents related - to the source code ("Material") are owned by Intel Corporation or its - suppliers or licensors. Title to the Material remains with Intel - Corporation or its suppliers and licensors. The Material is protected - by worldwide copyright laws and treaty provisions. No part of the - Material may be used, copied, reproduced, modified, published, uploaded, - posted, transmitted, distributed, or disclosed in any way without - Intel's prior express written permission. + This file is part of Threading Building Blocks. Threading Building Blocks is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. Threading Building Blocks is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. You should have received a copy of + the GNU General Public License along with Threading Building Blocks; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - No license under any patent, copyright, trade secret or other - intellectual property right is granted to or conferred upon you by - disclosure or delivery of the Materials, either expressly, by - implication, inducement, estoppel or otherwise. Any license under such - intellectual property rights must be express and approved by Intel in - writing. + As a special exception, you may use this file as part of a free software library without + restriction. Specifically, if other files instantiate templates or use macros or inline + functions from this file, or you compile this file and link it with other files to produce + an executable, this file does not by itself cause the resulting executable to be covered + by the GNU General Public License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General Public License. */ #pragma once diff --git a/examples/parallel_for/tachyon/msvs/win8ui/copy_libraries_and_assets.bat b/examples/parallel_for/tachyon/msvs/win8ui/copy_libraries_and_assets.bat old mode 100755 new mode 100644 index dc90411..874dd4d --- a/examples/parallel_for/tachyon/msvs/win8ui/copy_libraries_and_assets.bat +++ b/examples/parallel_for/tachyon/msvs/win8ui/copy_libraries_and_assets.bat @@ -2,21 +2,21 @@ REM REM Copyright 2005-2016 Intel Corporation. All Rights Reserved. REM -REM The source code contained or described herein and all documents related -REM to the source code ("Material") are owned by Intel Corporation or its -REM suppliers or licensors. Title to the Material remains with Intel -REM Corporation or its suppliers and licensors. The Material is protected -REM by worldwide copyright laws and treaty provisions. No part of the -REM Material may be used, copied, reproduced, modified, published, uploaded, -REM posted, transmitted, distributed, or disclosed in any way without -REM Intel's prior express written permission. +REM This file is part of Threading Building Blocks. Threading Building Blocks is free software; +REM you can redistribute it and/or modify it under the terms of the GNU General Public License +REM version 2 as published by the Free Software Foundation. Threading Building Blocks is +REM distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the +REM implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +REM See the GNU General Public License for more details. You should have received a copy of +REM the GNU General Public License along with Threading Building Blocks; if not, write to the +REM Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA REM -REM No license under any patent, copyright, trade secret or other -REM intellectual property right is granted to or conferred upon you by -REM disclosure or delivery of the Materials, either expressly, by -REM implication, inducement, estoppel or otherwise. Any license under such -REM intellectual property rights must be express and approved by Intel in -REM writing. +REM As a special exception, you may use this file as part of a free software library without +REM restriction. Specifically, if other files instantiate templates or use macros or inline +REM functions from this file, or you compile this file and link it with other files to produce +REM an executable, this file does not by itself cause the resulting executable to be covered +REM by the GNU General Public License. This exception does not however invalidate any other +REM reasons why the executable file might be covered by the GNU General Public License. REM :: Getting parameters :: Architecture diff --git a/examples/parallel_for/tachyon/msvs/win8ui/pch.h b/examples/parallel_for/tachyon/msvs/win8ui/pch.h index 59cde67..e1d10d1 100644 --- a/examples/parallel_for/tachyon/msvs/win8ui/pch.h +++ b/examples/parallel_for/tachyon/msvs/win8ui/pch.h @@ -1,21 +1,21 @@ /* Copyright 2005-2016 Intel Corporation. All Rights Reserved. - The source code contained or described herein and all documents related - to the source code ("Material") are owned by Intel Corporation or its - suppliers or licensors. Title to the Material remains with Intel - Corporation or its suppliers and licensors. The Material is protected - by worldwide copyright laws and treaty provisions. No part of the - Material may be used, copied, reproduced, modified, published, uploaded, - posted, transmitted, distributed, or disclosed in any way without - Intel's prior express written permission. + This file is part of Threading Building Blocks. Threading Building Blocks is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. Threading Building Blocks is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. You should have received a copy of + the GNU General Public License along with Threading Building Blocks; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - No license under any patent, copyright, trade secret or other - intellectual property right is granted to or conferred upon you by - disclosure or delivery of the Materials, either expressly, by - implication, inducement, estoppel or otherwise. Any license under such - intellectual property rights must be express and approved by Intel in - writing. + As a special exception, you may use this file as part of a free software library without + restriction. Specifically, if other files instantiate templates or use macros or inline + functions from this file, or you compile this file and link it with other files to produce + an executable, this file does not by itself cause the resulting executable to be covered + by the GNU General Public License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General Public License. */ #pragma once diff --git a/examples/parallel_for/tachyon/msvs/win8ui/tbbTachyonRenderer.cpp b/examples/parallel_for/tachyon/msvs/win8ui/tbbTachyonRenderer.cpp index 4c2093c..68fbf65 100644 --- a/examples/parallel_for/tachyon/msvs/win8ui/tbbTachyonRenderer.cpp +++ b/examples/parallel_for/tachyon/msvs/win8ui/tbbTachyonRenderer.cpp @@ -1,21 +1,21 @@ /* -Copyright 2005-2016 Intel Corporation. All Rights Reserved. + Copyright 2005-2016 Intel Corporation. All Rights Reserved. -The source code contained or described herein and all documents related -to the source code ("Material") are owned by Intel Corporation or its -suppliers or licensors. Title to the Material remains with Intel -Corporation or its suppliers and licensors. The Material is protected -by worldwide copyright laws and treaty provisions. No part of the -Material may be used, copied, reproduced, modified, published, uploaded, -posted, transmitted, distributed, or disclosed in any way without -Intel's prior express written permission. + This file is part of Threading Building Blocks. Threading Building Blocks is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. Threading Building Blocks is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. You should have received a copy of + the GNU General Public License along with Threading Building Blocks; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -No license under any patent, copyright, trade secret or other -intellectual property right is granted to or conferred upon you by -disclosure or delivery of the Materials, either expressly, by -implication, inducement, estoppel or otherwise. Any license under such -intellectual property rights must be express and approved by Intel in -writing. + As a special exception, you may use this file as part of a free software library without + restriction. Specifically, if other files instantiate templates or use macros or inline + functions from this file, or you compile this file and link it with other files to produce + an executable, this file does not by itself cause the resulting executable to be covered + by the GNU General Public License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General Public License. */ #include "pch.h" diff --git a/examples/parallel_for/tachyon/msvs/win8ui/tbbTachyonRenderer.h b/examples/parallel_for/tachyon/msvs/win8ui/tbbTachyonRenderer.h index 58663bc..5916f96 100644 --- a/examples/parallel_for/tachyon/msvs/win8ui/tbbTachyonRenderer.h +++ b/examples/parallel_for/tachyon/msvs/win8ui/tbbTachyonRenderer.h @@ -1,21 +1,21 @@ /* Copyright 2005-2016 Intel Corporation. All Rights Reserved. - The source code contained or described herein and all documents related - to the source code ("Material") are owned by Intel Corporation or its - suppliers or licensors. Title to the Material remains with Intel - Corporation or its suppliers and licensors. The Material is protected - by worldwide copyright laws and treaty provisions. No part of the - Material may be used, copied, reproduced, modified, published, uploaded, - posted, transmitted, distributed, or disclosed in any way without - Intel's prior express written permission. + This file is part of Threading Building Blocks. Threading Building Blocks is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. Threading Building Blocks is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. You should have received a copy of + the GNU General Public License along with Threading Building Blocks; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - No license under any patent, copyright, trade secret or other - intellectual property right is granted to or conferred upon you by - disclosure or delivery of the Materials, either expressly, by - implication, inducement, estoppel or otherwise. Any license under such - intellectual property rights must be express and approved by Intel in - writing. + As a special exception, you may use this file as part of a free software library without + restriction. Specifically, if other files instantiate templates or use macros or inline + functions from this file, or you compile this file and link it with other files to produce + an executable, this file does not by itself cause the resulting executable to be covered + by the GNU General Public License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General Public License. */ #pragma once diff --git a/examples/task_arena/fractal/msvs/resource.h b/examples/task_arena/fractal/msvs/resource.h index ef7ac10..e3ea078 100644 --- a/examples/task_arena/fractal/msvs/resource.h +++ b/examples/task_arena/fractal/msvs/resource.h @@ -1,3 +1,23 @@ +/* + Copyright 2005-2016 Intel Corporation. All Rights Reserved. + + This file is part of Threading Building Blocks. Threading Building Blocks is free software; + you can redistribute it and/or modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. Threading Building Blocks is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. You should have received a copy of + the GNU General Public License along with Threading Building Blocks; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + As a special exception, you may use this file as part of a free software library without + restriction. Specifically, if other files instantiate templates or use macros or inline + functions from this file, or you compile this file and link it with other files to produce + an executable, this file does not by itself cause the resulting executable to be covered + by the GNU General Public License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General Public License. +*/ + #define IDC_MYICON 2 #define IDD_GUI 102 #define IDS_APP_TITLE 103 diff --git a/include/tbb/concurrent_unordered_map.h b/include/tbb/concurrent_unordered_map.h index 09a2a28..47ae858 100644 --- a/include/tbb/concurrent_unordered_map.h +++ b/include/tbb/concurrent_unordered_map.h @@ -142,7 +142,7 @@ public: } #endif //# __TBB_INITIALIZER_LISTS_PRESENT -#if __TBB_CPP11_RVALUE_REF_PRESENT && __TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_FOR_DERIVED_BROKEN +#if __TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_BROKEN concurrent_unordered_map(const concurrent_unordered_map& table) : base_type(table) { @@ -162,7 +162,7 @@ public: { return static_cast(base_type::operator=(std::move(table))); } -#endif //__TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_FOR_DERIVED_BROKEN +#endif //__TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_BROKEN concurrent_unordered_map(const concurrent_unordered_map& table, const Allocator& a) : base_type(table, a) @@ -283,7 +283,7 @@ public: } #endif //# __TBB_INITIALIZER_LISTS_PRESENT -#if __TBB_CPP11_RVALUE_REF_PRESENT && __TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_FOR_DERIVED_BROKEN +#if __TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_BROKEN concurrent_unordered_multimap(const concurrent_unordered_multimap& table) : base_type(table) { @@ -303,7 +303,7 @@ public: { return static_cast(base_type::operator=(std::move(table))); } -#endif //__TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_FOR_DERIVED_BROKEN +#endif //__TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_BROKEN concurrent_unordered_multimap(const concurrent_unordered_multimap& table, const Allocator& a) : base_type(table, a) diff --git a/include/tbb/concurrent_unordered_set.h b/include/tbb/concurrent_unordered_set.h index 62d992b..846ac79 100644 --- a/include/tbb/concurrent_unordered_set.h +++ b/include/tbb/concurrent_unordered_set.h @@ -119,7 +119,7 @@ public: } #endif //# __TBB_INITIALIZER_LISTS_PRESENT -#if __TBB_CPP11_RVALUE_REF_PRESENT && __TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_FOR_DERIVED_BROKEN +#if __TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_BROKEN concurrent_unordered_set(const concurrent_unordered_set& table) : base_type(table) { @@ -139,7 +139,7 @@ public: { return static_cast(base_type::operator=(std::move(table))); } -#endif //__TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_FOR_DERIVED_BROKEN +#endif //__TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_BROKEN concurrent_unordered_set(const concurrent_unordered_set& table, const Allocator& a) : base_type(table, a) @@ -225,7 +225,7 @@ public: } #endif //# __TBB_INITIALIZER_LISTS_PRESENT -#if __TBB_CPP11_RVALUE_REF_PRESENT && __TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_FOR_DERIVED_BROKEN +#if __TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_BROKEN concurrent_unordered_multiset(const concurrent_unordered_multiset& table) : base_type(table) { @@ -245,7 +245,7 @@ public: { return static_cast(base_type::operator=(std::move(table))); } -#endif //__TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_FOR_DERIVED_BROKEN +#endif //__TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_BROKEN concurrent_unordered_multiset(const concurrent_unordered_multiset& table, const Allocator& a) : base_type(table, a) diff --git a/include/tbb/internal/_concurrent_unordered_impl.h b/include/tbb/internal/_concurrent_unordered_impl.h index 21f2ae6..f1bc705 100644 --- a/include/tbb/internal/_concurrent_unordered_impl.h +++ b/include/tbb/internal/_concurrent_unordered_impl.h @@ -708,7 +708,7 @@ protected: my_allocator(a), my_maximum_bucket_size((float) initial_bucket_load) { if( n_of_buckets == 0) ++n_of_buckets; - my_number_of_buckets = 1<<__TBB_Log2((uintptr_t)n_of_buckets*2-1); // round up to power of 2 + my_number_of_buckets = size_type(1)<<__TBB_Log2((uintptr_t)n_of_buckets*2-1); // round up to power of 2 internal_init(); } @@ -1194,7 +1194,7 @@ public: size_type current_buckets = my_number_of_buckets; if (current_buckets >= buckets) return; - my_number_of_buckets = 1<<__TBB_Log2((uintptr_t)buckets*2-1); // round up to power of 2 + my_number_of_buckets = size_type(1)<<__TBB_Log2((uintptr_t)buckets*2-1); // round up to power of 2 } private: diff --git a/include/tbb/scalable_allocator.h b/include/tbb/scalable_allocator.h index 26853b4..e2bdaec 100644 --- a/include/tbb/scalable_allocator.h +++ b/include/tbb/scalable_allocator.h @@ -282,18 +282,18 @@ public: template void construct(U *p, Args&&... args) { ::new((void *)p) U(std::forward(args)...); } -#else // __TBB_ALLOCATOR_CONSTRUCT_VARIADIC +#else /* __TBB_ALLOCATOR_CONSTRUCT_VARIADIC */ #if __TBB_CPP11_RVALUE_REF_PRESENT void construct( pointer p, value_type&& value ) { ::new((void*)(p)) value_type( std::move( value ) ); } #endif void construct( pointer p, const value_type& value ) {::new((void*)(p)) value_type(value);} -#endif // __TBB_ALLOCATOR_CONSTRUCT_VARIADIC +#endif /* __TBB_ALLOCATOR_CONSTRUCT_VARIADIC */ void destroy( pointer p ) {p->~value_type();} }; #if _MSC_VER && !defined(__INTEL_COMPILER) #pragma warning (pop) -#endif // warning 4100 is back +#endif /* warning 4100 is back */ //! Analogous to std::allocator, as defined in ISO C++ Standard, Section 20.4.1 /** @ingroup memory_allocation */ @@ -336,6 +336,6 @@ inline bool operator!=( const scalable_allocator&, const scalable_allocator= 40700 || __TBB_CPP11_TYPE_PROPERTIES_PRESENT) -// In GCC and MSVC, implementation of std::move_if_noexcept is not aligned with noexcept +// In GCC, std::move_if_noexcept appeared later than noexcept #define __TBB_MOVE_IF_NOEXCEPT_PRESENT (__GXX_EXPERIMENTAL_CXX0X__ && __TBB_GCC_VERSION >= 40700 || _MSC_VER >= 1900 || __clang__ && _LIBCPP_VERSION && __TBB_NOEXCEPT_PRESENT) //TODO: Probably more accurate way is to analyze version of stdlibc++ via__GLIBCXX__ instead of __TBB_GCC_VERSION #define __TBB_ALLOCATOR_TRAITS_PRESENT (__cplusplus >= 201103L && _LIBCPP_VERSION || _MSC_VER >= 1700 || \ @@ -552,7 +552,7 @@ #endif #if (_WIN32||_WIN64) && __INTEL_COMPILER == 1110 - /** That's a bug in Intel compiler 11.1.044/IA-32/Windows, that leads to a worker thread crash on the thread's startup. **/ + /** That's a bug in Intel(R) C++ Compiler 11.1.044/IA-32 architecture/Windows* OS, that leads to a worker thread crash on the thread's startup. **/ #define __TBB_ICL_11_1_CODE_GEN_BROKEN 1 #endif @@ -585,7 +585,7 @@ #endif /* __FreeBSD__ */ #if (__linux__ || __APPLE__) && __i386__ && defined(__INTEL_COMPILER) - /** The Intel compiler for IA-32 (Linux|OS X) crashes or generates + /** The Intel(R) C++ Compiler for IA-32 architecture (Linux* OS|OS X*) crashes or generates incorrect code when __asm__ arguments have a cast to volatile. **/ #define __TBB_ICC_ASM_VOLATILE_BROKEN 1 #endif @@ -639,11 +639,12 @@ #define __TBB_GCC_CAS8_BUILTIN_INLINING_BROKEN 1 #endif -#if __TBB_x86_32 && (__linux__ || __APPLE__ || _WIN32 || __sun || __ANDROID__) && (__INTEL_COMPILER || (__GNUC__==3 && __GNUC_MINOR__==3 )||(__MINGW32__ ) && (__GNUC__==4 && __GNUC_MINOR__==5 ) || __SUNPRO_CC) - // Some compilers for IA-32 fail to provide 8-byte alignment of objects on the stack, - // even if the object specifies 8-byte alignment. On such platforms, the IA-32 implementation - // of 64 bit atomics (e.g. atomic) use different tactics depending upon - // whether the object is properly aligned or not. +#if __TBB_x86_32 && ( __INTEL_COMPILER || (__GNUC__==5 && __GNUC_MINOR__==2 && __GXX_EXPERIMENTAL_CXX0X__) \ + || (__GNUC__==3 && __GNUC_MINOR__==3) || (__MINGW32__ && __GNUC__==4 && __GNUC_MINOR__==5) || __SUNPRO_CC ) + // Some compilers for IA-32 architecture fail to provide 8-byte alignment of objects on the stack, + // even if the object specifies 8-byte alignment. On such platforms, the implementation + // of 64 bit atomics for IA-32 architecture (e.g. atomic) use different tactics + // depending upon whether the object is properly aligned or not. #define __TBB_FORCE_64BIT_ALIGNMENT_BROKEN 1 #else #define __TBB_FORCE_64BIT_ALIGNMENT_BROKEN 0 @@ -662,9 +663,17 @@ // A compiler bug: a disabled copy constructor prevents use of the moving constructor #define __TBB_IF_NO_COPY_CTOR_MOVE_SEMANTICS_BROKEN (_MSC_VER && (__INTEL_COMPILER >= 1300 && __INTEL_COMPILER <= 1310) && !__INTEL_CXX11_MODE__) -// MSVC 2013 and ICC do not generate implicit move constructor for empty derived class -#define __TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_FOR_DERIVED_BROKEN (__TBB_CPP11_RVALUE_REF_PRESENT && \ - ( !__INTEL_COMPILER && _MSC_VER && _MSC_VER <= 1800 || __INTEL_COMPILER && __INTEL_COMPILER <= 1600 )) +#if __TBB_CPP11_RVALUE_REF_PRESENT +//Some compilers added implicit generation of move constructor & assignment operator in a later version +#if _MSC_VER + // Covers Intel C++ Compiler for Windows, which has compatible behavior + #define __TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_BROKEN (_MSC_VER <= 1800) +#elif __INTEL_COMPILER + #define __TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_BROKEN (__INTEL_COMPILER < 1400 || __INTEL_COMPILER==1600) +#elif __clang__ + #define __TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_BROKEN (!__has_feature(cxx_implicit_moves)) +#endif +#endif /* __TBB_CPP11_RVALUE_REF_PRESENT */ #define __TBB_CPP11_DECLVAL_BROKEN (_MSC_VER == 1600 || (__GNUC__ && __TBB_GCC_VERSION < 40500) ) @@ -686,8 +695,8 @@ #define __TBB_ATOMIC_CTORS (__TBB_CONSTEXPR_PRESENT && __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT && (!__TBB_ZERO_INIT_WITH_DEFAULTED_CTOR_BROKEN)) // Many OS versions (Android 4.0.[0-3] for example) need workaround for dlopen to avoid non-recursive loader lock hang -// Setting the workaround for all compile targets ($APP_PLATFORM) below Android 4.4 (android-19) -#if __ANDROID__ +// Setting the workaround for all compile targets ($APP_PLATFORM) below Android 4.4 (android-19) +#if __ANDROID__ #include #define __TBB_USE_DLOPEN_REENTRANCY_WORKAROUND (__ANDROID_API__ < 19) #endif diff --git a/include/tbb/tbb_stddef.h b/include/tbb/tbb_stddef.h index 20f6718..7198c22 100644 --- a/include/tbb/tbb_stddef.h +++ b/include/tbb/tbb_stddef.h @@ -26,7 +26,7 @@ #define TBB_VERSION_MINOR 4 // Engineering-focused interface version -#define TBB_INTERFACE_VERSION 9004 +#define TBB_INTERFACE_VERSION 9005 #define TBB_INTERFACE_VERSION_MAJOR TBB_INTERFACE_VERSION/1000 // The oldest major interface version still supported diff --git a/index.html b/index.html index 4e95262..abcefa6 100644 --- a/index.html +++ b/index.html @@ -1,41 +1,35 @@ +

      Overview

      -Top level directory for Intel® Threading Building Blocks. -

      Common directories

      -
      -
      doc -
      Documentation for the library. -
      include -
      Include files required for compiling code that uses the library. -
      examples -
      Examples of how to use the library. -
      -

      Intel TBB source package

      +Top level directory for Intel® Threading Building Blocks (Intel® TBB).

      To build Intel TBB, use the top-level Makefile; see also the build directions. To port Intel TBB to a new platform, operating system or architecture, see the porting directions.

      -

      Files

      + +

      Files

      Makefile -
      Top-level Makefile for Intel TBB. See also the build directions. +
      Top-level Makefile for Intel TBB. See also the build directions.
      -

      Directories

      + +

      Directories

      +
      bin +
      Start-up scripts for sourcing library. +
      include +
      Include files required for compiling code that uses the library. +
      examples +
      Examples of how to use the library. +
      lib +
      Platform-specific binary files for the library.
      src
      Source code for the library.
      build
      Internal Makefile infrastructure for Intel TBB. Do not use directly; see the build directions.
      -

      Intel TBB binary package

      -

      Directories

      -
      -
      bin -
      Start-up scripts for sourcing library for Linux* OS and OS X*. For Windows* OS: start-up scripts and dynamic-link libraries. -
      lib -
      Platform-specific binary files for the library. -
      +

      Copyright © 2005-2016 Intel Corporation. All Rights Reserved. @@ -46,3 +40,4 @@ or its subsidiaries in the United States and other countries. * Other names and brands may be claimed as the property of others. + diff --git a/python/Makefile b/python/Makefile new file mode 100644 index 0000000..42d3e7c --- /dev/null +++ b/python/Makefile @@ -0,0 +1,38 @@ +# Copyright 2005-2016 Intel Corporation. All Rights Reserved. +# +# This file is part of Threading Building Blocks. Threading Building Blocks is free software; +# you can redistribute it and/or modify it under the terms of the GNU General Public License +# version 2 as published by the Free Software Foundation. Threading Building Blocks is +# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. You should have received a copy of +# the GNU General Public License along with Threading Building Blocks; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +# As a special exception, you may use this file as part of a free software library without +# restriction. Specifically, if other files instantiate templates or use macros or inline +# functions from this file, or you compile this file and link it with other files to produce +# an executable, this file does not by itself cause the resulting executable to be covered +# by the GNU General Public License. This exception does not however invalidate any other +# reasons why the executable file might be covered by the GNU General Public License. + +all: release test + +clean: + python setup.py clean + -rm -rf build/ tbb_wrap.* _TBB.* *.pyc TBB.py* + +release: TBB.py + +TBB.py: tbb.i tbb.src.py setup.py + python setup.py build_ext -f --inplace + +test: TBB.py + python TBB.py test + +install: + python setup.py install + +test-install: + @echo Testing installed module + python -m TBB test diff --git a/python/index.html b/python/index.html new file mode 100644 index 0000000..61bb2d2 --- /dev/null +++ b/python/index.html @@ -0,0 +1,75 @@ + + +

      Python* API for Intel® Threading Building Blocks (Intel® TBB). +

      + +

      Overview

      +It is a preview Python* module which unlocks opportunities for additional performance in multi-threaded Python programs by enabling threading composability +between two or more thread-enabled libraries like Numpy, Scipy, Sklearn, Dask, Joblib, and etc. +

      +The biggest improvement can be achieved when a task pool like the ThreadPool from the Python standard library or libraries like Dask or Joblib (used in multi-threading mode) +execute tasks calling compute-intensive functions of Numpy/Scipy/Sklearn/PyDAAL which in turn are parallelized using Intel® Math Kernel Library or/and Intel® TBB. +

      +The module implements Pool class with the standard interface using Intel® TBB which can be used to replace Python's ThreadPool. +Thanks to the monkey-patching technique implemented in class Monkey, no source code change is needed in order to enable threading composability in Python programs. +

      +For more information and examples, please refer to online blog. + +

      Files

      +
      +
      setup.py +
      Standard Python setup script. +
      Makefile +
      Makefile for building, installing, and testing. See below. +
      tbb.i +
      SWIG interface description file. +
      tbb.src.py +
      Python part of module implementation. +
      + +

      Build and install

      +Prior to building it, please set up the environment using corresponding tbbvars script, e.g. `source tbbvars.sh intel64` +
      +
      make +
      Default build and run. Equivalent to 'make release test'. +
      make release +
      Compile and link against the release version of Intel TBB runtime library. The resulting executable is left in the directory for the example. +
      make test +
      Run local build of the module previously produced by one of the above commands. +
      make install +
      Install module into Python. +
      make [(above options or targets)] CXX={icl, icc} +
      Build and run as above, but use Intel® C++ compiler instead of default, native compilers +(e.g., icl instead of cl.exe on Windows* systems, or icc instead of g++ on Linux* or OS X* systems). +Please note, CXX=icl works on Windows only with Intel® Distribution for Python*. +
      make clean +
      Remove any intermediate files produced by the above commands. +
      + +

      Command-line interface

      +
      +
      pydoc TBB +
      Read built-in documentation for Python interfaces. +
      python -m TBB your_script.py +
      Run your_script.py in context of `with TBB.Monkey():` when Intel TBB is enabled. +
      + +

      System Requirements

      +The Python module was not tested on older versions of Python thus we require at least Python versions 2.7 and 3.5 or higher.
      +SWIG must be of version 3.0.6 or higher
      +OS versions: +Microsoft* Windows* Server 2012, +Microsoft* Windows* 10, +Ubuntu* 14.04 LTS, +Red Hat* Enterprise Linux* 7. +
      +Up to parent directory +

      +Copyright © 2005-2016 Intel Corporation. All Rights Reserved. +

      +Intel is a registered trademark or trademark of Intel Corporation +or its subsidiaries in the United States and other countries. +

      +* Other names and brands may be claimed as the property of others. + + diff --git a/python/setup.py b/python/setup.py new file mode 100644 index 0000000..85b5a28 --- /dev/null +++ b/python/setup.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python +# +# Copyright 2005-2016 Intel Corporation. All Rights Reserved. +# +# This file is part of Threading Building Blocks. Threading Building Blocks is free software; +# you can redistribute it and/or modify it under the terms of the GNU General Public License +# version 2 as published by the Free Software Foundation. Threading Building Blocks is +# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. You should have received a copy of +# the GNU General Public License along with Threading Building Blocks; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +# As a special exception, you may use this file as part of a free software library without +# restriction. Specifically, if other files instantiate templates or use macros or inline +# functions from this file, or you compile this file and link it with other files to produce +# an executable, this file does not by itself cause the resulting executable to be covered +# by the GNU General Public License. This exception does not however invalidate any other +# reasons why the executable file might be covered by the GNU General Public License. + + +# System imports +from __future__ import print_function +import platform +import os + +from distutils.core import * +from distutils.command.build import build + +if any(i in os.environ for i in ["CC", "CXX"]): + if "CC" not in os.environ: + os.environ['CC'] = os.environ['CXX'] + if "CXX" not in os.environ: + os.environ['CXX'] = os.environ['CC'] + if platform.system() == 'Linux': + os.environ['LDSHARED'] = os.environ['CXX'] + " -shared" + +intel_compiler = os.getenv('CC', '') in ['icl', 'icpc', 'icc'] +try: + tbb_root = os.environ['TBBROOT'] + print("Using TBBROOT=", tbb_root) +except: + tbb_root = '.' + if not intel_compiler: + print("Warning: TBBROOT env var is not set and Intel's compiler is not used. It might lead\n" + " !!!: to compile/link problems. Source tbbvars.sh/.csh file to set environment") +use_compiler_tbb = intel_compiler and tbb_root == '.' +if use_compiler_tbb: + print("Using Intel TBB from Intel's compiler") +if platform.system() == 'Windows': + if intel_compiler: + os.environ['DISTUTILS_USE_SDK'] = '1' # Enable environment settings in distutils + os.environ['MSSdk'] = '1' + print("Using compiler settings from environment") + tbb_flag = ['/Qtbb'] if use_compiler_tbb else [] + compile_flags = ['/Qstd=c++11'] if intel_compiler else [] +else: + tbb_flag = ['-tbb'] if use_compiler_tbb else [] + compile_flags = ['-std=c++11', '-Wno-unused-variable'] + +_tbb = Extension("_TBB", ["tbb.i"], + include_dirs=[os.path.join(tbb_root, 'include')] if not use_compiler_tbb else [], + swig_opts =['-c++', '-O', '-threads'] + ( # add '-builtin' later + ['-I' + os.path.join(tbb_root, 'include')] if not use_compiler_tbb else []), + extra_compile_args=compile_flags + tbb_flag, + extra_link_args=tbb_flag, + libraries =['tbb'] if not use_compiler_tbb else [], + library_dirs=[os.path.join(tbb_root, 'lib', 'intel64', 'gcc4.4'), # for Linux + os.path.join(tbb_root, 'lib'), # for MacOS + os.path.join(tbb_root, 'lib', 'intel64', 'vc_mt'), # for Windows + ] if not use_compiler_tbb else [], + language ='c++', + ) + + +class TBBBuild(build): + sub_commands = [ # define build order + ('build_ext', build.has_ext_modules), + ('build_py', build.has_pure_modules), + ] + + +setup( name ="TBB", + description ="Python API for Intel TBB", + long_description="Python API to Intel(R) Threading Building Blocks library (Intel(R) TBB) " + "extended with standard Pool implementation and monkey-patching", + url ="https://www.threadingbuildingblocks.org/", + author ="Intel Corporation", + author_email="Anton.Malakhov@intel.com", + license ="BSD License", + version ="0.1", + classifiers =[ + 'Development Status :: 4 - Beta', + 'Environment :: Console', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: System Administrators', + 'Intended Audience :: Other Audience', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: BSD License', + 'Operating System :: MacOS :: MacOS X', + 'Operating System :: Microsoft :: Windows', + 'Operating System :: POSIX', + 'Operating System :: Unix', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 3', + 'Programming Language :: C++', + 'Topic :: System :: Hardware :: Symmetric Multi-processing', + 'Topic :: Software Development :: Libraries', + ], + keywords='tbb multiprocessing multithreading composable parallelism', + ext_modules=[_tbb], + py_modules=['TBB'], + cmdclass={'build': TBBBuild} +) diff --git a/python/tbb.i b/python/tbb.i new file mode 100644 index 0000000..bd50904 --- /dev/null +++ b/python/tbb.i @@ -0,0 +1,146 @@ +%pythonbegin %{ +# +# Copyright 2005-2016 Intel Corporation. All Rights Reserved. +# +# This file is part of Threading Building Blocks. Threading Building Blocks is free software; +# you can redistribute it and/or modify it under the terms of the GNU General Public License +# version 2 as published by the Free Software Foundation. Threading Building Blocks is +# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. You should have received a copy of +# the GNU General Public License along with Threading Building Blocks; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +# As a special exception, you may use this file as part of a free software library without +# restriction. Specifically, if other files instantiate templates or use macros or inline +# functions from this file, or you compile this file and link it with other files to produce +# an executable, this file does not by itself cause the resulting executable to be covered +# by the GNU General Public License. This exception does not however invalidate any other +# reasons why the executable file might be covered by the GNU General Public License. + + +# Based on the software developed by: +# Copyright (c) 2008,2016 david decotigny (Pool of threads) +# Copyright (c) 2006-2008, R Oudkerk (multiprocessing.Pool) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of author nor the names of any contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +from __future__ import print_function +%} +%begin %{ +/* Defines Python wrappers for Intel(R) Threading Building Blocks (Intel TBB).*/ +%} +%module TBB + +#if SWIG_VERSION < 0x030001 +#error SWIG version 3.0.6 or newer is required for correct functioning +#endif + +%{ +#include +using namespace tbb; + +class PyCaller : public swig::SwigPtr_PyObject { +public: + // icpc 2013 does not support simple using SwigPtr_PyObject::SwigPtr_PyObject; + PyCaller(const PyCaller& s) : SwigPtr_PyObject(s) {} + PyCaller(PyObject *p, bool initial = true) : SwigPtr_PyObject(p, initial) {} + + void operator()() const { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyObject* r = PyObject_CallFunctionObjArgs((PyObject*)*this, NULL); + if(r) Py_DECREF(r); + SWIG_PYTHON_THREAD_END_BLOCK; + } +}; + +struct ArenaPyCaller { + task_arena *my_arena; + PyObject *my_callable; + ArenaPyCaller(task_arena *a, PyObject *c) : my_arena(a), my_callable(c) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + Py_XINCREF(c); + SWIG_PYTHON_THREAD_END_BLOCK; + } + void operator()() const { + my_arena->execute(PyCaller(my_callable, false)); + } +}; + +%} + +namespace tbb { + class task_scheduler_init { + public: + //! Typedef for number of threads that is automatic. + static const int automatic = -1; + //! Argument to initialize() or constructor that causes initialization to be deferred. + static const int deferred = -2; + task_scheduler_init( int max_threads=automatic, + size_t thread_stack_size=0 ); + ~task_scheduler_init(); + void initialize( int max_threads=automatic ); + void terminate(); + static int default_num_threads(); + bool is_active() const; + }; + + class task_arena { + public: + static const int automatic = -1; + static int current_thread_index(); + task_arena(int max_concurrency = automatic, unsigned reserved_for_masters = 1); + task_arena(const task_arena &s); + ~task_arena(); + void initialize(); + void initialize(int max_concurrency, unsigned reserved_for_masters = 1); + void terminate(); + bool is_active(); + %extend { + void enqueue( PyObject *c ) { $self->enqueue(PyCaller(c)); } + void execute( PyObject *c ) { $self->execute(PyCaller(c)); } + }; + }; + + class task_group { + public: + task_group(); + ~task_group(); + void wait(); + bool is_canceling(); + void cancel(); + %extend { + void run( PyObject *c ) { $self->run(PyCaller(c)); } + void run( PyObject *c, task_arena *a ) { $self->run(ArenaPyCaller(a, c)); } + }; + }; + +} + +// Python part of the module +%pythoncode "tbb.src.py" diff --git a/python/tbb.src.py b/python/tbb.src.py new file mode 100644 index 0000000..9c3c063 --- /dev/null +++ b/python/tbb.src.py @@ -0,0 +1,840 @@ + +# +# Copyright 2005-2016 Intel Corporation. All Rights Reserved. +# +# This file is part of Threading Building Blocks. Threading Building Blocks is free software; +# you can redistribute it and/or modify it under the terms of the GNU General Public License +# version 2 as published by the Free Software Foundation. Threading Building Blocks is +# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. You should have received a copy of +# the GNU General Public License along with Threading Building Blocks; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +# As a special exception, you may use this file as part of a free software library without +# restriction. Specifically, if other files instantiate templates or use macros or inline +# functions from this file, or you compile this file and link it with other files to produce +# an executable, this file does not by itself cause the resulting executable to be covered +# by the GNU General Public License. This exception does not however invalidate any other +# reasons why the executable file might be covered by the GNU General Public License. + +# Based on the software developed by: +# Copyright (c) 2008,2016 david decotigny (Pool of threads) +# Copyright (c) 2006-2008, R Oudkerk (multiprocessing.Pool) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of author nor the names of any contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +# @brief Python Pool implementation based on TBB with monkey-patching +# +# See http://docs.python.org/dev/library/multiprocessing.html +# Differences: added imap_async and imap_unordered_async, and terminate() +# has to be called explicitly (it's not registered by atexit). +# +# The general idea is that we submit works to a workqueue, either as +# single Jobs (one function to call), or JobSequences (batch of +# Jobs). Each Job is associated with an ApplyResult object which has 2 +# states: waiting for the Job to complete, or Ready. Instead of +# waiting for the jobs to finish, we wait for their ApplyResult object +# to become ready: an event mechanism is used for that. +# When we apply a function to several arguments in "parallel", we need +# a way to wait for all/part of the Jobs to be processed: that's what +# "collectors" are for; they group and wait for a set of ApplyResult +# objects. Once a collector is ready to be used, we can use a +# CollectorIterator to iterate over the result values it's collecting. +# +# The methods of a Pool object use all these concepts and expose +# them to their caller in a very simple way. + +import sys +import threading +import traceback + +__all__ = ["Pool", "Monkey", "task_arena", "task_group", "task_scheduler_init"] +__doc__ = """ +Python API to Intel(R) Threading Building Blocks library (Intel TBB) +extended with standard Pool implementation and monkey-patching. + +Command-line interface: +$ python -m TBB $your_script.py + +Runs your_script.py in context of `with Monkey():` +""" + +default_num_threads = task_scheduler_init_default_num_threads + + +class TimeoutError(Exception): + """Raised when a result is not available within the given timeout""" + pass + + +class Pool(object): + """ + The Pool class provides standard multiprocessing.Pool interface + which is mapped onto Intel TBB tasks executing in its thread pool + """ + + def __init__(self, nworkers=0, name="Pool"): + """ + \param nworkers (integer) number of worker threads to start + \param name (string) prefix for the worker threads' name + """ + self._closed = False + self._tasks = task_group() + self._pool = [None,]*default_num_threads() # Dask asks for len(_pool) + + def apply(self, func, args=(), kwds=dict()): + """Equivalent of the apply() builtin function. It blocks till + the result is ready.""" + return self.apply_async(func, args, kwds).get() + + def map(self, func, iterable, chunksize=None): + """A parallel equivalent of the map() builtin function. It + blocks till the result is ready. + + This method chops the iterable into a number of chunks which + it submits to the process pool as separate tasks. The + (approximate) size of these chunks can be specified by setting + chunksize to a positive integer.""" + return self.map_async(func, iterable, chunksize).get() + + def imap(self, func, iterable, chunksize=1): + """ + An equivalent of itertools.imap(). + + The chunksize argument is the same as the one used by the + map() method. For very long iterables using a large value for + chunksize can make the job complete much faster than + using the default value of 1. + + Also if chunksize is 1 then the next() method of the iterator + returned by the imap() method has an optional timeout + parameter: next(timeout) will raise processing.TimeoutError if + the result cannot be returned within timeout seconds. + """ + collector = OrderedResultCollector(as_iterator=True) + self._create_sequences(func, iterable, chunksize, collector) + return iter(collector) + + def imap_unordered(self, func, iterable, chunksize=1): + """The same as imap() except that the ordering of the results + from the returned iterator should be considered + arbitrary. (Only when there is only one worker process is the + order guaranteed to be "correct".)""" + collector = UnorderedResultCollector() + self._create_sequences(func, iterable, chunksize, collector) + return iter(collector) + + def apply_async(self, func, args=(), kwds=dict(), callback=None): + """A variant of the apply() method which returns an + ApplyResult object. + + If callback is specified then it should be a callable which + accepts a single argument. When the result becomes ready, + callback is applied to it (unless the call failed). callback + should complete immediately since otherwise the thread which + handles the results will get blocked.""" + assert not self._closed # No lock here. We assume it's atomic... + apply_result = ApplyResult(callback=callback) + job = Job(func, args, kwds, apply_result) + self._tasks.run(job) + return apply_result + + def map_async(self, func, iterable, chunksize=None, callback=None): + """A variant of the map() method which returns a ApplyResult + object. + + If callback is specified then it should be a callable which + accepts a single argument. When the result becomes ready + callback is applied to it (unless the call failed). callback + should complete immediately since otherwise the thread which + handles the results will get blocked.""" + apply_result = ApplyResult(callback=callback) + collector = OrderedResultCollector(apply_result, as_iterator=False) + if not self._create_sequences(func, iterable, chunksize, collector): + apply_result._set_value([]) + return apply_result + + def imap_async(self, func, iterable, chunksize=None, callback=None): + """A variant of the imap() method which returns an ApplyResult + object that provides an iterator (next method(timeout) + available). + + If callback is specified then it should be a callable which + accepts a single argument. When the resulting iterator becomes + ready, callback is applied to it (unless the call + failed). callback should complete immediately since otherwise + the thread which handles the results will get blocked.""" + apply_result = ApplyResult(callback=callback) + collector = OrderedResultCollector(apply_result, as_iterator=True) + if not self._create_sequences(func, iterable, chunksize, collector): + apply_result._set_value(iter([])) + return apply_result + + def imap_unordered_async(self, func, iterable, chunksize=None, + callback=None): + """A variant of the imap_unordered() method which returns an + ApplyResult object that provides an iterator (next + method(timeout) available). + + If callback is specified then it should be a callable which + accepts a single argument. When the resulting iterator becomes + ready, callback is applied to it (unless the call + failed). callback should complete immediately since otherwise + the thread which handles the results will get blocked.""" + apply_result = ApplyResult(callback=callback) + collector = UnorderedResultCollector(apply_result) + if not self._create_sequences(func, iterable, chunksize, collector): + apply_result._set_value(iter([])) + return apply_result + + def close(self): + """Prevents any more tasks from being submitted to the + pool. Once all the tasks have been completed the worker + processes will exit.""" + # No lock here. We assume it's sufficiently atomic... + self._closed = True + + def terminate(self): + """Stops the worker processes immediately without completing + outstanding work. When the pool object is garbage collected + terminate() will be called immediately.""" + self.close() + self._tasks.cancel() + + def join(self): + """Wait for the worker processes to exit. One must call + close() or terminate() before using join().""" + self._tasks.wait() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.join() + + def __del__(self): + self.terminate() + self.join() + + def _create_sequences(self, func, iterable, chunksize, collector): + """ + Create callable objects to process and pushes them on the + work queue. Each work unit is meant to process a slice of + iterable of size chunksize. If collector is specified, then + the ApplyResult objects associated with the jobs will notify + collector when their result becomes ready. + + \return the list callable objects (basically: JobSequences) + pushed onto the work queue + """ + assert not self._closed # No lock here. We assume it's atomic... + it_ = iter(iterable) + exit_loop = False + sequences = [] + while not exit_loop: + seq = [] + for _ in range(chunksize or 1): + try: + arg = next(it_) + except StopIteration: + exit_loop = True + break + apply_result = ApplyResult(collector) + job = Job(func, (arg,), {}, apply_result) + seq.append(job) + if seq: + sequences.append(JobSequence(seq)) + for t in sequences: + self._tasks.run(t) + return sequences + + +class Job: + """A work unit that corresponds to the execution of a single function""" + + def __init__(self, func, args, kwds, apply_result): + """ + \param func/args/kwds used to call the function + \param apply_result ApplyResult object that holds the result + of the function call + """ + self._func = func + self._args = args + self._kwds = kwds + self._result = apply_result + + def __call__(self): + """ + Call the function with the args/kwds and tell the ApplyResult + that its result is ready. Correctly handles the exceptions + happening during the execution of the function + """ + try: + result = self._func(*self._args, **self._kwds) + except: + self._result._set_exception() + else: + self._result._set_value(result) + + +class JobSequence: + """A work unit that corresponds to the processing of a continuous + sequence of Job objects""" + + def __init__(self, jobs): + self._jobs = jobs + + def __call__(self): + """ + Call all the Job objects that have been specified + """ + for job in self._jobs: + job() + + +class ApplyResult(object): + """An object associated with a Job object that holds its result: + it's available during the whole life the Job and after, even when + the Job didn't process yet. It's possible to use this object to + wait for the result/exception of the job to be available. + + The result objects returns by the Pool::*_async() methods are of + this type""" + + def __init__(self, collector=None, callback=None): + """ + \param collector when not None, the notify_ready() method of + the collector will be called when the result from the Job is + ready + \param callback when not None, function to call when the + result becomes available (this is the paramater passed to the + Pool::*_async() methods. + """ + self._success = False + self._event = threading.Event() + self._data = None + self._collector = None + self._callback = callback + + if collector is not None: + collector.register_result(self) + self._collector = collector + + def get(self, timeout=None): + """ + Returns the result when it arrives. If timeout is not None and + the result does not arrive within timeout seconds then + TimeoutError is raised. If the remote call raised an exception + then that exception will be reraised by get(). + """ + if not self.wait(timeout): + raise TimeoutError("Result not available within %fs" % timeout) + if self._success: + return self._data + if sys.version_info[0] == 3: + raise self._data[0](self._data[1]).with_traceback(self._data[2]) + else: + exec("raise self._data[0], self._data[1], self._data[2]") + + def wait(self, timeout=None): + """Waits until the result is available or until timeout + seconds pass.""" + self._event.wait(timeout) + return self._event.isSet() + + def ready(self): + """Returns whether the call has completed.""" + return self._event.isSet() + + def successful(self): + """Returns whether the call completed without raising an + exception. Will raise AssertionError if the result is not + ready.""" + assert self.ready() + return self._success + + def _set_value(self, value): + """Called by a Job object to tell the result is ready, and + provides the value of this result. The object will become + ready and successful. The collector's notify_ready() method + will be called, and the callback method too""" + assert not self.ready() + self._data = value + self._success = True + self._event.set() + if self._collector is not None: + self._collector.notify_ready(self) + if self._callback is not None: + try: + self._callback(value) + except: + traceback.print_exc() + + def _set_exception(self): + """Called by a Job object to tell that an exception occured + during the processing of the function. The object will become + ready but not successful. The collector's notify_ready() + method will be called, but NOT the callback method""" + # traceback.print_exc() + assert not self.ready() + self._data = sys.exc_info() + self._success = False + self._event.set() + if self._collector is not None: + self._collector.notify_ready(self) + + +class AbstractResultCollector(object): + """ABC to define the interface of a ResultCollector object. It is + basically an object which knows whuich results it's waiting for, + and which is able to get notify when they get available. It is + also able to provide an iterator over the results when they are + available""" + + def __init__(self, to_notify): + """ + \param to_notify ApplyResult object to notify when all the + results we're waiting for become available. Can be None. + """ + self._to_notify = to_notify + + def register_result(self, apply_result): + """Used to identify which results we're waiting for. Will + always be called BEFORE the Jobs get submitted to the work + queue, and BEFORE the __iter__ and _get_result() methods can + be called + \param apply_result ApplyResult object to add in our collection + """ + raise NotImplementedError("Children classes must implement it") + + def notify_ready(self, apply_result): + """Called by the ApplyResult object (already registered via + register_result()) that it is now ready (ie. the Job's result + is available or an exception has been raised). + \param apply_result ApplyResult object telling us that the job + has been processed + """ + raise NotImplementedError("Children classes must implement it") + + def _get_result(self, idx, timeout=None): + """Called by the CollectorIterator object to retrieve the + result's values one after another (order defined by the + implementation) + \param idx The index of the result we want, wrt collector's order + \param timeout integer telling how long to wait (in seconds) + for the result at index idx to be available, or None (wait + forever) + """ + raise NotImplementedError("Children classes must implement it") + + def __iter__(self): + """Return a new CollectorIterator object for this collector""" + return CollectorIterator(self) + + +class CollectorIterator(object): + """An iterator that allows to iterate over the result values + available in the given collector object. Equipped with an extended + next() method accepting a timeout argument. Created by the + AbstractResultCollector::__iter__() method""" + + def __init__(self, collector): + """\param AbstractResultCollector instance""" + self._collector = collector + self._idx = 0 + + def __iter__(self): + return self + + def next(self, timeout=None): + """Return the next result value in the sequence. Raise + StopIteration at the end. Can raise the exception raised by + the Job""" + try: + apply_result = self._collector._get_result(self._idx, timeout) + except IndexError: + # Reset for next time + self._idx = 0 + raise StopIteration + except: + self._idx = 0 + raise + self._idx += 1 + assert apply_result.ready() + return apply_result.get(0) + + def __next__(self): + return self.next() + + +class UnorderedResultCollector(AbstractResultCollector): + """An AbstractResultCollector implementation that collects the + values of the ApplyResult objects in the order they become ready. The + CollectorIterator object returned by __iter__() will iterate over + them in the order they become ready""" + + def __init__(self, to_notify=None): + """ + \param to_notify ApplyResult object to notify when all the + results we're waiting for become available. Can be None. + """ + AbstractResultCollector.__init__(self, to_notify) + self._cond = threading.Condition() + self._collection = [] + self._expected = 0 + + def register_result(self, apply_result): + """Used to identify which results we're waiting for. Will + always be called BEFORE the Jobs get submitted to the work + queue, and BEFORE the __iter__ and _get_result() methods can + be called + \param apply_result ApplyResult object to add in our collection + """ + self._expected += 1 + + def _get_result(self, idx, timeout=None): + """Called by the CollectorIterator object to retrieve the + result's values one after another, in the order the results have + become available. + \param idx The index of the result we want, wrt collector's order + \param timeout integer telling how long to wait (in seconds) + for the result at index idx to be available, or None (wait + forever) + """ + self._cond.acquire() + try: + if idx >= self._expected: + raise IndexError + elif idx < len(self._collection): + return self._collection[idx] + elif idx != len(self._collection): + # Violation of the sequence protocol + raise IndexError() + else: + self._cond.wait(timeout=timeout) + try: + return self._collection[idx] + except IndexError: + # Still not added ! + raise TimeoutError("Timeout while waiting for results") + finally: + self._cond.release() + + def notify_ready(self, apply_result=None): + """Called by the ApplyResult object (already registered via + register_result()) that it is now ready (ie. the Job's result + is available or an exception has been raised). + \param apply_result ApplyResult object telling us that the job + has been processed + """ + first_item = False + self._cond.acquire() + try: + self._collection.append(apply_result) + first_item = (len(self._collection) == 1) + + self._cond.notifyAll() + finally: + self._cond.release() + + if first_item and self._to_notify is not None: + self._to_notify._set_value(iter(self)) + + +class OrderedResultCollector(AbstractResultCollector): + """An AbstractResultCollector implementation that collects the + values of the ApplyResult objects in the order they have been + submitted. The CollectorIterator object returned by __iter__() + will iterate over them in the order they have been submitted""" + + def __init__(self, to_notify=None, as_iterator=True): + """ + \param to_notify ApplyResult object to notify when all the + results we're waiting for become available. Can be None. + \param as_iterator boolean telling whether the result value + set on to_notify should be an iterator (available as soon as 1 + result arrived) or a list (available only after the last + result arrived) + """ + AbstractResultCollector.__init__(self, to_notify) + self._results = [] + self._lock = threading.Lock() + self._remaining = 0 + self._as_iterator = as_iterator + + def register_result(self, apply_result): + """Used to identify which results we're waiting for. Will + always be called BEFORE the Jobs get submitted to the work + queue, and BEFORE the __iter__ and _get_result() methods can + be called + \param apply_result ApplyResult object to add in our collection + """ + self._results.append(apply_result) + self._remaining += 1 + + def _get_result(self, idx, timeout=None): + """Called by the CollectorIterator object to retrieve the + result's values one after another (order defined by the + implementation) + \param idx The index of the result we want, wrt collector's order + \param timeout integer telling how long to wait (in seconds) + for the result at index idx to be available, or None (wait + forever) + """ + res = self._results[idx] + res.wait(timeout) + return res + + def notify_ready(self, apply_result): + """Called by the ApplyResult object (already registered via + register_result()) that it is now ready (ie. the Job's result + is available or an exception has been raised). + \param apply_result ApplyResult object telling us that the job + has been processed + """ + got_first = False + got_last = False + self._lock.acquire() + try: + assert self._remaining > 0 + got_first = (len(self._results) == self._remaining) + self._remaining -= 1 + got_last = (self._remaining == 0) + finally: + self._lock.release() + + if self._to_notify is not None: + if self._as_iterator and got_first: + self._to_notify._set_value(iter(self)) + elif not self._as_iterator and got_last: + try: + lst = [r.get(0) for r in self._results] + except: + self._to_notify._set_exception() + else: + self._to_notify._set_value(lst) + + +def _test(arg=None): + """Some tests""" + if arg == "-v": + def say(*x): + print(*x) + else: + def say(*x): + pass + say("Start Pool testing") + import time + + get_tid = lambda: threading.current_thread().ident + + def return42(): + return 42 + + def f(x): + return x * x + + def work(mseconds): + res = str(mseconds) + if mseconds < 0: + mseconds = -mseconds + say("[%d] Start to work for %fms..." % (get_tid(), mseconds*10)) + time.sleep(mseconds/100.) + say("[%d] Work done (%fms)." % (get_tid(), mseconds*10)) + return res + + ### Test copy/pasted from multiprocessing + pool = Pool(4) # start worker threads + + # edge cases + assert pool.map(return42, []) == [] + assert pool.apply_async(return42, []).get() == 42 + assert pool.apply(return42, []) == 42 + assert list(pool.imap(return42, iter([]))) == [] + assert list(pool.imap_unordered(return42, iter([]))) == [] + assert pool.map_async(return42, []).get() == [] + assert list(pool.imap_async(return42, iter([])).get()) == [] + assert list(pool.imap_unordered_async(return42, iter([])).get()) == [] + + # basic tests + result = pool.apply_async(f, (10,)) # evaluate "f(10)" asynchronously + assert result.get(timeout=1) == 100 # ... unless slow computer + assert list(pool.map(f, range(10))) == list(map(f, range(10))) + it = pool.imap(f, range(10)) + assert next(it) == 0 + assert next(it) == 1 + assert next(it) == 4 + + # Test apply_sync exceptions + result = pool.apply_async(time.sleep, (3,)) + try: + say(result.get(timeout=1)) # raises `TimeoutError` + except TimeoutError: + say("Good. Got expected timeout exception.") + else: + assert False, "Expected exception !" + assert result.get() is None # sleep() returns None + + def cb(s): + say("Result ready: %s" % s) + + # Test imap() + assert list(pool.imap(work, range(10, 3, -1), chunksize=4)) == list(map( + str, range(10, 3, -1))) + + # Test imap_unordered() + assert sorted(pool.imap_unordered(work, range(10, 3, -1))) == sorted(map( + str, range(10, 3, -1))) + + # Test map_async() + result = pool.map_async(work, range(10), callback=cb) + try: + result.get(timeout=0.01) # raises `TimeoutError` + except TimeoutError: + say("Good. Got expected timeout exception.") + else: + assert False, "Expected exception !" + say(result.get()) + + # Test imap_async() + result = pool.imap_async(work, range(3, 10), callback=cb) + try: + result.get(timeout=0.01) # raises `TimeoutError` + except TimeoutError: + say("Good. Got expected timeout exception.") + else: + assert False, "Expected exception !" + for i in result.get(): + say("Item:", i) + say("### Loop again:") + for i in result.get(): + say("Item2:", i) + + # Test imap_unordered_async() + result = pool.imap_unordered_async(work, range(10, 3, -1), callback=cb) + try: + say(result.get(timeout=0.01)) # raises `TimeoutError` + except TimeoutError: + say("Good. Got expected timeout exception.") + else: + assert False, "Expected exception !" + for i in result.get(): + say("Item1:", i) + for i in result.get(): + say("Item2:", i) + r = result.get() + for i in r: + say("Item3:", i) + for i in r: + say("Item4:", i) + for i in r: + say("Item5:", i) + + # + # The case for the exceptions + # + + # Exceptions in imap_unordered_async() + result = pool.imap_unordered_async(work, range(2, -10, -1), callback=cb) + time.sleep(3) + try: + for i in result.get(): + say("Got item:", i) + except (IOError, ValueError): + say("Good. Got expected exception") + + # Exceptions in imap_async() + result = pool.imap_async(work, range(2, -10, -1), callback=cb) + time.sleep(3) + try: + for i in result.get(): + say("Got item:", i) + except (IOError, ValueError): + say("Good. Got expected exception") + + # Stop the test: need to stop the pool !!! + pool.terminate() + pool.join() + print("done") + + +# End of david's derived file content + +class Monkey: + """ + Context manager which replaces standard multiprocessing.pool.ThreadPool + implementation with TBB.Pool using monkey-patching. It also enables TBB + threading for Intel MKL. For example: + + with TBB.Monkey(): + run_my_numpy_code() + + """ + _items = {'ThreadPool': None} + + def __init__(self): + pass + + def __enter__(self): + import os + self.env = os.getenv('MKL_THREADING_LAYER') + os.environ['MKL_THREADING_LAYER'] = 'TBB' + self.module = __import__('multiprocessing.pool', globals(), locals(), self._items.keys()) + for name in self._items.keys(): + oldattr = getattr(self.module, name) + self._items[name] = oldattr + setattr(self.module, name, Pool) + return self + + def __exit__(self, exc_type, exc_value, traceback): + import os + if self.env is None: + del os.environ['MKL_THREADING_LAYER'] + else: + os.environ['MKL_THREADING_LAYER'] = self.env + for name in self._items.keys(): + setattr(self.module, name, self._items[name]) + + +def _main(): + # Run the module specified as the next command line argument + # python -m TBB user_app.py + del sys.argv[0] # shift arguments + if len(sys.argv) < 1: + print("No file name specified for execution", file=sys.stderr) + elif '_' + sys.argv[0] in globals(): + globals()['_' + sys.argv[0]](*sys.argv[1:]) + else: + import runpy + with Monkey(): + runpy.run_path(sys.argv[0], run_name='__main__') + + +if __name__ == "__main__": + sys.exit(_main()) diff --git a/src/Makefile b/src/Makefile index d457e77..f1fee32 100644 --- a/src/Makefile +++ b/src/Makefile @@ -94,6 +94,9 @@ else @$(MAKE) -C "$(work_dir)_$(cfg)" -r -f $(tbb_root)/build/Makefile.test $@ endif +python_%: tbb_release + bash -c ". $(work_dir)_release$(SLASH)tbbvars.sh && $(MAKE) -rC '$(full_tbb_root)/python' CXX=$(compiler) $(subst python_,,$@)" + .PHONY: test_release test_debug test_release_no_depends test_debug_no_depends .PHONY: tbb_release tbb_debug tbb_test_release tbb_test_debug tbb_test_release_no_depends tbb_test_debug_no_depends # do not delete double-space after -C option diff --git a/src/index.html b/src/index.html index 30ebf79..77c719c 100644 --- a/src/index.html +++ b/src/index.html @@ -44,6 +44,8 @@ This directory contains the source code and unit tests for Intel® Threading
      Enables warnings as errors.
      make examples/{target}
      Invokes examples/Makefile with specified target. +
      make python_{target} [compiler={icl, icc}] +
      Invokes Makefile with the specified target in python directory. E.g. 'python_install' target builds and installs the module into Python.
      make clean_release clean_debug clean_examples
      Removes release or debug build directories, or cleans all examples.
      make test_no_depends diff --git a/src/rml/test/test_rml_mixed.cpp b/src/rml/test/test_rml_mixed.cpp index 7ed06a1..1de5bcc 100644 --- a/src/rml/test/test_rml_mixed.cpp +++ b/src/rml/test/test_rml_mixed.cpp @@ -38,7 +38,7 @@ int TestMain () { // non-deterministic. Thus dynamic_link fails on some systems when the // application changes its current directory after the library (TBB/OpenMP/...) // is loaded but before the static constructors in the library are executed. -#define CHDIR_SUPPORT_BROKEN ( (__TBB_GCC_VERSION >= 40600 && __TBB_GCC_VERSION < 50200) || (__linux__ && __TBB_CLANG_VERSION == 30500) ) +#define CHDIR_SUPPORT_BROKEN ( __TBB_GCC_VERSION >= 40600 || (__linux__ && __TBB_CLANG_VERSION >= 30500) ) const int OMP_ParallelRegionSize = 16; int TBB_MaxThread = 4; // Includes master diff --git a/src/tbb/arena.cpp b/src/tbb/arena.cpp index fbf42b5..12eac90 100644 --- a/src/tbb/arena.cpp +++ b/src/tbb/arena.cpp @@ -225,7 +225,7 @@ arena::arena ( market& m, unsigned num_slots, unsigned num_reserved_slots ) { my_task_stream.initialize(my_num_slots); ITT_SYNC_CREATE(&my_task_stream, SyncType_Scheduler, SyncObj_TaskStream); #if __TBB_ENQUEUE_ENFORCED_CONCURRENCY - my_mandatory_mode = no_mandatory; + my_concurrency_mode = cm_normal; #endif #if !__TBB_FP_CONTEXT my_cpu_ctl_env.get_env(); @@ -236,7 +236,7 @@ arena& arena::allocate_arena( market& m, unsigned num_slots, unsigned num_reserv __TBB_ASSERT( sizeof(base_type) + sizeof(arena_slot) == sizeof(arena), "All arena data fields must go to arena_base" ); __TBB_ASSERT( sizeof(base_type) % NFS_GetLineSize() == 0, "arena slots area misaligned: wrong padding" ); __TBB_ASSERT( sizeof(mail_outbox) == NFS_MaxLineSize, "Mailbox padding is wrong" ); - size_t n = allocation_size(num_slots); + size_t n = allocation_size(num_arena_slots(num_slots)); unsigned char* storage = (unsigned char*)NFS_Allocate( 1, n, NULL ); // Zero all slots to indicate that they are empty memset( storage, 0, n ); @@ -249,7 +249,7 @@ void arena::free_arena () { __TBB_ASSERT( !my_num_workers_requested && !my_num_workers_allotted, "Dying arena requests workers" ); __TBB_ASSERT( my_pool_state == SNAPSHOT_EMPTY || !my_max_num_workers, "Inconsistent state of a dying arena" ); #if __TBB_ENQUEUE_ENFORCED_CONCURRENCY - __TBB_ASSERT( my_mandatory_mode != global_mandatory, NULL ); + __TBB_ASSERT( my_concurrency_mode != cm_enforced_global, NULL ); #endif #if !__TBB_STATISTICS_EARLY_DUMP GATHER_STATISTIC( dump_arena_statistics() ); @@ -286,7 +286,7 @@ void arena::free_arena () { __TBB_ASSERT( my_pool_state == SNAPSHOT_EMPTY || !my_max_num_workers, NULL ); this->~arena(); #if TBB_USE_ASSERT > 1 - memset( storage, 0, allocation_size(my_max_num_workers) ); + memset( storage, 0, allocation_size(my_num_slots) ); #endif /* TBB_USE_ASSERT */ NFS_Free( storage ); } @@ -365,24 +365,21 @@ void arena::orphan_offloaded_tasks(generic_scheduler& s) { } #endif /* __TBB_TASK_PRIORITY */ -void arena::restore_priorities_if_need() { +bool arena::has_enqueued_tasks() { + // Look for enqueued tasks at all priority levels + for ( int p = 0; p < num_priority_levels; ++p ) + if ( !my_task_stream.empty(p) ) + return true; + return false; +} + +void arena::restore_priority_if_need() { // Check for the presence of enqueued tasks "lost" on some of // priority levels because updating arena priority and switching // arena into "populated" (FULL) state happen non-atomically. // Imposing atomicity would require task::enqueue() to use a lock, // which is unacceptable. -#if __TBB_TASK_PRIORITY - bool switch_back = false; - for ( int p = 0; p < num_priority_levels; ++p ) { - if ( !my_task_stream.empty(p) ) { - switch_back = true; - break; - } - } -#else - bool switch_back = !my_task_stream.empty(0); -#endif /* __TBB_TASK_PRIORITY */ - if ( switch_back ) { + if ( has_enqueued_tasks() ) { advertise_new_work(); #if __TBB_TASK_PRIORITY // update_arena_priority() expects non-zero arena::my_num_workers_requested, @@ -500,17 +497,17 @@ bool arena::is_out_of_work() { int current_demand = (int)my_max_num_workers; if( my_pool_state.compare_and_swap( SNAPSHOT_EMPTY, busy )==busy ) { #if __TBB_ENQUEUE_ENFORCED_CONCURRENCY - if( my_mandatory_mode==global_mandatory ) { + if( my_concurrency_mode==cm_enforced_global ) { // adjust_demand() called inside, if needed my_market->mandatory_concurrency_disable( this ); } else #endif /* __TBB_ENQUEUE_ENFORCED_CONCURRENCY */ { // This thread transitioned pool to empty state, and thus is - // responsible for telling RML that there is no other work to do. + // responsible for telling the market that there is no work to do. my_market->adjust_demand( *this, -current_demand ); } - restore_priorities_if_need(); + restore_priority_if_need(); return true; } return false; diff --git a/src/tbb/arena.h b/src/tbb/arena.h index 41fd86c..2be98d6 100644 --- a/src/tbb/arena.h +++ b/src/tbb/arena.h @@ -43,11 +43,11 @@ class allocate_root_with_context_proxy; namespace internal { -//! arena data except the array of slots +//! The structure of an arena, except the array of slots. /** Separated in order to simplify padding. Intrusive list node base class is used by market to form a list of arenas. **/ struct arena_base : padded { - //! Number of workers that have been marked out by the resource manager to service the arena + //! The number of workers that have been marked out by the resource manager to service the arena. unsigned my_num_workers_allotted; // heavy use in stealing loop //! Reference counter for the arena. @@ -57,30 +57,27 @@ struct arena_base : padded { atomic my_references; // heavy use in stealing loop #if __TBB_TASK_PRIORITY - //! Highest priority of recently spawned or enqueued tasks. + //! The highest priority of recently spawned or enqueued tasks. volatile intptr_t my_top_priority; // heavy use in stealing loop #endif /* !__TBB_TASK_PRIORITY */ - //! Maximal number of currently busy slots. + //! The maximal number of currently busy slots. atomic my_limit; // heavy use in stealing loop - //! Task pool for the tasks scheduled via task::enqueue() method + //! Task pool for the tasks scheduled via task::enqueue() method. /** Such scheduling guarantees eventual execution even if - new tasks are constantly coming (by extracting scheduled tasks in relaxed FIFO order); - - the enqueuing thread does not call any of wait_for_all methods. **/ -#if __TBB_TASK_PRIORITY + - the enqueuing thread does not call any of wait_for_all methods. + Depending on __TBB_TASK_PRIORITY, num_priority_levels can be 1 or more. **/ task_stream my_task_stream; // heavy use in stealing loop -#else /* !__TBB_TASK_PRIORITY */ - task_stream<1> my_task_stream; // heavy use in stealing loop -#endif /* !__TBB_TASK_PRIORITY */ - //! Number of workers that are currently requested from the resource manager - int my_num_workers_requested; - - //! Number of workers requested by the master thread owning the arena + //! The number of workers requested by the master thread owning the arena. unsigned my_max_num_workers; + //! The number of workers that are currently requested from the resource manager. + int my_num_workers_requested; + //! Current task pool state and estimate of available tasks amount. /** The estimate is either 0 (SNAPSHOT_EMPTY) or infinity (SNAPSHOT_FULL). Special state is "busy" (any other unsigned value). @@ -89,12 +86,12 @@ struct arena_base : padded { tbb::atomic my_pool_state; #if __TBB_ARENA_OBSERVER - //! List of local observers attached to this arena. + //! The list of local observers attached to this arena. observer_list my_observers; #endif #if __TBB_TASK_PRIORITY - //! Lowest normalized priority of available spawned or enqueued tasks. + //! The lowest normalized priority of available spawned or enqueued tasks. intptr_t my_bottom_priority; //! Tracks events that may bring tasks in offload areas to the top priority level. @@ -102,13 +99,13 @@ struct arena_base : padded { is elevated to the current arena's top level. **/ uintptr_t my_reload_epoch; - //! List of offloaded tasks abandoned by workers revoked by the market + //! The list of offloaded tasks abandoned by workers revoked by the market. task* my_orphaned_tasks; //! Counter used to track the occurrence of recent orphaning and re-sharing operations. tbb::atomic my_abandonment_epoch; - //! Highest priority level containing enqueued tasks + //! The highest priority level containing enqueued tasks. /** It being greater than 0 means that high priority enqueued tasks had to be bypassed because all workers were blocked in nested dispatch loops and were unable to progress at then current priority level. **/ @@ -117,10 +114,10 @@ struct arena_base : padded { // Below are rarely modified members - //! Market owning this arena + //! The market that owns this arena. market* my_market; - //! ABA prevention marker + //! ABA prevention marker. uintptr_t my_aba_epoch; #if !__TBB_FP_CONTEXT @@ -135,24 +132,25 @@ struct arena_base : padded { task_group_context* my_default_ctx; #endif /* __TBB_TASK_GROUP_CONTEXT */ - //! Number of slots in the arena + //! The number of slots in the arena. unsigned my_num_slots; - //! Number of reserved slots (can be occupied only by masters) + //! The number of reserved slots (can be occupied only by masters). unsigned my_num_reserved_slots; #if __TBB_ENQUEUE_ENFORCED_CONCURRENCY - enum mandatory_mode { - no_mandatory, - local_mandatory, - global_mandatory + //! Possible states for the concurrency mode of an arena. + enum concurrency_mode { + cm_normal = 0, // arena is served by workers as usual + cm_enforced_local, // arena needs an extra worker despite the arena limit + cm_enforced_global // arena needs an extra worker despite a global limit }; - //! Is mandatory concurrency subject of per-arena set or global control? - mandatory_mode my_mandatory_mode; + //! The concurrency mode of an arena. + concurrency_mode my_concurrency_mode; #endif /* __TBB_ENQUEUE_ENFORCED_CONCURRENCY */ - //! exit notifications after arena slot is released + //! Waiting object for master threads that cannot join the arena. concurrent_monitor my_exit_monitors; #if TBB_USE_ASSERT @@ -163,12 +161,12 @@ struct arena_base : padded { class arena: public padded { - //! Restore priorities of arenas and task presence status of the arena, if new enqueued tasks found - void restore_priorities_if_need(); + //! If enqueued tasks found, restore arena priority and task presence status + void restore_priority_if_need(); public: typedef padded base_type; - //! type of work that advertised by advertise_new_work() + //! Types of work advertised by advertise_new_work() enum new_work_type { work_spawned, wakeup, @@ -185,8 +183,8 @@ public: return max(2u, num_slots); } - static int allocation_size ( unsigned max_num_workers ) { - return sizeof(base_type) + num_arena_slots(max_num_workers) * (sizeof(mail_outbox) + sizeof(arena_slot)); + static int allocation_size ( unsigned num_slots ) { + return sizeof(base_type) + num_slots * (sizeof(mail_outbox) + sizeof(arena_slot)); } //! Get reference to mailbox corresponding to given affinity_id. @@ -259,16 +257,19 @@ public: intptr_t workers_task_node_count(); #endif + //! Check for the presence of enqueued tasks at all priority levels + bool has_enqueued_tasks(); + #if __TBB_ENQUEUE_ENFORCED_CONCURRENCY //! Recall worker if global mandatory is enabled, but not for this arena bool recall_by_mandatory_request() const { - return my_market->my_mandatory_num_requested && my_mandatory_mode==arena_base::no_mandatory; + return my_market->my_mandatory_num_requested && my_concurrency_mode==cm_normal; } - //! Mandatory parallelism requested by this arena - bool mandatory_requested() const { - return my_num_workers_requested && my_market->my_mandatory_num_requested - && my_mandatory_mode!=arena_base::no_mandatory; + //! The arena is currently in an enforced concurrency mode + bool must_have_concurrency() const { + return my_num_workers_requested && + ( my_concurrency_mode==cm_enforced_local || my_concurrency_mode==cm_enforced_global ); } #endif static const size_t out_of_arena = ~size_t(0); @@ -355,11 +356,8 @@ inline void arena::on_thread_leaving ( ) { // because it can create the demand of workers, // but the arena can be already empty (and so ready for destroying) if( ref_param==ref_external && my_num_slots != my_num_reserved_slots - && 0 == m->my_num_workers_soft_limit && my_mandatory_mode==no_mandatory ) { + && 0 == m->my_num_workers_soft_limit && my_concurrency_mode==cm_normal ) { bool is_out = false; -#if !__TBB_TASK_PRIORITY - const int num_priority_levels = 1; -#endif for (int i=0; i void arena::advertise_new_work() { if( work_type == work_enqueued ) { #if __TBB_ENQUEUE_ENFORCED_CONCURRENCY if( my_market->my_num_workers_soft_limit == 0 ) { - if( my_mandatory_mode!=global_mandatory ) { + if( my_concurrency_mode!=cm_enforced_global ) { if( my_market->mandatory_concurrency_enable( this ) ) { my_pool_state = SNAPSHOT_FULL; return; @@ -387,19 +385,19 @@ template void arena::advertise_new_work() { } } else if( my_max_num_workers==0 ) { my_max_num_workers = 1; - __TBB_ASSERT(my_mandatory_mode==no_mandatory, ""); - my_mandatory_mode = local_mandatory; + __TBB_ASSERT(my_concurrency_mode==cm_normal, NULL); + my_concurrency_mode = cm_enforced_local; my_pool_state = SNAPSHOT_FULL; my_market->adjust_demand( *this, 1 ); return; } #endif /* __TBB_ENQUEUE_ENFORCED_CONCURRENCY */ // Local memory fence here and below is required to avoid missed wakeups; see the comment below. - // Starvation resistant tasks require mandatory concurrency, so missed wakeups are unacceptable. + // Starvation resistant tasks require concurrency, so missed wakeups are unacceptable. atomic_fence(); } else if( work_type == wakeup ) { - __TBB_ASSERT(my_max_num_workers!=0, "Not expect mandatory concurrency request."); + __TBB_ASSERT(my_max_num_workers!=0, "Unexpected worker wakeup request"); atomic_fence(); } // Double-check idiom that, in case of spawning, is deliberately sloppy about memory fences. @@ -424,12 +422,12 @@ template void arena::advertise_new_work() { } } // This thread transitioned pool from empty to full state, and thus is responsible for - // telling RML that there is work to do. + // telling the market that there is work to do. #if __TBB_ENQUEUE_ENFORCED_CONCURRENCY if( work_type == work_spawned ) { - if( my_mandatory_mode!=no_mandatory ) { - switch( my_mandatory_mode ) { - case local_mandatory: + if( my_concurrency_mode!=cm_normal ) { + switch( my_concurrency_mode ) { + case cm_enforced_local: __TBB_ASSERT(my_max_num_workers==1, ""); __TBB_ASSERT(!governor::local_scheduler()->is_worker(), ""); // There was deliberate oversubscription on 1 core for sake of starvation-resistant tasks. @@ -437,11 +435,11 @@ template void arena::advertise_new_work() { // with relaxed sequential semantics, and oversubscription should be avoided. // Demand for workers has been decreased to 0 during SNAPSHOT_EMPTY, so just keep it. my_max_num_workers = 0; - my_mandatory_mode = no_mandatory; + my_concurrency_mode = cm_normal; break; - case global_mandatory: + case cm_enforced_global: my_market->mandatory_concurrency_disable( this ); - restore_priorities_if_need(); + restore_priority_if_need(); break; default: break; diff --git a/src/tbb/custom_scheduler.h b/src/tbb/custom_scheduler.h index 6174f00..14e2e2c 100644 --- a/src/tbb/custom_scheduler.h +++ b/src/tbb/custom_scheduler.h @@ -203,6 +203,7 @@ task* custom_scheduler::receive_or_steal_task( __TBB_atomic ref #if __TBB_TASK_PRIORITY // Check if any earlier offloaded non-top priority tasks become returned to the top level else if ( my_offloaded_tasks && (t=reload_tasks()) ) { + __TBB_ASSERT( !is_proxy(*t), "The proxy task cannot be offloaded" ); // just proceed with the obtained task } #endif /* __TBB_TASK_PRIORITY */ @@ -295,6 +296,7 @@ fail: if ( t ) { if( SchedulerTraits::itt_possible ) ITT_NOTIFY(sync_cancel, this); + __TBB_ASSERT( !is_proxy(*t), "The proxy task cannot be offloaded" ); break; // exit stealing loop and return } } @@ -417,6 +419,7 @@ void custom_scheduler::local_wait_for_all( task& parent, task* assert_context_valid(t->prefix().context); if ( !t->prefix().context->my_cancellation_requested ) #endif + // TODO: make the assert stronger by prohibiting allocated state. __TBB_ASSERT( 1L<state() & (1L<my_max_num_workers > 0 || my_market->my_ref_count > 1 - // || parent.prefix().ref_count == 1, "deadlock detected" ); - // Dispatching task pointer is NULL *iff* this is a worker thread in its outermost // dispatch loop (i.e. its execution stack is empty). In this case it should exit it // either when there is no more work in the current arena, or when revoked by the market. diff --git a/src/tbb/itt_notify.cpp b/src/tbb/itt_notify.cpp index 82d0524..2e0e449 100644 --- a/src/tbb/itt_notify.cpp +++ b/src/tbb/itt_notify.cpp @@ -49,6 +49,12 @@ extern "C" void MallocInitializeITT(); namespace tbb { namespace internal { int __TBB_load_ittnotify() { +#if !(_WIN32||_WIN64) + // tool_api crashes without dlopen, check that it's present. Common case + // for lack of dlopen is static binaries, i.e. ones build with -static. + if (dlopen == NULL) + return 0; +#endif return __itt_init_ittlib(NULL, // groups for: (__itt_group_id)(__itt_group_sync // prepare/cancel/acquired/releasing | __itt_group_thread // name threads diff --git a/src/tbb/market.cpp b/src/tbb/market.cpp index 7eadfef..0d257e5 100644 --- a/src/tbb/market.cpp +++ b/src/tbb/market.cpp @@ -214,7 +214,7 @@ void market::set_active_num_workers ( unsigned soft_limit ) { } // have my_ref_count for market, use it safely { - arenas_list_mutex_type::scoped_lock lock(m->my_arenas_list_mutex); + arenas_list_mutex_type::scoped_lock lock( m->my_arenas_list_mutex ); __TBB_ASSERT(soft_limit <= m->my_num_workers_hard_limit, NULL); m->my_num_workers_soft_limit = soft_limit; // report only once after new soft limit value is set @@ -236,7 +236,7 @@ void market::set_active_num_workers ( unsigned soft_limit ) { m->my_num_workers_requested = requested; #if __TBB_TASK_PRIORITY m->my_priority_levels[m->my_global_top_priority].workers_available = soft_limit; - m->update_allotment(m->my_global_top_priority); + m->update_allotment( m->my_global_top_priority ); #else m->update_allotment(); #endif @@ -246,32 +246,31 @@ void market::set_active_num_workers ( unsigned soft_limit ) { // enable mandatory concurrency, if enqueued tasks are found // and zero soft_limit requested #if __TBB_TASK_PRIORITY - for ( int p = m->my_global_top_priority; - p >= m->my_global_bottom_priority; --p ) { + for( int p = m->my_global_top_priority; p >= m->my_global_bottom_priority; --p ) { priority_level_info &pl = m->my_priority_levels[p]; arena_list_type &arenas = pl.arenas; #else const int p = 0; arena_list_type &arenas = m->my_arenas; #endif /* __TBB_TASK_PRIORITY */ - for (arena_list_type::iterator it = arenas.begin(); - it != arenas.end(); ++it ) + for( arena_list_type::iterator it = arenas.begin(); it != arenas.end(); ++it ) { if( !it->my_task_stream.empty(p) ) { // switch local_mandatory to global_mandatory unconditionally if( m->mandatory_concurrency_enable_impl( &*it ) ) need_mandatory = true; } + } #if __TBB_TASK_PRIORITY } #endif /* __TBB_TASK_PRIORITY */ } #endif /* __TBB_ENQUEUE_ENFORCED_CONCURRENCY */ } - // Must be called outside of any locks - if ( requested != old_requested ) - m->my_server->adjust_job_count_estimate( requested - old_requested ); - if( need_mandatory ) - m->my_server->adjust_job_count_estimate( 1 ); + // adjust_job_count_estimate must be called outside of any locks + int delta = requested - old_requested; + if( need_mandatory ) ++delta; + if( delta!=0 ) + m->my_server->adjust_job_count_estimate( delta ); // release internal market reference to match ++m->my_ref_count above m->release(); } @@ -365,13 +364,11 @@ arena* market::arena_in_need ( arena_list_type &arenas, arena *&next ) { return NULL; } -void market::update_allotment ( arena_list_type& arenas, int workers_demand, int max_workers ) { +int market::update_allotment ( arena_list_type& arenas, int workers_demand, int max_workers ) { __TBB_ASSERT( workers_demand, NULL ); max_workers = min(workers_demand, max_workers); int carry = 0; -#if TBB_USE_ASSERT int assigned = 0; -#endif /* TBB_USE_ASSERT */ arena_list_type::iterator it = arenas.begin(); for ( ; it != arenas.end(); ++it ) { arena& a = *it; @@ -383,16 +380,20 @@ void market::update_allotment ( arena_list_type& arenas, int workers_demand, int int allotted = tmp / workers_demand; carry = tmp % workers_demand; // a.my_num_workers_requested may temporarily exceed a.my_max_num_workers - a.my_num_workers_allotted = min( allotted, (int)a.my_max_num_workers ); + allotted = min( allotted, (int)a.my_max_num_workers ); #if __TBB_ENQUEUE_ENFORCED_CONCURRENCY - if ( !a.my_num_workers_allotted && a.mandatory_requested() ) - a.my_num_workers_allotted = 1; + if ( !allotted && a.must_have_concurrency() ) + allotted = 1; #endif -#if TBB_USE_ASSERT - assigned += a.my_num_workers_allotted; -#endif /* TBB_USE_ASSERT */ + a.my_num_workers_allotted = allotted; + assigned += allotted; } - __TBB_ASSERT( assigned <= workers_demand, NULL ); +#if __TBB_ENQUEUE_ENFORCED_CONCURRENCY + __TBB_ASSERT( assigned <= workers_demand, NULL ); // weaker assertion due to enforced allotment +#else + __TBB_ASSERT( assigned <= max_workers, NULL ); +#endif + return assigned; } #if __TBB_TASK_PRIORITY @@ -437,9 +438,8 @@ void market::update_allotment ( intptr_t highest_affected_priority ) { priority_level_info &pl = my_priority_levels[i]; pl.workers_available = available; if ( pl.workers_requested ) { - update_allotment( pl.arenas, pl.workers_requested, available ); - available -= pl.workers_requested; - if ( available < 0 ) { + available -= update_allotment( pl.arenas, pl.workers_requested, available ); + if ( available < 0 ) { // TODO: assertion? available = 0; break; } @@ -453,11 +453,10 @@ void market::update_allotment ( intptr_t highest_affected_priority ) { for ( ; it != pl.arenas.end(); ++it ) { __TBB_ASSERT( it->my_num_workers_requested >= 0 || !it->my_num_workers_allotted, NULL ); #if __TBB_ENQUEUE_ENFORCED_CONCURRENCY - if ( it->mandatory_requested() ) - it->my_num_workers_allotted = 1; - else + it->my_num_workers_allotted = it->must_have_concurrency() ? 1 : 0; +#else + it->my_num_workers_allotted = 0; #endif - it->my_num_workers_allotted = 0; } } } @@ -465,7 +464,7 @@ void market::update_allotment ( intptr_t highest_affected_priority ) { #if __TBB_ENQUEUE_ENFORCED_CONCURRENCY bool market::mandatory_concurrency_enable_impl ( arena *a, bool *enabled ) { - if( a->my_mandatory_mode==arena_base::global_mandatory ) { + if( a->my_concurrency_mode==arena_base::cm_enforced_global ) { if( enabled ) *enabled = false; return false; @@ -473,7 +472,7 @@ bool market::mandatory_concurrency_enable_impl ( arena *a, bool *enabled ) { if( enabled ) *enabled = true; a->my_max_num_workers = 1; - a->my_mandatory_mode = arena_base::global_mandatory; + a->my_concurrency_mode = arena_base::cm_enforced_global; #if __TBB_TASK_PRIORITY priority_level_info &pl = my_priority_levels[a->my_top_priority]; pl.workers_requested++; @@ -510,7 +509,7 @@ void market::mandatory_concurrency_disable ( arena *a ) { { arenas_list_mutex_type::scoped_lock lock(my_arenas_list_mutex); - if( a->my_mandatory_mode!=arena_base::global_mandatory ) + if( a->my_concurrency_mode!=arena_base::cm_enforced_global ) return; __TBB_ASSERT( a->my_max_num_workers==1, NULL ); a->my_max_num_workers = 0; @@ -544,7 +543,7 @@ void market::mandatory_concurrency_disable ( arena *a ) { else if( p!= my_global_top_priority ) update_global_top_priority(p); #endif - a->my_mandatory_mode = arena::no_mandatory; + a->my_concurrency_mode = arena::cm_normal; } if( delta_adjust_demand ) adjust_demand( *a, -delta_adjust_demand ); @@ -563,7 +562,7 @@ void market::adjust_demand ( arena& a, int delta ) { if ( a.my_num_workers_requested <= 0 ) { #if __TBB_ENQUEUE_ENFORCED_CONCURRENCY // must not recall worker from arena with mandatory parallelism - if ( a.my_market->my_mandatory_num_requested && a.my_mandatory_mode!=arena_base::no_mandatory ) + if ( a.my_market->my_mandatory_num_requested && a.my_concurrency_mode!=arena_base::cm_normal ) a.my_num_workers_allotted = 1; else #endif @@ -612,7 +611,7 @@ void market::adjust_demand ( arena& a, int delta ) { #if __TBB_ENQUEUE_ENFORCED_CONCURRENCY // must not recall worker from arena with mandatory parallelism if ( !a.my_num_workers_allotted && a.my_num_workers_requested - && a.my_market->my_mandatory_num_requested && a.my_mandatory_mode!=arena_base::no_mandatory ) + && a.my_market->my_mandatory_num_requested && a.my_concurrency_mode!=arena_base::cm_normal ) a.my_num_workers_allotted = 1; #endif my_priority_levels[p - 1].workers_available = my_num_workers_soft_limit - a.my_num_workers_allotted; @@ -645,13 +644,13 @@ void market::adjust_demand ( arena& a, int delta ) { if ( delta > 0 ) { // can't overflow soft_limit, but remember values request by arenas in // my_total_demand to not prematurely release workers to RML - if ( my_num_workers_requested+delta > (int)my_num_workers_soft_limit ) { + if ( my_num_workers_requested+delta > (int)my_num_workers_soft_limit ) delta = my_num_workers_soft_limit - my_num_workers_requested; - } - } else + } else { // the number of workers should not be decreased below my_total_demand if ( my_num_workers_requested+delta < my_total_demand ) delta = min(my_total_demand, (int)my_num_workers_soft_limit) - my_num_workers_requested; + } my_num_workers_requested += delta; __TBB_ASSERT( my_num_workers_requested <= (int)my_num_workers_soft_limit, NULL ); @@ -783,6 +782,7 @@ bool market::update_arena_priority ( arena& a, intptr_t new_priority ) { // TODO: do not acquire this global lock while checking arena's state. arenas_list_mutex_type::scoped_lock lock(my_arenas_list_mutex); + tbb::internal::assert_priority_valid(new_priority); __TBB_ASSERT( my_global_top_priority >= a.my_top_priority || a.my_num_workers_requested <= 0, NULL ); assert_market_valid(); if ( a.my_top_priority == new_priority ) { @@ -830,11 +830,11 @@ bool market::update_arena_priority ( arena& a, intptr_t new_priority ) { ++my_global_bottom_priority; __TBB_ASSERT( my_global_bottom_priority <= new_priority, NULL ); #if __TBB_ENQUEUE_ENFORCED_CONCURRENCY - const bool active_mandatory = my_mandatory_num_requested && a.my_mandatory_mode!=arena_base::no_mandatory; + const bool enforced_concurrency = my_mandatory_num_requested && a.must_have_concurrency(); #else - const bool active_mandatory = false; + const bool enforced_concurrency = false; #endif - __TBB_ASSERT_EX(active_mandatory || my_priority_levels[my_global_bottom_priority].workers_requested > 0, NULL ); + __TBB_ASSERT_EX( enforced_concurrency || my_priority_levels[my_global_bottom_priority].workers_requested > 0, NULL ); } update_allotment( highest_affected_level ); diff --git a/src/tbb/market.h b/src/tbb/market.h index 5ab8fe5..6fb5f8f 100644 --- a/src/tbb/market.h +++ b/src/tbb/market.h @@ -227,9 +227,6 @@ private: void assert_market_valid () const {} #endif /* !__TBB_TASK_PRIORITY */ - //! Returns number of masters doing computational (CPU-intensive) work - int num_active_masters () { return 1; } // APM TODO: replace with a real mechanism - //////////////////////////////////////////////////////////////////////////////// // Helpers to unify code branches dependent on priority feature presence @@ -239,7 +236,7 @@ private: arena* arena_in_need ( arena_list_type &arenas, arena *&next ); - static void update_allotment ( arena_list_type& arenas, int total_demand, int max_workers ); + static int update_allotment ( arena_list_type& arenas, int total_demand, int max_workers ); //////////////////////////////////////////////////////////////////////////////// diff --git a/src/tbb/queuing_rw_mutex.cpp b/src/tbb/queuing_rw_mutex.cpp index b0a2ad9..0a517ea 100644 --- a/src/tbb/queuing_rw_mutex.cpp +++ b/src/tbb/queuing_rw_mutex.cpp @@ -319,7 +319,7 @@ retry: __TBB_store_relaxed(my_prev, pred); acquire_internal_lock(); - __TBB_store_with_release(pred->my_next,reinterpret_cast(NULL)); + __TBB_store_with_release(pred->my_next,static_cast(NULL)); if( !__TBB_load_relaxed(my_next) && this != my_mutex->q_tail.compare_and_swap(pred, this) ) { spin_wait_while_eq( my_next, (void*)NULL ); diff --git a/src/tbb/scheduler.cpp b/src/tbb/scheduler.cpp index a0e2d83..db8bd43 100644 --- a/src/tbb/scheduler.cpp +++ b/src/tbb/scheduler.cpp @@ -561,7 +561,7 @@ inline task* generic_scheduler::prepare_for_spawning( task* t ) { // Mark proxy as present in both locations (sender's task pool and destination mailbox) proxy.task_and_tag = intptr_t(t) | task_proxy::location_mask; #if __TBB_TASK_PRIORITY - proxy.prefix().context = t->prefix().context; + poison_pointer( proxy.prefix().context ); #endif /* __TBB_TASK_PRIORITY */ ITT_NOTIFY( sync_releasing, proxy.outbox ); // Mail the proxy - after this point t may be destroyed by another thread at any moment. @@ -683,84 +683,46 @@ task* generic_scheduler::winnow_task_pool () { // the corresponding checking sequence in arena::is_out_of_work() is not atomic // anyway, fences aren't used, so that not to penalize warmer path. auto_indicator indicator(my_pool_reshuffling_pending); - // The purpose of the synchronization algorithm here is for the owner thread - // to avoid locking task pool most of the time. -#if __TBB_TODO - // Just locking the task pool unconditionally would produce simpler code, + + // Locking the task pool unconditionally produces simpler code, // scalability of which should not suffer unless priority jitter takes place. - // Since priority jitter is nocuous by itself, we may want to evaluate - // applicability of the simpler variant... - // Non-blocking variant also prevent us from relocating remaining tasks to - // the beginning of the task pool, not sure if it makes much sense. -#endif + // TODO: consider the synchronization algorithm here is for the owner thread + // to avoid locking task pool most of the time. + acquire_task_pool(); size_t T0 = __TBB_load_relaxed(my_arena_slot->tail); - __TBB_store_relaxed( my_arena_slot->tail, __TBB_load_relaxed(my_arena_slot->head) - 1 ); - atomic_fence(); - size_t H = __TBB_load_relaxed(my_arena_slot->head); - size_t T = __TBB_load_relaxed(my_arena_slot->tail); - __TBB_ASSERT( (intptr_t)T <= (intptr_t)T0, NULL); - __TBB_ASSERT( (intptr_t)H >= (intptr_t)T || (H == T0 && T == T0), NULL ); - bool acquired = false; - if ( H == T ) { - // Either no contention with thieves during arbitration protocol execution or ... - if ( H >= T0 ) { - // ... the task pool got empty - reset_task_pool_and_leave( /*locked=*/false ); - return NULL; + size_t H0 = __TBB_load_relaxed(my_arena_slot->head); + size_t dst = 0; + for ( size_t src = H0; src < T0; ++src ) { + task *curr = my_arena_slot->task_pool_ptr[src]; + // We cannot offload a proxy task (check the priority of it) because it can be already consumed. + if ( !is_proxy(*curr) ) { + intptr_t p = priority(*curr); + if ( p < *my_ref_top_priority ) { + offload_task( *curr, p ); + continue; + } } - } - else { - // Contention with thieves detected. Now without taking lock it is impossible - // to define the current head value because of its jitter caused by continuing - // stealing attempts (the pool is not locked so far). - acquired = true; - acquire_task_pool(); - H = __TBB_load_relaxed(my_arena_slot->head); - if ( H >= T0 ) { - reset_task_pool_and_leave( /*locked=*/true ); - return NULL; - } - } - size_t src, - dst = T0; - // Find the first task to offload. - for ( src = H; src < T0; ++src ) { - task &t = *my_arena_slot->task_pool_ptr[src]; - intptr_t p = priority(t); - if ( p < *my_ref_top_priority ) { - // Position of the first offloaded task will be the starting point - // for relocation of subsequent tasks that survive winnowing. - dst = src; - offload_task( t, p ); - break; - } - } - for ( ++src; src < T0; ++src ) { - task &t = *my_arena_slot->task_pool_ptr[src]; - intptr_t p = priority(t); - if ( p < *my_ref_top_priority ) - offload_task( t, p ); - else - my_arena_slot->task_pool_ptr[dst++] = &t; + my_arena_slot->task_pool_ptr[dst++] = curr; } __TBB_ASSERT( T0 >= dst, NULL ); - task *t = H < dst ? my_arena_slot->task_pool_ptr[--dst] : NULL; - if ( H == dst ) { - // No tasks remain the primary pool - reset_task_pool_and_leave( acquired ); + + task *t = NULL; + while ( !t && dst ) { + t = my_arena_slot->task_pool_ptr[--dst]; + __TBB_ASSERT( !is_poisoned(t), NULL ); + poison_pointer( my_arena_slot->task_pool_ptr[dst] ); + if ( is_proxy(*t) ) + t = consume_proxy( *t ); } - else if ( acquired ) { - __TBB_ASSERT( !is_poisoned(my_arena_slot->task_pool_ptr[H]), NULL ); - __TBB_store_relaxed( my_arena_slot->tail, dst ); + if (dst) { + __TBB_store_relaxed(my_arena_slot->head, 0); + __TBB_store_relaxed(my_arena_slot->tail, dst); release_task_pool(); + } else { + reset_task_pool_and_leave(/*locked = */true); } - else { - __TBB_ASSERT( !is_poisoned(my_arena_slot->task_pool_ptr[H]), NULL ); - // Release fence is necessary to make sure possibly relocated task pointers - // become visible to potential thieves - __TBB_store_with_release( my_arena_slot->tail, dst ); - } - my_arena_slot->fill_with_canary_pattern( dst, T0 ); + // Choose max(dst, H0) because ranges [0,dst) and [H0,T0) can overlap. + my_arena_slot->fill_with_canary_pattern(max(dst, H0), T0); assert_task_pool_valid(); return t; } @@ -774,13 +736,14 @@ task* generic_scheduler::reload_tasks ( task*& offloaded_tasks, task**& offloade task *t; while ( (t = *link) ) { task** next_ptr = &t->prefix().next_offloaded; + __TBB_ASSERT( !is_proxy(*t), "The proxy tasks cannot be offloaded" ); if ( priority(*t) >= top_priority ) { tasks.push_back( t ); // Note that owner is an alias of next_offloaded. Thus the following // assignment overwrites *next_ptr task* next = *next_ptr; t->prefix().owner = this; - __TBB_ASSERT( t->prefix().state == task::ready || t->prefix().extra_state == es_task_proxy, NULL ); + __TBB_ASSERT( t->prefix().state == task::ready, NULL ); *link = next; } else { @@ -852,6 +815,24 @@ task* generic_scheduler::reload_tasks () { } #endif /* __TBB_TASK_PRIORITY */ +inline task* generic_scheduler::consume_proxy( task &proxy ) { + __TBB_ASSERT( is_proxy(proxy), NULL ); + task_proxy &tp = static_cast(proxy); + task *result = tp.extract_task(); + if (!result) { + // Proxy was empty, so it's our responsibility to free it + free_task(tp); + return NULL; + } + GATHER_STATISTIC(++my_counters.proxies_executed); + // Following assertion should be true because TBB 2.0 tasks never specify affinity, and hence are not proxied. + __TBB_ASSERT(is_version_3_task(*result), "backwards compatibility with TBB 2.0 broken"); + // Task affinity has changed. + my_innermost_running_task = result; + result->note_affinity(my_affinity_id); + return result; +} + inline task* generic_scheduler::get_task() { __TBB_ASSERT( is_task_pool_published(), NULL ); task* result = NULL; @@ -885,22 +866,10 @@ retry: poison_pointer( my_arena_slot->task_pool_ptr[T] ); } if( result && is_proxy(*result) ) { - task_proxy &tp = *(task_proxy*)result; - result = tp.extract_task(); - if( !result ) { - // Proxy was empty, so it's our responsibility to free it - free_task(tp); - if ( is_task_pool_published() ) + result = consume_proxy(*result ); + // The task can be grabbed when a thief backs off. As a result, the pool can be reset. + if ( !result && is_task_pool_published() ) goto retry; - __TBB_ASSERT( is_quiescent_local_task_pool_reset(), NULL ); - return NULL; - } - GATHER_STATISTIC( ++my_counters.proxies_executed ); - // Following assertion should be true because TBB 2.0 tasks never specify affinity, and hence are not proxied. - __TBB_ASSERT( is_version_3_task(*result), "backwards compatibility with TBB 2.0 broken" ); - // Task affinity has changed. - my_innermost_running_task = result; - result->note_affinity(my_affinity_id); } __TBB_ASSERT( result || is_quiescent_local_task_pool_reset(), NULL ); return result; @@ -1200,7 +1169,7 @@ void generic_scheduler::cleanup_master( bool needs_wait_workers ) { enough information for the main thread on IA-64 architecture (RSE spill area and memory stack are allocated as two separate discontinuous chunks of memory), and there is no portable way to discern the main and the secondary threads. - Thus for OS X* and IA-64 Linux architecture we use the TBB worker stack size for + Thus for OS X* and IA-64 architecture for Linux* OS we use the TBB worker stack size for all threads and use the current stack top as the stack base. This simplified approach is based on the following assumptions: 1) If the default stack size is insufficient for the user app needs, the diff --git a/src/tbb/scheduler.h b/src/tbb/scheduler.h index fd8d439..e3510f8 100644 --- a/src/tbb/scheduler.h +++ b/src/tbb/scheduler.h @@ -228,6 +228,11 @@ public: // almost every class in TBB uses generic_scheduler In the latter case compacts the pool. **/ task* get_task(); + //! Extract a task from the proxy. + /** Returns the pointer to the extracted task or NULL if the proxy is empty. + In the latter case deallocates the proxy. **/ + task* consume_proxy( task& proxy ); + //! Attempt to get a task from the mailbox. /** Gets a task only if it has not been executed by its sender or a thief that has stolen it from the sender's task pool. Otherwise returns NULL. @@ -325,8 +330,8 @@ public: //! True if the scheduler is on the outermost dispatch level in a worker thread. inline bool worker_outermost_level () const; - //! Returns number of worker threads in the arena this thread belongs to. - unsigned number_of_workers_in_my_arena(); + //! Returns the concurrency limit of the current arena. + unsigned max_threads_in_arena(); #if __TBB_COUNT_TASK_NODES intptr_t get_task_node_count( bool count_arena_workers = false ); @@ -544,9 +549,9 @@ inline bool generic_scheduler::is_worker() { return my_is_worker; } -inline unsigned generic_scheduler::number_of_workers_in_my_arena() { +inline unsigned generic_scheduler::max_threads_in_arena() { __TBB_ASSERT(my_arena, NULL); - return my_arena->my_max_num_workers; + return my_arena->my_num_slots; } //! Return task object to the memory allocator. @@ -648,13 +653,14 @@ inline intptr_t generic_scheduler::effective_reference_priority () const { return !worker_outermost_level() || (my_arena->my_num_workers_allotted < my_arena->num_workers_active() #if __TBB_ENQUEUE_ENFORCED_CONCURRENCY - && my_arena->my_mandatory_mode!=arena_base::global_mandatory + && my_arena->my_concurrency_mode!=arena_base::cm_enforced_global #endif ) ? *my_ref_top_priority : my_arena->my_top_priority; } inline void generic_scheduler::offload_task ( task& t, intptr_t /*priority*/ ) { GATHER_STATISTIC( ++my_counters.prio_tasks_offloaded ); + __TBB_ASSERT( !is_proxy(t), "The proxy task cannot be offloaded" ); __TBB_ASSERT( my_offloaded_task_list_tail_link && !*my_offloaded_task_list_tail_link, NULL ); #if TBB_USE_ASSERT t.prefix().state = task::ready; diff --git a/src/tbb/scheduler_common.h b/src/tbb/scheduler_common.h index 975db09..8cb753a 100644 --- a/src/tbb/scheduler_common.h +++ b/src/tbb/scheduler_common.h @@ -120,6 +120,8 @@ inline void assert_priority_valid ( intptr_t p ) { inline intptr_t& priority ( task& t ) { return t.prefix().context->my_priority; } +#else /* __TBB_TASK_PRIORITY */ +static const intptr_t num_priority_levels = 1; #endif /* __TBB_TASK_PRIORITY */ //! Mutex type for global locks in the scheduler diff --git a/src/tbb/task.cpp b/src/tbb/task.cpp index c9254d4..c314282 100644 --- a/src/tbb/task.cpp +++ b/src/tbb/task.cpp @@ -154,7 +154,7 @@ void allocate_additional_child_of_proxy::free( task& task ) const { //------------------------------------------------------------------------ size_t get_initial_auto_partitioner_divisor() { const size_t X_FACTOR = 4; - return X_FACTOR * (1+governor::local_scheduler()->number_of_workers_in_my_arena()); + return X_FACTOR * governor::local_scheduler()->max_threads_in_arena(); } //------------------------------------------------------------------------ @@ -162,7 +162,7 @@ size_t get_initial_auto_partitioner_divisor() { //------------------------------------------------------------------------ void affinity_partitioner_base_v3::resize( unsigned factor ) { // Check factor to avoid asking for number of workers while there might be no arena. - size_t new_size = factor ? factor*(1+governor::local_scheduler()->number_of_workers_in_my_arena()) : 0; + size_t new_size = factor ? factor*governor::local_scheduler()->max_threads_in_arena() : 0; if( new_size!=my_size ) { if( my_array ) { NFS_Free( my_array ); diff --git a/src/test/harness_defs.h b/src/test/harness_defs.h index fa9082b..0992318 100644 --- a/src/test/harness_defs.h +++ b/src/test/harness_defs.h @@ -102,15 +102,6 @@ // MSVC 2015 does not do compile-time initialization of static variables with constexpr constructors in debug mode #define __TBB_STATIC_CONSTEXPR_INIT_BROKEN (_MSC_VER==1900 && !__INTEL_COMPILER && _DEBUG) -//some compilers do not generate implicitly move constructor and assignment operator, as this feature (r-value reference 3.0) was added later -#if __INTEL_COMPILER - #define __TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_BROKEN (__TBB_CPP11_RVALUE_REF_PRESENT && (__INTEL_COMPILER < 1400 || __INTEL_COMPILER == 1600 && __INTEL_COMPILER_UPDATE <= 2)) -#elif __clang__ - #define __TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_BROKEN !__has_feature(cxx_implicit_moves) -#else - #define __TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_BROKEN (__TBB_CPP11_RVALUE_REF_PRESENT && _MSC_VER && _MSC_VER <=1800) -#endif /* __INTEL_COMPILER */ - #if __GNUC__ && __ANDROID__ #define __TBB_EXCEPTION_TYPE_INFO_BROKEN ( __TBB_GCC_VERSION < 40600 ) #elif _MSC_VER diff --git a/src/test/test_async_msg.cpp b/src/test/test_async_msg.cpp index accef62..1dd5ae5 100644 --- a/src/test/test_async_msg.cpp +++ b/src/test/test_async_msg.cpp @@ -26,6 +26,10 @@ #if __TBB_PREVIEW_ASYNC_MSG +#if _MSC_VER +#pragma warning (disable: 4503) // Suppress "decorated name length exceeded, name was truncated" warning +#endif + #include "tbb/flow_graph.h" #include "tbb/tbb_thread.h" #include "tbb/concurrent_queue.h" diff --git a/src/test/test_atomic.cpp b/src/test/test_atomic.cpp index dcaf532..dce82da 100644 --- a/src/test/test_atomic.cpp +++ b/src/test/test_atomic.cpp @@ -613,8 +613,8 @@ void TestAlignment( const char* name ) { } #if _MSC_VER && !defined(__INTEL_COMPILER) - // unary minus operator applied to unsigned type, result still unsigned - #pragma warning( disable: 4146 ) + #pragma warning( disable: 4146 ) // unary minus operator applied to unsigned type, result still unsigned + #pragma warning( disable: 4334 ) // result of 32-bit shift implicitly converted to 64 bits #endif /** T is an integral type. */ diff --git a/src/test/test_concurrent_priority_queue.cpp b/src/test/test_concurrent_priority_queue.cpp index 3dcd941..ac622e6 100644 --- a/src/test/test_concurrent_priority_queue.cpp +++ b/src/test/test_concurrent_priority_queue.cpp @@ -399,7 +399,10 @@ void TestExceptions() { my_throwing_type::throw_flag = 1; cpq_ex_test_type q; } catch(...) { +#if !(_MSC_VER==1900) ASSERT(false, "FAILED: allocating empty queue should not throw exception.\n"); + // VS2015 warns about the code in this catch block being unreachable +#endif } // Allocate small queue should not throw for reasonably sized type try { diff --git a/src/test/test_concurrent_unordered_common.h b/src/test/test_concurrent_unordered_common.h index 978b9eb..4d820b1 100644 --- a/src/test/test_concurrent_unordered_common.h +++ b/src/test/test_concurrent_unordered_common.h @@ -781,13 +781,14 @@ struct unordered_move_traits_base { }; template -void test_rvalue_ref_support(const char* /*container_name*/){ +void test_rvalue_ref_support(const char* container_name){ TestMoveConstructor(); TestMoveAssignOperator(); #if TBB_USE_EXCEPTIONS TestExceptionSafetyGuaranteesMoveConstructorWithUnEqualAllocatorMemoryFailure(); TestExceptionSafetyGuaranteesMoveConstructorWithUnEqualAllocatorExceptionInElementCtor(); #endif //TBB_USE_EXCEPTIONS + REMARK("passed -- %s move support tests\n", container_name); } #endif //__TBB_CPP11_RVALUE_REF_PRESENT diff --git a/src/test/test_concurrent_vector.cpp b/src/test/test_concurrent_vector.cpp index 20c395e..2b0a8a5 100644 --- a/src/test/test_concurrent_vector.cpp +++ b/src/test/test_concurrent_vector.cpp @@ -927,10 +927,10 @@ void TestSerialGrowByWithMoveIterators(){ namespace test_move_in_shrink_to_fit_helpers { struct dummy : Harness::StateTrackable<>{ int i; - dummy(int an_i) __TBB_NOTHROW : Harness::StateTrackable<>(0), i(an_i) {}; + dummy(int an_i) __TBB_NOTHROW : Harness::StateTrackable<>(0), i(an_i) {} #if __TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_BROKEN - dummy(const dummy &src) __TBB_NOTHROW : Harness::StateTrackable<>(src), i(src.i) {}; - dummy(dummy &&src) __TBB_NOTHROW : Harness::StateTrackable<>(std::move(src)), i(src.i) {}; + dummy(const dummy &src) __TBB_NOTHROW : Harness::StateTrackable<>(src), i(src.i) {} + dummy(dummy &&src) __TBB_NOTHROW : Harness::StateTrackable<>(std::move(src)), i(src.i) {} dummy& operator=(dummy &&src) __TBB_NOTHROW { Harness::StateTrackable<>::operator=(std::move(src)); @@ -939,7 +939,7 @@ namespace test_move_in_shrink_to_fit_helpers { } //somehow magically this declaration make std::is_nothrow_move_constructible::value to works correctly on icc14+msvc2013 - ~dummy() __TBB_NOTHROW {}; + ~dummy() __TBB_NOTHROW {} #endif //__TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_BROKEN friend bool operator== (const dummy &lhs, const dummy &rhs){ return lhs.i == rhs.i; } }; diff --git a/src/test/test_indexer_node.cpp b/src/test/test_indexer_node.cpp index 606caf4..8c06d40 100644 --- a/src/test/test_indexer_node.cpp +++ b/src/test/test_indexer_node.cpp @@ -25,7 +25,7 @@ // Tests // - #if defined(_MSC_VER) && _MSC_VER < 1600 +#if defined(_MSC_VER) && _MSC_VER < 1600 #pragma warning (disable : 4503) //disabling the "decorated name length exceeded" warning for VS2008 and earlier #endif diff --git a/src/test/test_join_node.cpp b/src/test/test_join_node.cpp index 1e600f7..f7efb2a 100644 --- a/src/test/test_join_node.cpp +++ b/src/test/test_join_node.cpp @@ -230,10 +230,6 @@ void print_my_value(std::string const &i) { REMARK("\"%s\"", i.c_str()); } -#if defined(_MSC_VER) && _MSC_VER < 1600 - #pragma warning (disable : 4503) //disabling the "decorated name length exceeded" warning for VS2008 and earlier -#endif - // // Tests // diff --git a/src/test/test_malloc_compliance.cpp b/src/test/test_malloc_compliance.cpp index 04d15c7..454d707 100644 --- a/src/test/test_malloc_compliance.cpp +++ b/src/test/test_malloc_compliance.cpp @@ -732,7 +732,7 @@ void CMemTest::NULLReturn(UINT MinSize, UINT MaxSize, int total_threads) /* There is a bug in the specific version of GLIBC (2.5-12) shipped with RHEL5 that leads to erroneous working of the test - on Intel64 and IPF systems when setrlimit-related part is enabled. + on Intel(R) 64 and Itanium(R) architecture when setrlimit-related part is enabled. Switching to GLIBC 2.5-18 from RHEL5.1 resolved the issue. */ if (perProcessLimits) diff --git a/src/test/test_malloc_overload.cpp b/src/test/test_malloc_overload.cpp index 14afbec..75be1c8 100644 --- a/src/test/test_malloc_overload.cpp +++ b/src/test/test_malloc_overload.cpp @@ -186,6 +186,11 @@ const uint32_t minLargeObjectSize = fittingSize5 + 1; static void scalableMallocCheckSize(void *object, size_t size) { +#if __APPLE__ && __clang__ && __TBB_CLANG_VERSION == 70300 +// This prevents Clang 703.0.29 under OS X from throwing out the +// calls to new & delete in CheckNewDeleteOverload(). + static void *v = object; +#endif ASSERT(object, NULL); if (size >= minLargeObjectSize) { LargeMemoryBlock *lmb = ((LargeObjectHdr*)object-1)->memoryBlock; @@ -201,10 +206,6 @@ static void scalableMallocCheckSize(void *object, size_t size) #endif } -struct BigStruct { - char f[minLargeObjectSize]; -}; - void CheckStdFuncOverload(void *(*malloc_p)(size_t), void *(*calloc_p)(size_t, size_t), void *(*realloc_p)(void *, size_t), void (*free_p)(void *)) { @@ -307,6 +308,30 @@ void TestZoneOverload() { #define TestZoneOverload() #endif +struct BigStruct { + char f[minLargeObjectSize]; +}; + +void CheckNewDeleteOverload() { + BigStruct *s1, *s2, *s3, *s4; + + s1 = new BigStruct; + scalableMallocCheckSize(s1, sizeof(BigStruct)); + delete s1; + + s2 = new BigStruct[10]; + scalableMallocCheckSize(s2, 10*sizeof(BigStruct)); + delete []s2; + + s3 = new(std::nothrow) BigStruct; + scalableMallocCheckSize(s3, sizeof(BigStruct)); + delete s3; + + s4 = new(std::nothrow) BigStruct[2]; + scalableMallocCheckSize(s4, 2*sizeof(BigStruct)); + delete []s4; +} + int TestMain() { void *ptr, *ptr1; @@ -393,22 +418,7 @@ int TestMain() { #endif CheckFreeAligned(); - BigStruct *s1 = new BigStruct; - scalableMallocCheckSize(s1, sizeof(BigStruct)); - delete s1; - - BigStruct *s2 = new BigStruct[10]; - scalableMallocCheckSize(s2, 10*sizeof(BigStruct)); - delete []s2; - - BigStruct *s3 = new(std::nothrow) BigStruct; - scalableMallocCheckSize(s3, sizeof(BigStruct)); - delete s3; - - BigStruct *s4 = new(std::nothrow) BigStruct[2]; - scalableMallocCheckSize(s4, 2*sizeof(BigStruct)); - delete []s4; - + CheckNewDeleteOverload(); #if _WIN32 std::string stdstring = "dependence on msvcpXX.dll"; ASSERT(strcmp(stdstring.c_str(), "dependence on msvcpXX.dll") == 0, NULL); diff --git a/src/test/test_parallel_invoke.cpp b/src/test/test_parallel_invoke.cpp index dd9c810..83e2773 100644 --- a/src/test/test_parallel_invoke.cpp +++ b/src/test/test_parallel_invoke.cpp @@ -84,7 +84,7 @@ TEST_FUNCTOR(9) #define INIT_TEST function_counter = 0; #define VALIDATE_INVOKE_RUN(number_of_args, test_type) \ - ASSERT( (size_t)function_counter == (size_t)(1 << number_of_args) - 1, "parallel_invoke called with " #number_of_args " arguments didn't process all " #test_type); + ASSERT( size_t(function_counter) == (size_t(1) << number_of_args) - 1, "parallel_invoke called with " #number_of_args " arguments didn't process all " #test_type); // Calls parallel_invoke for different number of arguments // It can be called with and without user context @@ -235,7 +235,7 @@ void TestExceptionHandling() { REMARK (__FUNCTION__); for( size_t n = 2; n <= 10; ++n ) { - for( exception_mask = 1; exception_mask < (size_t) (1 << n); ++exception_mask ) { + for( exception_mask = 1; exception_mask < (size_t(1) << n); ++exception_mask ) { ResetEhGlobals(); TRY(); REMARK("Calling parallel_invoke, number of functions = %d, exception_mask = %d\n", n, exception_mask); diff --git a/src/test/test_task_priority.cpp b/src/test/test_task_priority.cpp index 0898dc3..3196a37 100644 --- a/src/test/test_task_priority.cpp +++ b/src/test/test_task_priority.cpp @@ -298,6 +298,7 @@ void TestPrioritySwitchBetweenTwoMasters () { REPORT_ONCE( "Known issue: TestPrioritySwitchBetweenTwoMasters is skipped for big number of threads\n" ); return; } + tbb::task_scheduler_init init; // keeps the market alive to reduce the amount of TBB warnings REMARK( "Stress tests: %s / %s \n", Low == tbb::priority_low ? "Low" : "Normal", High == tbb::priority_normal ? "Normal" : "High" ); PrepareGlobals( 2 ); for ( int i = 0; i < TestSwitchBetweenMastersRepeats; ++i ) { @@ -401,6 +402,7 @@ void TestPeriodicConcurrentActivities () { void TestPriorityAssertions () { #if TRY_BAD_EXPR_ENABLED && __TBB_TASK_PRIORITY REMARK( "TestPriorityAssertions\n" ); + tbb::task_scheduler_init init; // to avoid autoinit that'd affect subsequent tests tbb::priority_t bad_low_priority = tbb::priority_t( tbb::priority_low - 1 ), bad_high_priority = tbb::priority_t( tbb::priority_high + 1 ); tbb::task_group_context ctx; @@ -546,6 +548,31 @@ void TestSetPriority() { } }//namespace test_propagation +// TODO: consider common helper for empty bodies, e.g. Harness::DummyBody. +struct NestedParFor { + void operator()(int) const { + for (volatile int i = 0; i < 1000; ++i); + } +}; + +struct OuterParFor { + void operator()(int) const { + tbb::affinity_partitioner ap; + tbb::task_group_context ctx; + ctx.set_priority(tbb::priority_high); + tbb::parallel_for(0, 100, NestedParFor(), ap, ctx); + } +}; + +// Test priorities with affinity tasks. +void TestAffinityTasks() { + REMARK("Test priorities with affinity tasks\n"); + tbb::task_scheduler_init init; + tbb::affinity_partitioner ap; + for (int i = 0; i < 10; ++i) + tbb::parallel_for(0, 100, OuterParFor(), ap); +} + namespace regression { // This is a regression test for a bug with task_group_context used from a thread that created its local scheduler but not the implicit arena class TestTGContext { @@ -594,6 +621,7 @@ int RunTests () { TestPrioritySwitchBetweenTwoMasters(); PreemptionActivatorId = 1; TestPrioritySwitchBetweenTwoMasters(); + TestAffinityTasks(); regression::TestTGContextOnNewThread(); return Harness::Done; diff --git a/src/test/test_task_scheduler_init.cpp b/src/test/test_task_scheduler_init.cpp index 3a1c612..c0c27a5 100644 --- a/src/test/test_task_scheduler_init.cpp +++ b/src/test/test_task_scheduler_init.cpp @@ -64,7 +64,7 @@ void InitializeAndTerminate( int maxthread ) { default: { tbb::task_scheduler_init init( threads ); ASSERT(init.is_active(), NULL); - ASSERT(ArenaConcurrency()==threads, NULL); + ASSERT(ArenaConcurrency()==(threads==1)?2:threads, NULL); ASSERT(!test_mandatory_parallelism || Harness::CanReachConcurrencyLevel(threads), NULL); if(i&0x20) tbb::task::enqueue( (*new( tbb::task::allocate_root() ) TaskGenerator(2,6)) ); // a work deferred to workers break; @@ -72,7 +72,7 @@ void InitializeAndTerminate( int maxthread ) { case 0: { tbb::task_scheduler_init init; ASSERT(init.is_active(), NULL); - ASSERT(ArenaConcurrency()==init.default_num_threads(), NULL); + ASSERT(ArenaConcurrency()==(DefaultThreads==1)?2:init.default_num_threads(), NULL); ASSERT(!test_mandatory_parallelism || Harness::CanReachConcurrencyLevel(init.default_num_threads()), NULL); if(i&0x40) tbb::task::enqueue( (*new( tbb::task::allocate_root() ) TaskGenerator(3,5)) ); // a work deferred to workers break; @@ -82,7 +82,7 @@ void InitializeAndTerminate( int maxthread ) { ASSERT(!init.is_active(), "init should not be active; initialization was deferred"); init.initialize( threads ); ASSERT(init.is_active(), NULL); - ASSERT(ArenaConcurrency()==threads, NULL); + ASSERT(ArenaConcurrency()==(threads==1)?2:threads, NULL); ASSERT(!test_mandatory_parallelism || Harness::CanReachConcurrencyLevel(threads), NULL); init.terminate(); ASSERT(!init.is_active(), "init should not be active; it was terminated"); @@ -91,7 +91,7 @@ void InitializeAndTerminate( int maxthread ) { case 2: { tbb::task_scheduler_init init( tbb::task_scheduler_init::automatic ); ASSERT(init.is_active(), NULL); - ASSERT(ArenaConcurrency()==init.default_num_threads(), NULL); + ASSERT(ArenaConcurrency()==(DefaultThreads==1)?2:init.default_num_threads(), NULL); ASSERT(!test_mandatory_parallelism || Harness::CanReachConcurrencyLevel(init.default_num_threads()), NULL); break; } @@ -138,10 +138,9 @@ public: /** The test will fail in particular if task_scheduler_init mistakenly hooks up auto-initialization mechanism. **/ void AssertExplicitInitIsNotSupplanted () { - int hardwareConcurrency = tbb::task_scheduler_init::default_num_threads(); tbb::task_scheduler_init init(1); Harness::ConcurrencyTracker::Reset(); - tbb::parallel_for( Range(0, hardwareConcurrency * 2, 1), ConcurrencyTrackingBody(), tbb::simple_partitioner() ); + tbb::parallel_for( Range(0, DefaultThreads * 2, 1), ConcurrencyTrackingBody(), tbb::simple_partitioner() ); ASSERT( Harness::ConcurrencyTracker::PeakParallelism() == 1, "Manual init provided more threads than requested. See also the comment at the beginning of main()." ); } diff --git a/src/test/test_tbb_version.cpp b/src/test/test_tbb_version.cpp index a70ef91..9d12929 100644 --- a/src/test/test_tbb_version.cpp +++ b/src/test/test_tbb_version.cpp @@ -240,7 +240,7 @@ int main(int argc, char *argv[] ) { void initialize_strings_vector(std::vector * vector) { vector->push_back(string_pair("TBB: VERSION\t\t4.4", required)); // check TBB_VERSION - vector->push_back(string_pair("TBB: INTERFACE VERSION\t9004", required)); // check TBB_INTERFACE_VERSION + vector->push_back(string_pair("TBB: INTERFACE VERSION\t9005", required)); // check TBB_INTERFACE_VERSION vector->push_back(string_pair("TBB: BUILD_DATE", required)); vector->push_back(string_pair("TBB: BUILD_HOST", required)); vector->push_back(string_pair("TBB: BUILD_OS", required));