Last active
February 9, 2016 19:34
-
-
Save synapticarbors/570a38565e5eaa6f8116 to your computer and use it in GitHub Desktop.
Numba jitclass timings
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "cells": [ | |
| { | |
| "cell_type": "code", | |
| "execution_count": 1, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "import numpy as np\n", | |
| "import numba as nb\n", | |
| "\n", | |
| "import pandas as pd\n", | |
| "\n", | |
| "import matplotlib.pyplot as plt\n", | |
| "%matplotlib inline" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 2, | |
| "metadata": { | |
| "collapsed": true | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "spec = [\n", | |
| " ('A', nb.float64[:,::1]),\n", | |
| " ('B', nb.float64[::1])\n", | |
| "]\n", | |
| "\n", | |
| "@nb.jitclass(spec)\n", | |
| "class Data(object):\n", | |
| " def __init__(self, A, B):\n", | |
| " self.A = A\n", | |
| " self.B = B\n", | |
| " \n", | |
| " def funcd(self):\n", | |
| " A = self.A\n", | |
| " B = self.B\n", | |
| " m,n = A.shape\n", | |
| " X = np.zeros(m)\n", | |
| "\n", | |
| " for i in range(m):\n", | |
| " for j in range(n):\n", | |
| " X[i] += A[i,j] * B[j]\n", | |
| "\n", | |
| " return X\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 3, | |
| "metadata": { | |
| "collapsed": true | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "@nb.jit(nopython=True)\n", | |
| "def func1(A, B):\n", | |
| " m,n = A.shape\n", | |
| " X = np.zeros(m)\n", | |
| " \n", | |
| " for i in range(m):\n", | |
| " for j in range(n):\n", | |
| " X[i] += A[i,j] * B[j]\n", | |
| " \n", | |
| " return X\n", | |
| "\n", | |
| "@nb.jit(nopython=True)\n", | |
| "def func2(d):\n", | |
| " A = d.A\n", | |
| " B = d.B\n", | |
| " m,n = A.shape\n", | |
| " X = np.zeros(m)\n", | |
| " \n", | |
| " for i in range(m):\n", | |
| " for j in range(n):\n", | |
| " X[i] += A[i,j] * B[j]\n", | |
| " \n", | |
| " return X\n", | |
| "\n", | |
| "@nb.jit(nopython=True)\n", | |
| "def func3(d):\n", | |
| " return func1(d.A, d.B)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 37, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "The slowest run took 47205.00 times longer than the fastest. This could mean that an intermediate result is being cached \n", | |
| "100000 loops, best of 3: 1.96 µs per loop\n", | |
| "The slowest run took 12108.55 times longer than the fastest. This could mean that an intermediate result is being cached \n", | |
| "100000 loops, best of 3: 8.06 µs per loop\n", | |
| "The slowest run took 7601.81 times longer than the fastest. This could mean that an intermediate result is being cached \n", | |
| "100000 loops, best of 3: 8.3 µs per loop\n", | |
| "The slowest run took 16328.53 times longer than the fastest. This could mean that an intermediate result is being cached \n", | |
| "100000 loops, best of 3: 8.5 µs per loop\n", | |
| "100000 loops, best of 3: 5.43 µs per loop\n", | |
| "The slowest run took 4.90 times longer than the fastest. This could mean that an intermediate result is being cached \n", | |
| "100000 loops, best of 3: 11.8 µs per loop\n", | |
| "100000 loops, best of 3: 12 µs per loop\n", | |
| "100000 loops, best of 3: 12.2 µs per loop\n", | |
| "100000 loops, best of 3: 9.7 µs per loop\n", | |
| "100000 loops, best of 3: 16.8 µs per loop\n", | |
| "100000 loops, best of 3: 16.6 µs per loop\n", | |
| "100000 loops, best of 3: 16.8 µs per loop\n", | |
| "10000 loops, best of 3: 44.2 µs per loop\n", | |
| "10000 loops, best of 3: 53.4 µs per loop\n", | |
| "10000 loops, best of 3: 50.8 µs per loop\n", | |
| "10000 loops, best of 3: 51.9 µs per loop\n", | |
| "10000 loops, best of 3: 85.5 µs per loop\n", | |
| "10000 loops, best of 3: 96.4 µs per loop\n", | |
| "10000 loops, best of 3: 91.3 µs per loop\n", | |
| "10000 loops, best of 3: 95 µs per loop\n", | |
| "1000 loops, best of 3: 860 µs per loop\n", | |
| "1000 loops, best of 3: 921 µs per loop\n", | |
| "1000 loops, best of 3: 894 µs per loop\n", | |
| "1000 loops, best of 3: 922 µs per loop\n", | |
| "100 loops, best of 3: 4.28 ms per loop\n", | |
| "100 loops, best of 3: 4.48 ms per loop\n", | |
| "100 loops, best of 3: 4.29 ms per loop\n", | |
| "100 loops, best of 3: 4.38 ms per loop\n", | |
| "100 loops, best of 3: 8.69 ms per loop\n", | |
| "100 loops, best of 3: 8.78 ms per loop\n", | |
| "100 loops, best of 3: 8.54 ms per loop\n", | |
| "100 loops, best of 3: 8.8 ms per loop\n", | |
| "10 loops, best of 3: 48.3 ms per loop\n", | |
| "10 loops, best of 3: 48.1 ms per loop\n", | |
| "10 loops, best of 3: 47.5 ms per loop\n", | |
| "10 loops, best of 3: 47.9 ms per loop\n", | |
| "10 loops, best of 3: 95.2 ms per loop\n", | |
| "10 loops, best of 3: 97.1 ms per loop\n", | |
| "10 loops, best of 3: 94.1 ms per loop\n", | |
| "10 loops, best of 3: 94.6 ms per loop\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "t1 = {}\n", | |
| "t2 = {}\n", | |
| "t3 = {}\n", | |
| "td = {}\n", | |
| "for N in [10, 50, 100, 500, 1000, 10000, 50000, 100000, 500000, 1000000]:\n", | |
| " a = np.random.normal(size=(N,100))\n", | |
| " b = np.random.normal(size=(100))\n", | |
| "\n", | |
| " data = Data(a, b)\n", | |
| "\n", | |
| " r1 = %timeit -o func1(a,b)\n", | |
| " r2 = %timeit -o func2(data)\n", | |
| " r3 = %timeit -o func3(data)\n", | |
| " rd = %timeit -o data.funcd()\n", | |
| " \n", | |
| " t1[N] = r1.best\n", | |
| " t2[N] = r2.best\n", | |
| " t3[N] = r3.best\n", | |
| " td[N] = rd.best" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 38, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "df = pd.DataFrame({'func1': pd.Series(t1), 'func2': pd.Series(t2), \n", | |
| " 'func3': pd.Series(t3), 'funcd': pd.Series(td)})" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 39, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/html": [ | |
| "<div>\n", | |
| "<table border=\"1\" class=\"dataframe\">\n", | |
| " <thead>\n", | |
| " <tr style=\"text-align: right;\">\n", | |
| " <th></th>\n", | |
| " <th>func1</th>\n", | |
| " <th>func2</th>\n", | |
| " <th>func3</th>\n", | |
| " <th>funcd</th>\n", | |
| " </tr>\n", | |
| " </thead>\n", | |
| " <tbody>\n", | |
| " <tr>\n", | |
| " <th>10</th>\n", | |
| " <td>0.000002</td>\n", | |
| " <td>0.000008</td>\n", | |
| " <td>0.000008</td>\n", | |
| " <td>0.000009</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>50</th>\n", | |
| " <td>0.000005</td>\n", | |
| " <td>0.000012</td>\n", | |
| " <td>0.000012</td>\n", | |
| " <td>0.000012</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>100</th>\n", | |
| " <td>0.000010</td>\n", | |
| " <td>0.000017</td>\n", | |
| " <td>0.000017</td>\n", | |
| " <td>0.000017</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>500</th>\n", | |
| " <td>0.000044</td>\n", | |
| " <td>0.000053</td>\n", | |
| " <td>0.000051</td>\n", | |
| " <td>0.000052</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>1000</th>\n", | |
| " <td>0.000085</td>\n", | |
| " <td>0.000096</td>\n", | |
| " <td>0.000091</td>\n", | |
| " <td>0.000095</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>10000</th>\n", | |
| " <td>0.000860</td>\n", | |
| " <td>0.000921</td>\n", | |
| " <td>0.000894</td>\n", | |
| " <td>0.000922</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>50000</th>\n", | |
| " <td>0.004284</td>\n", | |
| " <td>0.004484</td>\n", | |
| " <td>0.004293</td>\n", | |
| " <td>0.004383</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>100000</th>\n", | |
| " <td>0.008693</td>\n", | |
| " <td>0.008777</td>\n", | |
| " <td>0.008539</td>\n", | |
| " <td>0.008803</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>500000</th>\n", | |
| " <td>0.048321</td>\n", | |
| " <td>0.048144</td>\n", | |
| " <td>0.047470</td>\n", | |
| " <td>0.047916</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>1000000</th>\n", | |
| " <td>0.095212</td>\n", | |
| " <td>0.097141</td>\n", | |
| " <td>0.094092</td>\n", | |
| " <td>0.094573</td>\n", | |
| " </tr>\n", | |
| " </tbody>\n", | |
| "</table>\n", | |
| "</div>" | |
| ], | |
| "text/plain": [ | |
| " func1 func2 func3 funcd\n", | |
| "10 0.000002 0.000008 0.000008 0.000009\n", | |
| "50 0.000005 0.000012 0.000012 0.000012\n", | |
| "100 0.000010 0.000017 0.000017 0.000017\n", | |
| "500 0.000044 0.000053 0.000051 0.000052\n", | |
| "1000 0.000085 0.000096 0.000091 0.000095\n", | |
| "10000 0.000860 0.000921 0.000894 0.000922\n", | |
| "50000 0.004284 0.004484 0.004293 0.004383\n", | |
| "100000 0.008693 0.008777 0.008539 0.008803\n", | |
| "500000 0.048321 0.048144 0.047470 0.047916\n", | |
| "1000000 0.095212 0.097141 0.094092 0.094573" | |
| ] | |
| }, | |
| "execution_count": 39, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "df" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 44, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "<matplotlib.legend.Legend at 0x127aa6950>" | |
| ] | |
| }, | |
| "execution_count": 44, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| }, | |
| { | |
| "data": { | |
| "image/png": "iVBORw0KGgoAAAANSUhEUgAAAf4AAAH4CAYAAACrNo84AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzs3Xl0VdX5//H3TsKUkCAJkGAIU5gCqICCCAbCGAitrXO1\nqF+H1oqgRYutQis/bS1F1CogVcQWxVq1UotlTiCCIwiiyCBzmIQAIUAEA0n274+TxBASuBnu/Hmt\ndRf33DM9XFk+d+999n6MtRYREREJDiHeDkBEREQ8R4lfREQkiCjxi4iIBBElfhERkSCixC8iIhJE\nlPhFRESCiNcSvzEmxBiz1hgzr4J9/Y0xucX71xpjJngjRhERkUAT5sV7PwhsBKIq2b/CWnuNB+MR\nEREJeF5p8RtjWgBpwCvnO8xD4YiIiAQNb3X1PweMA863bOBVxph1xpj5xpjOHopLREQkoHk88Rtj\nRgAHrbXrcFr1FbXs1wAtrbXdgGnAex4MUUREJGAZT6/Vb4x5ChgJFAANgEhgrrX29vOcsxO43Fqb\nU+5zFRoQEZGgY62t9nC4x1v81trHrLUtrbVtgZ8By8onfWNMbJn3vXB+oORQAWutR16PP/64x853\n5djzHVPZvoo+L//Zhbb1Hdf8O/bn77mq517oeH3HNT+/Jt9xVb5PV77TYP2OL3RMbf9brilvPtV/\nFmPMvYC11r4M3GCMuQ84A5wCbvZqcEBKSorHznfl2PMdU9m+ij4v/1lN/541ESzfsav3d5ea3Luq\n517oeH3HNT+/Jt9xZftd/e71Hbt2jK/9W/Z4V39tMsZYf47fH0ycOJGJEyd6O4yAp+/Z/fQdu5++\nY88wxmD9qatf/Is3f9EHE33P7qfv2P30HfsHtfhFRET8SE1b/D4zxi8iIjXXunVrsrKyvB2G1IJW\nrVqxa9euWr+uWvwiIgGkuDXo7TCkFlT231Jj/CIiIuIyJX4REZEgosQvIiISRJT4RUREgogSv4iI\neMyWLVvo3r07jRo1Ytq0ad4OB4AZM2YQFxdHVFQUR48e9XY4bqfELyIiHjN58mQGDhzIsWPHGD16\ndK1f//Tp09xzzz20bt2aRo0a0aNHDxYtWnTOcZMmTWLChAkUFBTw8MMPk56ezvHjx2ncuHGtxwRw\n5swZbrzxRtq0aUNISAgrVqxwy31cocQvIiIek5WVRZcuXdx2/YKCAlq2bMnKlSs5duwYTz75JDfd\ndBO7d+8+67j58+eTlpbGgQMHyM/PJykpyW0xlUhOTuaNN96gefPmbr/X+Sjxi4gEiYICGDMGBg92\n/iwo8Oz5gwYNYvny5YwePZrIyEji4+N59dVXS/fPnj2b5OTk0u2QkBBeeuklOnToQHR09Dk9BDNn\nzqRz585ERUXRtWtX1q1bR3h4OH/4wx9ISEgAYMSIEbRp04Y1a9aUnpebm8vWrVtp2rQpnTp1AqBx\n48YMHjyYrKwsQkJCKCoqKj1+wIABpXGWxDhu3Diio6NJTEw8q0fh6NGj3HXXXcTHxxMTE8N1110H\nQJ06dXjggQfo06cPISHeTb3+n/ir869PRCQIjR0LM2ZARobz50MPefb8jIwMkpOTmT59OidOnKBD\nhw7nHGPM2evSzJ8/nzVr1vDll1/y9ttvs2TJEgDeeecdnnjiCebMmcPx48eZN28eMTEx51zv4MGD\nbN269axehsWLFzNo0CDat2/Phg0bADh27Bjp6ekVxlDeqlWrSEpK4siRI4wbN4677767dN/IkSM5\ndeoUmzZtIjs7m7Fjx7r47XiO/y/ZO2MGGAMvvODtSEREfNqmTVBY6LwvLISpU51XdRQWwsaN1Tu3\nKisLPvroo0RGRhIZGcmAAQNYt24dQ4cOZdasWTzyyCP06NEDgLZt255zbkFBASNHjuT//u//zvqR\nUdLNXz6mCyX8Eq1ateKuu+4C4I477mDUqFFkZ2dTVFTE4sWLycnJISoqCuCsHgxf4f8t/pr86xMR\nCSJJSRAa6rwPDXU6TK11/TV69Nnnd+7s/phjY2NL34eHh5OXlwfAnj17SExMrPQ8ay0jR46kXr16\nTC3z68Zay9KlSxk2bFi1Y4qLiyt936BBAwDy8vLYs2cP0dHRpUnfV/l/i99T//pERPzcc885HaQb\nNzr/23z2Wc+eX15ERAQnT54s3T5w4IDL5yYkJLB9+/ZK9999990cPnyYBQsWEFryawVYvXo1rVu3\nrnBYoCQmgJMnT9KwYcMqxZWQkEBOTg7Hjx/36eTv/y3+ESNq/q9PRCQIhIU5o6Lp6c6fYVVs+tX0\n/PK6devG3LlzOXXqFNu2bWPWrFkun3vPPfcwZcoU1q5dC8D27dvZs2cPAL/61a/YvHkz8+bNo27d\numedt2DBAkaMGHHWZ2WHHpo0aUJ8fDxz5syhqKiIV1999bw/MMqKi4tj+PDhjBo1itzcXAoKCli5\ncmXp/tOnT/P9998DkJ+fT35+vst/39rk/4m/ffua/+sTERGPKDuOPnbsWOrUqUNcXBx33nknI0eO\nrPTY8ts33HAD48eP59ZbbyUyMpJrr72WnJwcdu/ezcsvv8y6deuIjY0lMjKSqKgo3nzzTaDi8f3y\n95k5cyaTJ0+mSZMmbNq0ib59+7r8d3r99dcJCwujU6dOxMbG8vzzz5fu69ixIxEREezfv59hw4YR\nHh5+zjRDT/D/sryXXQbr1nk7FBERn6CyvJXLzs6mR48e7N2719uhuERleSuzaxdkZ3s7ChER8XHH\njh3jmWee8XYYXuf/Lf5rroFbboGf/czb4YiIeJ1a/IFDLf7KDB4MS5d6OwoRERG/EDiJX79wRURE\nLsj/E3+nTlBUBNu2eTsSERERn+f3iX/MogcoGjTQmVgqIiIi5+X3iX/G6hnMaXZA4/wiIiIu8PvE\nX2gL+V/CKVi+/IfqEyIiIlIhv0/8oSaUuPbdoUULKFNvWUREfM+WLVvo3r07jRo1Ytq0ad4OB4AZ\nM2YQFxdHVFQUR48e9XY4buf3ib9/q/48m/qs83S/xvlFRHza5MmTGThwIMeOHWP06NFuucdtt91G\n8+bNueiii+jUqVOFNQAmTZrEhAkTKCgo4OGHHyY9PZ3jx4/TuHFjt8R05swZbrzxRtq0aUNISAgr\nVqxwy31c4feJPyY8hrCQMM3nFxHxA1lZWXTp0sWt93j00UfZuXMnubm5zJs3jwkTJvDFF1+cdUzJ\nmv0HDhwgPz+fpKQkt8YEkJyczBtvvEHz5s3dfq/z8fvEn7Ezg8KiQujfH1avhu++83ZIIiI+qaCo\ngDELxzD4tcGMWTiGgqICj54/aNAgli9fzujRo4mMjCQ+Pp5XX321dP/s2bNJTk4u3Q4JCeGll16i\nQ4cOREdHn9NDMHPmTDp37kxUVBRdu3ZlXXHdls6dO1O/fn3AqbxnjDmrwl5ubi5bt26ladOmdOrU\nCYDGjRszePBgsrKyCAkJoaioqPT4AQMGlMZZEuO4ceOIjo4mMTGRRYsWlR579OhR7rrrLuLj44mJ\nieG6664DoE6dOjzwwAP06dOHkBDvpl6/T/zxkfGs3r8aGjaEHj3gww+9HZKIiE8au3gsM1bPIGNn\nBjNWz+ChxQ959PyMjAySk5OZPn06J06coEOHDuccU75S3vz581mzZg1ffvklb7/9NkuWLAHgnXfe\n4YknnmDOnDkcP36cefPmERMTU3re/fffT0REBElJSVx88cVnVeRbvHgxgwYNon379mzYsAFw1vFP\nLx4uLh9DeatWrSIpKYkjR44wbtw47r777tJ9I0eO5NSpU2zatIns7GzGjh1bpe/IE/y+nm1qYiqL\nty2md4veP3T3p6Z6OywREZ+z6dAmCq0z+6nQFjJ11VSmrpparWsV2kI2HtpYrXOrUkvg0UcfJTIy\nksjISAYMGMC6desYOnQos2bN4pFHHqFHjx4AtG3b9qzzpk+fzrRp0/jkk0/IzMykXr16pfsqKs1b\n0jPgilatWnHXXXcBcMcddzBq1Ciys7MpKipi8eLF5OTkEBUVBXBWD4av8PsW/9DEoSzevtjZ0AN+\nIiKVSmqaRKgJBZwZUWN6jcE+bl1+je41+qzzOzft7PaYY2NjS9+Hh4eTl5cHwJ49e0hMTDzvucYY\n+vTpw549e5gxYwbgJPilS5cybNiwascUFxdX+r5BgwYA5OXlsWfPHqKjo0uTvq/y+xZ/cqtk1mev\n5+ipozTu1euHMr3Nmnk7NBERn/Jc6nMYDBsPbaRz087OjCgPnl9eREQEJ0+eLN0+cOCAy+cmJCSc\nNW5/PgUFBaXHrl69mtatW581LFA+JoCTJ0/SsGHDKsWVkJBATk4Ox48f9+nk7/ct/vph9bm65dVk\n7MyAsDDnIb9ly7wdloiIzwkLCeOF4S+Qfns6Lwx/wZkR5cHzy+vWrRtz587l1KlTbNu2rcJpd5W5\n5557mDJlCmvXrgVg+/bt7N69m0OHDvHWW2/x3XfflXa9/+tf/2Lw4MEALFiwgBEjRpx1rbJDD02a\nNCE+Pp45c+ZQVFTEq6++6vIPjLi4OIYPH86oUaPIzc2loKCAlStXlu4/ffo033//PQD5+fnk5+e7\n/PetTX6f+OGHcX5A0/pERHxY2XH0sWPHUqdOHeLi4rjzzjsZOXJkpceW377hhhsYP348t956K5GR\nkVx77bUcPXoUYwwzZswgISGB6OhoHnnkEZ5//vnSZF/R+H75+8ycOZPJkyfTpEkTNm3aRN++fV3+\nO73++uuEhYXRqVMnYmNjef7550v3dezYkYiICPbv38+wYcMIDw9n9+7d5722O5iqPGTha4wxdvRo\nyy/Hb2LEm6lk/ToLs3mz83BfVha4+KCGiEigMMZU6eG5YJKdnU2PHj3Yu3evt0NxSWX/LYs/r3aC\n8/sx/hkzANMJ2sDmw5tJKlumt317b4cnIiI+4tixYzzzzDPeDsPr/L6rv7AQNm00Tnf/9sVOK19P\n94uISDnt27fn5ptv9nYYXuf3iT80FDp3htR2qWdP69M4v4iIyDn8fox/2DDL++/DiTNHafnXlhwa\nd4j6h3MhKQkOH3Z+GYiIBAmN8QcOd43x+32LPzbWmcXXuEFjLml2CSuzVkJcnMr0ioiIVMDvE//C\nhc6zfMAP4/ygcX4REZEK+H3ij4mB4vUbNM4vIiJyAX6f+NPSYMEC533Pi3uy/8R+9h3fpzK9IiIi\nFQioxB8aEsqgNoNYsn2JyvSKiPigLVu20L17dxo1asS0adM8cs8777yTP/zhD5XunzFjBnFxcURF\nRXH06FGPxORNXkv8xpgQY8xaY8y8Sva/YIzZaoxZZ4zpVtl1rr4aNm+GQ4ec7XPG+dXdLyLiMyZP\nnszAgQM5duwYo0eP9lockyZNYsKECRQUFPDwww+Tnp7O8ePHady4sVvud+bMGW688UbatGlDSEgI\nK1ascMt9XOHNFv+DQIXFnI0xw4FEa2174F7gb5VdpG5dGDgQFhfn+tR2qaTvSKewqFAP+ImI+Jis\nrCy6dOni7TBK1+w/cOAA+fn5JCUluf2eycnJvPHGGzRv3tzt9zofryR+Y0wLIA14pZJDfgK8BmCt\n/QxoZIyJreTYs7r7W0S1ILZhLGu+XQNly/SKiAS7ggIYM8ZpFI0Z42x78PxBgwaxfPlyRo8eTWRk\nJPHx8bz66qul+2fPnk1ycnLpdkhICC+99BIdOnQgOjr6nB6CmTNn0rlzZ6KioujatSvr1q0D4Isv\nvuDyyy+nUaNG/OxnPyutiFciNzeXrVu30rRpUzp16gRA48aNGTx4MFlZWYSEhFBUMl0MGDBgQGmc\nJTGOGzeO6OhoEhMTWbRoUemxR48e5a677iI+Pp6YmBiuu+46AOrUqcMDDzxAnz59CAnx7ii7t+7+\nHDAOqGyViXhgT5ntfcWfVWj4cKfFX1jobJdW61OZXhGRH4wd6xQ4ychw/nzoIY+en5GRQXJyMtOn\nT+fEiRN06NDhnGPKV8qbP38+a9as4csvv+Ttt99myZIlALzzzjs88cQTzJkzh+PHjzNv3jxiYmI4\nc+YM1157LXfccQc5OTnceOONvPvuu2ddc/HixQwaNIj27duzYcMGwFnHP724h7h8DOWtWrWKpKQk\njhw5wrhx47j77rtL940cOZJTp06xadMmsrOzGTt2bJW+I0/weOI3xowADlpr1wGm+FUj8fGQkACf\nfeZsa5xfRKQCmzb90EIqLISpU536Jq6+pk07+/yNFY7WXlBVVhZ89NFHiYyMJCEhgQEDBpS26mfN\nmsUjjzxCjx49AGjbti0JCQl8+umnFBQU8MADDxAaGsr1119Pz549z7pmRaV5qxJTq1atuOuuuzDG\ncMcdd/Dtt9+SnZ3NgQMHWLx4MS+99BJRUVGEhoae1YPhK7xRna8vcI0xJg1oAEQaY16z1t5e5ph9\nQEKZ7RbFn51j4sSJAERGwosvptCnTwr9WvXjy4Nfcuz7YzQaMgSefhqsVZleEQluSUmQmekk7dBQ\nGDUKXnjB9fPHjHFa+iXnd+7stlBLxMb+MMobHh5OXl4eAHv27CExMfGc4/fv3098/NkdxK1atSp9\nb61l6dKlPPfcc9WOKS4urvR9gwYNAMjLy+PIkSNER0cTFRVV7WtXJDMzk8zMzFq7nscTv7X2MeAx\nAGNMf+DhckkfYB5wP/CWMaY3kGutPVjR9UoSf8mQE0CDOg3ok9CHjJ0ZXNfpWpXpFREBeO45pwG0\ncaOTtJ991rPnlxMREcHJkydLtw8cOODyuQkJCWzfvv2cz5s3b86+fWe3E3fv3k27du0AWL16Na1b\ntyYmJqbSmABOnjxJw4YNqxRXQkICOTk5HD9+vFaTf0pKCikpKaXb/+///b8aXc9n5vEbY+41xvwS\nwFq7ANhpjNkGvASMutD5vXtDVhaU/PcuHedXmV4REUdYmNPCT093/gyrYtuvpueX061bN+bOncup\nU6fYtm0bs2bNcvnce+65hylTprC2eOnW7du3s2fPHq666irCwsKYOnUqBQUFzJ07l1WrVpWet2DB\nAkaMGHHWtcp28zdp0oT4+HjmzJlDUVERr776aoU/MCoSFxfH8OHDGTVqFLm5uRQUFLBy5crS/adP\nny590DA/P5/8/HyX/761yauJ31r7gbX2muL3L1lrXy6zb7S1tp219jJr7doLXSssDIYOhZKHK0vG\n+a21GucXEfERZR+cGzt2LHXq1CEuLo4777yTkSNHVnps+e0bbriB8ePHc+uttxIVFcW1115LTk4O\nderUYe7cufz9738nJiaGd955h+uvv770vIrG98vfZ+bMmUyePJkmTZqwadMm+vbt6/Lf6fXXXycs\n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\nAABJRU5ErkJggg==\n", | |
| "text/plain": [ | |
| "<matplotlib.figure.Figure at 0x116cce090>" | |
| ] | |
| }, | |
| "metadata": {}, | |
| "output_type": "display_data" | |
| } | |
| ], | |
| "source": [ | |
| "plt.figure(figsize=(8,8))\n", | |
| "plt.plot(df.index, df.func2 / df.func1, '.-', ms=8, label='func2/func1')\n", | |
| "plt.plot(df.index, df.func3 / df.func1, '.-', ms=8, label='func3/func1')\n", | |
| "plt.plot(df.index, df.funcd / df.func1, '.-', ms=8, label='funcd/func1')\n", | |
| "\n", | |
| "plt.plot(df.index, np.ones_like(df.index), 'k--')\n", | |
| "plt.xscale('log')\n", | |
| "plt.xlabel('N', fontsize=16)\n", | |
| "plt.ylabel('Ratio Elapsed Time', fontsize=16)\n", | |
| "plt.legend()" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "collapsed": true | |
| }, | |
| "source": [ | |
| "## Attempt to remove python->numba marshalling of jitclass\n", | |
| "\n", | |
| "*i.e what I was seeing before was not overhead within numba*" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 5, | |
| "metadata": { | |
| "collapsed": true | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "@nb.jit(nopython=True)\n", | |
| "def repeat_call_func1(A, B, N):\n", | |
| " for k in range(N):\n", | |
| " c = func1(A,B)\n", | |
| " \n", | |
| "@nb.jit(nopython=True)\n", | |
| "def repeat_call_func2(data, N):\n", | |
| " for k in range(N):\n", | |
| " c = func2(data)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 12, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "100000 loops, best of 3: 5.31 µs per loop\n", | |
| "The slowest run took 4.21 times longer than the fastest. This could mean that an intermediate result is being cached \n", | |
| "100000 loops, best of 3: 11.6 µs per loop\n", | |
| "100000 loops, best of 3: 9.72 µs per loop\n", | |
| "100000 loops, best of 3: 15.6 µs per loop\n", | |
| "10000 loops, best of 3: 43.8 µs per loop\n", | |
| "10000 loops, best of 3: 48.9 µs per loop\n", | |
| "1000 loops, best of 3: 206 µs per loop\n", | |
| "1000 loops, best of 3: 227 µs per loop\n", | |
| "1000 loops, best of 3: 435 µs per loop\n", | |
| "1000 loops, best of 3: 442 µs per loop\n", | |
| "100 loops, best of 3: 2.11 ms per loop\n", | |
| "100 loops, best of 3: 2.09 ms per loop\n", | |
| "100 loops, best of 3: 4.14 ms per loop\n", | |
| "100 loops, best of 3: 4.15 ms per loop\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "t1 = {}\n", | |
| "t2 = {}\n", | |
| "\n", | |
| "for N in [1, 2, 10, 50, 100, 500, 1000]:\n", | |
| " a = np.random.normal(size=(50,100))\n", | |
| " b = np.random.normal(size=(100))\n", | |
| "\n", | |
| " data = Data(a, b)\n", | |
| "\n", | |
| " r1 = %timeit -o repeat_call_func1(a,b, N)\n", | |
| " r2 = %timeit -o repeat_call_func2(data, N)\n", | |
| " \n", | |
| " t1[N] = r1.best\n", | |
| " t2[N] = r2.best\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 13, | |
| "metadata": { | |
| "collapsed": true | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "df = pd.DataFrame({'func1': pd.Series(t1), 'func2': pd.Series(t2)})" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 14, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "(-0.5, 3)" | |
| ] | |
| }, | |
| "execution_count": 14, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| }, | |
| { | |
| "data": { | |
| "image/png": "iVBORw0KGgoAAAANSUhEUgAAAgYAAAH4CAYAAAAxTyVUAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3XmYXGWZ///33QlbIMmwJhhC2JeACFFZBKQxyC6MiqAM\ng0ZwFJKAwFf5Ig7JT0dlj+ygAl/3ZRxHZcCFxbAoAgJRlrAoww5BdiFAtvv3x+mcNKE7XemuqlPd\n/X5dV11dVeepc+5OztX96ec853kiM5EkSQJoq7oASZLUOgwGkiSpZDCQJEklg4EkSSoZDCRJUslg\nIEmSSi0XDCJipYi4JSLujIi7ImJaN+3OjYgHI2JWRGzb7DolSRqIhlZdwNIy842I2D0z50bEEOD3\nEfGrzLx1cZuI2AfYODM3jYgdgIuBHauqWZKkgaLlegwAMnNux9OVKMLL0rMwHQh8p6PtLcDIiBjV\nvAolSRqYWjIYRERbRNwJPA1cnZm3LdVkDPBYp9dPdLwnSZL6oCWDQWYuysztgPWAHSJifNU1SZI0\nGLTcGIPOMvPliPgdsDdwb6dNTwBjO71er+O9t4gIF4OQJA0qmRm9/WzL9RhExFoRMbLj+SrA+4H7\nlmr2S+DwjjY7Ai9m5pzu9pmZ/eYxbdq0fnesvuxneT5ba9ta2vXUprvtzfz/abX/52Yep7f7Wt7P\nNeuc6u22Vn14TvW9fSPPqb5qxR6DdYFvR0QbRXD5cWZeFRGfBjIzv9Hxet+I+CvwKjCpyoLrqb29\nvd8dqy/7WZ7P1tq2lnY9tWnm/0OjNet7qedxeruv5f1cs86pgXQ+gedUPdq38jkV9UgXrSwicqB/\nj2qe6dOnM3369KrL0ADiOaV6iwhyIF1KkFrZQPvLT9XznFKrscdAkqQBpK89Bq04xkCS1EAbbLAB\njzzySNVlqI/GjRvHww8/XPf92mMgSYNMx1+UVZehPuru/9ExBpIkqW4MBpIkqWQwkCRJJYOBJEkq\nGQwkSS3jgQceYLvttmPkyJGcf/75VZcDwEUXXcTo0aMZMWIEL7zwQtXlNJzBQJLUMk4//XTe9773\n8dJLLzFlypS673/evHkceeSRbLDBBowcOZIJEybw61//+i3tTj31VL74xS+yYMECTjjhBK655hpe\nfvllVl999brXBDB//nw+8pGPsOGGG9LW1sYNN9zQkOPUwmAgSWoZjzzyCFtttVXD9r9gwQLWX399\nbrzxRl566SW+/OUvc/DBB/Poo4++qd2VV17Jvvvuy9NPP80bb7zBlltu2bCaFtt11135/ve/z7rr\nrtvwYy2LwUCSBMCCBTB1KuyxR/F1wYLm7mPixIn87ne/Y8qUKQwfPpwxY8Zw2WWXldu//e1vs+uu\nu5av29rauOSSS9hss81YY4013tLD8M1vfpPx48czYsQItt56a2bNmsWwYcM45ZRTGDt2LAD77bcf\nG264Ibfffnv5uRdffJEHH3yQtddemy222AKA1VdfnT322INHHnmEtrY2Fi1aVLbffffdyzoX1/i5\nz32ONdZYg4033vhNPRIvvPACn/zkJxkzZgxrrrkmH/rQhwBYYYUVOOaYY3jPe95DW1u1v5qd+VCS\nBMBxx8FFF8HChTBzJkTAuec2bx/XXnstu+++O4cffjiTJk1i9913f0ubiDfP23PllVdy++238+KL\nL/LOd76TAw44gD333JP//M//5Etf+hK/+MUvmDBhAg899BArrLDCW/Y3Z84cHnzwwTf1UvzmN79h\n4sSJbLrpptxzzz1stNFGvPTSS0QEjzzyyFtqWNqtt97KpEmTeO6557jkkks44ogjeOKJJwA47LDD\nGDFiBLNnz2bVVVflD3/4Q23/OE1kMJAkATB7dvELHYqv551XPHpr4UK4997l/9zyzMp40kknMXz4\ncIYPH87uu+/OrFmz2HPPPbn00kv5/Oc/z4QJEwDYaKON3vLZBQsWcNhhh/GJT3yCzTbbrHx/8WWE\npWvqKRAsNm7cOD75yU8C8PGPf5yjjz6aZ555hkWLFvGb3/yG559/nhEjRgC8qQekVXgpQZIEwJZb\nwpAhxfMhQ4pLAZnL95gy5c37GD++sTWPGjWqfD5s2DBeeeUVAB577DE23njjbj+XmRx22GGstNJK\nnNcp/WQmV199NXvvvXevaxo9enT5fJVVVgHglVde4bHHHmONNdYoQ0GrssdAkgTAjBlF1/+99xa/\n0M8+u5p9LLbqqqsyd+7c8vXTTz9d82fHjh3L3/72t263H3HEETz77LNcddVVDFmcZIDbbruNDTbY\ngDXXXLPbmgDmzp3Laquttlx1jR07lueff56XX365pcOBPQaSJACGDi3GA1xzTfF1aC/+dKzHPhbb\ndttt+dnPfsZrr73GX//6Vy699NKaP3vkkUdy5plncscddwDwt7/9jcceewyAz3zmM9x333388pe/\n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\n", | |
| "text/plain": [ | |
| "<matplotlib.figure.Figure at 0x11a6d8650>" | |
| ] | |
| }, | |
| "metadata": {}, | |
| "output_type": "display_data" | |
| } | |
| ], | |
| "source": [ | |
| "plt.figure(figsize=(8,8))\n", | |
| "plt.plot(df.index, df.func2 / df.func1, '.-', ms=8, label='func2/func1')\n", | |
| "\n", | |
| "plt.plot(df.index, np.ones_like(df.index), 'k--')\n", | |
| "plt.xscale('log')\n", | |
| "plt.xlabel('N', fontsize=16)\n", | |
| "plt.ylabel('Ratio Elapsed Time', fontsize=16)\n", | |
| "plt.legend()\n", | |
| "plt.ylim(-0.5, 3)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 15, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/html": [ | |
| "<div>\n", | |
| "<table border=\"1\" class=\"dataframe\">\n", | |
| " <thead>\n", | |
| " <tr style=\"text-align: right;\">\n", | |
| " <th></th>\n", | |
| " <th>func1</th>\n", | |
| " <th>func2</th>\n", | |
| " </tr>\n", | |
| " </thead>\n", | |
| " <tbody>\n", | |
| " <tr>\n", | |
| " <th>1</th>\n", | |
| " <td>0.000005</td>\n", | |
| " <td>0.000012</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>2</th>\n", | |
| " <td>0.000010</td>\n", | |
| " <td>0.000016</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>10</th>\n", | |
| " <td>0.000044</td>\n", | |
| " <td>0.000049</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>50</th>\n", | |
| " <td>0.000206</td>\n", | |
| " <td>0.000227</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>100</th>\n", | |
| " <td>0.000435</td>\n", | |
| " <td>0.000442</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>500</th>\n", | |
| " <td>0.002112</td>\n", | |
| " <td>0.002086</td>\n", | |
| " </tr>\n", | |
| " <tr>\n", | |
| " <th>1000</th>\n", | |
| " <td>0.004141</td>\n", | |
| " <td>0.004146</td>\n", | |
| " </tr>\n", | |
| " </tbody>\n", | |
| "</table>\n", | |
| "</div>" | |
| ], | |
| "text/plain": [ | |
| " func1 func2\n", | |
| "1 0.000005 0.000012\n", | |
| "2 0.000010 0.000016\n", | |
| "10 0.000044 0.000049\n", | |
| "50 0.000206 0.000227\n", | |
| "100 0.000435 0.000442\n", | |
| "500 0.002112 0.002086\n", | |
| "1000 0.004141 0.004146" | |
| ] | |
| }, | |
| "execution_count": 15, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "df" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": true | |
| }, | |
| "outputs": [], | |
| "source": [] | |
| } | |
| ], | |
| "metadata": { | |
| "kernelspec": { | |
| "display_name": "Python 2", | |
| "language": "python", | |
| "name": "python2" | |
| }, | |
| "language_info": { | |
| "codemirror_mode": { | |
| "name": "ipython", | |
| "version": 2 | |
| }, | |
| "file_extension": ".py", | |
| "mimetype": "text/x-python", | |
| "name": "python", | |
| "nbconvert_exporter": "python", | |
| "pygments_lexer": "ipython2", | |
| "version": "2.7.11" | |
| } | |
| }, | |
| "nbformat": 4, | |
| "nbformat_minor": 0 | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment