Compare commits

...
14 changed files with 2023 additions and 274 deletions
+7 -8
View File
@@ -1,18 +1,17 @@
# Intel(R) Threading Building Blocks 2017 Update 5
[![Stable release](https://img.shields.io/badge/version-2017_U5-green.svg)] (https://github.com/01org/tbb/releases/tag/2017_U5)
[![Stable release](https://img.shields.io/badge/version-2017_U5-green.svg)](https://github.com/01org/tbb/releases/tag/2017_U5)
[![Apache License Version 2.0](https://img.shields.io/badge/license-Apache_2.0-green.svg)](LICENSE)
Intel(R) Threading Building Blocks (Intel(R) TBB) lets you easily write parallel C++ programs that take
full advantage of multicore performance, that are portable, composable and have future-proof scalability.
## Release Information
Here are the latest [Changes] (CHANGES) and [Release Notes]
(doc/Release_Notes.txt) (contains system requirements and known issues).
Here are the latest [Changes](CHANGES) and [Release Notes](doc/Release_Notes.txt) (contains system requirements and known issues).
## Documentation
* Intel(R) TBB [tutorial] (https://software.intel.com/en-us/tbb-tutorial)
* Intel(R) TBB general documentation: [stable] (https://software.intel.com/en-us/tbb-documentation)
and [latest] (https://www.threadingbuildingblocks.org/docs/help/index.htm)
* Intel(R) TBB [tutorial](https://software.intel.com/en-us/tbb-tutorial)
* Intel(R) TBB general documentation: [stable](https://software.intel.com/en-us/tbb-documentation)
and [latest](https://www.threadingbuildingblocks.org/docs/help/index.htm)
## Support
Please report issues and suggestions via
@@ -20,10 +19,10 @@ Please report issues and suggestions via
[Intel(R) TBB forum](http://software.intel.com/en-us/forums/intel-threading-building-blocks/).
## How to Contribute
Please, read the instructions on the official [Intel(R) TBB open source site] (https://www.threadingbuildingblocks.org/submit-contribution).
Please, read the instructions on the official [Intel(R) TBB open source site](https://www.threadingbuildingblocks.org/submit-contribution).
## Engineering team contacts
* [E-mail us.] (mailto:inteltbbdevelopers@intel.com)
* [E-mail us.](mailto:inteltbbdevelopers@intel.com)
------------------------------------------------------------------------
Intel and the Intel logo are trademarks of Intel Corporation or its subsidiaries in the U.S. and/or other countries.
+5 -1
View File
@@ -19,14 +19,18 @@
all: release test
clean:
$(MAKE) -rf rml/Makefile tbb_root=.. clean
python setup.py clean
-rm -rf build/ tbb_wrap.* _TBB.* *.pyc TBB.py*
release: TBB.py
release: rml_release TBB.py
TBB.py: tbb.i tbb.src.py setup.py
python setup.py build_ext -f --inplace
ipc-rml:
$(MAKE) -rf rml/Makefile tbb_root=.. rml_dll cfg=release
test: TBB.py
python TBB.py test
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env python
#
# Copyright (c) 2005-2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from tbb import *
from tbb import __all__, __doc__
if __name__ == "__main__":
from tbb import _main
import sys
sys.exit(_main())
+28 -11
View File
@@ -4,10 +4,10 @@
</H2>
<H2>Overview</H2>
It is a preview Python* module which unlocks opportunities for additional performance in multi-threaded Python programs by enabling threading composability
It is a preview Python* module which unlocks opportunities for additional performance in multi-threaded and multiprocess Python programs by enabling threading composability
between two or more thread-enabled libraries like Numpy, Scipy, Sklearn, Dask, Joblib, and etc.
<p></p>
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)
The biggest improvement can be achieved when a task pool like the ThreadPool or Pool from the Python standard library or libraries like Dask or Joblib (used either in multi-threading or multi-processing mode)
execute tasks calling compute-intensive functions of Numpy/Scipy/Sklearn/PyDAAL which in turn are parallelized using Intel&reg; Math Kernel Library or/and Intel&reg; TBB.
<p></p>
The module implements Pool class with the standard interface using Intel&reg; TBB which can be used to replace Python's ThreadPool.
@@ -15,20 +15,32 @@ Thanks to the monkey-patching technique implemented in class Monkey, no source c
<p></p>
For more information and examples, please refer to <A HREF="http://software.intel.com/en-us/blogs/2016/04/04/unleash-parallel-performance-of-python-programs">online blog</A>.
<H2>Directories</H2>
<DL>
<DT><A HREF="rml">rml</A>
<DD>The folder contains needed sources to build the plugin with cross-process dynamic thread scheduler implementation.
<DT><A HREF="tbb">tbb</A>
<DD>The folder contains Python module sources.
</DL>
<H2>Files</H2>
<DL>
<DT><A HREF="setup.py">setup.py</A>
<DD>Standard Python setup script.
<DT><A HREF="Makefile">Makefile</A>
<DD>Makefile for building, installing, and testing. See below.
<DT><A HREF="tbb.i">tbb.i</A>
<DD>SWIG interface description file.
<DT><A HREF="tbb.src.py">tbb.src.py</A>
<DD>Python part of module implementation.
<DT><A HREF="TBB.py">TBB.py</A>
<DD>Alternative entry point for Python module.
</DL>
<A NAME=build><H2>Build and install</H2></A>
Prior to building it, please set up the environment using corresponding tbbvars script, e.g. `source tbbvars.sh intel64`
Prior to building it, please do the following first:
<UL>
<LI>Download this source package;</LI>
<LI>Build Intel&reg; TBB (for more informantion, please refer to <A HREF="../index.html">documentation</A>);</LI>
<LI>Set up the environment using generated tbbvars.sh script that can be found in $TBBROOT/build/*_release/ or $TBBROOT/build/*_debug/ folders.</LI>
</UL>
<DL>
<DT><TT>make</TT>
<DD>Default build and run. Equivalent to 'make release test'.
@@ -48,10 +60,15 @@ Please note, CXX=icl works on Windows only with Intel&reg; Distribution for Pyth
<H2>Command-line interface</H2>
<DL>
<DT><TT>pydoc TBB</TT>
<DD>Read built-in documentation for Python interfaces.
<DT><TT>python -m TBB your_script.py</TT>
<DD>Run your_script.py in context of `with TBB.Monkey():` when Intel TBB is enabled.
<DT><TT>python -m tbb -h</TT>
<DD>Print documentation on command-line interface</DD>
<DT><TT>pydoc tbb</TT>
<DD>Read built-in documentation for Python interfaces.</DD>
<DT><TT>python-tbb your_script.py</TT>
<DT><TT>python -m tbb your_script.py</TT>
<DD>Run your_script.py in context of `with tbb.Monkey():` when Intel&reg; TBB is enabled. By default only multi-threading will be covered.</DD>
<DT><TT>python -m tbb --ipc your_script.py</TT>
<DD>Run your_script.py in context of `with tbb.Monkey():` when Intel&reg; TBB enabled in both multi-threading and multi-processing modes.</DD>
</DL>
<H2>System Requirements</H2>
+151
View File
@@ -0,0 +1,151 @@
# Copyright (c) 2005-2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
#
#
.NOTPARALLEL:
tbb_root ?= ../..
BUILDING_PHASE=0
TEST_RESOURCE = $(RML.RES)
include $(tbb_root)/build/common.inc
DEBUG_SUFFIX=$(findstring _debug,_$(cfg))
ifeq (android,$(target))
$(error "RML is not supported on Android")
endif
.PHONY: default_rml rml rml_test clean
# default target
default_rml: rml rml_test
RML_ROOT ?= $(tbb_root)/src/rml
RML_SERVER_ROOT = $(RML_ROOT)/server
# TODO: new API needs to be added for this server, exposing everything
RML.DEF =
VPATH = $(tbb_root)/src/tbb $(tbb_root)/src/tbb/$(ASSEMBLY_SOURCE)
VPATH += $(tbb_root)/python/rml $(RML_ROOT)/test $(tbb_root)/src/test
include $(tbb_root)/build/common_rules.inc
#--------------------------------------------------------------------------
# Define rules for making the RML server shared library and client objects.
#--------------------------------------------------------------------------
# Object files that make up RML server
RML_SERVER.OBJ = ipc_server.$(OBJ)
# Object files that RML clients need
RML_TBB_CLIENT.OBJ ?= ipc_utils.$(OBJ)
RML.OBJ = $(RML_SERVER.OBJ) $(RML_TBB_CLIENT.OBJ)
ifeq (windows,$(tbb_os))
RML_ASM.OBJ = $(if $(findstring intel64,$(arch)),$(TBB_ASM.OBJ))
endif
ifeq (linux,$(tbb_os))
RML_ASM.OBJ = $(if $(findstring ia64,$(arch)),$(TBB_ASM.OBJ))
endif
RML_TBB_DEP= cache_aligned_allocator_rml.$(OBJ) dynamic_link_rml.$(OBJ) tbb_misc_rml.$(OBJ) tbb_misc_ex_rml.$(OBJ)
TBB_DEP_NON_RML_TEST?= cache_aligned_allocator_rml.$(OBJ) dynamic_link_rml.$(OBJ) $(RML_ASM.OBJ) tbb_misc_rml.$(OBJ) tbb_misc_ex_rml.$(OBJ)
ifeq ($(cfg),debug)
RML_TBB_DEP+= spin_mutex_rml.$(OBJ)
TBB_DEP_RML_TEST?= $(RML_ASM.OBJ) tbb_misc_rml.$(OBJ)
else
TBB_DEP_RML_TEST?= $(RML_ASM.OBJ)
endif
LIBS += $(LIBDL)
INCLUDES += $(INCLUDE_KEY)$(RML_ROOT)/include $(INCLUDE_KEY).
T_INCLUDES = $(INCLUDES) $(INCLUDE_KEY)$(tbb_root)/src/test $(INCLUDE_KEY)$(RML_SERVER_ROOT)
# Suppress superfluous warnings for RML compilation
R_CPLUS_FLAGS = $(subst DO_ITT_NOTIFY,DO_ITT_NOTIFY=0,$(CPLUS_FLAGS)) $(WARNING_SUPPRESS) \
$(DEFINE_KEY)TBB_USE_THREADING_TOOLS=0 $(DEFINE_KEY)__TBB_RML_STATIC=1 $(DEFINE_KEY)__TBB_NO_IMPLICIT_LINKAGE=1
%.$(OBJ): %.cpp
$(CPLUS) $(COMPILE_ONLY) $(R_CPLUS_FLAGS) $(PIC_KEY) $(DSE_KEY) $(INCLUDES) $<
tbb_misc_rml.$(OBJ) $(RML_SERVER.OBJ): version_string.ver
RML_TEST.OBJ = test_job_automaton.$(OBJ) test_thread_monitor.$(OBJ) test_rml_tbb.$(OBJ)
$(RML_TBB_DEP): %_rml.$(OBJ): %.cpp
$(CPLUS) $(COMPILE_ONLY) $(OUTPUTOBJ_KEY)$@ $(R_CPLUS_FLAGS) $(PIC_KEY) $(DSE_KEY) $(INCLUDES) $<
$(RML_TEST.OBJ): %.$(OBJ): %.cpp
$(CPLUS) $(COMPILE_ONLY) $(R_CPLUS_FLAGS) $(PIC_KEY) $(T_INCLUDES) $<
ifneq (,$(RML.DEF))
rml.def: $(RML.DEF)
$(CPLUS) $(PREPROC_ONLY) $< $(CPLUS_FLAGS) $(INCLUDES) > $@
LIB_LINK_FLAGS += $(EXPORT_KEY)rml.def
$(RML.DLL): rml.def
endif
$(RML.DLL): CPLUS_FLAGS += $(SDL_FLAGS)
$(RML.DLL): BUILDING_LIBRARY = $(RML.DLL)
$(RML.DLL): $(RML_TBB_DEP) $(RML.OBJ) $(RML.RES) $(RML_NO_VERSION.DLL) $(RML_ASM.OBJ)
$(LIB_LINK_CMD) $(LIB_OUTPUT_KEY)$(RML.DLL) $(RML.OBJ) $(RML_TBB_DEP) $(RML_ASM.OBJ) $(RML.RES) $(LIB_LINK_LIBS) $(LIB_LINK_FLAGS)
ifneq (,$(RML_NO_VERSION.DLL))
$(RML_NO_VERSION.DLL):
echo "INPUT ($(RML.DLL))" > $(RML_NO_VERSION.DLL)
endif
rml: rml_dll
rml_dll: $(RML.DLL)
#------------------------------------------------------
# End of rules for making the RML server shared library
#------------------------------------------------------
#------------------------------------------------------
# Define rules for making the RML unit tests
#------------------------------------------------------
add_debug=$(basename $(1))_debug$(suffix $(1))
cross_suffix=$(if $(crosstest),$(if $(DEBUG_SUFFIX),$(subst _debug,,$(1)),$(call add_debug,$(1))),$(1))
RML_TESTS = test_job_automaton.$(TEST_EXT) test_thread_monitor.$(TEST_EXT)
RML_CUSTOM_TESTS = test_rml_tbb.$(TEST_EXT)
test_rml_tbb.$(TEST_EXT): test_rml_tbb.$(OBJ) $(RML_TBB_CLIENT.OBJ) $(TBB_DEP_RML_TEST)
$(CPLUS) $(OUTPUT_KEY)$@ $(CPLUS_FLAGS) test_rml_tbb.$(OBJ) $(RML_TBB_CLIENT.OBJ) $(TBB_DEP_RML_TEST) $(LIBS) $(LINK_FLAGS)
$(RML_TESTS): %.$(TEST_EXT): %.$(OBJ) $(TBB_DEP_NON_RML_TEST)
$(CPLUS) $(OUTPUT_KEY)$@ $(CPLUS_FLAGS) $< $(TBB_DEP_NON_RML_TEST) $(LIBS) $(LINK_FLAGS)
### run_cmd is usually empty
rml_test: $(call cross_suffix,$(RML.DLL)) $(TEST_PREREQUISITE) $(RML_TESTS) $(RML_CUSTOM_TESTS)
$(run_cmd) ./test_job_automaton.$(TEST_EXT) $(args)
$(run_cmd) ./test_thread_monitor.$(TEST_EXT) $(args)
$(run_cmd) ./test_rml_tbb.$(TEST_EXT) $(args)
#------------------------------------------------------
# End of rules for making the TBBMalloc unit tests
#------------------------------------------------------
# Include automatically generated dependencies
-include *.d
clean:
-rm -rf *.o *.so* *.d *.def version_string.ver
-rm -rf $(work_dir)_release/libirml*
-rm -rf $(work_dir)_debug/libirml*
File diff suppressed because it is too large Load Diff
+144
View File
@@ -0,0 +1,144 @@
/*
Copyright (c) 2017 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "ipc_utils.h"
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
namespace tbb {
namespace internal {
namespace rml {
#define MAX_STR_LEN 255
#define STARTTIME_ITEM_ID 21
static char* get_stat_item(char* line, int item_id) {
int id = 0, i = 0;
while( id!=item_id ) {
while( line[i]!='(' && line[i]!=' ' && line[i]!='\0' ) {
++i;
}
if( line[i]==' ' ) {
++id;
++i;
} else if( line[i]=='(' ) {
while( line[i]!=')' && line[i]!='\0' ) {
++i;
}
if( line[i]==')' ) {
++i;
} else {
return NULL;
}
} else {
return NULL;
}
}
return line + i;
}
unsigned long long get_start_time(int pid) {
const char* stat_file_path_template = "/proc/%d/stat";
char stat_file_path[MAX_STR_LEN + 1];
sprintf( stat_file_path, stat_file_path_template, pid );
FILE* stat_file = fopen( stat_file_path, "rt" );
if( stat_file==NULL ) {
return 0;
}
char stat_line[MAX_STR_LEN + 1];
char* line = fgets( stat_line, MAX_STR_LEN, stat_file );
if( line==NULL ) {
return 0;
}
char* starttime_str = get_stat_item( stat_line, STARTTIME_ITEM_ID );
if( starttime_str==NULL ) {
return 0;
}
unsigned long long starttime = strtoull( starttime_str, NULL, 10 );
if( starttime==ULLONG_MAX ) {
return 0;
}
return starttime;
}
char* get_shared_name(const char* prefix, int pid, unsigned long long time) {
const char* name_template = "%s_%d_%llu";
const int digits_in_int = 10;
const int digits_in_long = 20;
int len = strlen( name_template ) + strlen( prefix ) + digits_in_int + digits_in_long + 1;
char* name = new char[len];
sprintf( name, name_template, prefix, pid, time );
return name;
}
char* get_shared_name(const char* prefix) {
int pid = getpgrp();
unsigned long long time = get_start_time( pid );
return get_shared_name( prefix, pid, time );
}
int get_num_threads(const char* env_var) {
if( env_var==NULL ) {
return 0;
}
char* value = getenv( env_var );
if( value==NULL ) {
return 0;
}
int num_threads = (int)strtol( value, NULL, 10 );
return num_threads;
}
bool get_enable_flag(const char* env_var) {
if( env_var==NULL ) {
return false;
}
char* value = getenv( env_var );
if( value==NULL ) {
return false;
}
if( strcmp( value, "0" ) == 0 ||
strcmp( value, "false" ) == 0 ||
strcmp( value, "False" ) == 0 ||
strcmp( value, "FALSE" ) == 0 ) {
return false;
}
return true;
}
}}} //tbb::internal::rml
+34
View File
@@ -0,0 +1,34 @@
/*
Copyright (c) 2017 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef __IPC_UTILS_H
#define __IPC_UTILS_H
namespace tbb {
namespace internal {
namespace rml {
char* get_shared_name(const char* prefix);
int get_num_threads(const char* env_var);
bool get_enable_flag(const char* env_var);
}}} //tbb::internal::rml
#endif
+6 -6
View File
@@ -58,13 +58,14 @@ else:
tbb_flag = ['-tbb'] if use_compiler_tbb else []
compile_flags = ['-std=c++11', '-Wno-unused-variable']
_tbb = Extension("_TBB", ["tbb.i"],
_tbb = Extension("tbb._api", ["tbb/api.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 [],
libraries =(['tbb'] if not use_compiler_tbb else []) +
(['irml'] if platform.system() == "Linux" else []), # TODO: why do we need this?
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
@@ -98,11 +99,9 @@ setup( name ="TBB",
'Intended Audience :: Other Audience',
'Intended Audience :: Science/Research',
'License :: OSI Approved :: Apache Software License',
'License :: Other/Proprietary License',
'Operating System :: MacOS :: MacOS X',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX',
'Operating System :: Unix',
'Operating System :: POSIX :: Linux',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3',
@@ -110,8 +109,9 @@ setup( name ="TBB",
'Topic :: System :: Hardware :: Symmetric Multi-processing',
'Topic :: Software Development :: Libraries',
],
keywords='tbb multiprocessing multithreading composable parallelism',
keywords='TBB multiprocessing multithreading composable parallelism',
ext_modules=[_tbb],
packages=['tbb'],
py_modules=['TBB'],
cmdclass={'build': TBBBuild}
)
+264
View File
@@ -0,0 +1,264 @@
#
# Copyright (c) 2005-2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import print_function
import multiprocessing.pool
import ctypes
import atexit
import sys
import os
from .api import *
from .api import __all__ as api__all
from .pool import *
from .pool import __all__ as pool__all
__all__ = ["Monkey"] + api__all + pool__all
__doc__ = """
Python API for Intel(R) Threading Building Blocks library (Intel(R) TBB)
extended with standard Python's pools implementation and monkey-patching.
Command-line interface example:
$ python -m tbb $your_script.py
Runs your_script.py in context of tbb.Monkey
"""
ipc_enabled = False
libirml = "libirml.so.1"
def _test(arg=None):
"""Some tests"""
import platform
if platform.system() == "Linux":
ctypes.CDLL(libirml)
from .test import test
test(arg)
print("done")
def tbb_process_pool_worker27(inqueue, outqueue, initializer=None, initargs=(),
maxtasks=None):
from multiprocessing.pool import worker
worker(inqueue, outqueue, initializer, initargs, maxtasks)
if ipc_enabled:
try:
librml = ctypes.CDLL(libirml)
librml.release_resources()
except:
print("Warning: Can not load ", libirml, file=sys.stderr)
class TBBProcessPool27(multiprocessing.pool.Pool):
def _repopulate_pool(self):
"""Bring the number of pool processes up to the specified number,
for use after reaping workers which have exited.
"""
from multiprocessing.util import debug
for i in range(self._processes - len(self._pool)):
w = self.Process(target=tbb_process_pool_worker27,
args=(self._inqueue, self._outqueue,
self._initializer,
self._initargs, self._maxtasksperchild)
)
self._pool.append(w)
w.name = w.name.replace('Process', 'PoolWorker')
w.daemon = True
w.start()
debug('added worker')
def __del__(self):
self.close()
for p in self._pool:
p.join()
def __exit__(self):
self.close()
for p in self._pool:
p.join()
def tbb_process_pool_worker35(inqueue, outqueue, initializer=None, initargs=(),
maxtasks=None, wrap_exception=False):
from multiprocessing.pool import worker
worker(inqueue, outqueue, initializer, initargs, maxtasks, wrap_exception)
if ipc_enabled:
try:
librml = ctypes.CDLL(libirml)
librml.release_resources()
except:
print("Warning: Can not load ", libirml, file=sys.stderr)
class TBBProcessPool35(multiprocessing.pool.Pool):
def _repopulate_pool(self):
"""Bring the number of pool processes up to the specified number,
for use after reaping workers which have exited.
"""
from multiprocessing.util import debug
for i in range(self._processes - len(self._pool)):
w = self.Process(target=tbb_process_pool_worker35,
args=(self._inqueue, self._outqueue,
self._initializer,
self._initargs, self._maxtasksperchild,
self._wrap_exception)
)
self._pool.append(w)
w.name = w.name.replace('Process', 'PoolWorker')
w.daemon = True
w.start()
debug('added worker')
def __del__(self):
self.close()
for p in self._pool:
p.join()
def __exit__(self):
self.close()
for p in self._pool:
p.join()
class Monkey:
"""
Context manager which replaces standard multiprocessing.pool
implementations with tbb.pool using monkey-patching. It also enables TBB
threading for Intel(R) Math Kernel Library (Intel(R) MKL). For example:
with tbb.Monkey():
run_my_numpy_code()
It allows multiple parallel tasks to be executed on the same thread pool
and coordinate number of threads across multiple processes thus avoiding
overheads from oversubscription.
"""
_items = {'ThreadPool' : None,
'Pool' : None}
_modules = {'ThreadPool' : None,
'Pool' : None}
def __init__(self, max_num_threads=None):
"""
Create context manager for running under TBB scheduler.
:param max_num_threads: if specified, limits maximal number of threads
"""
if max_num_threads:
self.ctl = global_control(global_control.max_allowed_parallelism, int(max_num_threads))
def _patch(self, class_name, module_name, object):
self._modules[class_name] = __import__(module_name, globals(),
locals(), [class_name])
if self._modules[class_name] == None:
return
oldattr = getattr(self._modules[class_name], class_name, None)
if oldattr == None:
self._modules[class_name] = None
return
self._items[class_name] = oldattr
setattr(self._modules[class_name], class_name, object)
def __enter__(self):
self.env = os.getenv('MKL_THREADING_LAYER')
os.environ['MKL_THREADING_LAYER'] = 'TBB'
if sys.version_info.major == 2 and sys.version_info.minor >= 7:
self._patch("Pool", "multiprocessing.pool", TBBProcessPool27)
elif sys.version_info.major == 3 and sys.version_info.minor >= 5:
self._patch("Pool", "multiprocessing.pool", TBBProcessPool35)
self._patch("ThreadPool", "multiprocessing.pool", Pool)
return self
def __exit__(self, exc_type, exc_value, traceback):
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._modules[name], name, self._items[name])
def init_sem_name():
try:
librml = ctypes.CDLL(libirml)
librml.set_active_sem_name()
librml.set_stop_sem_name()
except Exception as e:
print("Warning: Can not initialize name of shared semaphores:", e,
file=sys.stderr)
def tbb_atexit():
if ipc_enabled:
try:
librml = ctypes.CDLL(libirml)
librml.release_semaphores()
except:
print("Warning: Can not release shared semaphores",
file=sys.stderr)
def _main():
# Run the module specified as the next command line argument
# python -m TBB user_app.py
global ipc_enabled
import platform
import argparse
parser = argparse.ArgumentParser(prog="python -m tbb", description="""
Run your Python script in context of tbb.Monkey, which
replaces standard Python pools and threading layer of
Intel(R) Math Kernel Library by implementation based on
Intel(R) Threading Building Blocks. It enables multiple parallel
tasks to be executed on the same thread pool and coordinate
number of threads across multiple processes thus avoiding
overheads from oversubscription.
""", formatter_class=argparse.ArgumentDefaultsHelpFormatter)
if platform.system() == "Linux":
parser.add_argument('--ipc', action='store_true',
help="Enable inter-precess (IPC) synchronization")
parser.add_argument('-p', '--max-num-threads', default=default_num_threads(), type=int,
help="Initialize TBB with P max number of threads per process", metavar='P')
#parser.add_argument('-a', '--replace-allocator', action='store_true',
# help="Enable TBB malloc")
#parser.add_argument('--huge-pages', action='store_true',
# help="Enable huge pages for TBB malloc")
parser.add_argument('-m', action='store_true', dest='module',
help="Executes following as a module")
parser.add_argument('name', help="Script or module name")
parser.add_argument('args', nargs=argparse.REMAINDER,
help="Command line arguments")
args = parser.parse_args()
sys.argv = [args.name] + args.args
ipc_enabled = platform.system() == "Linux" and args.ipc
os.environ["IPC_ENABLE"] = "1" if ipc_enabled else "0"
if ipc_enabled:
atexit.register(tbb_atexit)
init_sem_name()
if not os.environ.get("KMP_BLOCKTIME"): # TODO move
os.environ["KMP_BLOCKTIME"] = "0"
if '_' + args.name in globals():
return globals()['_' + args.name](*args.args)
else:
import runpy
runf = runpy.run_module if args.module else runpy.run_path
with Monkey(max_num_threads=args.max_num_threads):
runf(args.name, run_name='__main__')
+19
View File
@@ -0,0 +1,19 @@
#
# Copyright (c) 2005-2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from . import _main
from sys import exit
exit(_main())
+20 -37
View File
@@ -18,50 +18,19 @@
#
#
# 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
__all__ = ["task_arena", "task_group", "task_scheduler_init", "global_control", "default_num_threads"]
%}
%begin %{
/* Defines Python wrappers for Intel(R) Threading Building Blocks (Intel TBB).*/
%}
%module TBB
%module api
#if SWIG_VERSION < 0x030001
#error SWIG version 3.0.6 or newer is required for correct functioning
#endif
%{
#define TBB_PREVIEW_GLOBAL_CONTROL 1
#include <tbb/tbb.h>
using namespace tbb;
@@ -140,7 +109,21 @@ namespace tbb {
};
};
}
class global_control {
public:
enum parameter {
max_allowed_parallelism,
thread_stack_size,
parameter_max // insert new parameters above this point
};
global_control(parameter param, size_t value);
~global_control();
static size_t active_value(parameter param);
};
// Python part of the module
%pythoncode "tbb.src.py"
} // tbb
// Additional definitions for Python part of the module
%pythoncode %{
default_num_threads = task_scheduler_init_default_num_threads
%}
+5 -211
View File
@@ -1,4 +1,3 @@
#
# Copyright (c) 2005-2017 Intel Corporation
#
@@ -73,20 +72,14 @@
import sys
import threading
import traceback
from .api import *
__all__ = ["Pool", "Monkey", "task_arena", "task_group", "task_scheduler_init"]
__all__ = ["Pool", "TimeoutError"]
__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():`
Standard Python Pool implementation based on Python API
for Intel(R) Threading Building Blocks library (Intel(R) TBB)
"""
default_num_threads = task_scheduler_init_default_num_threads
class TimeoutError(Exception):
"""Raised when a result is not available within the given timeout"""
@@ -96,7 +89,7 @@ class TimeoutError(Exception):
class Pool(object):
"""
The Pool class provides standard multiprocessing.Pool interface
which is mapped onto Intel TBB tasks executing in its thread pool
which is mapped onto Intel(R) TBB tasks executing in its thread pool
"""
def __init__(self, nworkers=0, name="Pool"):
@@ -639,202 +632,3 @@ class OrderedResultCollector(AbstractResultCollector):
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())
+198
View File
@@ -0,0 +1,198 @@
#
# Copyright (c) 2005-2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
#
#
# 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
import time
import threading
from .api import *
from .pool import *
def test(arg=None):
if arg == "-v":
def say(*x):
print(*x)
else:
def say(*x):
pass
say("Start Pool testing")
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()