- Easier to wrap the C API?
- Need SIMD to scale with pandas/numpy
- Can use OpenMP
# setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
extensions = [
Extension(
'divide',
sources=['divide.pyx', 'main.cpp'],
extra_compile_args=['-Ofast', '-fopenmp', '-march=native'],
extra_link_args=['-fopenmp'],
language="c++",
)
]
setup(
name='divide',
ext_modules=cythonize(extensions),
)
# divide.pyx
from libcpp.vector cimport vector
cdef extern from "binding.h":
cdef vector[long int] divide(vector[long int], int)
def do_div(x, y):
return divide(<vector[long int]>x, <int>y)
// main.cpp
#include <vector>
#include "libdivide.h"
#include "binding.h"
std::vector<int64_t> divide(std::vector<int64_t> vect, int64_t divisor) {
libdivide::divider<int64_t> fast_d(divisor);
int len = vect.size();
// Fast, computes division using libdivide
#pragma omp parallel
{
#pragma omp for
for (int i = 0; i < len; i++) {
vect[i] /= fast_d;
}
}
return vect;
}
// binding.h
#pragma once
template <typename T>
class Vector;
std::vector<int64_t> divide(std::vector<int64_t> vect, int64_t divisor);
import pandas as pd
from divide import do_div
l = pd.Series(range(0, 100000, 2))
expected = [x / 2 for x in l]
def test_do_div(benchmark):
r = benchmark(do_div, l.values, 2)
assert r == expected
def test_div(benchmark):
r = benchmark(lambda x, y: [z // y for z in x], l.values, 2)
assert r == expected
def test_pd(benchmark):
r = benchmark(lambda s, d: s // d, l, 2)
assert pd.np.array_equal(r.values, expected)
---------------------------------------------------------------------------------------------- benchmark: 3 tests ----------------------------------------------------------------------------------------------
Name (time in us) Min Max Mean StdDev Median IQR Outliers OPS Rounds Iterations
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_pd 622.5750 (1.0) 2,694.6820 (1.0) 951.7428 (1.0) 349.7697 (1.0) 803.2140 (1.0) 529.8907 (1.0) 91;7 1,050.7041 (1.0) 409 1
test_do_div 8,371.0710 (13.45) 25,566.2690 (9.49) 10,195.2598 (10.71) 2,848.5078 (8.14) 9,255.6070 (11.52) 1,040.2705 (1.96) 11;14 98.0848 (0.09) 120 1
test_div 16,505.9700 (26.51) 31,855.5470 (11.82) 19,863.2356 (20.87) 3,651.7666 (10.44) 18,423.3260 (22.94) 3,387.7065 (6.39) 6;3 50.3443 (0.05) 49 1
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------