diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ab44d8c3ce9a261f38f5d308959d3a9ab5bfcb8..a9aa34c9486e8138f9bcb5637dfa7be9a4fc5733 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,13 +4,6 @@ project(nbtest VERSION 0.1.0 LANGUAGES C CXX) find_package(Python 3.10 COMPONENTS Interpreter Development.Module REQUIRED) add_subdirectory(extern/nanobind) -# Find the NumPy include directory -execute_process( - COMMAND "${Python_EXECUTABLE}" -c "import numpy as np; print(np.get_include())" - OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE NUMPY_DIR) - -message(STATUS "NumPy include directory: ${NUMPY_DIR}") - # Ensure Release build type is set if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) @@ -19,7 +12,6 @@ endif() # Add the extension module to the build nanobind_add_module(my_ext src/my_ext.cc) -target_include_directories(my_ext PRIVATE ${NUMPY_DIR}) # Copy the built extension to the src directory add_custom_command(TARGET my_ext POST_BUILD diff --git a/src/main.py b/src/main.py index 71206aa9c6221f0dc0888a6235d289774702374b..eb4bc43bb8670ff5045be52c4e568f4040fe494c 100644 --- a/src/main.py +++ b/src/main.py @@ -1,5 +1,5 @@ # %% Imports -from my_ext import add, array_sum, array_sum_nocopy, array_sum_pyobj +from my_ext import add, array_sum, array_sum_nocopy import numpy as np # %% The simple add function @@ -12,7 +12,6 @@ x = np.random.normal(0, 1, 500) x.sum() array_sum(x) array_sum_nocopy(x) -array_sum_pyobj(x) # array_sum works with lists also (smart conversion) array_sum([1, 2, 3, 4, 5]) diff --git a/src/my_ext.cc b/src/my_ext.cc index d2845e9cb2dd7cc154c10cd73ea9a93ab14de2a5..8f8cd896072e99f03d7b89da09b70315b91f1fad 100644 --- a/src/my_ext.cc +++ b/src/my_ext.cc @@ -1,9 +1,3 @@ -extern "C" { -#include <Python.h> -#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -#include <numpy/ndarrayobject.h> -} - #include <nanobind/nanobind.h> #include <nanobind/ndarray.h> #include <nanobind/stl/vector.h> @@ -12,17 +6,6 @@ extern "C" { namespace nb = nanobind; -double -array_sum_pyobj(const nb::object &o) -{ - // This is an unsafe solution ... but fast - auto *a = reinterpret_cast<PyArrayObject *>(o.ptr()); // Now numpy array object - const auto p = static_cast<double *>(PyArray_DATA(a)); // Pointer to data - const auto sizes = PyArray_SHAPE(a); // Sizes of each dimension - - return std::accumulate(p, p + sizes[0], 0.0); -} - int add(int a, int b) { @@ -47,5 +30,4 @@ NB_MODULE(my_ext, m) m.def("add", &add); m.def("array_sum", &array_sum); m.def("array_sum_nocopy", &array_sum_nocopy); - m.def("array_sum_pyobj", &array_sum_pyobj); } diff --git a/src/timing_profile.py b/src/timing_profile.py deleted file mode 100644 index 4dff4b14f88f3dd66c854c98788af49ba674a225..0000000000000000000000000000000000000000 --- a/src/timing_profile.py +++ /dev/null @@ -1,59 +0,0 @@ -# %% -import timeit -from my_ext import array_sum, array_sum_nocopy, array_sum_pyobj # noqa -import numpy as np -import matplotlib.pyplot as plt -from seaborn import despine - - -# %% Utils -def bs_mean_ci(x, alpha=0.95, n_bootstrap=1000): - """Bootstrap mean and confidence interval.""" - n, _ = x.shape - mu = np.zeros(n) - ci = np.zeros((n, 2)) - for k, xi in enumerate(x): - bs = np.random.choice(xi, size=(n_bootstrap,), replace=True) - mu[k] = bs.mean() - ci[k] = np.percentile(bs, [(1 - alpha) * 100 / 2, 100 - (1 - alpha) * 100 / 2]) - return mu, ci - - -# %% Perform timing experiments -R = 20 # Number of repeated timing experiments -M = 500 # Number of iterations in each timing measurement -N = np.logspace(1, 5, 10).astype(int) # Sizes to test - -res = {"np": [], "array_sum": [], "array_sum_nocopy": [], "array_sum_pyobj": []} -for Ni in N: - print(f"Ni = {Ni}") - x = np.random.normal(0, 1, int(Ni)) - ri = np.array(timeit.repeat("x.sum()", globals=globals(), number=M, repeat=R)) / M - res["np"].append(ri) - - ri = np.array(timeit.repeat("array_sum(x)", globals=globals(), number=M, repeat=R)) / M - res["array_sum"].append(ri) - - ri = np.array(timeit.repeat("array_sum_nocopy(x)", globals=globals(), number=M, repeat=R)) / M - res["array_sum_nocopy"].append(ri) - - ri = np.array(timeit.repeat("array_sum_pyobj(x)", globals=globals(), number=M, repeat=R)) / M - res["array_sum_pyobj"].append(ri) - -for k in res: - res[k] = np.array(res[k]) - - -# %% Plot results -fig, ax = plt.subplots(num=10, clear=True) -for k in res: - mu, ci = bs_mean_ci(res[k]) - ax.loglog(N, mu * 1e9, label=k) - ax.fill_between(N, ci[:, 0] * 1e9, ci[:, 1] * 1e9, alpha=0.2) -ax.legend(frameon=False) -ax.set_xlabel("N") -ax.set_ylabel("Time (ns)") -despine(ax=ax) - -# %% -plt.show()