chore: import upstream snapshot with attribution
Build / Build and test on ubuntu-latest for x86_64 (push) Failing after 1s
Build / Build and test on ubuntu-latest (numpy 1.26) for x86_64 (push) Failing after 0s
Build / Build and test on ubuntu-24.04-arm for aarch64 (push) Has been cancelled
Build / Build and test on windows-11-arm for aarch64 (push) Has been cancelled
Build / Build and test on macos-latest for x86_64 (push) Has been cancelled
Build / Build and test on windows-latest for x86_64 (push) Has been cancelled
Build / Build and test on ubuntu-latest for x86_64 (push) Failing after 1s
Build / Build and test on ubuntu-latest (numpy 1.26) for x86_64 (push) Failing after 0s
Build / Build and test on ubuntu-24.04-arm for aarch64 (push) Has been cancelled
Build / Build and test on windows-11-arm for aarch64 (push) Has been cancelled
Build / Build and test on macos-latest for x86_64 (push) Has been cancelled
Build / Build and test on windows-latest for x86_64 (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
###################################################################
|
||||
# Numexpr - Fast numerical array expression evaluator for NumPy.
|
||||
#
|
||||
# License: MIT
|
||||
# Author: See AUTHORS.txt
|
||||
#
|
||||
# See LICENSE.txt and LICENSES/*.txt for details about copyright and
|
||||
# rights to use.
|
||||
####################################################################
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import timeit
|
||||
|
||||
import numpy
|
||||
|
||||
array_size = 5_000_000
|
||||
iterations = 10
|
||||
|
||||
numpy_ttime = []
|
||||
numpy_sttime = []
|
||||
numpy_nttime = []
|
||||
numexpr_ttime = []
|
||||
numexpr_sttime = []
|
||||
numexpr_nttime = []
|
||||
|
||||
|
||||
def compare_times(expr, nexpr):
|
||||
global numpy_ttime
|
||||
global numpy_sttime
|
||||
global numpy_nttime
|
||||
global numexpr_ttime
|
||||
global numexpr_sttime
|
||||
global numexpr_nttime
|
||||
|
||||
print("******************* Expression:", expr)
|
||||
|
||||
setup_contiguous = setupNP_contiguous
|
||||
setup_strided = setupNP_strided
|
||||
setup_unaligned = setupNP_unaligned
|
||||
|
||||
numpy_timer = timeit.Timer(expr, setup_contiguous)
|
||||
numpy_time = round(numpy_timer.timeit(number=iterations), 4)
|
||||
numpy_ttime.append(numpy_time)
|
||||
print('numpy:', numpy_time / iterations)
|
||||
|
||||
numpy_timer = timeit.Timer(expr, setup_strided)
|
||||
numpy_stime = round(numpy_timer.timeit(number=iterations), 4)
|
||||
numpy_sttime.append(numpy_stime)
|
||||
print('numpy strided:', numpy_stime / iterations)
|
||||
|
||||
numpy_timer = timeit.Timer(expr, setup_unaligned)
|
||||
numpy_ntime = round(numpy_timer.timeit(number=iterations), 4)
|
||||
numpy_nttime.append(numpy_ntime)
|
||||
print('numpy unaligned:', numpy_ntime / iterations)
|
||||
|
||||
evalexpr = 'evaluate("%s", optimization="aggressive")' % expr
|
||||
numexpr_timer = timeit.Timer(evalexpr, setup_contiguous)
|
||||
numexpr_time = round(numexpr_timer.timeit(number=iterations), 4)
|
||||
numexpr_ttime.append(numexpr_time)
|
||||
print("numexpr:", numexpr_time/iterations, end=" ")
|
||||
print("Speed-up of numexpr over numpy:", round(numpy_time/numexpr_time, 4))
|
||||
|
||||
evalexpr = 'evaluate("%s", optimization="aggressive")' % expr
|
||||
numexpr_timer = timeit.Timer(evalexpr, setup_strided)
|
||||
numexpr_stime = round(numexpr_timer.timeit(number=iterations), 4)
|
||||
numexpr_sttime.append(numexpr_stime)
|
||||
print("numexpr strided:", numexpr_stime/iterations, end=" ")
|
||||
print("Speed-up of numexpr strided over numpy:",
|
||||
round(numpy_stime/numexpr_stime, 4))
|
||||
|
||||
evalexpr = 'evaluate("%s", optimization="aggressive")' % expr
|
||||
numexpr_timer = timeit.Timer(evalexpr, setup_unaligned)
|
||||
numexpr_ntime = round(numexpr_timer.timeit(number=iterations), 4)
|
||||
numexpr_nttime.append(numexpr_ntime)
|
||||
print("numexpr unaligned:", numexpr_ntime/iterations, end=" ")
|
||||
print("Speed-up of numexpr unaligned over numpy:",
|
||||
round(numpy_ntime/numexpr_ntime, 4))
|
||||
|
||||
|
||||
|
||||
setupNP = """\
|
||||
from numpy import arange, where, arctan2, sqrt
|
||||
from numpy import rec as records
|
||||
from numexpr import evaluate
|
||||
|
||||
# Initialize a recarray of 16 MB in size
|
||||
r=records.array(None, formats='a%s,i4,f8', shape=%s)
|
||||
c1 = r.field('f0')%s
|
||||
i2 = r.field('f1')%s
|
||||
f3 = r.field('f2')%s
|
||||
c1[:] = "a"
|
||||
i2[:] = arange(%s)/1000
|
||||
f3[:] = i2/2.
|
||||
"""
|
||||
|
||||
setupNP_contiguous = setupNP % (4, array_size,
|
||||
".copy()", ".copy()", ".copy()",
|
||||
array_size)
|
||||
setupNP_strided = setupNP % (4, array_size, "", "", "", array_size)
|
||||
setupNP_unaligned = setupNP % (1, array_size, "", "", "", array_size)
|
||||
|
||||
|
||||
expressions = []
|
||||
expressions.append('i2 > 0')
|
||||
expressions.append('i2 < 0')
|
||||
expressions.append('i2 < f3')
|
||||
expressions.append('i2-10 < f3')
|
||||
expressions.append('i2*f3+f3*f3 > i2')
|
||||
expressions.append('0.1*i2 > arctan2(i2, f3)')
|
||||
expressions.append('i2%2 > 3')
|
||||
expressions.append('i2%10 < 4')
|
||||
expressions.append('i2**2 + (f3+1)**-2.5 < 3')
|
||||
expressions.append('(f3+1)**50 > i2')
|
||||
expressions.append('sqrt(i2**2 + f3**2) > 1')
|
||||
expressions.append('(i2>2) | ((f3**2>3) & ~(i2*f3<2))')
|
||||
|
||||
def compare(expression=None):
|
||||
if expression:
|
||||
compare_times(expression, 1)
|
||||
sys.exit(0)
|
||||
nexpr = 0
|
||||
for expr in expressions:
|
||||
nexpr += 1
|
||||
compare_times(expr, nexpr)
|
||||
print()
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
import numexpr
|
||||
numexpr.print_versions()
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
expression = sys.argv[1]
|
||||
print("expression-->", expression)
|
||||
compare(expression)
|
||||
else:
|
||||
compare()
|
||||
|
||||
tratios = numpy.array(numpy_ttime) / numpy.array(numexpr_ttime)
|
||||
stratios = numpy.array(numpy_sttime) / numpy.array(numexpr_sttime)
|
||||
ntratios = numpy.array(numpy_nttime) / numpy.array(numexpr_nttime)
|
||||
|
||||
|
||||
print("*************** Numexpr vs NumPy speed-ups *******************")
|
||||
# print "numpy total:", sum(numpy_ttime)/iterations
|
||||
# print "numpy strided total:", sum(numpy_sttime)/iterations
|
||||
# print "numpy unaligned total:", sum(numpy_nttime)/iterations
|
||||
# print "numexpr total:", sum(numexpr_ttime)/iterations
|
||||
print("Contiguous case:\t %s (mean), %s (min), %s (max)" % \
|
||||
(round(tratios.mean(), 2),
|
||||
round(tratios.min(), 2),
|
||||
round(tratios.max(), 2)))
|
||||
# print "numexpr strided total:", sum(numexpr_sttime)/iterations
|
||||
print("Strided case:\t\t %s (mean), %s (min), %s (max)" % \
|
||||
(round(stratios.mean(), 2),
|
||||
round(stratios.min(), 2),
|
||||
round(stratios.max(), 2)))
|
||||
# print "numexpr unaligned total:", sum(numexpr_nttime)/iterations
|
||||
print("Unaligned case:\t\t %s (mean), %s (min), %s (max)" % \
|
||||
(round(ntratios.mean(), 2),
|
||||
round(ntratios.min(), 2),
|
||||
round(ntratios.max(), 2)))
|
||||
@@ -0,0 +1,171 @@
|
||||
#################################################################################
|
||||
# To compare the performance of numexpr when free-threading CPython is used.
|
||||
#
|
||||
# This example makes use of Python threads, as opposed to C native ones
|
||||
# in order to highlight the improvement introduced by free-threading CPython,
|
||||
# which now disables the GIL altogether.
|
||||
#################################################################################
|
||||
"""
|
||||
Results with GIL-enabled CPython:
|
||||
|
||||
Benchmarking Expression 1:
|
||||
NumPy time (threaded over 32 chunks with 16 threads): 1.173090 seconds
|
||||
numexpr time (threaded with re_evaluate over 32 chunks with 16 threads): 0.951071 seconds
|
||||
numexpr speedup: 1.23x
|
||||
----------------------------------------
|
||||
Benchmarking Expression 2:
|
||||
NumPy time (threaded over 32 chunks with 16 threads): 10.410874 seconds
|
||||
numexpr time (threaded with re_evaluate over 32 chunks with 16 threads): 8.248753 seconds
|
||||
numexpr speedup: 1.26x
|
||||
----------------------------------------
|
||||
Benchmarking Expression 3:
|
||||
NumPy time (threaded over 32 chunks with 16 threads): 9.605909 seconds
|
||||
numexpr time (threaded with re_evaluate over 32 chunks with 16 threads): 11.087108 seconds
|
||||
numexpr speedup: 0.87x
|
||||
----------------------------------------
|
||||
Benchmarking Expression 4:
|
||||
NumPy time (threaded over 32 chunks with 16 threads): 3.836962 seconds
|
||||
numexpr time (threaded with re_evaluate over 32 chunks with 16 threads): 18.054531 seconds
|
||||
numexpr speedup: 0.21x
|
||||
----------------------------------------
|
||||
|
||||
Results with free-threading CPython:
|
||||
|
||||
Benchmarking Expression 1:
|
||||
NumPy time (threaded over 32 chunks with 16 threads): 3.415349 seconds
|
||||
numexpr time (threaded with re_evaluate over 32 chunks with 16 threads): 2.618876 seconds
|
||||
numexpr speedup: 1.30x
|
||||
----------------------------------------
|
||||
Benchmarking Expression 2:
|
||||
NumPy time (threaded over 32 chunks with 16 threads): 19.005238 seconds
|
||||
numexpr time (threaded with re_evaluate over 32 chunks with 16 threads): 12.611407 seconds
|
||||
numexpr speedup: 1.51x
|
||||
----------------------------------------
|
||||
Benchmarking Expression 3:
|
||||
NumPy time (threaded over 32 chunks with 16 threads): 20.555149 seconds
|
||||
numexpr time (threaded with re_evaluate over 32 chunks with 16 threads): 17.690749 seconds
|
||||
numexpr speedup: 1.16x
|
||||
----------------------------------------
|
||||
Benchmarking Expression 4:
|
||||
NumPy time (threaded over 32 chunks with 16 threads): 38.338372 seconds
|
||||
numexpr time (threaded with re_evaluate over 32 chunks with 16 threads): 35.074684 seconds
|
||||
numexpr speedup: 1.09x
|
||||
----------------------------------------
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
os.environ["NUMEXPR_NUM_THREADS"] = "2"
|
||||
import threading
|
||||
import timeit
|
||||
|
||||
import numpy as np
|
||||
|
||||
import numexpr as ne
|
||||
|
||||
array_size = 10**8
|
||||
num_runs = 10
|
||||
num_chunks = 32 # Number of chunks
|
||||
num_threads = 16 # Number of threads constrained by how many chunks memory can hold
|
||||
|
||||
a = np.random.rand(array_size).reshape(10**4, -1)
|
||||
b = np.random.rand(array_size).reshape(10**4, -1)
|
||||
c = np.random.rand(array_size).reshape(10**4, -1)
|
||||
|
||||
chunk_size = array_size // num_chunks
|
||||
|
||||
expressions_numpy = [
|
||||
lambda a, b, c: a + b * c,
|
||||
lambda a, b, c: a**2 + b**2 - 2 * a * b * np.cos(c),
|
||||
lambda a, b, c: np.sin(a) + np.log(b) * np.sqrt(c),
|
||||
lambda a, b, c: np.exp(a) + np.tan(b) - np.sinh(c),
|
||||
]
|
||||
|
||||
expressions_numexpr = [
|
||||
"a + b * c",
|
||||
"a**2 + b**2 - 2 * a * b * cos(c)",
|
||||
"sin(a) + log(b) * sqrt(c)",
|
||||
"exp(a) + tan(b) - sinh(c)",
|
||||
]
|
||||
|
||||
|
||||
def benchmark_numpy_chunk(func, a, b, c, results, indices):
|
||||
for index in indices:
|
||||
start = index * chunk_size
|
||||
end = (index + 1) * chunk_size
|
||||
time_taken = timeit.timeit(
|
||||
lambda: func(a[start:end], b[start:end], c[start:end]), number=num_runs
|
||||
)
|
||||
results.append(time_taken)
|
||||
|
||||
|
||||
def benchmark_numexpr_re_evaluate(expr, a, b, c, results, indices):
|
||||
for index in indices:
|
||||
start = index * chunk_size
|
||||
end = (index + 1) * chunk_size
|
||||
# if index == 0:
|
||||
# Evaluate the first chunk with evaluate
|
||||
time_taken = timeit.timeit(
|
||||
lambda: ne.evaluate(
|
||||
expr,
|
||||
local_dict={
|
||||
"a": a[start:end],
|
||||
"b": b[start:end],
|
||||
"c": c[start:end],
|
||||
},
|
||||
),
|
||||
number=num_runs,
|
||||
)
|
||||
results.append(time_taken)
|
||||
|
||||
|
||||
def run_benchmark_threaded():
|
||||
chunk_indices = list(range(num_chunks))
|
||||
|
||||
for i in range(len(expressions_numpy)):
|
||||
print(f"Benchmarking Expression {i+1}:")
|
||||
|
||||
results_numpy = []
|
||||
results_numexpr = []
|
||||
|
||||
threads_numpy = []
|
||||
for j in range(num_threads):
|
||||
indices = chunk_indices[j::num_threads] # Distribute chunks across threads
|
||||
thread = threading.Thread(
|
||||
target=benchmark_numpy_chunk,
|
||||
args=(expressions_numpy[i], a, b, c, results_numpy, indices),
|
||||
)
|
||||
threads_numpy.append(thread)
|
||||
thread.start()
|
||||
|
||||
for thread in threads_numpy:
|
||||
thread.join()
|
||||
|
||||
numpy_time = sum(results_numpy)
|
||||
print(
|
||||
f"NumPy time (threaded over {num_chunks} chunks with {num_threads} threads): {numpy_time:.6f} seconds"
|
||||
)
|
||||
|
||||
threads_numexpr = []
|
||||
for j in range(num_threads):
|
||||
indices = chunk_indices[j::num_threads] # Distribute chunks across threads
|
||||
thread = threading.Thread(
|
||||
target=benchmark_numexpr_re_evaluate,
|
||||
args=(expressions_numexpr[i], a, b, c, results_numexpr, indices),
|
||||
)
|
||||
threads_numexpr.append(thread)
|
||||
thread.start()
|
||||
|
||||
for thread in threads_numexpr:
|
||||
thread.join()
|
||||
|
||||
numexpr_time = sum(results_numexpr)
|
||||
print(
|
||||
f"numexpr time (threaded with re_evaluate over {num_chunks} chunks with {num_threads} threads): {numexpr_time:.6f} seconds"
|
||||
)
|
||||
print(f"numexpr speedup: {numpy_time / numexpr_time:.2f}x")
|
||||
print("-" * 40)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_benchmark_threaded()
|
||||
@@ -0,0 +1,37 @@
|
||||
# Small benchmark to get the even point where the threading code
|
||||
# performs better than the serial code. See issue #36 for details.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from time import time
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import assert_array_equal
|
||||
|
||||
import numexpr as ne
|
||||
|
||||
|
||||
def bench(N):
|
||||
print("*** array length:", N)
|
||||
a = np.arange(N)
|
||||
t0 = time()
|
||||
ntimes = (1000*2**15) // N
|
||||
for i in range(ntimes):
|
||||
ne.evaluate('a>1000')
|
||||
print("numexpr--> %.3g" % ((time()-t0)/ntimes,))
|
||||
|
||||
t0 = time()
|
||||
for i in range(ntimes):
|
||||
eval('a>1000')
|
||||
print("numpy--> %.3g" % ((time()-t0)/ntimes,))
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("****** Testing with 1 thread...")
|
||||
ne.set_num_threads(1)
|
||||
for N in range(10, 20):
|
||||
bench(2**N)
|
||||
|
||||
print("****** Testing with 2 threads...")
|
||||
ne.set_num_threads(2)
|
||||
for N in range(10, 20):
|
||||
bench(2**N)
|
||||
@@ -0,0 +1,8 @@
|
||||
import numpy
|
||||
|
||||
import numexpr
|
||||
|
||||
numexpr.set_num_threads(8)
|
||||
x0,x1,x2,x3,x4,x5 = [0,1,2,3,4,5]
|
||||
t = numpy.linspace(0,1,44100000).reshape(-1,1)
|
||||
numexpr.evaluate('(x0+x1*t+x2*t**2)* cos(x3+x4*t+x5**t)')
|
||||
@@ -0,0 +1,154 @@
|
||||
#################################################################################
|
||||
# To mimic the scenario that computation is i/o bound and constrained by memory
|
||||
#
|
||||
# It's a much simplified version that the chunk is computed in a loop,
|
||||
# and expression is evaluated in a sequence, which is not true in reality.
|
||||
# Neverthless, numexpr outperforms numpy.
|
||||
#################################################################################
|
||||
"""
|
||||
Benchmarking Expression 1:
|
||||
NumPy time (threaded over 32 chunks with 2 threads): 4.612313 seconds
|
||||
numexpr time (threaded with re_evaluate over 32 chunks with 2 threads): 0.951172 seconds
|
||||
numexpr speedup: 4.85x
|
||||
----------------------------------------
|
||||
Benchmarking Expression 2:
|
||||
NumPy time (threaded over 32 chunks with 2 threads): 23.862752 seconds
|
||||
numexpr time (threaded with re_evaluate over 32 chunks with 2 threads): 2.182058 seconds
|
||||
numexpr speedup: 10.94x
|
||||
----------------------------------------
|
||||
Benchmarking Expression 3:
|
||||
NumPy time (threaded over 32 chunks with 2 threads): 20.594895 seconds
|
||||
numexpr time (threaded with re_evaluate over 32 chunks with 2 threads): 2.927881 seconds
|
||||
numexpr speedup: 7.03x
|
||||
----------------------------------------
|
||||
Benchmarking Expression 4:
|
||||
NumPy time (threaded over 32 chunks with 2 threads): 12.834101 seconds
|
||||
numexpr time (threaded with re_evaluate over 32 chunks with 2 threads): 5.392480 seconds
|
||||
numexpr speedup: 2.38x
|
||||
----------------------------------------
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
os.environ["NUMEXPR_NUM_THREADS"] = "16"
|
||||
import threading
|
||||
import timeit
|
||||
|
||||
import numpy as np
|
||||
|
||||
import numexpr as ne
|
||||
|
||||
array_size = 10**8
|
||||
num_runs = 10
|
||||
num_chunks = 32 # Number of chunks
|
||||
num_threads = 2 # Number of threads constrained by how many chunks memory can hold
|
||||
|
||||
a = np.random.rand(array_size).reshape(10**4, -1)
|
||||
b = np.random.rand(array_size).reshape(10**4, -1)
|
||||
c = np.random.rand(array_size).reshape(10**4, -1)
|
||||
|
||||
chunk_size = array_size // num_chunks
|
||||
|
||||
expressions_numpy = [
|
||||
lambda a, b, c: a + b * c,
|
||||
lambda a, b, c: a**2 + b**2 - 2 * a * b * np.cos(c),
|
||||
lambda a, b, c: np.sin(a) + np.log(b) * np.sqrt(c),
|
||||
lambda a, b, c: np.exp(a) + np.tan(b) - np.sinh(c),
|
||||
]
|
||||
|
||||
expressions_numexpr = [
|
||||
"a + b * c",
|
||||
"a**2 + b**2 - 2 * a * b * cos(c)",
|
||||
"sin(a) + log(b) * sqrt(c)",
|
||||
"exp(a) + tan(b) - sinh(c)",
|
||||
]
|
||||
|
||||
|
||||
def benchmark_numpy_chunk(func, a, b, c, results, indices):
|
||||
for index in indices:
|
||||
start = index * chunk_size
|
||||
end = (index + 1) * chunk_size
|
||||
time_taken = timeit.timeit(
|
||||
lambda: func(a[start:end], b[start:end], c[start:end]), number=num_runs
|
||||
)
|
||||
results.append(time_taken)
|
||||
|
||||
|
||||
def benchmark_numexpr_re_evaluate(expr, a, b, c, results, indices):
|
||||
for index in indices:
|
||||
start = index * chunk_size
|
||||
end = (index + 1) * chunk_size
|
||||
if index == 0 or index == 1:
|
||||
# Evaluate the first chunk with evaluate
|
||||
time_taken = timeit.timeit(
|
||||
lambda: ne.evaluate(
|
||||
expr,
|
||||
local_dict={
|
||||
"a": a[start:end],
|
||||
"b": b[start:end],
|
||||
"c": c[start:end],
|
||||
},
|
||||
),
|
||||
number=num_runs,
|
||||
)
|
||||
else:
|
||||
# Re-evaluate subsequent chunks with re_evaluate
|
||||
time_taken = timeit.timeit(
|
||||
lambda: ne.re_evaluate(
|
||||
local_dict={"a": a[start:end], "b": b[start:end], "c": c[start:end]}
|
||||
),
|
||||
number=num_runs,
|
||||
)
|
||||
results.append(time_taken)
|
||||
|
||||
|
||||
def run_benchmark_threaded():
|
||||
chunk_indices = list(range(num_chunks))
|
||||
|
||||
for i in range(len(expressions_numpy)):
|
||||
print(f"Benchmarking Expression {i+1}:")
|
||||
|
||||
results_numpy = []
|
||||
results_numexpr = []
|
||||
|
||||
threads_numpy = []
|
||||
for j in range(num_threads):
|
||||
indices = chunk_indices[j::num_threads] # Distribute chunks across threads
|
||||
thread = threading.Thread(
|
||||
target=benchmark_numpy_chunk,
|
||||
args=(expressions_numpy[i], a, b, c, results_numpy, indices),
|
||||
)
|
||||
threads_numpy.append(thread)
|
||||
thread.start()
|
||||
|
||||
for thread in threads_numpy:
|
||||
thread.join()
|
||||
|
||||
numpy_time = sum(results_numpy)
|
||||
print(
|
||||
f"NumPy time (threaded over {num_chunks} chunks with {num_threads} threads): {numpy_time:.6f} seconds"
|
||||
)
|
||||
|
||||
threads_numexpr = []
|
||||
for j in range(num_threads):
|
||||
indices = chunk_indices[j::num_threads] # Distribute chunks across threads
|
||||
thread = threading.Thread(
|
||||
target=benchmark_numexpr_re_evaluate,
|
||||
args=(expressions_numexpr[i], a, b, c, results_numexpr, indices),
|
||||
)
|
||||
threads_numexpr.append(thread)
|
||||
thread.start()
|
||||
|
||||
for thread in threads_numexpr:
|
||||
thread.join()
|
||||
|
||||
numexpr_time = sum(results_numexpr)
|
||||
print(
|
||||
f"numexpr time (threaded with re_evaluate over {num_chunks} chunks with {num_threads} threads): {numexpr_time:.6f} seconds"
|
||||
)
|
||||
print(f"numexpr speedup: {numpy_time / numexpr_time:.2f}x")
|
||||
print("-" * 40)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_benchmark_threaded()
|
||||
@@ -0,0 +1,95 @@
|
||||
###################################################################
|
||||
# Numexpr - Fast numerical array expression evaluator for NumPy.
|
||||
#
|
||||
# License: MIT
|
||||
# Author: See AUTHORS.txt
|
||||
#
|
||||
# See LICENSE.txt and LICENSES/*.txt for details about copyright and
|
||||
# rights to use.
|
||||
####################################################################
|
||||
|
||||
# Script to check that multidimensional arrays are speed-up properly too
|
||||
# Based on a script provided by Andrew Collette.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import time
|
||||
|
||||
import numpy as np
|
||||
|
||||
import numexpr as nx
|
||||
|
||||
test_shapes = [
|
||||
(100*100*100),
|
||||
(100*100,100),
|
||||
(100,100,100),
|
||||
]
|
||||
|
||||
test_dtype = 'f4'
|
||||
nruns = 10 # Ensemble for timing
|
||||
|
||||
def chunkify(chunksize):
|
||||
""" Very stupid "chunk vectorizer" which keeps memory use down.
|
||||
This version requires all inputs to have the same number of elements,
|
||||
although it shouldn't be that hard to implement simple broadcasting.
|
||||
"""
|
||||
|
||||
def chunkifier(func):
|
||||
|
||||
def wrap(*args):
|
||||
|
||||
assert len(args) > 0
|
||||
assert all(len(a.flat) == len(args[0].flat) for a in args)
|
||||
|
||||
nelements = len(args[0].flat)
|
||||
nchunks, remain = divmod(nelements, chunksize)
|
||||
|
||||
out = np.ndarray(args[0].shape)
|
||||
|
||||
for start in range(0, nelements, chunksize):
|
||||
#print(start)
|
||||
stop = start+chunksize
|
||||
if start+chunksize > nelements:
|
||||
stop = nelements-start
|
||||
iargs = tuple(a.flat[start:stop] for a in args)
|
||||
out.flat[start:stop] = func(*iargs)
|
||||
return out
|
||||
|
||||
return wrap
|
||||
|
||||
return chunkifier
|
||||
|
||||
test_func_str = "63 + (a*b) + (c**2) + b"
|
||||
|
||||
def test_func(a, b, c):
|
||||
return 63 + (a*b) + (c**2) + b
|
||||
|
||||
test_func_chunked = chunkify(100*100)(test_func)
|
||||
|
||||
for test_shape in test_shapes:
|
||||
test_size = np.product(test_shape)
|
||||
# The actual data we'll use
|
||||
a = np.arange(test_size, dtype=test_dtype).reshape(test_shape)
|
||||
b = np.arange(test_size, dtype=test_dtype).reshape(test_shape)
|
||||
c = np.arange(test_size, dtype=test_dtype).reshape(test_shape)
|
||||
|
||||
|
||||
start1 = time.time()
|
||||
for idx in range(nruns):
|
||||
result1 = test_func(a, b, c)
|
||||
stop1 = time.time()
|
||||
|
||||
start2 = time.time()
|
||||
for idx in range(nruns):
|
||||
result2 = nx.evaluate(test_func_str)
|
||||
stop2 = time.time()
|
||||
|
||||
start3 = time.time()
|
||||
for idx in range(nruns):
|
||||
result3 = test_func_chunked(a, b, c)
|
||||
stop3 = time.time()
|
||||
|
||||
print("%s %s (average of %s runs)" % (test_shape, test_dtype, nruns))
|
||||
print("Simple: ", (stop1-start1)/nruns)
|
||||
print("Numexpr: ", (stop2-start2)/nruns)
|
||||
print("Chunked: ", (stop3-start3)/nruns)
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/* ####################################################################### */
|
||||
/* This script compares the speed of the computation of a polynomial */
|
||||
/* in C in a couple of different ways. */
|
||||
/* */
|
||||
/* Author: Francesc Alted */
|
||||
/* Date: 2010-02-05 */
|
||||
/* ####################################################################### */
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
#include <time.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define N 10*1000*1000
|
||||
|
||||
double x[N];
|
||||
double y[N];
|
||||
|
||||
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
|
||||
#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
|
||||
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
|
||||
#else
|
||||
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
|
||||
#endif
|
||||
|
||||
struct timezone
|
||||
{
|
||||
int tz_minuteswest; /* minutes W of Greenwich */
|
||||
int tz_dsttime; /* type of dst correction */
|
||||
};
|
||||
|
||||
int gettimeofday(struct timeval *tv, struct timezone *tz)
|
||||
{
|
||||
FILETIME ft;
|
||||
unsigned __int64 tmpres = 0;
|
||||
static int tzflag;
|
||||
|
||||
if (NULL != tv)
|
||||
{
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
|
||||
tmpres |= ft.dwHighDateTime;
|
||||
tmpres <<= 32;
|
||||
tmpres |= ft.dwLowDateTime;
|
||||
|
||||
/*converting file time to unix epoch*/
|
||||
tmpres -= DELTA_EPOCH_IN_MICROSECS;
|
||||
tmpres /= 10; /*convert into microseconds*/
|
||||
tv->tv_sec = (long)(tmpres / 1000000UL);
|
||||
tv->tv_usec = (long)(tmpres % 1000000UL);
|
||||
}
|
||||
|
||||
if (NULL != tz)
|
||||
{
|
||||
if (!tzflag)
|
||||
{
|
||||
_tzset();
|
||||
tzflag++;
|
||||
}
|
||||
tz->tz_minuteswest = _timezone / 60;
|
||||
tz->tz_dsttime = _daylight;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
|
||||
/* Given two timeval stamps, return the difference in seconds */
|
||||
float getseconds(struct timeval last, struct timeval current) {
|
||||
int sec, usec;
|
||||
|
||||
sec = current.tv_sec - last.tv_sec;
|
||||
usec = current.tv_usec - last.tv_usec;
|
||||
return (float)(((double)sec + usec*1e-6));
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int i;
|
||||
double inf = -1;
|
||||
struct timeval last, current;
|
||||
float tspend;
|
||||
|
||||
for(i=0; i<N; i++) {
|
||||
x[i] = inf+(2.*i)/N;
|
||||
}
|
||||
|
||||
gettimeofday(&last, NULL);
|
||||
for(i=0; i<N; i++) {
|
||||
//y[i] = .25*pow(x[i],3.) + .75*pow(x[i],2.) - 1.5*x[i] - 2;
|
||||
y[i] = ((.25*x[i] + .75)*x[i] - 1.5)*x[i] - 2;
|
||||
}
|
||||
gettimeofday(¤t, NULL);
|
||||
tspend = getseconds(last, current);
|
||||
printf("Compute time:\t %.3fs\n", tspend);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
###################################################################
|
||||
# Numexpr - Fast numerical array expression evaluator for NumPy.
|
||||
#
|
||||
# License: MIT
|
||||
# Author: See AUTHORS.txt
|
||||
#
|
||||
# See LICENSE.txt and LICENSES/*.txt for details about copyright and
|
||||
# rights to use.
|
||||
####################################################################
|
||||
|
||||
#######################################################################
|
||||
# This script compares the speed of the computation of a polynomial
|
||||
# for different (numpy and numexpr) in-memory paradigms.
|
||||
#
|
||||
# Author: Francesc Alted
|
||||
# Date: 2010-07-06
|
||||
#######################################################################
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
from time import time
|
||||
|
||||
import numpy as np
|
||||
|
||||
import numexpr as ne
|
||||
|
||||
#expr = ".25*x**3 + .75*x**2 - 1.5*x - 2" # the polynomial to compute
|
||||
expr = "((.25*x + .75)*x - 1.5)*x - 2" # a computer-friendly polynomial
|
||||
N = 10*1000*1000 # the number of points to compute expression
|
||||
x = np.linspace(-1, 1, N) # the x in range [-1, 1]
|
||||
|
||||
#what = "numpy" # uses numpy for computations
|
||||
what = "numexpr" # uses numexpr for computations
|
||||
|
||||
def compute():
|
||||
"""Compute the polynomial."""
|
||||
if what == "numpy":
|
||||
y = eval(expr)
|
||||
else:
|
||||
y = ne.evaluate(expr)
|
||||
return len(y)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) > 1: # first arg is the package to use
|
||||
what = sys.argv[1]
|
||||
if len(sys.argv) > 2: # second arg is the number of threads to use
|
||||
nthreads = int(sys.argv[2])
|
||||
if "ncores" in dir(ne):
|
||||
ne.set_num_threads(nthreads)
|
||||
if what not in ("numpy", "numexpr"):
|
||||
print("Unrecognized module:", what)
|
||||
sys.exit(0)
|
||||
print("Computing: '%s' using %s with %d points" % (expr, what, N))
|
||||
t0 = time()
|
||||
result = compute()
|
||||
ts = round(time() - t0, 3)
|
||||
print("*** Time elapsed:", ts)
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
###################################################################
|
||||
# Numexpr - Fast numerical array expression evaluator for NumPy.
|
||||
#
|
||||
# License: MIT
|
||||
# Author: See AUTHORS.txt
|
||||
#
|
||||
# See LICENSE.txt and LICENSES/*.txt for details about copyright and
|
||||
# rights to use.
|
||||
####################################################################
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import timeit
|
||||
|
||||
import numpy
|
||||
|
||||
array_size = 5e6
|
||||
iterations = 2
|
||||
|
||||
# Choose the type you want to benchmark
|
||||
#dtype = 'int8'
|
||||
#dtype = 'int16'
|
||||
#dtype = 'int32'
|
||||
#dtype = 'int64'
|
||||
dtype = 'float32'
|
||||
#dtype = 'float64'
|
||||
|
||||
def compare_times(setup, expr):
|
||||
print("Expression:", expr)
|
||||
namespace = {}
|
||||
exec(setup, namespace)
|
||||
|
||||
numpy_timer = timeit.Timer(expr, setup)
|
||||
numpy_time = numpy_timer.timeit(number=iterations)
|
||||
print('numpy:', numpy_time / iterations)
|
||||
|
||||
try:
|
||||
weave_timer = timeit.Timer('blitz("result=%s")' % expr, setup)
|
||||
weave_time = weave_timer.timeit(number=iterations)
|
||||
print("Weave:", weave_time/iterations)
|
||||
|
||||
print("Speed-up of weave over numpy:", round(numpy_time/weave_time, 2))
|
||||
except:
|
||||
print("Skipping weave timing")
|
||||
|
||||
numexpr_timer = timeit.Timer('evaluate("%s", optimization="aggressive")' % expr, setup)
|
||||
numexpr_time = numexpr_timer.timeit(number=iterations)
|
||||
print("numexpr:", numexpr_time/iterations)
|
||||
|
||||
tratio = numpy_time/numexpr_time
|
||||
print("Speed-up of numexpr over numpy:", round(tratio, 2))
|
||||
return tratio
|
||||
|
||||
setup1 = """\
|
||||
from numpy import arange
|
||||
try: from scipy.weave import blitz
|
||||
except: pass
|
||||
from numexpr import evaluate
|
||||
result = arange(%f, dtype='%s')
|
||||
b = arange(%f, dtype='%s')
|
||||
c = arange(%f, dtype='%s')
|
||||
d = arange(%f, dtype='%s')
|
||||
e = arange(%f, dtype='%s')
|
||||
""" % ((array_size, dtype)*5)
|
||||
expr1 = 'b*c+d*e'
|
||||
|
||||
setup2 = """\
|
||||
from numpy import arange
|
||||
try: from scipy.weave import blitz
|
||||
except: pass
|
||||
from numexpr import evaluate
|
||||
a = arange(%f, dtype='%s')
|
||||
b = arange(%f, dtype='%s')
|
||||
result = arange(%f, dtype='%s')
|
||||
""" % ((array_size, dtype)*3)
|
||||
expr2 = '2*a+3*b'
|
||||
|
||||
|
||||
setup3 = """\
|
||||
from numpy import arange, sin, cos, sinh
|
||||
try: from scipy.weave import blitz
|
||||
except: pass
|
||||
from numexpr import evaluate
|
||||
a = arange(2*%f, dtype='%s')[::2]
|
||||
b = arange(%f, dtype='%s')
|
||||
result = arange(%f, dtype='%s')
|
||||
""" % ((array_size, dtype)*3)
|
||||
expr3 = '2*a + (cos(3)+5)*sinh(cos(b))'
|
||||
|
||||
|
||||
setup4 = """\
|
||||
from numpy import arange, sin, cos, sinh, arctan2
|
||||
try: from scipy.weave import blitz
|
||||
except: pass
|
||||
from numexpr import evaluate
|
||||
a = arange(2*%f, dtype='%s')[::2]
|
||||
b = arange(%f, dtype='%s')
|
||||
result = arange(%f, dtype='%s')
|
||||
""" % ((array_size, dtype)*3)
|
||||
expr4 = '2*a + arctan2(a, b)'
|
||||
|
||||
|
||||
setup5 = """\
|
||||
from numpy import arange, sin, cos, sinh, arctan2, sqrt, where
|
||||
try: from scipy.weave import blitz
|
||||
except: pass
|
||||
from numexpr import evaluate
|
||||
a = arange(2*%f, dtype='%s')[::2]
|
||||
b = arange(%f, dtype='%s')
|
||||
result = arange(%f, dtype='%s')
|
||||
""" % ((array_size, dtype)*3)
|
||||
expr5 = 'where(0.1*a > arctan2(a, b), 2*a, arctan2(a,b))'
|
||||
|
||||
expr6 = 'where(a != 0.0, 2, b)'
|
||||
|
||||
expr7 = 'where(a-10 != 0.0, a, 2)'
|
||||
|
||||
expr8 = 'where(a%2 != 0.0, b+5, 2)'
|
||||
|
||||
expr9 = 'where(a%2 != 0.0, 2, b+5)'
|
||||
|
||||
expr10 = 'a**2 + (b+1)**-2.5'
|
||||
|
||||
expr11 = '(a+1)**50'
|
||||
|
||||
expr12 = 'sqrt(a**2 + b**2)'
|
||||
|
||||
def compare(check_only=False):
|
||||
experiments = [(setup1, expr1), (setup2, expr2), (setup3, expr3),
|
||||
(setup4, expr4), (setup5, expr5), (setup5, expr6),
|
||||
(setup5, expr7), (setup5, expr8), (setup5, expr9),
|
||||
(setup5, expr10), (setup5, expr11), (setup5, expr12),
|
||||
]
|
||||
total = 0
|
||||
for params in experiments:
|
||||
total += compare_times(*params)
|
||||
print
|
||||
average = total / len(experiments)
|
||||
print("Average =", round(average, 2))
|
||||
return average
|
||||
|
||||
if __name__ == '__main__':
|
||||
import numexpr
|
||||
print("Numexpr version: ", numexpr.__version__)
|
||||
|
||||
averages = []
|
||||
for i in range(iterations):
|
||||
averages.append(compare())
|
||||
print("Averages:", ', '.join("%.2f" % x for x in averages))
|
||||
@@ -0,0 +1,44 @@
|
||||
###################################################################
|
||||
# Numexpr - Fast numerical array expression evaluator for NumPy.
|
||||
#
|
||||
# License: MIT
|
||||
# Author: See AUTHORS.txt
|
||||
#
|
||||
# See LICENSE.txt and LICENSES/*.txt for details about copyright and
|
||||
# rights to use.
|
||||
####################################################################
|
||||
|
||||
"""Very simple test that compares the speed of operating with
|
||||
aligned vs unaligned arrays.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from timeit import Timer
|
||||
|
||||
import numpy as np
|
||||
|
||||
import numexpr as ne
|
||||
|
||||
niter = 10
|
||||
#shape = (1000*10000) # unidimensional test
|
||||
shape = (1000, 10000) # multidimensional test
|
||||
|
||||
print("Numexpr version: ", ne.__version__)
|
||||
|
||||
Z_fast = np.zeros(shape, dtype=[('x',np.float64),('y',np.int64)])
|
||||
Z_slow = np.zeros(shape, dtype=[('y1',np.int8),('x',np.float64),('y2',np.int8,(7,))])
|
||||
|
||||
x_fast = Z_fast['x']
|
||||
t = Timer("x_fast * x_fast", "from __main__ import x_fast")
|
||||
print("NumPy aligned: \t", round(min(t.repeat(3, niter)), 3), "s")
|
||||
|
||||
x_slow = Z_slow['x']
|
||||
t = Timer("x_slow * x_slow", "from __main__ import x_slow")
|
||||
print("NumPy unaligned:\t", round(min(t.repeat(3, niter)), 3), "s")
|
||||
|
||||
t = Timer("ne.evaluate('x_fast * x_fast')", "from __main__ import ne, x_fast")
|
||||
print("Numexpr aligned:\t", round(min(t.repeat(3, niter)), 3), "s")
|
||||
|
||||
t = Timer("ne.evaluate('x_slow * x_slow')", "from __main__ import ne, x_slow")
|
||||
print("Numexpr unaligned:\t", round(min(t.repeat(3, niter)), 3), "s")
|
||||
@@ -0,0 +1,57 @@
|
||||
###################################################################
|
||||
# Numexpr - Fast numerical array expression evaluator for NumPy.
|
||||
#
|
||||
# License: MIT
|
||||
# Author: See AUTHORS.txt
|
||||
#
|
||||
# See LICENSE.txt and LICENSES/*.txt for details about copyright and
|
||||
# rights to use.
|
||||
####################################################################
|
||||
|
||||
# Benchmark for checking if numexpr leaks memory when evaluating
|
||||
# expressions that changes continously. It also serves for computing
|
||||
# the latency of numexpr when working with small arrays.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
from time import time
|
||||
|
||||
import numpy as np
|
||||
|
||||
import numexpr as ne
|
||||
|
||||
N = 100
|
||||
M = 10
|
||||
|
||||
def timed_eval(eval_func, expr_func):
|
||||
t1 = time()
|
||||
for i in range(N):
|
||||
r = eval_func(expr_func(i))
|
||||
if i % 10 == 0:
|
||||
sys.stdout.write('.')
|
||||
print(" done in %s seconds" % round(time() - t1, 3))
|
||||
|
||||
print("Number of iterations %s. Length of the array: %s " % (N, M))
|
||||
|
||||
a = np.arange(M)
|
||||
|
||||
# lots of duplicates to collapse
|
||||
#expr = '+'.join('(a + 1) * %d' % i for i in range(50))
|
||||
# no duplicate to collapse
|
||||
expr = '+'.join('(a + %d) * %d' % (i, i) for i in range(50))
|
||||
|
||||
def non_cacheable(i):
|
||||
return expr + '+ %d' % i
|
||||
|
||||
def cacheable(i):
|
||||
return expr + '+ i'
|
||||
|
||||
print("* Numexpr with non-cacheable expressions: ", end=" ")
|
||||
timed_eval(ne.evaluate, non_cacheable)
|
||||
print("* Numexpr with cacheable expressions: ", end=" ")
|
||||
timed_eval(ne.evaluate, cacheable)
|
||||
print("* Numpy with non-cacheable expressions: ", end=" ")
|
||||
timed_eval(eval, non_cacheable)
|
||||
print("* Numpy with cacheable expressions: ", end=" ")
|
||||
timed_eval(eval, cacheable)
|
||||
@@ -0,0 +1,174 @@
|
||||
###################################################################
|
||||
# Numexpr - Fast numerical array expression evaluator for NumPy.
|
||||
#
|
||||
# License: MIT
|
||||
# Author: See AUTHORS.txt
|
||||
#
|
||||
# See LICENSE.txt and LICENSES/*.txt for details about copyright and
|
||||
# rights to use.
|
||||
####################################################################
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import timeit
|
||||
|
||||
import numpy
|
||||
|
||||
import numexpr
|
||||
|
||||
array_size = 5_000_000
|
||||
iterations = 10
|
||||
|
||||
numpy_ttime = []
|
||||
numpy_sttime = []
|
||||
numpy_nttime = []
|
||||
numexpr_ttime = []
|
||||
numexpr_sttime = []
|
||||
numexpr_nttime = []
|
||||
|
||||
def compare_times(expr, nexpr):
|
||||
global numpy_ttime
|
||||
global numpy_sttime
|
||||
global numpy_nttime
|
||||
global numexpr_ttime
|
||||
global numexpr_sttime
|
||||
global numexpr_nttime
|
||||
|
||||
print("******************* Expression:", expr)
|
||||
|
||||
setup_contiguous = setupNP_contiguous
|
||||
setup_strided = setupNP_strided
|
||||
setup_unaligned = setupNP_unaligned
|
||||
|
||||
numpy_timer = timeit.Timer(expr, setup_contiguous)
|
||||
numpy_time = round(numpy_timer.timeit(number=iterations), 4)
|
||||
numpy_ttime.append(numpy_time)
|
||||
print('%30s %.4f'%('numpy:', numpy_time / iterations))
|
||||
|
||||
numpy_timer = timeit.Timer(expr, setup_strided)
|
||||
numpy_stime = round(numpy_timer.timeit(number=iterations), 4)
|
||||
numpy_sttime.append(numpy_stime)
|
||||
print('%30s %.4f'%('numpy strided:', numpy_stime / iterations))
|
||||
|
||||
numpy_timer = timeit.Timer(expr, setup_unaligned)
|
||||
numpy_ntime = round(numpy_timer.timeit(number=iterations), 4)
|
||||
numpy_nttime.append(numpy_ntime)
|
||||
print('%30s %.4f'%('numpy unaligned:', numpy_ntime / iterations))
|
||||
|
||||
evalexpr = 'evaluate("%s", optimization="aggressive")' % expr
|
||||
numexpr_timer = timeit.Timer(evalexpr, setup_contiguous)
|
||||
numexpr_time = round(numexpr_timer.timeit(number=iterations), 4)
|
||||
numexpr_ttime.append(numexpr_time)
|
||||
print('%30s %.4f'%("numexpr:", numexpr_time/iterations,), end=" ")
|
||||
print("Speed-up of numexpr over numpy:", round(numpy_time/numexpr_time, 4))
|
||||
|
||||
evalexpr = 'evaluate("%s", optimization="aggressive")' % expr
|
||||
numexpr_timer = timeit.Timer(evalexpr, setup_strided)
|
||||
numexpr_stime = round(numexpr_timer.timeit(number=iterations), 4)
|
||||
numexpr_sttime.append(numexpr_stime)
|
||||
print('%30s %.4f'%("numexpr strided:", numexpr_stime/iterations,), end=" ")
|
||||
print("Speed-up of numexpr over numpy:", \
|
||||
round(numpy_stime/numexpr_stime, 4))
|
||||
|
||||
evalexpr = 'evaluate("%s", optimization="aggressive")' % expr
|
||||
numexpr_timer = timeit.Timer(evalexpr, setup_unaligned)
|
||||
numexpr_ntime = round(numexpr_timer.timeit(number=iterations), 4)
|
||||
numexpr_nttime.append(numexpr_ntime)
|
||||
print('%30s %.4f'%("numexpr unaligned:", numexpr_ntime/iterations,), end=" ")
|
||||
print("Speed-up of numexpr over numpy:", \
|
||||
round(numpy_ntime/numexpr_ntime, 4))
|
||||
|
||||
print()
|
||||
|
||||
|
||||
setupNP = """\
|
||||
from numpy import arange, linspace, arctan2, sqrt, sin, cos, exp, log
|
||||
from numpy import rec as records
|
||||
#from numexpr import evaluate
|
||||
from numexpr import %s
|
||||
|
||||
# Initialize a recarray of 16 MB in size
|
||||
r=records.array(None, formats='a%s,i4,f4,f8', shape=%s)
|
||||
c1 = r.field('f0')%s
|
||||
i2 = r.field('f1')%s
|
||||
f3 = r.field('f2')%s
|
||||
f4 = r.field('f3')%s
|
||||
c1[:] = "a"
|
||||
i2[:] = arange(%s)/1000
|
||||
f3[:] = linspace(0,1,len(i2))
|
||||
f4[:] = f3*1.23
|
||||
"""
|
||||
|
||||
eval_method = "evaluate"
|
||||
setupNP_contiguous = setupNP % ((eval_method, 4, array_size,) + \
|
||||
(".copy()",)*4 + \
|
||||
(array_size,))
|
||||
setupNP_strided = setupNP % (eval_method, 4, array_size,
|
||||
"", "", "", "", array_size)
|
||||
setupNP_unaligned = setupNP % (eval_method, 1, array_size,
|
||||
"", "", "", "", array_size)
|
||||
|
||||
|
||||
expressions = []
|
||||
expressions.append('i2 > 0')
|
||||
expressions.append('f3+f4')
|
||||
expressions.append('f3+i2')
|
||||
expressions.append('exp(f3)')
|
||||
expressions.append('log(exp(f3)+1)/f4')
|
||||
expressions.append('0.1*i2 > arctan2(f3, f4)')
|
||||
expressions.append('sqrt(f3**2 + f4**2) > 1')
|
||||
expressions.append('sin(f3)>cos(f4)')
|
||||
expressions.append('f3**f4')
|
||||
|
||||
def compare(expression=False):
|
||||
if expression:
|
||||
compare_times(expression, 1)
|
||||
sys.exit(0)
|
||||
nexpr = 0
|
||||
for expr in expressions:
|
||||
nexpr += 1
|
||||
compare_times(expr, nexpr)
|
||||
print()
|
||||
|
||||
if __name__ == '__main__':
|
||||
import numexpr
|
||||
print("Numexpr version: ", numexpr.__version__)
|
||||
|
||||
numpy.seterr(all='ignore')
|
||||
|
||||
numexpr.set_vml_accuracy_mode('low')
|
||||
numexpr.set_vml_num_threads(2)
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
expression = sys.argv[1]
|
||||
print("expression-->", expression)
|
||||
compare(expression)
|
||||
else:
|
||||
compare()
|
||||
|
||||
tratios = numpy.array(numpy_ttime) / numpy.array(numexpr_ttime)
|
||||
stratios = numpy.array(numpy_sttime) / numpy.array(numexpr_sttime)
|
||||
ntratios = numpy.array(numpy_nttime) / numpy.array(numexpr_nttime)
|
||||
|
||||
|
||||
print("eval method: %s" % eval_method)
|
||||
print("*************** Numexpr vs NumPy speed-ups *******************")
|
||||
# print("numpy total:", sum(numpy_ttime)/iterations)
|
||||
# print("numpy strided total:", sum(numpy_sttime)/iterations)
|
||||
# print("numpy unaligned total:", sum(numpy_nttime)/iterations)
|
||||
# print("numexpr total:", sum(numexpr_ttime)/iterations)
|
||||
print("Contiguous case:\t %s (mean), %s (min), %s (max)" % \
|
||||
(round(tratios.mean(), 2),
|
||||
round(tratios.min(), 2),
|
||||
round(tratios.max(), 2)))
|
||||
# print("numexpr strided total:", sum(numexpr_sttime)/iterations)
|
||||
print("Strided case:\t\t %s (mean), %s (min), %s (max)" % \
|
||||
(round(stratios.mean(), 2),
|
||||
round(stratios.min(), 2),
|
||||
round(stratios.max(), 2)))
|
||||
# print("numexpr unaligned total:", sum(numexpr_nttime)/iterations)
|
||||
print("Unaligned case:\t\t %s (mean), %s (min), %s (max)" % \
|
||||
(round(ntratios.mean(), 2),
|
||||
round(ntratios.min(), 2),
|
||||
round(ntratios.max(), 2)))
|
||||
@@ -0,0 +1,57 @@
|
||||
# References:
|
||||
#
|
||||
# http://software.intel.com/en-us/intel-mkl
|
||||
# https://github.com/pydata/numexpr/wiki/NumexprMKL
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import datetime
|
||||
import sys
|
||||
from time import time
|
||||
|
||||
import numpy as np
|
||||
|
||||
import numexpr as ne
|
||||
|
||||
N = int(2**28)
|
||||
|
||||
x = np.linspace(0, 1, N)
|
||||
y = np.linspace(0, 1, N)
|
||||
z = np.empty(N, dtype=np.float64)
|
||||
|
||||
# Our working set is 3 vectors of N doubles each
|
||||
working_set_GB = 3 * N * 8 / 2**30
|
||||
|
||||
print("NumPy version: %s" % (np.__version__,))
|
||||
|
||||
t0 = time()
|
||||
z = 2*y + 4*x
|
||||
t1 = time()
|
||||
gbs = working_set_GB / (t1-t0)
|
||||
print("Time for an algebraic expression: %.3f s / %.3f GB/s" % (t1-t0, gbs))
|
||||
|
||||
t0 = time()
|
||||
z = np.sin(x)**3.2 + np.cos(y)**3.2
|
||||
t1 = time()
|
||||
gbs = working_set_GB / (t1-t0)
|
||||
print("Time for a transcendental expression: %.3f s / %.3f GB/s" % (t1-t0, gbs))
|
||||
|
||||
if ne.use_vml:
|
||||
ne.set_vml_num_threads(1)
|
||||
ne.set_num_threads(16)
|
||||
print("NumExpr version: %s, Using MKL ver. %s, Num threads: %s" % (ne.__version__, ne.get_vml_version(), ne.nthreads))
|
||||
else:
|
||||
ne.set_num_threads(16)
|
||||
print("NumExpr version: %s, Not Using MKL, Num threads: %s" % (ne.__version__, ne.nthreads))
|
||||
|
||||
t0 = time()
|
||||
ne.evaluate('2*y + 4*x', out = z)
|
||||
t1 = time()
|
||||
gbs = working_set_GB / (t1-t0)
|
||||
print("Time for an algebraic expression: %.3f s / %.3f GB/s" % (t1-t0, gbs))
|
||||
|
||||
t0 = time()
|
||||
ne.evaluate('sin(x)**3.2 + cos(y)**3.2', out = z)
|
||||
t1 = time()
|
||||
gbs = working_set_GB / (t1-t0)
|
||||
print("Time for a transcendental expression: %.3f s / %.3f GB/s" % (t1-t0, gbs))
|
||||
@@ -0,0 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from timeit import default_timer as timer
|
||||
|
||||
import numpy as np
|
||||
|
||||
import numexpr as ne
|
||||
|
||||
x = np.ones(100000)
|
||||
scaler = -1J
|
||||
start = timer()
|
||||
for k in range(10000):
|
||||
cexp = ne.evaluate('exp(scaler * x)')
|
||||
exec_time=(timer() - start)
|
||||
|
||||
print("Execution took", str(round(exec_time, 3)), "seconds")
|
||||
Reference in New Issue
Block a user