Update benchmark suite with fair timing and micropython support
This commit is contained in:
parent
de76ba5394
commit
e4db90d392
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -10,5 +10,3 @@ jobs:
|
|||||||
run: make clean && make
|
run: make clean && make
|
||||||
- name: Test
|
- name: Test
|
||||||
run: make test
|
run: make test
|
||||||
- name: Benchmark
|
|
||||||
run: make bench
|
|
||||||
|
2
Makefile
2
Makefile
@ -155,6 +155,8 @@ bench:
|
|||||||
@for i in bench/*.krk; do ./kuroko "$$i"; done
|
@for i in bench/*.krk; do ./kuroko "$$i"; done
|
||||||
@echo "CPython:"
|
@echo "CPython:"
|
||||||
@for i in bench/*.py; do python3 "$$i"; done
|
@for i in bench/*.py; do python3 "$$i"; done
|
||||||
|
@echo "Micropython:"
|
||||||
|
@for i in bench/*.py; do micropython -X heapsize=128M "$$i"; done
|
||||||
|
|
||||||
# Really should be up to you to set, not us...
|
# Really should be up to you to set, not us...
|
||||||
multiarch ?= $(shell gcc -print-multiarch)
|
multiarch ?= $(shell gcc -print-multiarch)
|
||||||
|
@ -120,10 +120,10 @@ def write_instancevar():
|
|||||||
a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1
|
a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1
|
||||||
|
|
||||||
if __name__=='__main__':
|
if __name__=='__main__':
|
||||||
from timeit import timeit
|
from fasttimer import timeit
|
||||||
for f in [read_local, read_nonlocal, read_global, read_builtin,
|
for f in [read_local, read_nonlocal, read_global, read_builtin,
|
||||||
read_classvar, read_instancevar, read_unboundmethod, read_boundmethod,
|
read_classvar, read_instancevar, read_unboundmethod, read_boundmethod,
|
||||||
write_local, write_nonlocal, write_global,
|
write_local, write_nonlocal, write_global,
|
||||||
write_classvar, write_instancevar]:
|
write_classvar, write_instancevar]:
|
||||||
print(timeit(f,number=1000000), f.__qualname__)
|
print(timeit(f,number=1000000), f.__qualname__ if hasattr(f,'__qualname__') else f.__name__ if hasattr(f,'__name__') else '?')
|
||||||
|
|
||||||
|
2
bench/fasttimer/.gitignore
vendored
Normal file
2
bench/fasttimer/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
build/
|
||||||
|
__pycache__/
|
8
bench/fasttimer/Makefile
Normal file
8
bench/fasttimer/Makefile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
all: _fasttimer.so _mpytimer.so
|
||||||
|
|
||||||
|
_fasttimer.so: py_fasttimer.c
|
||||||
|
python3 setup.py build
|
||||||
|
cp build/*/*.so ./$@
|
||||||
|
|
||||||
|
_mpytimer.so: mpy_timer.c
|
||||||
|
$(CC) -shared -o $@ $<
|
13
bench/fasttimer/__init__.py
Normal file
13
bench/fasttimer/__init__.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
try:
|
||||||
|
from ._fasttimer import timeit
|
||||||
|
except:
|
||||||
|
import ffi
|
||||||
|
path = __file__.split('/')[:-1]
|
||||||
|
if not path: path = '.'
|
||||||
|
else: path = '/'.join(path)
|
||||||
|
lib = ffi.open(path + '/_mpytimer.so')
|
||||||
|
_timeit = lib.func('d','timeit','Ci')
|
||||||
|
def timeit(callback,number=1000000):
|
||||||
|
cb = ffi.callback('v',callback,'')
|
||||||
|
return _timeit(cb,number)
|
||||||
|
|
18
bench/fasttimer/mpy_timer.c
Normal file
18
bench/fasttimer/mpy_timer.c
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
double
|
||||||
|
timeit(void (*callback)(void), int times)
|
||||||
|
{
|
||||||
|
struct timeval tv_before, tv_after;
|
||||||
|
gettimeofday(&tv_before,NULL);
|
||||||
|
for (int t = 0; t < times; ++t) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
gettimeofday(&tv_after,NULL);
|
||||||
|
|
||||||
|
double before = (double)tv_before.tv_sec + (double)tv_before.tv_usec / 1000000.0;
|
||||||
|
double after = (double)tv_after.tv_sec + (double)tv_after.tv_usec / 1000000.0;
|
||||||
|
|
||||||
|
return after-before;
|
||||||
|
}
|
59
bench/fasttimer/py_fasttimer.c
Normal file
59
bench/fasttimer/py_fasttimer.c
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#define PY_SSIZE_T_CLEAN
|
||||||
|
#include <Python.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
fasttimer_timeit(PyObject * self, PyObject * args, PyObject* kwargs)
|
||||||
|
{
|
||||||
|
PyObject * callable;
|
||||||
|
int times = 1000000;
|
||||||
|
|
||||||
|
static char * keywords[] = {"callable","number",NULL};
|
||||||
|
|
||||||
|
if (!PyArg_ParseTupleAndKeywords(args,kwargs,"O|i:timeit",
|
||||||
|
keywords, &callable, ×)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "bad arguments?");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PyCallable_Check(callable)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "expected callable");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Py_XINCREF(callable);
|
||||||
|
struct timeval tv_before, tv_after;
|
||||||
|
gettimeofday(&tv_before,NULL);
|
||||||
|
for (int t = 0; t < times; ++t) {
|
||||||
|
/* Call it here */
|
||||||
|
PyObject_CallObject(callable, NULL);
|
||||||
|
}
|
||||||
|
gettimeofday(&tv_after,NULL);
|
||||||
|
Py_XDECREF(callable);
|
||||||
|
|
||||||
|
double before = (double)tv_before.tv_sec + (double)tv_before.tv_usec / 1000000.0;
|
||||||
|
double after = (double)tv_after.tv_sec + (double)tv_after.tv_usec / 1000000.0;
|
||||||
|
|
||||||
|
return PyFloat_FromDouble(after-before);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef FasttimerMethods[] = {
|
||||||
|
{"timeit", (PyCFunction)(void(*)(void))fasttimer_timeit, METH_VARARGS | METH_KEYWORDS, "Call a callable in a tight loop."},
|
||||||
|
{NULL,NULL,0,NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct PyModuleDef fasttimermodule = {
|
||||||
|
PyModuleDef_HEAD_INIT,
|
||||||
|
"fasttimer",
|
||||||
|
NULL,
|
||||||
|
-1,
|
||||||
|
FasttimerMethods
|
||||||
|
};
|
||||||
|
|
||||||
|
PyMODINIT_FUNC
|
||||||
|
PyInit__fasttimer(void)
|
||||||
|
{
|
||||||
|
return PyModule_Create(&fasttimermodule);
|
||||||
|
}
|
4
bench/fasttimer/setup.py
Normal file
4
bench/fasttimer/setup.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
from distutils.core import setup, Extension
|
||||||
|
|
||||||
|
fasttimer = Extension('_fasttimer',sources=['py_fasttimer.c'])
|
||||||
|
setup(name="_fasttimer",version='1.0',description='fast timer',ext_modules=[fasttimer])
|
@ -5,6 +5,6 @@ def __main__():
|
|||||||
fib(30)
|
fib(30)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
from timeit import timeit
|
from fasttimer import timeit
|
||||||
print(timeit(__main__,number=1),'fib(30)')
|
print(timeit(__main__,number=1),'fib(30)')
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from timeit import timeit
|
from fasttimer import timeit
|
||||||
|
|
||||||
l = []
|
l = []
|
||||||
add = l.append
|
add = l.append
|
||||||
|
@ -10,5 +10,5 @@ def makeTree(depth):
|
|||||||
return Node(n1,n2)
|
return Node(n1,n2)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
from timeit import timeit
|
from fasttimer import timeit
|
||||||
print(timeit(lambda: makeTree(16), number=10), 'makeTree')
|
print(timeit(lambda: makeTree(16), number=10), 'makeTree')
|
||||||
|
Loading…
Reference in New Issue
Block a user