|
2086 | 2086 | },
|
2087 | 2087 | {
|
2088 | 2088 | "cell_type": "code",
|
2089 |
| - "execution_count": 16, |
2090 |
| - "metadata": { |
2091 |
| - "collapsed": true |
2092 |
| - }, |
| 2089 | + "execution_count": 32, |
| 2090 | + "metadata": {}, |
2093 | 2091 | "outputs": [],
|
2094 | 2092 | "source": [
|
2095 | 2093 | "#ctypes\n",
|
|
2101 | 2099 | " ('height', ctypes.c_int),\n",
|
2102 | 2100 | " ('data', ctypes.POINTER(ctypes.c_uint8)), # HUH?\n",
|
2103 | 2101 | " ]\n",
|
2104 |
| - "\n", |
| 2102 | + " array_cache = {}\n", |
2105 | 2103 | " def __init__(self, width, height):\n",
|
2106 | 2104 | " self.width = width\n",
|
2107 | 2105 | " self.height = height\n",
|
2108 |
| - " # Note this creates a class for each width*height value\n", |
2109 |
| - " # but will keep the img.data alive in the interpreter\n", |
2110 |
| - " self.data = (ctypes.c_uint8 * (width * height))() # !!!!!!\n", |
| 2106 | + " # Create a class type to hold the data.\n", |
| 2107 | + " # Since this creates a type, cache it for reuse rather\n", |
| 2108 | + " # than create a new one each time\n", |
| 2109 | + " if width*height not in self.array_cache:\n", |
| 2110 | + " self.array_cache[width*height] = ctypes.c_uint8 * (width * height)\n", |
| 2111 | + " # Note this keeps the img.data alive in the interpreter\n", |
| 2112 | + " self.data = self.array_cache[width*height]() # !!!!!!\n", |
2111 | 2113 | "\n",
|
2112 | 2114 | " def asmemoryview(self):\n",
|
2113 | 2115 | " # There must be a better way, but this code will not\n",
|
2114 | 2116 | " # be timed, so explicit trumps implicit\n",
|
2115 |
| - " ret = (ctypes.c_uint8 * (width * height))()\n", |
| 2117 | + " ret = self.data = self.array_cache[width*height]()\n", |
2116 | 2118 | " for i in range(width*height):\n",
|
2117 | 2119 | " ret[i] = self.data[i]\n",
|
2118 | 2120 | " return memoryview(ret)\n",
|
|
2128 | 2130 | "create_fractal_ctypes.argtypes = [CtypesImg, ctypes.c_int]\n",
|
2129 | 2131 | "\n",
|
2130 | 2132 | "mandel_ctypes = cdll.mandel\n",
|
2131 |
| - "mandel_ctypes.argtypes = [ctypes.c_float, ctypes.c_float, ctypes.c_int, ctypes.POINTER(ctypes.c_uint8)]" |
| 2133 | + "mandel_ctypes.argtypes = [ctypes.c_float, ctypes.c_float, ctypes.c_int, \n", |
| 2134 | + " ctypes.POINTER(ctypes.c_uint8)]" |
2132 | 2135 | ]
|
2133 | 2136 | },
|
2134 | 2137 | {
|
|
2144 | 2147 | },
|
2145 | 2148 | {
|
2146 | 2149 | "cell_type": "code",
|
2147 |
| - "execution_count": 17, |
| 2150 | + "execution_count": 33, |
2148 | 2151 | "metadata": {},
|
2149 | 2152 | "outputs": [
|
2150 | 2153 | {
|
2151 | 2154 | "name": "stdout",
|
2152 | 2155 | "output_type": "stream",
|
2153 | 2156 | "text": [
|
2154 |
| - "ctypes calling create_fractal required 203.95 millisecs\n", |
2155 |
| - "ctypes calling mandel required 2604.29 millisecs\n" |
| 2157 | + "ctypes calling create_fractal required 197.33 millisecs\n", |
| 2158 | + "ctypes calling mandel required 2463.65 millisecs\n" |
2156 | 2159 | ]
|
2157 | 2160 | }
|
2158 | 2161 | ],
|
|
4592 | 4595 | " unsigned char * data\n",
|
4593 | 4596 | " \n",
|
4594 | 4597 | " int create_fractal(cImg img, int iters);\n",
|
4595 |
| - " int mandel(float real, float imag, int max_iters, unsigned char * val);\n", |
| 4598 | + " int mandel(float real, float imag, int max_iters,\n", |
| 4599 | + " unsigned char * val);\n", |
4596 | 4600 | " \n",
|
4597 | 4601 | "def cython_create_fractal(pyimg, iters):\n",
|
4598 | 4602 | " cdef cImg cimg\n",
|
|
4606 | 4610 | " return create_fractal(cimg, citers)\n",
|
4607 | 4611 | "\n",
|
4608 | 4612 | "\n",
|
4609 |
| - "cpdef int cython_mandel(float real, float imag, int max_iters, unsigned char[::1] val):\n", |
| 4613 | + "cpdef int cython_mandel(float real, float imag, int max_iters,\n", |
| 4614 | + " unsigned char[::1] val):\n", |
4610 | 4615 | " return mandel(real, imag, max_iters, &val[0])"
|
4611 | 4616 | ]
|
4612 | 4617 | },
|
|
5463 | 5468 | {
|
5464 | 5469 | "cell_type": "code",
|
5465 | 5470 | "execution_count": 27,
|
5466 |
| - "metadata": {}, |
| 5471 | + "metadata": { |
| 5472 | + "scrolled": true |
| 5473 | + }, |
5467 | 5474 | "outputs": [
|
5468 | 5475 | {
|
5469 | 5476 | "name": "stdout",
|
|
5479 | 5486 | }
|
5480 | 5487 | ],
|
5481 | 5488 | "source": [
|
5482 |
| - "# Now let's try and work out who is the good, who the bad, and who the ugly\n", |
| 5489 | + "# Now let's try and work out who is the good, who the bad, \n", |
| 5490 | + "# and who the ugly\n", |
5483 | 5491 | "import pprint\n",
|
5484 | 5492 | "pprint.pprint([[' ', 'CreateFractal in Python', 'CreateFractal in C'],\n",
|
5485 | 5493 | " ['Python', '{:13.2f} millisecs'.format(1000*pure_python), '{:18s}'.format('')],\n",
|
|
5500 | 5508 | " - What happens when the C code changes?\n",
|
5501 | 5509 | "* Compiler dependency\n",
|
5502 | 5510 | " - ctypes needs none, Cython requires one, CFFI can go either way\n",
|
5503 |
| - "* Suseptability to bugs (object lifetimes, signature mismatches)\n", |
| 5511 | + "* Susceptability to bugs (object lifetimes, signature mismatches)\n", |
5504 | 5512 | " - All use a minilanguage for interfacing, only CFFI's is standard C\n",
|
5505 | 5513 | " - Cython will handle most transformations automatically\n",
|
5506 | 5514 | " - CFFI can be tricky for C-level pointers\n",
|
5507 | 5515 | "* Speed and productivity\n",
|
5508 | 5516 | " - Cython is heavily optimized, tightly integrated to the C-API\n",
|
5509 | 5517 | " - If the headers are pure C, CFFI should be simple\n",
|
5510 | 5518 | " - Projects exist to generate wrappers for all three\n",
|
5511 |
| - "* Which technology is actively maintained (ctypes went into the stdlib to die?)\n", |
| 5519 | + "* Which technology is actively maintained (ctypes went into the stdlib to die?)" |
| 5520 | + ] |
| 5521 | + }, |
| 5522 | + { |
| 5523 | + "cell_type": "markdown", |
| 5524 | + "metadata": {}, |
| 5525 | + "source": [ |
| 5526 | + " --- \n", |
| 5527 | + " --- \n", |
| 5528 | + " --- \n", |
| 5529 | + " --- \n", |
| 5530 | + " \n", |
5512 | 5531 | "\n",
|
| 5532 | + "\n" |
| 5533 | + ] |
| 5534 | + }, |
| 5535 | + { |
| 5536 | + "cell_type": "markdown", |
| 5537 | + "metadata": {}, |
| 5538 | + "source": [ |
5513 | 5539 | "And now the pop-quiz. If we run the pure python version in PyPy what time will we get?:\n",
|
5514 | 5540 | "\n",
|
5515 | 5541 | "* Around a 2X speed up\n",
|
|
0 commit comments