{ "metadata": { "name": "numba_vs_cython" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "code", "collapsed": false, "input": [ "%load_ext cythonmagic\n", "\n", "import numpy as np\n", "X = np.random.random((1000, 3))\n", "D = np.empty((1000, 1000))" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 1 }, { "cell_type": "code", "collapsed": false, "input": [ "# Pure python version\n", "\n", "def pairwise_python(X, D):\n", " M = X.shape[0]\n", " N = X.shape[1]\n", " for i in range(M):\n", " for j in range(M):\n", " d = 0.0\n", " for k in range(N):\n", " tmp = X[i, k] - X[j, k]\n", " d += tmp * tmp\n", " D[i, j] = np.sqrt(d)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "# numba version\n", "\n", "import numpy as np\n", "from numba import double\n", "from numba.decorators import jit\n", "\n", "@jit(arg_types=[double[:,:], double[:,:]])\n", "def pairwise_numba(X, D):\n", " M = X.shape[0]\n", " N = X.shape[1]\n", " for i in range(M):\n", " for j in range(M):\n", " d = 0.0\n", " for k in range(N):\n", " tmp = X[i, k] - X[j, k]\n", " d += tmp * tmp\n", " D[i, j] = np.sqrt(d)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "CONVERTING double[:, :]\n", "CONVERTING double\n", "['d']\n", "CONVERTING double[:, :]\n", "CONVERTING double\n", "['d']\n", "str_to_llvmtype(): str = 'f64'\n", "{'blocks': {0: ,\n", " 29: ,\n", " 39: ,\n", " 42: ,\n", " 45: ,\n", " 48: ,\n", " 58: ,\n", " 61: ,\n", " 64: ,\n", " 73: ,\n", " 83: ,\n", " 86: ,\n", " 89: ,\n", " 136: ,\n", " 165: ,\n", " 169: },\n", " 'blocks_dom': {0: set([0]),\n", " 29: set([0, 29]),\n", " 39: set([0, 29, 39, 42, 45, 48, 61, 165]),\n", " 42: set([0, 29, 42]),\n", " 45: set([0, 29, 42, 45]),\n", " 48: set([0, 29, 42, 45, 48]),\n", " 58: set([0, 29, 42, 45, 48, 58, 61, 64, 73, 86, 136]),\n", " 61: set([0, 29, 42, 45, 48, 61]),\n", " 64: set([0, 29, 42, 45, 48, 61, 64]),\n", " 73: set([0, 29, 42, 45, 48, 61, 64, 73]),\n", " 83: set([0, 29, 42, 45, 48, 61, 64, 73, 83, 86, 89]),\n", " 86: set([0, 29, 42, 45, 48, 61, 64, 73, 86]),\n", " 89: set([0, 29, 42, 45, 48, 61, 64, 73, 86, 89]),\n", " 136: set([0, 29, 42, 45, 48, 61, 64, 73, 86, 136]),\n", " 165: set([0, 29, 42, 45, 48, 61, 165]),\n", " 169: set([0, 29, 42, 169])},\n", " 'blocks_in': {0: set(),\n", " 29: set([0]),\n", " 39: set([165]),\n", " 42: set([29, 39]),\n", " 45: set([42]),\n", " 48: set([45]),\n", " 58: set([136]),\n", " 61: set([48, 58]),\n", " 64: set([61]),\n", " 73: set([64]),\n", " 83: set([89]),\n", " 86: set([73, 83]),\n", " 89: set([86]),\n", " 136: set([86]),\n", " 165: set([61]),\n", " 169: set([42])},\n", " 'blocks_out': {0: set([29]),\n", " 29: set([42]),\n", " 39: set([42]),\n", " 42: set([45, 169]),\n", " 45: set([48]),\n", " 48: set([61]),\n", " 58: set([61]),\n", " 61: set([64, 165]),\n", " 64: set([73]),\n", " 73: set([86]),\n", " 83: set([86]),\n", " 86: set([89, 136]),\n", " 89: set([83]),\n", " 136: set([58]),\n", " 165: set([39]),\n", " 169: set()},\n", " 'blocks_reaching': {0: set([0]),\n", " 29: set([0, 29]),\n", " 39: set([0,\n", " 29,\n", " 39,\n", " 42,\n", " 45,\n", " 48,\n", " 58,\n", " 61,\n", " 64,\n", " 73,\n", " 83,\n", " 86,\n", " 89,\n", " 136,\n", " 165]),\n", " 42: set([0,\n", " 29,\n", " 39,\n", " 42,\n", " 45,\n", " 48,\n", " 58,\n", " 61,\n", " 64,\n", " 73,\n", " 83,\n", " 86,\n", " 89,\n", " 136,\n", " 165]),\n", " 45: set([0,\n", " 29,\n", " 39,\n", " 42,\n", " 45,\n", " 48,\n", " 58,\n", " 61,\n", " 64,\n", " 73,\n", " 83,\n", " 86,\n", " 89,\n", " 136,\n", " 165]),\n", " 48: set([0,\n", " 29,\n", " 39,\n", " 42,\n", " 45,\n", " 48,\n", " 58,\n", " 61,\n", " 64,\n", " 73,\n", " 83,\n", " 86,\n", " 89,\n", " 136,\n", " 165]),\n", " 58: set([0,\n", " 29,\n", " 39,\n", " 42,\n", " 45,\n", " 48,\n", " 58,\n", " 61,\n", " 64,\n", " 73,\n", " 83,\n", " 86,\n", " 89,\n", " 136,\n", " 165]),\n", " 61: set([0,\n", " 29,\n", " 39,\n", " 42,\n", " 45,\n", " 48,\n", " 58,\n", " 61,\n", " 64,\n", " 73,\n", " 83,\n", " 86,\n", " 89,\n", " 136,\n", " 165]),\n", " 64: set([0,\n", " 29,\n", " 39,\n", " 42,\n", " 45,\n", " 48,\n", " 58,\n", " 61,\n", " 64,\n", " 73,\n", " 83,\n", " 86,\n", " 89,\n", " 136,\n", " 165]),\n", " 73: set([0,\n", " 29,\n", " 39,\n", " 42,\n", " 45,\n", " 48,\n", " 58,\n", " 61,\n", " 64,\n", " 73,\n", " 83,\n", " 86,\n", " 89,\n", " 136,\n", " 165]),\n", " 83: set([0,\n", " 29,\n", " 39,\n", " 42,\n", " 45,\n", " 48,\n", " 58,\n", " 61,\n", " 64,\n", " 73,\n", " 83,\n", " 86,\n", " 89,\n", " 136,\n", " 165]),\n", " 86: set([0,\n", " 29,\n", " 39,\n", " 42,\n", " 45,\n", " 48,\n", " 58,\n", " 61,\n", " 64,\n", " 73,\n", " 83,\n", " 86,\n", " 89,\n", " 136,\n", " 165]),\n", " 89: set([0,\n", " 29,\n", " 39,\n", " 42,\n", " 45,\n", " 48,\n", " 58,\n", " 61,\n", " 64,\n", " 73,\n", " 83,\n", " 86,\n", " 89,\n", " 136,\n", " 165]),\n", " 136: set([0,\n", " 29,\n", " 39,\n", " 42,\n", " 45,\n", " 48,\n", " 58,\n", " 61,\n", " 64,\n", " 73,\n", " 83,\n", " 86,\n", " 89,\n", " 136,\n", " 165]),\n", " 165: set([0,\n", " 29,\n", " 39,\n", " 42,\n", " 45,\n", " 48,\n", " 58,\n", " 61,\n", " 64,\n", " 73,\n", " 83,\n", " 86,\n", " 89,\n", " 136,\n", " 165]),\n", " 169: set([0,\n", " 29,\n", " 39,\n", " 42,\n", " 45,\n", " 48,\n", " 58,\n", " 61,\n", " 64,\n", " 73,\n", " 83,\n", " 86,\n", " 89,\n", " 136,\n", " 165,\n", " 169])},\n", " 'blocks_reads': {0: set([0]),\n", " 29: set([2]),\n", " 39: set(),\n", " 42: set([4]),\n", " 45: set(),\n", " 48: set([2]),\n", " 58: set(),\n", " 61: set([5]),\n", " 64: set(),\n", " 73: set([3]),\n", " 83: set(),\n", " 86: set([7]),\n", " 89: set([0, 4, 5, 6, 7, 8]),\n", " 136: set([1, 4, 5, 6]),\n", " 165: set(),\n", " 169: set()},\n", " 'blocks_writer': {0: {2: 10, 3: 23},\n", " 29: {4: 38},\n", " 39: {4: 39},\n", " 42: {4: 42},\n", " 45: {},\n", " 48: {5: 57},\n", " 58: {5: 58},\n", " 61: {5: 61},\n", " 64: {6: 67},\n", " 73: {7: 82},\n", " 83: {7: 83},\n", " 86: {6: 86, 7: 86},\n", " 89: {6: 130, 8: 116},\n", " 136: {},\n", " 165: {},\n", " 169: {}},\n", " 'blocks_writes': {0: set([0, 1, 2, 3]),\n", " 29: set([4]),\n", " 39: set([4]),\n", " 42: set([4]),\n", " 45: set(),\n", " 48: set([5]),\n", " 58: set([5]),\n", " 61: set([5]),\n", " 64: set([6]),\n", " 73: set([7]),\n", " 83: set([7]),\n", " 86: set([6, 7]),\n", " 89: set([6, 8]),\n", " 136: set(),\n", " 165: set(),\n", " 169: set()},\n", " 'translator': }\n", "op_LOAD_ATTR(): 3 106 shape , _llvm=, typ='arr[f64]')> arr[f64]\n", "op_LOAD_ATTR(): { i64, i32*, i8*, i32, i64*, i64*, i8*, i8*, i32, i8*, i8*, i8*, i64* }*\n", "op_LOAD_ATTR(): 16 106 shape , _llvm=, typ='arr[f64]')> arr[f64]\n", "op_LOAD_ATTR(): { i64, i32*, i8*, i32, i64*, i64*, i8*, i8*, i32, i8*, i8*, i8*, i64* }*\n", "('op_CALL_FUNCTION():', , _llvm=None, typ=['func'])>)\n", "str_to_llvmtype(): str = 'i64'\n", "add_phi_incomming(): reaching_defs = {29: {0: 0, 1: 0, 2: 0, 3: 0, 4: 29},\n", " 39: {0: 0, 1: 0, 2: 0, 3: 0, 4: 39, 5: 61}}\n", " crnt_block=42, pred=39, local=4\n", "op_BINARY_ADD(): , _llvm=, typ='i64')> + , _llvm=, typ='i64')>\n", "resolve_type(): arg1 = , _llvm=, typ='i64')>, arg2 = , _llvm=, typ='i64')>\n", "resolve_type() ==> 'i64'\n", "resolve_type(): arg1 = , _llvm=, typ='i64')>, arg2 = , _llvm=, typ='i64')>\n", "resolve_type() ==> 'i64'\n", "('op_CALL_FUNCTION():', , _llvm=None, typ=['func'])>)\n", "str_to_llvmtype(): str = 'i64'\n", "add_phi_incomming(): reaching_defs = {48: {0: 0, 1: 0, 2: 0, 3: 0, 4: 42, 5: 48},\n", " 58: {0: 0, 1: 0, 2: 0, 3: 0, 4: 42, 5: 58, 6: 86, 7: 86}}\n", " crnt_block=61, pred=58, local=5\n", "op_BINARY_ADD(): , _llvm=, typ='i64')> + , _llvm=, typ='i64')>\n", "resolve_type(): arg1 = , _llvm=, typ='i64')>, arg2 = , _llvm=, typ='i64')>\n", "resolve_type() ==> 'i64'\n", "resolve_type(): arg1 = , _llvm=, typ='i64')>, arg2 = , _llvm=, typ='i64')>\n", "resolve_type() ==> 'i64'\n", "('op_CALL_FUNCTION():', , _llvm=None, typ=['func'])>)\n", "str_to_llvmtype(): str = 'f64'\n", "add_phi_incomming(): reaching_defs = {73: {0: 0, 1: 0, 2: 0, 3: 0, 4: 42, 5: 61, 6: 64, 7: 73},\n", " 83: {0: 0, 1: 0, 2: 0, 3: 0, 4: 42, 5: 61, 6: 89, 7: 83, 8: 89}}\n", " crnt_block=86, pred=83, local=6\n", "str_to_llvmtype(): str = 'i64'\n", "add_phi_incomming(): reaching_defs = {73: {0: 0, 1: 0, 2: 0, 3: 0, 4: 42, 5: 61, 6: 64, 7: 73},\n", " 83: {0: 0, 1: 0, 2: 0, 3: 0, 4: 42, 5: 61, 6: 89, 7: 83, 8: 89}}\n", " crnt_block=86, pred=83, local=7\n", "op_BINARY_ADD(): , _llvm=, typ='i64')> + , _llvm=, typ='i64')>\n", "resolve_type(): arg1 = , _llvm=, typ='i64')>, arg2 = , _llvm=, typ='i64')>\n", "resolve_type() ==> 'i64'\n", "resolve_type(): arg1 = , _llvm=, typ='i64')>, arg2 = , _llvm=, typ='i64')>\n", "resolve_type() ==> 'i64'\n", "op_BINARY_SUBSCR(): arr_var.typ = arr[f64]\n", "str_to_llvmtype(): str = 'f64'\n", " %28 = load double* %27\n", "op_BINARY_SUBSCR(): arr_var.typ = arr[f64]\n", "str_to_llvmtype(): str = 'f64'\n", " %39 = load double* %38\n", "resolve_type(): arg1 = , _llvm=, typ='f64')>, arg2 = , _llvm=, typ='f64')>\n", "resolve_type() ==> 'f64'\n", "resolve_type(): arg1 = , _llvm=, typ='f64')>, arg2 = , _llvm=, typ='f64')>\n", "resolve_type() ==> 'f64'\n", "op_BINARY_ADD(): , _llvm=, typ='f64')> + , _llvm=, typ='f64')>\n", "resolve_type(): arg1 = , _llvm=, typ='f64')>, arg2 = , _llvm=, typ='f64')>\n", "resolve_type() ==> 'f64'\n", "op_LOAD_ATTR(): 140 106 sqrt , _llvm=None, typ=None)> None\n", "('op_CALL_FUNCTION():', , _llvm=None, typ=None)>)\n", "str_to_llvmtype(): str = 'f64'\n", "op_STORE_SUBSCR(): 161 60 None\n", "op_STORE_SUBSCR(): , _llvm=, typ='arr[f64]')>[, _llvm=, typ='i64')>, , _llvm=, typ='i64')>), _llvm=None, typ='tuple')>] = , _llvm=, typ='f64')>\n", "op_STORE_SUBSCR(): arr_lval = '{ i64, i32*, i8*, i32, i64*, i64*, i8*, i8*, i32, i8*, i8*, i8*, i64* }* %D', arr_ltype = '{ i64, i32*, i8*, i32, i64*, i64*, i8*, i8*, i32, i8*, i8*, i8*, i64* }*'\n", "str_to_llvmtype(): str = 'f64'\n", "; ModuleID = 'pairwise_numba_mod_2e6ed90'\n", "\n", "define double @pairwise_numba({ i64, i32*, i8*, i32, i64*, i64*, i8*, i8*, i32, i8*, i8*, i8*, i64* }* %X, { i64, i32*, i8*, i32, i64*, i64*, i8*, i8*, i32, i8*, i8*, i8*, i64* }* %D) {\n", "Entry:\n", " %0 = getelementptr { i64, i32*, i8*, i32, i64*, i64*, i8*, i8*, i32, i8*, i8*, i8*, i64* }* %X, i32 0, i32 4\n", " %1 = load i64** %0\n", " %2 = getelementptr i64* %1, i32 0\n", " %3 = load i64* %2\n", " %4 = getelementptr { i64, i32*, i8*, i32, i64*, i64*, i8*, i8*, i32, i8*, i8*, i8*, i64* }* %X, i32 0, i32 4\n", " %5 = load i64** %4\n", " %6 = getelementptr i64* %5, i32 1\n", " %7 = load i64* %6\n", " br label %BLOCK_29\n", "\n", "BLOCK_29: ; preds = %Entry\n", " br label %BLOCK_42\n", "\n", "BLOCK_39: ; preds = %BLOCK_165\n", " %8 = add i64 %9, 1\n", " br label %BLOCK_42\n", "\n", "BLOCK_42: ; preds = %BLOCK_39, %BLOCK_29\n", " %9 = phi i64 [ 0, %BLOCK_29 ], [ %8, %BLOCK_39 ]\n", " %10 = icmp slt i64 %9, %3\n", " br i1 %10, label %BLOCK_45, label %BLOCK_169\n", "\n", "BLOCK_169: ; preds = %BLOCK_42\n", " ret double 0.000000e+00\n", "\n", "BLOCK_45: ; preds = %BLOCK_42\n", " br label %BLOCK_48\n", "\n", "BLOCK_48: ; preds = %BLOCK_45\n", " br label %BLOCK_61\n", "\n", "BLOCK_58: ; preds = %BLOCK_136\n", " %11 = add i64 %12, 1\n", " br label %BLOCK_61\n", "\n", "BLOCK_61: ; preds = %BLOCK_58, %BLOCK_48\n", " %12 = phi i64 [ 0, %BLOCK_48 ], [ %11, %BLOCK_58 ]\n", " %13 = icmp slt i64 %12, %3\n", " br i1 %13, label %BLOCK_64, label %BLOCK_165\n", "\n", "BLOCK_165: ; preds = %BLOCK_61\n", " br label %BLOCK_39\n", "\n", "BLOCK_64: ; preds = %BLOCK_61\n", " br label %BLOCK_73\n", "\n", "BLOCK_73: ; preds = %BLOCK_64\n", " br label %BLOCK_86\n", "\n", "BLOCK_83: ; preds = %BLOCK_89\n", " %14 = add i64 %16, 1\n", " br label %BLOCK_86\n", "\n", "BLOCK_86: ; preds = %BLOCK_83, %BLOCK_73\n", " %15 = phi double [ 0.000000e+00, %BLOCK_73 ], [ %53, %BLOCK_83 ]\n", " %16 = phi i64 [ 0, %BLOCK_73 ], [ %14, %BLOCK_83 ]\n", " %17 = icmp slt i64 %16, %7\n", " br i1 %17, label %BLOCK_89, label %BLOCK_136\n", "\n", "BLOCK_136: ; preds = %BLOCK_86\n", " %18 = call double @llvm.sqrt.f64(double %15)\n", " %19 = getelementptr { i64, i32*, i8*, i32, i64*, i64*, i8*, i8*, i32, i8*, i8*, i8*, i64* }* %D, i32 0, i32 5\n", " %20 = load i64** %19\n", " %21 = getelementptr i64* %20, i32 0\n", " %22 = load i64* %21\n", " %23 = mul i64 %9, %22\n", " %24 = getelementptr { i64, i32*, i8*, i32, i64*, i64*, i8*, i8*, i32, i8*, i8*, i8*, i64* }* %D, i32 0, i32 2\n", " %25 = load i8** %24\n", " %26 = getelementptr i8* %25, i64 %23\n", " %27 = bitcast i8* %26 to double*\n", " %28 = getelementptr double* %27, i64 %12\n", " store double %18, double* %28\n", " br label %BLOCK_58\n", "\n", "BLOCK_89: ; preds = %BLOCK_86\n", " %29 = getelementptr { i64, i32*, i8*, i32, i64*, i64*, i8*, i8*, i32, i8*, i8*, i8*, i64* }* %X, i32 0, i32 5\n", " %30 = load i64** %29\n", " %31 = getelementptr i64* %30, i32 0\n", " %32 = load i64* %31\n", " %33 = mul i64 %9, %32\n", " %34 = getelementptr { i64, i32*, i8*, i32, i64*, i64*, i8*, i8*, i32, i8*, i8*, i8*, i64* }* %X, i32 0, i32 2\n", " %35 = load i8** %34\n", " %36 = getelementptr i8* %35, i64 %33\n", " %37 = bitcast i8* %36 to double*\n", " %38 = getelementptr double* %37, i64 %16\n", " %39 = load double* %38\n", " %40 = getelementptr { i64, i32*, i8*, i32, i64*, i64*, i8*, i8*, i32, i8*, i8*, i8*, i64* }* %X, i32 0, i32 5\n", " %41 = load i64** %40\n", " %42 = getelementptr i64* %41, i32 0\n", " %43 = load i64* %42\n", " %44 = mul i64 %12, %43\n", " %45 = getelementptr { i64, i32*, i8*, i32, i64*, i64*, i8*, i8*, i32, i8*, i8*, i8*, i64* }* %X, i32 0, i32 2\n", " %46 = load i8** %45\n", " %47 = getelementptr i8* %46, i64 %44\n", " %48 = bitcast i8* %47 to double*\n", " %49 = getelementptr double* %48, i64 %16\n", " %50 = load double* %49\n", " %51 = fsub double %39, %50\n", " %52 = fmul double %51, %51\n", " %53 = fadd double %15, %52\n", " br label %BLOCK_83\n", "}\n", "\n", "declare double @llvm.sqrt.f64(double) nounwind readonly\n", "\n" ] } ], "prompt_number": 3 }, { "cell_type": "code", "collapsed": false, "input": [ "%%cython\n", "\n", "cimport cython\n", "from libc.math cimport sqrt\n", "\n", "@cython.boundscheck(False)\n", "@cython.wraparound(False)\n", "def pairwise_cython(double[:, ::1] X, double[:, ::1] D):\n", " cdef int M = X.shape[0]\n", " cdef int N = X.shape[1]\n", " cdef double tmp, d\n", " for i in range(M):\n", " for j in range(M):\n", " d = 0.0\n", " for k in range(N):\n", " tmp = X[i, k] - X[j, k]\n", " d += tmp * tmp\n", " D[i, j] = sqrt(d)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 4 }, { "cell_type": "code", "collapsed": false, "input": [ "%timeit pairwise_python(X, D)\n", "%timeit pairwise_numba(X, D)\n", "%timeit pairwise_cython(X, D)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "1 loops, best of 3: 12.1 s per loop\n", "100 loops, best of 3: 15.5 ms per loop" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "100 loops, best of 3: 9.86 ms per loop" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n" ] } ], "prompt_number": 5 } ], "metadata": {} } ] }