import mpmath from mpmath import * from mpmath.libmpf import * from mpmath.libmpc import * from mpmath.libelefun import * import sys import os import platform cpuinfo = "Celeron M 520 (1.6 GHz)" raminfo = "1 GB" import time timeinfo = time.strftime("%Y-%m-%d %H:%M", time.localtime()) intro = """
Date: %s
mpmath version: %s
System information:In order to give an idea of the variation, three timings from separate runs (sorted from best to worst) are printed in each cell. For low-level benchmarks (such as addition), the difference between best and worst time is mainly due to different paths taken during rounding. Rounding is done to nearest; with rounding to floor or ceiling, both best and worst times would be slightly better. Exceptions: constant computations are only timed once.
The input arguments x and y are full precision pseudo-random numbers (actually non-exact quotients of small integers) close to unity (circa 0.5-2.0). Complex numbers w and z = x+y*i are used in complex benchmarks. Each of three runs is performed with a separate x, y (or w, z) pair.
Benchmarks marked with (*) involve precomputation of some table of numbers (e.g. series coefficients or quadrature weights). Such tables are cached by mpmath for subsequent uses. In these cases, the "worst time" will be the time with the precomputation included (the first call) and the "best time" will be roughly equal to the average time for subsequent calls.
Times marked mpf include the overhead of typechecking and instance creation. Times marked lib measure the computational performance more directly. The difference is primarily significant for basic arithmetic at low precision.
Benchmarks marked psyco are run with the Psyco JIT compiler enabled. This also primarily improves speed at low precision. Some timings with psyco may be inflated disproportionately due to initial compilation time.
For times marked gmpy, GMPY is used. This tends to slow things down slightly at low precision, while being much faster at high precision.
Each benchmark is run with a precision (dps) up to a maximum of 106 digits. Each benchmark is stopped as soon as the time for the next run is expected to exceed 10 seconds (based on linear interpolation from the two previous precision levels). Benchmarks with lib and psyco are not repeated above 10000 digits, since the difference becomes insignificant.
""" % (timeinfo, mpmath.__version__, cpuinfo, raminfo, \ platform.platform(), platform.python_version(), platform.python_compiler()) outro = """ """ code_template = \ """ import os import sys pairs = [(2,3,5,7,11,13,19,23), (31,37,53,73,89,59,97,67), (101,149,127,167,139,103,181,151)] def timing(case): from timeit import default_timer as _clock mp.dps = %DPS% d = pairs[case] x = mpf(d[0])/d[1] y = mpf(d[2])/d[3] w = mpc(x,y) z = mpc(mpf(d[4])/d[5], mpf(d[6])/d[7]) if %LIB%: prec=mp.prec; dps=mp.dps; rnd=round_nearest x = x._mpf_ y = y._mpf_ w = w._mpc_ z = z._mpc_ _t1 = _clock() %EXPR% _t2 = _clock() _dt = _t2-_t1 if _dt > 0.01 or %SINGLE%: return _dt _n = _N = max(int(0.001/_dt), 1) t1 = _clock() while _n: %EXPR% %EXPR% %EXPR% %EXPR% %EXPR% %EXPR% %EXPR% %EXPR% %EXPR% %EXPR% _n -= 1 _t2 = _clock() _dt = (_t2-_t1)/(10*_N) return _dt if %PSYCO%: import psyco psyco.full() if not %GMPY%: os.environ['MPMATH_NOGMPY'] = '1' import mpmath from mpmath import * from mpmath.libmpf import * from mpmath.libmpc import * from mpmath.libelefun import * if %SINGLE%: t = [timing(0)] else: t = sorted([timing(0), timing(1), timing(2)]) fp = open("time.txt", "w") fp.write(str(t)) """ def katime(expr, prec, config, single=False): fp = open("temp.py", "w") code = code_template code = code.replace("%EXPR%", str(expr)) code = code.replace("%DPS%", str(prec)) code = code.replace("%LIB%", str('lib' in config)) code = code.replace("%GMPY%", str('gmpy' in config)) code = code.replace("%PSYCO%", str('psyco' in config)) code = code.replace("%SINGLE%", str(single)) fp.write(code) fp.close() os.system("temp.py") t = eval(open("time.txt").read()) return t titles = [] code_info = {} data = {} configs = ['mpf', 'mpf+psyco', 'lib', 'lib+psyco', 'gmpy+mpf', 'gmpy+mpf+psyco', 'gmpy+lib', 'gmpy+lib+psyco'] precs = [15, 30, 100, 300, 1000, 3000, 10**4, 30000, 10**5, 300000, 10**6] def benchmark(title, expr, libexpr=None, single=False, maxprec=None): print title, "..." if title not in titles: titles.append(title) code_info[title] = expr, libexpr data[title] = data.get(title, {}) for config in configs: if 'lib' in config and not libexpr: continue last_time = 1e-10 for prec in precs: if maxprec and prec > maxprec: break if (prec > 10000 or single) and ('lib' in config or 'psyco' in config): continue print config, prec if single: t = data[title][(prec, config)] = katime(expr, prec, config, single=True) else: if 'lib' in config: t = data[title][(prec, config)] = katime(libexpr, prec, config) else: t = data[title][(prec, config)] = katime(expr, prec, config) t = max(t) if prec > 100 and t * (t / last_time) > 10.0: break last_time = t fp = open("mpbench.html", "w") print >> fp, intro output(fp) print >> fp, outro def per_second(t): rt = 1./t size = max(int(log(rt, 10)) - 2, 0) return int((rt // 10**size) * 10**size) def print_time(time): if time < 0.1: return "%f ms (%i/s)" % (time*1000, per_second(time)) else: return "%f s" % time def print_times(times): if not times: return "-" return "| dps | " for config in configs: print >> fp, "", config, " | " print >> fp, "
|---|---|
| ", prec, " | " for config in configs: print >> fp, "", print_times(dk.get((prec, config), 0)), " | " print >> fp, "