diff --git a/composability_bench b/composability_bench deleted file mode 160000 index 608337f..0000000 --- a/composability_bench +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 608337f62876c10c855849c98999f6f78c6b16d5 diff --git a/composability_bench/.gitignore b/composability_bench/.gitignore new file mode 100644 index 0000000..72364f9 --- /dev/null +++ b/composability_bench/.gitignore @@ -0,0 +1,89 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# IPython Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# dotenv +.env + +# virtualenv +venv/ +ENV/ + +# Spyder project settings +.spyderproject + +# Rope project settings +.ropeproject diff --git a/composability_bench/LICENSE b/composability_bench/LICENSE new file mode 100644 index 0000000..4aad977 --- /dev/null +++ b/composability_bench/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Intel Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/composability_bench/README.md b/composability_bench/README.md new file mode 100644 index 0000000..9348c54 --- /dev/null +++ b/composability_bench/README.md @@ -0,0 +1,23 @@ +# Composability Benchmarks +Show effects of over-subscription and ways to fix that + +## Installation +Install TBB and SMP modules for Python in order to evaluate benefits of composable multithreading +``` +conda install -c intel tbb4py smp +``` +Alternatively, run `set_python_envs.sh` to set up environment with components of Intel Distribution for Python + +## Running +Effects are visible on big enough machine with 32 and more cores. +Run following modes: + +``` +python -m tbb collab_filt.py +python -m tbb dask_bench2.py +python -m smp collab_filt.py +python -m smp dask_bench2.py +``` + +## See also +https://software.intel.com/en-us/blogs/2016/04/04/unleash-parallel-performance-of-python-programs diff --git a/composability_bench/collab_filt.py b/composability_bench/collab_filt.py new file mode 100755 index 0000000..8d58bb5 --- /dev/null +++ b/composability_bench/collab_filt.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# Copyright (c) 2017, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + + +import sys +import time +import timeit +import numpy as np +import dask.array as da +from dask.diagnostics import ProgressBar +import random +import argparse +import numba + +number_of_users = 400000 +features = 3260 +chunk = 10000 + +try: + import numpy.random_intel as rnd + numpy_ver="intel" +except: + import numpy.random as rnd + numpy_ver="std" + +parser = argparse.ArgumentParser(sys.argv[0]) +parser.add_argument('--math', required=False, default='dask_numba', help="Select computation approach: numpy, dask, numpy_numba, dask_numba") +parser.add_argument('--features', required=False, default=features, help="Number of features to process") +parser.add_argument('--users', required=False, default=number_of_users, help="Number of users to process") +parser.add_argument('--chunk', required=False, default=chunk, help="Chunk size for splitting dask arrays") +parser.add_argument('--verbose', '-v', required=False, default=False, help="show progress information") +parser.add_argument('--prefix', required=False, default="@", help="Prepend result output with this string") +args = parser.parse_args() + +features = int(args.features) +number_of_users = int(args.users) +chunk = int(args.chunk) + +print("Generating fake similarity") +#topk = da.random.normal(size=(features, features), chunks=(features, features)).compute() +topk = rnd.normal(size=(features, features)) +t = da.from_array(topk, chunks=(features, features)) + +print("Generating fake user data") +#users = da.random.normal(size=(features, number_of_users), chunks=(features, chunk)).compute() +#users = rnd.normal(size=(features, number_of_users)) +users = np.zeros(shape=(features, number_of_users), dtype=np.float64) +objects_idx = np.arange(features) +rated = rnd.randint(0, 10, size=number_of_users, dtype=np.int32) +for user in range(number_of_users): + rnd.shuffle(objects_idx) + items_rated = rated[user] + users[objects_idx[:items_rated], user] = rnd.randint(1, 5, size=items_rated, dtype=np.int32) + +u = da.from_array(users, chunks=(features, chunk), name=False) + +def run_numpy(): + x = topk.dot(users) + x = np.where(users>0, 0, x) + return x.argmax(axis=0) + + +def run_dask(): + x = t.dot(u) + x = da.where(u>0, 0, x) + r = x.argmax(axis=0) + return r.compute() + + +@numba.guvectorize('(f8[:],f8[:],i4[:])', '(n),(n)->()', nopython=True, target="parallel") +def recommendation(x, u, r): + maxx = x[0] + r[0] = -1 + for i in range(x.shape[0]): + if u[i] == 0 and maxx < x[i]: # if user has no rank for the item + maxx = x[i] + r[0] = i + + +def run_numpy_numba(): + x = topk.dot(users) + return recommendation(x, users) + + +def run_dask_numba(): + x = t.dot(u) + r = da.map_blocks(recommendation, x, u, drop_axis=0) + return r.compute() + + +# ====================== + +# ====================== + +runner_name= 'run_'+args.math +if runner_name not in globals(): + print('--math=', args.math, " is not implemented, running numpy") + runner = run_numpy +else: + runner = globals()[runner_name] + +if args.verbose: + ProgressBar().register() + +print("Running recommendation system") +for i in range(3): + tic = time.time() + r = runner() + toc = time.time() + time_diff = toc - tic + if args.verbose: + print("Result shape: ", r.shape, " strides: ", r.strides, " ", r) + + print("%s run=%d numpy=%s users=%d math=%s, chunk=%d in %.2f sec, %f users/sec" % \ + (str(args.prefix), i, numpy_ver, number_of_users, args.math, chunk, time_diff, + float(number_of_users)/time_diff)) + sys.stdout.flush() diff --git a/composability_bench/dask_bench2.py b/composability_bench/dask_bench2.py new file mode 100755 index 0000000..68be653 --- /dev/null +++ b/composability_bench/dask_bench2.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# Copyright (c) 2017, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + + +import dask, timeit +import dask.array as da +import dask.multiprocessing +import numpy as np + + +class common_bench: + sx, sy = 320000, 1000 + cx, cy = 10000, 1000 + +class dask_bench(common_bench): + def setup(self): + self.x = da.random.random((self.sx, self.sy), chunks=(self.cx, self.cy)) + + def _bench(self, get): + q, r = da.linalg.qr(self.x) + test = da.all(da.isclose(self.x, q.dot(r))) + test.compute(get=get) + + def time_threaded(self): + self._bench(dask.threaded.get) + + def time_multiproc(self): + self._bench(dask.multiprocessing.get) + + +class numpy_bench(common_bench): + def setup(self): + self.x = np.random.random((self.sx, self.sy)) + + def time_pure(self): + q, r = np.linalg.qr(self.x) + test = np.allclose(self.x, q.dot(r)) + +print("Numpy ", timeit.repeat('b.time_pure()', 'from __main__ import numpy_bench as B; b=B();b.setup()', number=1, repeat=3)) +print("Dask-MT", timeit.repeat('b.time_threaded()', 'from __main__ import dask_bench as B; b=B();b.setup()', number=1, repeat=3)) +#print("Dask-MP", timeit.repeat('b.time_multiproc()', 'from __main__ import dask_bench as B; b=B();b.setup()', number=1, repeat=3)) diff --git a/composability_bench/numpy_bench.py b/composability_bench/numpy_bench.py new file mode 100755 index 0000000..e3d031a --- /dev/null +++ b/composability_bench/numpy_bench.py @@ -0,0 +1,87 @@ +# Copyright (c) 2017, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 multiprocessing.pool import Pool +from multiprocessing.pool import ThreadPool +from concurrent.futures import ProcessPoolExecutor +from concurrent.futures import ThreadPoolExecutor +from numpy.random import random +from numpy.random import seed +from numpy import empty +import sys +import numpy + +n = 1024 +m = 64 +data_mt = random((n, n)) + +def bench(n): + seed([777]) + #data = random((n, n)) + result = numpy.linalg.eig(data_mt) + return result[0][0].real + +def bench_mt(n): + result = numpy.linalg.eig(data_mt) + return result[0][0].real + +def main(): + np = 1 + + if len(sys.argv) > 1: + np = int(sys.argv[1]) + print("Number of processes: ", np) + + pool_type = "multiprocessing" + if len(sys.argv) > 2: + pool_type = sys.argv[2] + print("Pool type: ", pool_type) + + if pool_type == "multiprocessing": + p = Pool(np) + result = p.map(bench, [n for i in range(m)]) + s = 0 + for val in result: + s = s + val + print(s) + elif pool_type == "concurrent": + with ProcessPoolExecutor(np) as p: + s = 0 + for val in p.map(bench, [n for i in range(m)]): + s = s + val + print(s) + elif pool_type == "threading": + p = ThreadPool(np) + result = p.map(bench_mt, [n for i in range(m)]) + s = 0 + for val in result: + s = s + val + print(s) + else: + print("Unsupported pool type: " + pool_type) + +if __name__ == '__main__': + main() diff --git a/composability_bench/scipy2017/bench_demo.py b/composability_bench/scipy2017/bench_demo.py new file mode 100644 index 0000000..4663d13 --- /dev/null +++ b/composability_bench/scipy2017/bench_demo.py @@ -0,0 +1,281 @@ +# Copyright (c) 2017, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + + +# http://software.intel.com/en-us/intel-mkl +# https://code.google.com/p/numexpr/wiki/NumexprVML + +from __future__ import print_function +import datetime +import sys +#from scipy import stats +import numpy as np +#import numexpr as ne +import time +import gc +import os.path +#import cPickle as pickle +import os +import argparse +from pprint import pprint +import logging + +data_dir = './' + +tests = ("qr", "eig", "svd", "inv", "cholesky", "dgemm") #, "det" - gives warning + +log = logging.getLogger(__name__) + +def prepare_default(N=100, dtype=np.double): + return ( np.asarray(np.random.rand(N, N), dtype=dtype), ) + #return toc/trials, (4/3)*N*N*N*1e-9, times + +def prepare_eig(N=100, dtype=np.double): + N/=4 + return ( np.asarray(np.random.rand(int(N), int(N)), dtype=dtype), ) + +def prepare_svd(N=100, dtype=np.double): + N/=2 + return ( np.asarray(np.random.rand(int(N), int(N)), dtype=dtype), False ) + +#det: return toc/trials, N*N*N*1e-9, times + +def kernel_dot(A, B): + """ + Dot product + """ + np.dot(A, B) + +def prepare_dot(N=100, dtype=np.double): + N=N*N*10 + A = np.asarray(np.random.rand(int(N)), dtype=dtype) + return (A, A) + #return 1.0*toc/(trials), 2*N*N*N*1e-9, times + +def kernel_ivi(A, B): + """ + Collaborative filtering + """ + A.dot(B) + +def prepare_ivi(N=100, dtype=np.double): + A = np.random.rand(3260, 3260) + B = np.random.rand(3260, 3000) + return (A, B) + #return 1.0*toc/(trials), 2*N*N*N*1e-9, times + +def prepare_dgemm(N=100, trials=3, dtype=np.double): + LARGEDIM = int(N*2) + KSIZE = int(N/2) + A = np.asarray(np.random.rand(LARGEDIM, KSIZE), dtype=dtype) + B = np.asarray(np.random.rand(KSIZE, LARGEDIM), dtype=dtype) + return (A, B) + +def kernel_dgemm(A, B): + """ + DGEMM + """ + A.dot(B) + +def prepare_cholesky(N=100, dtype=np.double): + N = int(N*2) + A = np.asarray(np.random.rand(N, N), dtype=dtype) + return ( A*A.transpose() + N*np.eye(N), ) + #return toc/trials, N*N*N/3.0*1e-9, times + +#inv: return toc/trials, 2*N*N*N*1e-9, times + + +################################################################################## + + +class tbb_job: + def __init__(self, i, body): + self._i = i + self._body = body + def __call__(self): + self._body(self._i) + +def run_tbb(n, body): + """PlainTBB""" + import TBB + pool = TBB.task_group() + global nested_tbb + if 'nested_tbb' not in globals(): + log.debug("Creating TBB task_group") + nested_tbb = TBB.task_arena() + for i in n: + b = tbb_job(i, body) + pool.run(b) #, nested_tbb) + pool.wait() + +def run_tbbpool(n, body): + """TBB.Pool""" + from TBB import Pool + global reused_pool, numthreads + if 'reused_pool' not in globals(): + log.debug("Creating TBB.Pool(%s)" % numthreads) + reused_pool = Pool(int(numthreads)) + reused_pool.map(body, n) + +def run_tp(n, body): + """ThreadPool.map""" + from multiprocessing.pool import ThreadPool + global reused_pool, numthreads + if 'reused_pool' not in globals(): + log.debug("Creating ThreadPool(%s)" % numthreads) + reused_pool = ThreadPool(int(numthreads)) + reused_pool.map(body, n) + +def run_pp(n, body): + """Process Pool.map""" + from multiprocessing.pool import Pool + global reused_pool, numthreads + global args + if 'reused_pool' not in globals(): + log.debug("Creating Pool(%s)" % numthreads) + reused_pool = Pool(int(numthreads)) + reused_pool.map(body, n) + +def run_tpaa(n, body): + """ThreadPool.apply_async""" + from multiprocessing.pool import ThreadPool + global reused_pool, numthreads + if 'reused_pool' not in globals(): + log.debug("Creating ThreadPool(%s) for apply_async()" % numthreads) + reused_pool = ThreadPool(int(numthreads)) + reused_pool.map(body, range(n)) + wait_list = [] + for i in n: + b = tbb_job(i, body) + a = reused_pool.apply_async(b) + wait_list.append(a) + for a in wait_list: + a.wait() + +def run_seq(n, body): + """Sequential""" + for i in n: + body(i) + +def empty_work(i): + pass + +class body: + def __init__(self, trials): + self.trials = trials + + def __call__(self, i): + global args, kernel, out + for j in range(self.trials): + t_start = time.time() + kernel(*args[i]) + out[i,j] = time.time() - t_start + +def bench_on(runner, sym, Ns, trials, dtype=None): + global args, kernel, out, mkl_layer + prepare = globals().get("prepare_"+sym, prepare_default) + kernel = globals().get("kernel_"+sym, None) + if not kernel: + kernel = getattr(np.linalg, sym) + out_lvl = runner.__doc__.split('.')[0].strip() + func_s = kernel.__doc__.split('.')[0].strip() + log.debug('Preparing input data for %s (%s).. ' % (sym, func_s)) + args = [prepare(int(i)) for i in Ns] + it = range(len(Ns)) + # pprint(Ns) + out = np.empty(shape=(len(Ns), trials)) + b = body(trials) + tic, toc = (0, 0) + log.debug('Warming up %s (%s).. ' % (sym, func_s)) + runner(range(1000), empty_work) + kernel(*args[0]) + runner(range(1000), empty_work) + log.debug('Benchmarking %s on %s: ' % (func_s, out_lvl)) + gc_old = gc.isenabled() +# gc.disable() + tic = time.time() + runner(it, b) + toc = time.time() - tic + if gc_old: + gc.enable() + if 'reused_pool' in globals(): + del globals()['reused_pool'] + + #calculate average time and min time and also keep track of outliers (max time in the loop) + min_time = np.amin(out) + max_time = np.amax(out) + mean_time = np.mean(out) + stdev_time = np.std(out) + + #print("Min = %.5f, Max = %.5f, Mean = %.5f, stdev = %.5f " % (min_time, max_time, mean_time, stdev_time)) + #final_times = [min_time, max_time, mean_time, stdev_time] + + print('## %s: Outter:%s, Inner:%s, Wall seconds:%f\n' % (sym, out_lvl, mkl_layer, float(toc))) + return out + + +if __name__ != '__main__': + print("not running as main? ", __name__) +else: + + parser = argparse.ArgumentParser(sys.argv[0]) + parser.add_argument('--threads', required=True, help="append number of threads used in benchmark to output resuts file") + parser.add_argument('--parallel', required=False, default='tp', help="Specify outermost parallelism") + parser.add_argument('--test', required=False, help="Run specified tests, comma-separated.") + args = parser.parse_args() + + global numthreads, mkl_layer + numthreads = args.threads + runner_name= 'run_'+args.parallel + if runner_name not in globals(): + print('--parallel=', args.parallel, " is not implemented, running sequential tests") + runner = run_seq + else: + runner = globals()[runner_name] + + mkl_layer = os.environ.get('MKL_THREADING_LAYER') + log.debug('MKL_THREADING_LAYER = ', mkl_layer) + log.debug('MKL_NUM_THREADS = ', os.environ.get('MKL_NUM_THREADS')) + log.debug('OMP_NUM_THREADS = ', os.environ.get('OMP_NUM_THREADS')) + log.debug('KMP_AFFINITY = ', os.environ.get('KMP_AFFINITY')) + + + trials = 3 + dtype = np.double + log.debug('Number of iterations:', trials) + + #Ns = [600,1000,2000,5000]*10 + Ns = [1500,3000]*17 + #Ns = [5000]*3 + [512]*207 + #Ns = [10]*100 + + if args.test: + tests = args.test.split(",") + + for sym in tests: + bench_on(runner, sym, Ns, trials) + + diff --git a/composability_bench/scipy2017/bench_demo_run.sh b/composability_bench/scipy2017/bench_demo_run.sh new file mode 100644 index 0000000..89dd95d --- /dev/null +++ b/composability_bench/scipy2017/bench_demo_run.sh @@ -0,0 +1,12 @@ +python -m smp bench_stats.py --parallel tp --threads 44 |& grep '##' +python -m tbb bench_stats.py --parallel tp --threads 44 |& grep '##' +KMP_BLOCK_TIME=0 python bench_stats.py --parallel tp --threads 44 +#expected to fail with: +#OMP: Error #34: System unable to allocate necessary resources for OMP thread: +#OMP: System error #11: Resource temporarily unavailable +#OMP: Hint: Try decreasing the value of OMP_NUM_THREADS. +OMP_NUM_THREADS=1 python bench_stats.py --parallel tp --threads 44 |& grep '##' + +python -m smp bench_stats.py --parallel pp --threads 44 --test svd |& grep '##' +python -m tbb bench_stats.py --parallel pp --threads 44 --test svd |& grep '##' +python bench_stats.py --parallel pp --threads 44 --test svd |& grep '##' diff --git a/composability_bench/scipy2017/dask_dh_mt.py b/composability_bench/scipy2017/dask_dh_mt.py new file mode 100644 index 0000000..49de30f --- /dev/null +++ b/composability_bench/scipy2017/dask_dh_mt.py @@ -0,0 +1,41 @@ +# Copyright (c) 2017, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + +# Dynamic/unbalanced with high inner subscription, Dask-threaded +import dask, time +import dask.array as da + +def qr(x): + t0 = time.time() + q, r = da.linalg.qr(x) + test = da.all(da.isclose(x, q.dot(r))) + test.compute() + print(time.time() - t0) + +sz = (440000, 1000) +x01 = da.random.random(sz, chunks=(440000, 1000)) +x22 = da.random.random(sz, chunks=(20000, 1000)) +x44 = da.random.random(sz, chunks=(10000, 1000)) +qr(x01); qr(x22); qr(x44) diff --git a/composability_bench/scipy2017/dask_sh_mt.py b/composability_bench/scipy2017/dask_sh_mt.py new file mode 100644 index 0000000..48d5499 --- /dev/null +++ b/composability_bench/scipy2017/dask_sh_mt.py @@ -0,0 +1,34 @@ +# Copyright (c) 2017, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + +# Static/balanced with high inner subscription, Dask-threaded +import time, dask, dask.array as da +x = da.random.random((440000, 1000), chunks=(10000, 1000)) +for i in range(3): + t0 = time.time() + q, r = da.linalg.qr(x) + test = da.all(da.isclose(x, q.dot(r))) + test.compute() + print(time.time() - t0) diff --git a/composability_bench/scipy2017/numpy_dl_mp.py b/composability_bench/scipy2017/numpy_dl_mp.py new file mode 100644 index 0000000..d940e0e --- /dev/null +++ b/composability_bench/scipy2017/numpy_dl_mp.py @@ -0,0 +1,50 @@ +# Copyright (c) 2017, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + +# Dynamic/unbalanced with low inner subscription, multi-processes +import time, numpy as np +from multiprocessing import Pool +from functools import partial +from utils import pool_args, noret + +p = Pool(*pool_args) +x = np.random.random((256, 256)) +y = np.random.random((8192, 8192)) + +mmul = partial(noret, np.matmul, y) +neig = partial(noret, np.linalg.eig) + +if __name__ == '__main__': + t0 = time.time() + p.map(mmul, [y for i in range(6)], 6) + print(time.time() - t0) + + t0 = time.time() + p.map(neig, [x for i in range(1408)], 64) + print(time.time() - t0) + + t0 = time.time() + p.map(neig, [x for i in range(1408)], 32) + print(time.time() - t0) diff --git a/composability_bench/scipy2017/numpy_dl_mt.py b/composability_bench/scipy2017/numpy_dl_mt.py new file mode 100644 index 0000000..6b3fef7 --- /dev/null +++ b/composability_bench/scipy2017/numpy_dl_mt.py @@ -0,0 +1,47 @@ +# Copyright (c) 2017, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + +# Dynamic/unbalanced with low inner subscription, multithreaded +import time, numpy as np +from multiprocessing.pool import ThreadPool +from functools import partial +from utils import pool_args + +x = np.random.random((256, 256)) +y = np.random.random((8192, 8192)) +p = ThreadPool(*pool_args) + +t0 = time.time() +mmul = partial(np.matmul, y) +p.map(mmul, [y for i in range(6)], 6) +print(time.time() - t0) + +t0 = time.time() +p.map(np.linalg.eig, [x for i in range(1408)], 64) +print(time.time() - t0) + +t0 = time.time() +p.map(np.linalg.eig, [x for i in range(1408)], 32) +print(time.time() - t0) diff --git a/composability_bench/scipy2017/numpy_sl_mp.py b/composability_bench/scipy2017/numpy_sl_mp.py new file mode 100644 index 0000000..689407d --- /dev/null +++ b/composability_bench/scipy2017/numpy_sl_mp.py @@ -0,0 +1,40 @@ +# Copyright (c) 2017, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + +# Static/balanced with low inner subscription, multi-processes +import time, sys, numpy as np +from multiprocessing import Pool +from functools import partial +from utils import pool_args, noret + +p = Pool(*pool_args) +neig = partial(noret, np.linalg.eig) +data = np.random.random((1024, 1024)) + +if __name__ == '__main__': + for j in range(3): + t0 = time.time() + p.map(neig, [data for i in range(254)]) + print(time.time() - t0) diff --git a/composability_bench/scipy2017/numpy_sl_mt.py b/composability_bench/scipy2017/numpy_sl_mt.py new file mode 100644 index 0000000..9380dc6 --- /dev/null +++ b/composability_bench/scipy2017/numpy_sl_mt.py @@ -0,0 +1,37 @@ +# Copyright (c) 2017, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + +# Static/balanced with low inner subscription, multithreaded +import time, sys, numpy as np +from multiprocessing.pool import ThreadPool +from utils import pool_args + +data = np.random.random((256, 256)) +p = ThreadPool(*pool_args) + +for j in range(3): + t0 = time.time() + p.map(np.linalg.eig, [data for i in range(1024)]) + print(time.time() - t0) diff --git a/composability_bench/scipy2017/run4paper.sh b/composability_bench/scipy2017/run4paper.sh new file mode 100755 index 0000000..7c8679d --- /dev/null +++ b/composability_bench/scipy2017/run4paper.sh @@ -0,0 +1,98 @@ +#!/bin/bash +# Copyright (c) 2017, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + + +DIR=$HOME/local/miniconda3 +CONDA=$DIR/bin/conda +ENAME=scipy2018 +log='echo' +mkdir -p $DIR +[ -x $CONDA ] || ( + $log "== Installing miniconda ==" + pushd $DIR + [ -f Miniconda3-latest-Linux-x86_64.sh ] || curl -O https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh + bash ./Miniconda3-latest-Linux-x86_64.sh -b -p $DIR -f + popd + [ -x $CONDA ] || exit 1 +) +[ -d $DIR/envs/$ENAME ] || ( + $log "== Installing environment ==" + $CONDA create -y -n $ENAME -c intel python=3 numpy tbb4py smp dask || exit 1 +) +source $DIR/bin/activate $ENAME || exit 1 +LIBIOMP=$DIR/envs/$ENAME/lib/libiomp5.so +[ -f $LIBIOMP ] || exit 1 +if [ `strings $LIBIOMP | grep -c KMP_COMPOSABILITY` != 0 ]; then + compe="KMP_COMPOSABILITY=mode=exclusive" + if [ `strings $LIBIOMP | grep -c "Using exclusive mode instead"` == 0 ]; then + compc="KMP_COMPOSABILITY=mode=counting" + fi + $log "$compc $compe support detected for OpenMP!" +elif [ `strings $LIBIOMP | grep -c KMP_FOREIGN_THREAD_LOCK` != 0 ]; then + $log "Limited composable OpenMP support detected! (Deprecated interface)" + compe="KMP_FOREIGN_THREAD_LOCK=1" +else + $log "New OpenMP composability interface is not available in this environment" +fi + +#log=':' +#set -x + +#: >scalability.csv +for f in numpy_sl_mp numpy_dl_mp numpy_sl_mt numpy_dl_mt; do + echo == $f + (for p in 88 44 22 16 8 4 2 1; do + $log "#Default $p" + KMP_BLOCKTIME=0 python $f.py $p + $log "#SMP $p" + python -m smp -f 1 $f.py $p + done) |& tee $f.log + sed -z 's/\n/ /g;s/#/\n/g' $f.log | sed "s/^/$f /;y/ /,/" >>scalability.csv +done + +#: >survey.csv +for f in numpy_sl_mt dask_sh_mt numpy_dl_mt dask_dh_mt; do + echo == $f + ( + $log "#Default" + KMP_BLOCKTIME=0 python $f.py + $log "#OMP=1" + OMP_NUM_THREADS=1 python $f.py + $log "#SMP" + python -m smp -f 1 $f.py + $log "#TBB" + python -m tbb $f.py + if [ ! -z $compe ]; then + $log "#OMP=exclusive" + env $compe python $f.py + fi + if [ ! -z $compc ]; then + $log "#OMP=counting" + env $compc python $f.py + fi + ) |& tee $f.log + sed -z 's/\n/ /g;s/#/\n/g' $f.log | sed "s/^/$f /;y/ /,/" >>survey.csv +done diff --git a/composability_bench/scipy2017/run_all.sh b/composability_bench/scipy2017/run_all.sh new file mode 100644 index 0000000..7e8a789 --- /dev/null +++ b/composability_bench/scipy2017/run_all.sh @@ -0,0 +1,24 @@ +#!/bin/bash +log=echo +for i in `seq 10`; do + $log === Run $i + for f in numpy_sl_mp numpy_dl_mp numpy_sl_mt numpy_dl_mt; do + $log == $f + (for p in 88 64 44 32 22 16 8 4 2 1; do + $log "#Default $p" + KMP_BLOCKTIME=0 python $f.py $p + $log "#SMP $p" + python -m smp -f 1 $f.py $p + if [[ "$f" =~ "_mp" ]]; then + $log "#TBB-ipc $p" + python -m tbb --ipc $f.py $p + else + $log "#TBB $p" + python -m tbb -p $p $f.py $p + fi + $log "#OMP=counting $p" + env KMP_COMPOSABILITY=mode=counting python $f.py $p + done) |& tee $f.log + sed -z 's/\n/ /g;s/#/\n/g' $f.log | sed "s/^/$f /;y/ /,/" >>scalability.csv + done +done diff --git a/composability_bench/scipy2017/utils.py b/composability_bench/scipy2017/utils.py new file mode 100644 index 0000000..27591be --- /dev/null +++ b/composability_bench/scipy2017/utils.py @@ -0,0 +1,36 @@ +# Copyright (c) 2017, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + + +import sys + +pool_args = [] +if len(sys.argv) > 1: + pool_args += [int(sys.argv[1])] + +def noret(f, *args): + f(*args) + return + diff --git a/composability_bench/scipy2018_demo/README.md b/composability_bench/scipy2018_demo/README.md new file mode 100644 index 0000000..7de479d --- /dev/null +++ b/composability_bench/scipy2018_demo/README.md @@ -0,0 +1,29 @@ +# Composability demo for SciPy 2018 + +## Installation +Install TBB and SMP modules for Python along with MKL-enabled numpy +in order to evaluate benefits of composable multithreading +``` +conda install -c intel mkl numpy tbb4py smp +``` + +## Runing +Effects are visible on big enough machine with 32 and more cores. + +``` +python demo.py +KMP_BLOCKTIME=0 python demo.py # Align settings with GNU OpenMP +python -m tbb demo.py +python -m smp demo.py +python -m smp -o demo.py +``` + +## Jupyter notebook +For running on the same host, `start_jupyter.sh`. + +For running a remote session from Windows machine, copy&edit `demo_config_example.bat` as `demo_config.bat`, +then run `start_jupyter.bat`. In Jupyter, open `composability_demo.ipynb` and follow instructions. + +## See also +- Introductionary blog: https://software.intel.com/en-us/blogs/2016/04/04/unleash-parallel-performance-of-python-programs +- Details in the whitepaper: http://conference.scipy.org/proceedings/scipy2018/pdfs/anton_malakhov.pdf diff --git a/composability_bench/scipy2018_demo/composability_demo.ipynb b/composability_bench/scipy2018_demo/composability_demo.ipynb new file mode 100644 index 0000000..33e3154 --- /dev/null +++ b/composability_bench/scipy2018_demo/composability_demo.ipynb @@ -0,0 +1,177 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Composability demo\n", + "This notebook assumes that MKL-enabled Numpy, TBB and SMP modules, and their IPython kernels are already installed like below:\n", + "```\n", + "conda install -c intel mkl numpy tbb4py smp\n", + "jupyter kernelspec install python-tbb/ --sys-prefix\n", + "jupyter kernelspec install python-smp/ --sys-prefix\n", + "```\n", + "\n", + "Change kernels using Jupyter menu, e.g. Kernel->Change kernel->Python 3/TBB; then re-run the first cell below:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "from multiprocessing.pool import ThreadPool\n", + "pool = ThreadPool(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Default Python kernel" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "341 ms ± 63.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" + ] + } + ], + "source": [ + "%timeit pool.map(np.linalg.qr, [np.random.random((256, 256)) for i in range(10)])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Python -m SMP kernel" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "19.5 ms ± 59.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + ] + } + ], + "source": [ + "%timeit pool.map(np.linalg.qr, [np.random.random((256, 256)) for i in range(10)])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Python -m TBB kernel" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "17.2 ms ± 581 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + ] + } + ], + "source": [ + "%timeit pool.map(np.linalg.qr, [np.random.random((256, 256)) for i in range(10)])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Machine specification\n", + "In order to observe any difference, machine should be big enough" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Architecture: x86_64\r\n", + "CPU op-mode(s): 32-bit, 64-bit\r\n", + "Byte Order: Little Endian\r\n", + "CPU(s): 88\r\n", + "On-line CPU(s) list: 0-87\r\n", + "Thread(s) per core: 2\r\n", + "Core(s) per socket: 22\r\n", + "Socket(s): 2\r\n", + "NUMA node(s): 2\r\n", + "Vendor ID: GenuineIntel\r\n", + "CPU family: 6\r\n", + "Model: 79\r\n", + "Model name: Intel(R) Xeon(R) CPU E5-2699 v4 @ 2.20GHz\r\n", + "Stepping: 1\r\n", + "CPU MHz: 1441.343\r\n", + "BogoMIPS: 4395.56\r\n", + "Virtualization: VT-x\r\n", + "L1d cache: 32K\r\n", + "L1i cache: 32K\r\n", + "L2 cache: 256K\r\n", + "L3 cache: 56320K\r\n", + "NUMA node0 CPU(s): 0-21,44-65\r\n", + "NUMA node1 CPU(s): 22-43,66-87\r\n" + ] + } + ], + "source": [ + "!lscpu" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/composability_bench/scipy2018_demo/demo.py b/composability_bench/scipy2018_demo/demo.py new file mode 100644 index 0000000..8fd085d --- /dev/null +++ b/composability_bench/scipy2018_demo/demo.py @@ -0,0 +1,10 @@ +import time, numpy as np +from multiprocessing.pool import ThreadPool + +p = ThreadPool() +data = np.random.random((2000, 2000)) + +for j in range(3): + t0 = time.time() + p.map(np.linalg.qr, [data for i in range(10)]) + print(time.time() - t0) diff --git a/composability_bench/scipy2018_demo/demo_config_example.bat b/composability_bench/scipy2018_demo/demo_config_example.bat new file mode 100755 index 0000000..a043d90 --- /dev/null +++ b/composability_bench/scipy2018_demo/demo_config_example.bat @@ -0,0 +1,4 @@ +set SSH="C:\Program Files (x86)\PuTTY"\plink.exe +set HOST="my remote linux server session name" +set REMOTE_DIR=~/composability_bench/scipy2018_demo +set REMOTE_ENV=. ~/miniconda3/bin/activate scipy2018 diff --git a/composability_bench/scipy2018_demo/python-smp/kernel.json b/composability_bench/scipy2018_demo/python-smp/kernel.json new file mode 100644 index 0000000..5cdb000 --- /dev/null +++ b/composability_bench/scipy2018_demo/python-smp/kernel.json @@ -0,0 +1,6 @@ +{ + "argv": ["python", "-m", "smp", "-m", "IPython.kernel", + "-f", "{connection_file}"], + "display_name": "Python 3/SMP", + "language": "python" +} diff --git a/composability_bench/scipy2018_demo/python-tbb/kernel.json b/composability_bench/scipy2018_demo/python-tbb/kernel.json new file mode 100644 index 0000000..9f81409 --- /dev/null +++ b/composability_bench/scipy2018_demo/python-tbb/kernel.json @@ -0,0 +1,6 @@ +{ + "argv": ["python", "-m", "tbb", "-m", "IPython.kernel", + "-f", "{connection_file}"], + "display_name": "Python 3/TBB", + "language": "python" +} diff --git a/composability_bench/scipy2018_demo/start_jupyter.bat b/composability_bench/scipy2018_demo/start_jupyter.bat new file mode 100755 index 0000000..c125902 --- /dev/null +++ b/composability_bench/scipy2018_demo/start_jupyter.bat @@ -0,0 +1,3 @@ +call demo_config.bat +start http://localhost:8888?token=Default +%SSH% -L 8888:localhost:8888 %HOST% bash -c "pwd;cd %REMOTE_DIR%;%REMOTE_ENV%;exec ./start_jupyter.sh" diff --git a/composability_bench/scipy2018_demo/start_jupyter.sh b/composability_bench/scipy2018_demo/start_jupyter.sh new file mode 100755 index 0000000..39426cb --- /dev/null +++ b/composability_bench/scipy2018_demo/start_jupyter.sh @@ -0,0 +1,5 @@ +#. activate scipy2018 +pwd +jupyter kernelspec install python-tbb/ --sys-prefix +jupyter kernelspec install python-smp/ --sys-prefix +jupyter notebook --notebook-dir=`pwd` --NotebookApp.token=Default diff --git a/composability_bench/set_python_envs.sh b/composability_bench/set_python_envs.sh new file mode 100755 index 0000000..3fa3b64 --- /dev/null +++ b/composability_bench/set_python_envs.sh @@ -0,0 +1,37 @@ +# Copyright (c) 2017, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + + +DIR=$HOME/miniconda3 +rm -r $DIR +mkdir -p $DIR +cd $DIR +curl -O https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh \ + && bash ./Miniconda3-latest-Linux-x86_64.sh -b -p $DIR -f \ + && rm ./Miniconda3-latest-Linux-x86_64.sh +#export ACCEPT_INTEL_PYTHON_EULA=yes +CONDA=$DIR/bin/conda + +$CONDA create -y -n intel3 -c intel python=3 numpy scipy scikit-learn tbb dask numba diff --git a/composability_bench/tbb_blog_bench.py b/composability_bench/tbb_blog_bench.py new file mode 100755 index 0000000..f7cb5ed --- /dev/null +++ b/composability_bench/tbb_blog_bench.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# Copyright (c) 2017, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Intel Corporation nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + + +import dask, time +import dask.array as da + +x = da.random.random((100000, 2000), chunks=(10000, 2000)) +t0 = time.time() + +q, r = da.linalg.qr(x) +test = da.all(da.isclose(x, q.dot(r))) +test.compute() # compute(get=dask.threaded.get) by default + +print(time.time() - t0)