{ "metadata": { "name": "" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "code", "collapsed": false, "input": [ "%autosave 10" ], "language": "python", "metadata": {}, "outputs": [ { "javascript": [ "IPython.notebook.set_autosave_interval(10000)" ], "metadata": {}, "output_type": "display_data" }, { "output_type": "stream", "stream": "stdout", "text": [ "Autosaving every 10 seconds\n" ] } ], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Look inside the `optimizing` subfolder of this folder.\n", "\n", "Also there's a massive 80 page handout. Handout contains the bulk of material for this tutorial, so run through \n", "\n", "He didn't get past profiling, so look at the handout and type it all up into this IPython Notebook. Make it comprehensive." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## How fast is fast enough?\n", "\n", "- Make sure it's slow. If so, does it matter if it's slow?\n", "- Why is it slow?\n", "- Don't optimize until you know you need it to be faster.\n", "- Focus on use cases and user experience.\n", "- Profile.\n", "- Maintain unit tests and run them as you optimize.\n", "\n", "Usually improving big-O of algorithms and data structures is the best first step.\n", "\n", "Hardware is cheaper than programmer time." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Benchmark your Python interpreter" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import test.pystone\n", "test.pystone.main()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Pystone(1.1) time for 50000 passes = 0.883939\n", "This machine benchmarks at 56565 pystones/second\n" ] } ], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "- IronPython is faster than CPython\n", "- PyPy is *significantly* faster than IronPython and PyPy." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Profiling CPU usage\n", "\n", "- cProfile (recommended)\n", "- profile (pure Python, not recommended)\n", "- hotshot (deprecated)\n", "\n", "But these all will affect performance of your program as you run them.\n", "\n", "Below are many ways of running cProfiler." ] }, { "cell_type": "code", "collapsed": false, "input": [ "%load optimizing/measuring/profile_me.py" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 12 }, { "cell_type": "markdown", "metadata": {}, "source": [ "the `%%prun` magic incantation shows output in the bottom pane of your IPython Notebook." ] }, { "cell_type": "code", "collapsed": false, "input": [ "%%prun\n", "# file profile_me.py\n", "\n", "\"\"\"Example to be profiled.\n", "\"\"\"\n", "\n", "import time\n", "\n", "\n", "def fast():\n", " \"\"\"Wait 0.001 seconds.\n", " \"\"\"\n", " time.sleep(1e-3)\n", "\n", "\n", "def slow():\n", " \"\"\"Wait 0.1 seconds.\n", " \"\"\"\n", " time.sleep(0.1)\n", "\n", "\n", "def use_fast():\n", " \"\"\"Call `fast` 100 times.\n", " \"\"\"\n", " for _ in xrange(100):\n", " fast()\n", "\n", "\n", "def use_slow():\n", " \"\"\"Call `slow` 100 times.\n", " \"\"\"\n", " for _ in xrange(100):\n", " slow()\n", "\n", "\n", "if __name__ == '__main__':\n", " use_fast()\n", " use_slow()\n" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "\n" ] } ], "prompt_number": 13 }, { "cell_type": "code", "collapsed": false, "input": [ "%timeit slow()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "10 loops, best of 3: 100 ms per loop\n" ] } ], "prompt_number": 23 }, { "cell_type": "code", "collapsed": false, "input": [ "%timeit fast()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "1000 loops, best of 3: 1.15 ms per loop\n" ] } ], "prompt_number": 24 }, { "cell_type": "code", "collapsed": false, "input": [ "import cProfile" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 20 }, { "cell_type": "code", "collapsed": false, "input": [ "cProfile.runctx(\"slow()\", globals(), locals())" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " 4 function calls in 0.100 seconds\n", "\n", " Ordered by: standard name\n", "\n", " ncalls tottime percall cumtime percall filename:lineno(function)\n", " 1 0.000 0.000 0.100 0.100 :1()\n", " 1 0.000 0.000 0.100 0.100 :16(slow)\n", " 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}\n", " 1 0.100 0.100 0.100 0.100 {time.sleep}\n", "\n", "\n" ] } ], "prompt_number": 21 }, { "cell_type": "code", "collapsed": false, "input": [ "cProfile.run(\"slow()\")" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " 4 function calls in 0.101 seconds\n", "\n", " Ordered by: standard name\n", "\n", " ncalls tottime percall cumtime percall filename:lineno(function)\n", " 1 0.000 0.000 0.101 0.101 :1()\n", " 1 0.000 0.000 0.101 0.101 :16(slow)\n", " 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}\n", " 1 0.101 0.101 0.101 0.101 {time.sleep}\n", "\n", "\n" ] } ], "prompt_number": 36 }, { "cell_type": "code", "collapsed": false, "input": [ "cProfile.runctx(\"fast()\", globals(), locals())" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " 4 function calls in 0.001 seconds\n", "\n", " Ordered by: standard name\n", "\n", " ncalls tottime percall cumtime percall filename:lineno(function)\n", " 1 0.000 0.000 0.001 0.001 :1()\n", " 1 0.000 0.000 0.001 0.001 :10(fast)\n", " 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}\n", " 1 0.001 0.001 0.001 0.001 {time.sleep}\n", "\n", "\n" ] } ], "prompt_number": 22 }, { "cell_type": "code", "collapsed": false, "input": [ "cProfile.run(\"use_fast()\", \"optimizing/fast.stats\")\n", "import pstats\n", "stats = pstats.Stats(\"optimizing/fast.stats\")\n", "stats.print_stats()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Fri Feb 21 13:55:09 2014 optimizing/fast.stats\n", "\n", " 203 function calls in 0.112 seconds\n", "\n", " Random listing order was used\n", "\n", " ncalls tottime percall cumtime percall filename:lineno(function)\n", " 100 0.111 0.001 0.111 0.001 {time.sleep}\n", " 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}\n", " 1 0.000 0.000 0.112 0.112 :22(use_fast)\n", " 100 0.001 0.000 0.112 0.001 :10(fast)\n", " 1 0.000 0.000 0.112 0.112 :1()\n", "\n", "\n" ] }, { "metadata": {}, "output_type": "pyout", "prompt_number": 37, "text": [ "" ] } ], "prompt_number": 37 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or sort by time" ] }, { "cell_type": "code", "collapsed": false, "input": [ "stats.sort_stats(\"time\").print_stats()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Fri Feb 21 13:55:09 2014 optimizing/fast.stats\n", "\n", " 203 function calls in 0.112 seconds\n", "\n", " Ordered by: internal time\n", "\n", " ncalls tottime percall cumtime percall filename:lineno(function)\n", " 100 0.111 0.001 0.111 0.001 {time.sleep}\n", " 100 0.001 0.000 0.112 0.001 :10(fast)\n", " 1 0.000 0.000 0.112 0.112 :22(use_fast)\n", " 1 0.000 0.000 0.112 0.112 :1()\n", " 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}\n", "\n", "\n" ] }, { "metadata": {}, "output_type": "pyout", "prompt_number": 38, "text": [ "" ] } ], "prompt_number": 38 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or print out who is calling a certain function:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "stats.print_callers(\"fast\")" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " Ordered by: internal time\n", " List reduced from 5 to 2 due to restriction <'fast'>\n", "\n", "Function was called by...\n", " ncalls tottime cumtime\n", ":10(fast) <- 100 0.001 0.112 :22(use_fast)\n", ":22(use_fast) <- 1 0.000 0.112 :1()\n", "\n", "\n" ] }, { "metadata": {}, "output_type": "pyout", "prompt_number": 39, "text": [ "" ] } ], "prompt_number": 39 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or who is calling you:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "stats.print_callees(\"use_fast\")" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " Ordered by: internal time\n", " List reduced from 5 to 1 due to restriction <'use_fast'>\n", "\n", "Function called...\n", " ncalls tottime cumtime\n", ":22(use_fast) -> 100 0.001 0.112 :10(fast)\n", "\n", "\n" ] }, { "metadata": {}, "output_type": "pyout", "prompt_number": 40, "text": [ "" ] } ], "prompt_number": 40 }, { "cell_type": "code", "collapsed": false, "input": [ "profiler = cProfile.Profile()" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 33 }, { "cell_type": "code", "collapsed": false, "input": [ "profiler.runcall(slow)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 34 }, { "cell_type": "code", "collapsed": false, "input": [ "profiler.print_stats()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " 3 function calls in 0.101 seconds\n", "\n", " Ordered by: standard name\n", "\n", " ncalls tottime percall cumtime percall filename:lineno(function)\n", " 1 0.000 0.000 0.101 0.101 :16(slow)\n", " 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}\n", " 1 0.101 0.101 0.101 0.101 {time.sleep}\n", "\n", "\n" ] } ], "prompt_number": 35 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Wall clock vs CPU time\n", "\n", "- We've measured wall clock time, time between start and top. How long was CPU actually occupied?\n", "- The `timeit` module's timer by default gives the CPU time, in particular `timeit.default_timer()`.\n", "- `cProfiler` can be used to do both, and by default measures wall-clock time.\n", "- In Python 2 need to be clever to specify the highest precision timer available for Windows. Not necessary for Linux/Mac." ] }, { "cell_type": "code", "collapsed": false, "input": [ "%load optimizing/measuring/cpu_time.py" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 41 }, { "cell_type": "code", "collapsed": false, "input": [ "# file: cpu_time.py\n", "\n", "\"\"\"Measuring CPU time instead of wall clock time.\n", "\"\"\"\n", "\n", "import cProfile\n", "import os\n", "import sys\n", "import time\n", "\n", "# Make it work with Python 2 and Python 3.\n", "if sys.version_info[0] < 3:\n", " range = xrange\n", "\n", "\n", "# This is important for Python 2.\n", "def cpu_time():\n", " \"\"\"Function for cpu time. Os dependent.\n", " \"\"\"\n", " if sys.platform == 'win32':\n", " return os.times()[0]\n", " else:\n", " return time.clock()\n", "\n", "\n", "def sleep():\n", " \"\"\"Wait 2 seconds.\n", " \"\"\"\n", " time.sleep(2)\n", "\n", "\n", "def count():\n", " \"\"\"100 million loops.\n", " \"\"\"\n", " for _ in range(int(1e8)):\n", " 1 + 1\n", "\n", "\n", "def test():\n", " \"\"\"Run functions\n", " \"\"\"\n", " sleep()\n", " count()\n", "\n", "\n", "def clock_check():\n", " \"\"\"Profile with wall clock and cpu time.\n", " \"\"\"\n", " \n", " #\u00a0wall clock time (first print block)\n", " profiler = cProfile.Profile()\n", " profiler.run('test()')\n", " profiler.print_stats()\n", "\n", " #\u00a0cpu time (second print block)\n", " profiler = cProfile.Profile(cpu_time)\n", " profiler.run('test()')\n", " profiler.print_stats()\n", "\n", "if __name__ == '__main__':\n", " clock_check()\n" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " 6 function calls in 5.888 seconds\n", "\n", " Ordered by: standard name\n", "\n", " ncalls tottime percall cumtime percall filename:lineno(function)\n", " 1 0.000 0.000 2.001 2.001 :25(sleep)\n", " 1 3.886 3.886 3.886 3.886 :31(count)\n", " 1 0.000 0.000 5.888 5.888 :38(test)\n", " 1 0.000 0.000 5.888 5.888 :1()\n", " 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}\n", " 1 2.001 2.001 2.001 2.001 {time.sleep}\n", "\n", "\n", " " ] }, { "output_type": "stream", "stream": "stdout", "text": [ " 6 function calls in 3.659 seconds\n", "\n", " Ordered by: standard name\n", "\n", " ncalls tottime percall cumtime percall filename:lineno(function)\n", " 1 0.000 0.000 0.000 0.000 :25(sleep)\n", " 1 3.659 3.659 3.659 3.659 :31(count)\n", " 1 0.000 0.000 3.659 3.659 :38(test)\n", " 1 0.000 0.000 3.659 3.659 :1()\n", " 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}\n", " 1 0.000 0.000 0.000 0.000 {time.sleep}\n", "\n", "\n" ] } ], "prompt_number": 44 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Line profiling\n", "\n", " pip install line_profiler\n", " \n", "- You need to decorate functions you want to call. Then Python script then only callable via `kernprof.py`." ] }, { "cell_type": "code", "collapsed": false, "input": [ "!cat optimizing/measuring/profile_me_use_line_profiler.py\n", "!kernprof.py -l -v optimizing/measuring/profile_me_use_line_profiler.py" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "# file profile_me_use_line_profiler.py\r\n", "\r\n", "\"\"\"Example to be profiled.\r\n", "\"\"\"\r\n", "\r\n", "import time\r\n", "\r\n", "\r\n", "def fast():\r\n", " \"\"\"Wait 0.001 seconds.\r\n", " \"\"\"\r\n", " time.sleep(1e-3)\r\n", "\r\n", "\r\n", "def slow():\r\n", " \"\"\"Wait 0.1 seconds.\r\n", " \"\"\"\r\n", " time.sleep(0.1)\r\n", "\r\n", "@profile\r\n", "def use_fast():\r\n", " \"\"\"Call `fast` 100 times.\r\n", " \"\"\"\r\n", " for _ in xrange(100):\r\n", " fast()\r\n", "\r\n", "@profile\r\n", "def use_slow():\r\n", " \"\"\"Call `slow` 100 times.\r\n", " \"\"\"\r\n", " for _ in xrange(100):\r\n", " slow()\r\n", "\r\n", "\r\n", "if __name__ == '__main__':\r\n", " use_fast()\r\n", " use_slow()\r\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Wrote profile results to profile_me_use_line_profiler.py.lprof\r\n", "Timer unit: 1e-06 s\r\n", "\r\n", "File: optimizing/measuring/profile_me_use_line_profiler.py\r\n", "Function: use_fast at line 20\r\n", "Total time: 0.224622 s\r\n", "\r\n", "Line # Hits Time Per Hit % Time Line Contents\r\n", "==============================================================\r\n", " 20 @profile\r\n", " 21 def use_fast():\r\n", " 22 \"\"\"Call `fast` 100 times.\r\n", " 23 \"\"\"\r\n", " 24 101 532 5.3 0.2 for _ in xrange(100):\r\n", " 25 100 224090 2240.9 99.8 fast()\r\n", "\r\n", "File: optimizing/measuring/profile_me_use_line_profiler.py\r\n", "Function: use_slow at line 27\r\n", "Total time: 10.1059 s\r\n", "\r\n", "Line # Hits Time Per Hit % Time Line Contents\r\n", "==============================================================\r\n", " 27 @profile\r\n", " 28 def use_slow():\r\n", " 29 \"\"\"Call `slow` 100 times.\r\n", " 30 \"\"\"\r\n", " 31 101 836 8.3 0.0 for _ in xrange(100):\r\n", " 32 100 10105048 101050.5 100.0 slow()\r\n", "\r\n" ] } ], "prompt_number": 52 }, { "cell_type": "code", "collapsed": false, "input": [ "!cat optimizing/measuring/accumulate.py\n", "!kernprof.py -l -v optimizing/measuring/accumulate.py" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "# file accumulate.py\r\n", "\r\n", "\"\"\"Simple test function for line_profiler.\r\n", "\"\"\"\r\n", "\r\n", "@profile\r\n", "def accumulate(iterable):\r\n", " \"\"\"Accumulate the intermediate steps in summing all elements.\r\n", "\r\n", " The result is a list with the length of `iterable`.\r\n", " The last element is the sum of all elements of `iterable`\r\n", " >>>accumulate(range(5))\r\n", " [0, 1, 3, 6, 10]\r\n", " accumulate(range(10))\r\n", " [0, 1, 3, 6, 10, 15, 21, 28, 36, 45]\r\n", " \"\"\"\r\n", " acm = [iterable[0]]\r\n", " for elem in iterable[1:]:\r\n", " old_value = acm[-1]\r\n", " new_value = old_value + elem\r\n", " acm.append(new_value)\r\n", " return acm\r\n", "\r\n", "\r\n", "if __name__ == '__main__':\r\n", " accumulate(range(10))\r\n", " accumulate(range(100))\r\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Wrote profile results to accumulate.py.lprof\r\n", "Timer unit: 1e-06 s\r\n", "\r\n", "File: optimizing/measuring/accumulate.py\r\n", "Function: accumulate at line 6\r\n", "Total time: 0.000835 s\r\n", "\r\n", "Line # Hits Time Per Hit % Time Line Contents\r\n", "==============================================================\r\n", " 6 @profile\r\n", " 7 def accumulate(iterable):\r\n", " 8 \"\"\"Accumulate the intermediate steps in summing all elements.\r\n", " 9 \r\n", " 10 The result is a list with the length of `iterable`.\r\n", " 11 The last element is the sum of all elements of `iterable`\r\n", " 12 >>>accumulate(range(5))\r\n", " 13 [0, 1, 3, 6, 10]\r\n", " 14 accumulate(range(10))\r\n", " 15 [0, 1, 3, 6, 10, 15, 21, 28, 36, 45]\r\n", " 16 \"\"\"\r\n", " 17 2 8 4.0 1.0 acm = [iterable[0]]\r\n", " 18 110 183 1.7 21.9 for elem in iterable[1:]:\r\n", " 19 108 194 1.8 23.2 old_value = acm[-1]\r\n", " 20 108 189 1.8 22.6 new_value = old_value + elem\r\n", " 21 108 257 2.4 30.8 acm.append(new_value)\r\n", " 22 2 4 2.0 0.5 return acm\r\n", "\r\n" ] } ], "prompt_number": 51 }, { "cell_type": "code", "collapsed": false, "input": [ "!cat optimizing/measuring/calc.py\n", "!kernprof.py -l -v optimizing/measuring/calc.py" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "#calc.py\r\n", "\r\n", "\"\"\"Simple test function for line_profiler doing some math.\r\n", "\"\"\"\r\n", "\r\n", "import math\r\n", "\r\n", "\r\n", "@profile\r\n", "def calc(number, loops=1000):\r\n", " \"\"\"Do some math calculations.\r\n", " \"\"\"\r\n", " sqrt = math.sqrt\r\n", " for x in xrange(loops):\r\n", " x = number + 10\r\n", " x = number * 10\r\n", " x = number ** 10\r\n", " x = pow(x, 10)\r\n", " x = math.sqrt(number)\r\n", " x = sqrt(number)\r\n", " math.sqrt\r\n", " sqrt\r\n", "\r\n", "if __name__ == '__main__':\r\n", " calc(100, int(1e5))\r\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Wrote profile results to calc.py.lprof\r\n", "Timer unit: 1e-06 s\r\n", "\r\n", "File: optimizing/measuring/calc.py\r\n", "Function: calc at line 9\r\n", "Total time: 3.22063 s\r\n", "\r\n", "Line # Hits Time Per Hit % Time Line Contents\r\n", "==============================================================\r\n", " 9 @profile\r\n", " 10 def calc(number, loops=1000):\r\n", " 11 \"\"\"Do some math calculations.\r\n", " 12 \"\"\"\r\n", " 13 1 4 4.0 0.0 sqrt = math.sqrt\r\n", " 14 100001 181809 1.8 5.6 for x in xrange(loops):\r\n", " 15 100000 222135 2.2 6.9 x = number + 10\r\n", " 16 100000 203972 2.0 6.3 x = number * 10\r\n", " 17 100000 738871 7.4 22.9 x = number ** 10\r\n", " 18 100000 878143 8.8 27.3 x = pow(x, 10)\r\n", " 19 100000 312327 3.1 9.7 x = math.sqrt(number)\r\n", " 20 100000 264540 2.6 8.2 x = sqrt(number)\r\n", " 21 100000 218328 2.2 6.8 math.sqrt\r\n", " 22 100000 200501 2.0 6.2 sqrt\r\n", "\r\n" ] } ], "prompt_number": 50 }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you're willing to accept a performance hit you can catch the NameError exception and define an empty `profile` decorator, and let your program be executable without `kernprof.py`." ] }, { "cell_type": "code", "collapsed": false, "input": [ "try:\n", " @profile\n", " def dummy():\n", " \"\"\"Needs to be here to avoid syntax error\"\"\"\n", " pass\n", "except NameError:\n", " def profile(func):\n", " \"\"\"Empty decorator if not under kernprof.py\"\"\"\n", " return func" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 53 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Do local references of functions make a difference?\n", "\n", "Often claimed to be much faster." ] }, { "cell_type": "code", "collapsed": false, "input": [ "!cat optimizing/measuring/local_ref.py\n", "!kernprof.py -l -v optimizing/measuring/local_ref.py\n", "!kernprof.py -v optimizing/measuring/local_ref.py" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "# local_ref.py\r\n", "\r\n", "\"\"\"Testing access to local name and name referenced on another module.\r\n", "\"\"\"\r\n", "\r\n", "import math\r\n", "\r\n", "# If there is no decorator `profile`, make one that just calls the function,\r\n", "# i.e. does nothing.\r\n", "# This allows to call `kernprof` with and without the option `-l` without\r\n", "# commenting or un-commentimg `@profile' all the time.\r\n", "# You can add this to the builtins to make it available in the whole program.\r\n", "try:\r\n", " @profile\r\n", " def dummy():\r\n", " \"\"\"Needs to be here to avoid a syntax error.\r\n", " \"\"\"\r\n", " pass\r\n", "except NameError:\r\n", " def profile(func):\r\n", " \"\"\"Will act as the decorator `profile` if it was already found.\r\n", " \"\"\"\r\n", " return func\r\n", "\r\n", "\r\n", "def local_ref(counter):\r\n", " \"\"\"Access local name.\r\n", " \"\"\"\r\n", " # make it local\r\n", " sqrt = math.sqrt\r\n", " for _ in xrange(counter):\r\n", " sqrt\r\n", "\r\n", "\r\n", "def module_ref(counter):\r\n", " \"\"\"Access name as attribute of another module.\r\n", " \"\"\"\r\n", " for _ in xrange(counter):\r\n", " math.sqrt\r\n", "\r\n", "\r\n", "@profile\r\n", "def test(counter):\r\n", " \"\"\"Call both functions.\r\n", " \"\"\"\r\n", " local_ref(counter)\r\n", " module_ref(counter)\r\n", "\r\n", "if __name__ == '__main__':\r\n", " test(int(1e6))\r\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Wrote profile results to local_ref.py.lprof\r\n", "Timer unit: 1e-06 s\r\n", "\r\n", "File: optimizing/measuring/local_ref.py\r\n", "Function: dummy at line 14\r\n", "Total time: 0 s\r\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\r\n", "Line # Hits Time Per Hit % Time Line Contents\r\n", "==============================================================\r\n", " 14 @profile\r\n", " 15 def dummy():\r\n", " 16 \"\"\"Needs to be here to avoid a syntax error.\r\n", " 17 \"\"\"\r\n", " 18 pass\r\n", "\r\n", "File: optimizing/measuring/local_ref.py\r\n", "Function: test at line 42\r\n", "Total time: 2.81661 s\r\n", "\r\n", "Line # Hits Time Per Hit % Time Line Contents\r\n", "==============================================================\r\n", " 42 @profile\r\n", " 43 def test(counter):\r\n", " 44 \"\"\"Call both functions.\r\n", " 45 \"\"\"\r\n", " 46 1 1431722 1431722.0 50.8 local_ref(counter)\r\n", " 47 1 1384886 1384886.0 49.2 module_ref(counter)\r\n", "\r\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Wrote profile results to local_ref.py.prof\r\n", " 8 function calls in 0.269 seconds\r\n", "\r\n", " Ordered by: standard name\r\n", "\r\n", " ncalls tottime percall cumtime percall filename:lineno(function)\r\n", " 1 0.000 0.000 0.269 0.269 :1()\r\n", " 1 0.000 0.000 0.000 0.000 local_ref.py:20(profile)\r\n", " 1 0.069 0.069 0.069 0.069 local_ref.py:26(local_ref)\r\n", " 1 0.199 0.199 0.199 0.199 local_ref.py:35(module_ref)\r\n", " 1 0.001 0.001 0.269 0.269 local_ref.py:4()\r\n", " 1 0.000 0.000 0.268 0.268 local_ref.py:42(test)\r\n", " 1 0.001 0.001 0.269 0.269 {execfile}\r\n", " 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}\r\n", "\r\n", "\r\n" ] } ], "prompt_number": 56 }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Note that using line profiling (-l) increases total run time by an order of magnitude\n", "- Note that the local reference is, proportionally, significantly faster, but is unlikely to be the CPU bottleneck in your application" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##\u00a0Profiling Memory Usage\n", "\n", "- `guppy` heaves you heappy. `pip install guppy`.\n", "- !!AI this isn't working in the IPython Notebook. Maybe the way it calls into the IPython kernel doesn't let this work?" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from guppy import hpy\n", "h = hpy()" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 62 }, { "cell_type": "code", "collapsed": false, "input": [ "h.heap()" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 68, "text": [ "Partition of a set of 277252 objects. Total size = 37926632 bytes.\n", " Index Count % Size % Cumulative % Kind (class / dict of class)\n", " 0 125560 45 14174840 37 14174840 37 str\n", " 1 65536 24 5839736 15 20014576 53 tuple\n", " 2 778 0 2525680 7 22540256 59 dict of module\n", " 3 2131 1 2323528 6 24863784 66 dict (no owner)\n", " 4 16485 6 2110080 6 26973864 71 types.CodeType\n", " 5 16251 6 1950120 5 28923984 76 function\n", " 6 1717 1 1549256 4 30473240 80 type\n", " 7 1713 1 1429272 4 31902512 84 dict of type\n", " 8 675 0 642888 2 32545400 86 dict of class\n", " 9 3547 1 624472 2 33169872 87 list\n", "<756 more rows. Type e.g. '_.more' to view.>" ] } ], "prompt_number": 68 }, { "cell_type": "code", "collapsed": false, "input": [ "biglist = range(1000000)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 69 }, { "cell_type": "code", "collapsed": false, "input": [ "h.heap()" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 70, "text": [ "Partition of a set of 277274 objects. Total size = 37929160 bytes.\n", " Index Count % Size % Cumulative % Kind (class / dict of class)\n", " 0 125570 45 14176216 37 14176216 37 str\n", " 1 65538 24 5839912 15 20016128 53 tuple\n", " 2 778 0 2525680 7 22541808 59 dict of module\n", " 3 2131 1 2323528 6 24865336 66 dict (no owner)\n", " 4 16485 6 2110080 6 26975416 71 types.CodeType\n", " 5 16251 6 1950120 5 28925536 76 function\n", " 6 1717 1 1549256 4 30474792 80 type\n", " 7 1713 1 1429272 4 31904064 84 dict of type\n", " 8 675 0 642888 2 32546952 86 dict of class\n", " 9 3549 1 624744 2 33171696 87 list\n", "<756 more rows. Type e.g. '_.more' to view.>" ] } ], "prompt_number": 70 }, { "cell_type": "code", "collapsed": false, "input": [ "h.heap()[0]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 72, "text": [ "Partition of a set of 125655 objects. Total size = 14187984 bytes.\n", " Index Count % Size % Cumulative % Kind (class / dict of class)\n", " 0 125655 100 14187984 100 14187984 100 str" ] } ], "prompt_number": 72 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here are some command-line examples of `hpy`. We've written our own decorator to track the memory change resulting from a function call." ] }, { "cell_type": "code", "collapsed": false, "input": [ "!cat optimizing/measuring/memory_size_hpy.py\n", "!python optimizing/measuring/memory_size_hpy.py" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "# file: memory_size_hpy.py\r\n", "\r\n", "\"\"\"Measure the size of used memory with a decorator.\r\n", "\"\"\"\r\n", "\r\n", "import functools #1\r\n", "\r\n", "from guppy import hpy #2\r\n", "\r\n", "memory = {} #3\r\n", "\r\n", "\r\n", "def measure_memory(function): #4\r\n", " \"\"\"Decorator to measure memory size.\r\n", " \"\"\"\r\n", "\r\n", " @functools.wraps(function) #5\r\n", " def _measure_memory(*args, **kwargs): #6\r\n", " \"\"\"This replaces the function that is to be measured.\r\n", " \"\"\"\r\n", " measurer = hpy() #7\r\n", " measurer.setref() #8\r\n", " inital_memory = measurer.heap().size #9\r\n", " try:\r\n", " res = function(*args, **kwargs) #10\r\n", " return res\r\n", " finally: #11\r\n", " memory[function.__name__] = (measurer.heap().size -\r\n", " inital_memory)\r\n", " return _measure_memory #12\r\n", "\r\n", "\r\n", "if __name__ == '__main__':\r\n", "\r\n", " @measure_memory #13\r\n", " def make_big(number):\r\n", " \"\"\"Example function that makes a large list.\r\n", " \"\"\"\r\n", " return range(number) #14\r\n", "\r\n", " make_big(int(1e6)) #15\r\n", " print 'used memory', memory #16\r\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "used memory {'make_big': 32124976}\r\n" ] } ], "prompt_number": 74 }, { "cell_type": "markdown", "metadata": {}, "source": [ "And again we can use the same `kernprof.py` empty profile decorator as before if we wanted to no-op this decorator in code." ] }, { "cell_type": "code", "collapsed": false, "input": [ "!cat optimizing/measuring/memory_growth_hpy.py\n", "!python optimizing/measuring/memory_growth_hpy.py" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "# file memory._growth_hpy.py\r\n", "\r\n", "\"\"\"Measure the memory growth during a function call.\r\n", "\"\"\"\r\n", "\r\n", "from guppy import hpy #1\r\n", "\r\n", "\r\n", "def check_memory_growth(function, *args, **kwargs): #2\r\n", " \"\"\"Measure the memory usage of `function`.\r\n", " \"\"\"\r\n", " measurer = hpy() #3\r\n", " measurer.setref() #4\r\n", " inital_memory = measurer.heap().size #5\r\n", " function(*args, **kwargs) #6\r\n", " return measurer.heap().size - inital_memory #7\r\n", "\r\n", "if __name__ == '__main__':\r\n", "\r\n", " def test():\r\n", " \"\"\"Do some tests with different memory usage patterns.\r\n", " \"\"\"\r\n", "\r\n", " def make_big(number): #8\r\n", " \"\"\"Function without side effects.\r\n", "\r\n", " It cleans up all used memory after it returns.\r\n", " \"\"\"\r\n", " return range(number)\r\n", "\r\n", " data = [] #9\r\n", "\r\n", " def grow(number):\r\n", " \"\"\"Function with side effects on global list.\r\n", " \"\"\"\r\n", " for x in xrange(number):\r\n", " data.append(x) #10\r\n", " size = int(1e6)\r\n", " print 'memory make_big:', check_memory_growth(make_big,\r\n", " size) #11\r\n", " print 'memory grow:', check_memory_growth(grow, size) #12\r\n", "\r\n", " test()\r\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "memory make_big: 1320\r\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "memory grow: 23998472\r\n" ] } ], "prompt_number": 76 }, { "cell_type": "markdown", "metadata": {}, "source": [ "`make_big` is very small because CPython uses a reference-counted synchronous garbage collector. The unused value is immediately garbage collected." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using pympler for memory profiling\n", "\n", "Easier to compile for Python 2.7+" ] }, { "cell_type": "code", "collapsed": false, "input": [ "!cat optimizing/measuring/memory_growth_pympler.py\n", "!python optimizing/measuring/memory_growth_pympler.py" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "# file memory_growth_pympler.py\r\n", "\r\n", "\"\"\"Measure the memory growth during a function call.\r\n", "\"\"\"\r\n", "\r\n", "from pympler import tracker #1\r\n", "\r\n", "\r\n", "def check_memory_growth(function, *args, **kwargs): #2\r\n", " \"\"\"Measure the memory usage of `function`.\r\n", " \"\"\"\r\n", " measurer = tracker.SummaryTracker() #3\r\n", " for _ in xrange(5): #4\r\n", " measurer.diff() #5 \r\n", " function(*args, **kwargs) #6\r\n", " return measurer.diff() #7\r\n", "\r\n", "if __name__ == '__main__':\r\n", "\r\n", " def test():\r\n", " \"\"\"Do some tests with different memory usage patterns.\r\n", " \"\"\"\r\n", "\r\n", " def make_big(number): #8\r\n", " \"\"\"Function without side effects.\r\n", "\r\n", " It cleans up all used memory after it returns.\r\n", " \"\"\"\r\n", " return range(number)\r\n", "\r\n", " data = [] #9\r\n", "\r\n", " def grow(number):\r\n", " \"\"\"Function with side effects on global list.\r\n", " \"\"\"\r\n", " for x in xrange(number):\r\n", " data.append(x) #10\r\n", " size = int(1e6)\r\n", " print 'memory make_big:', check_memory_growth(make_big,\r\n", " size) #11\r\n", " print 'memory grow:', check_memory_growth(grow, size) #12\r\n", "\r\n", " test()\r\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "memory make_big: []\r\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "memory grow: [['list', 0, 8697400], ['int', 999860, 23996640]]\r\n" ] } ], "prompt_number": 81 }, { "cell_type": "markdown", "metadata": {}, "source": [ "!!AI why is make_big empty?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "###\u00a0Different pympler ways of measuring size of an object" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import sys\n", "from pympler.asizeof import asizeof, flatsize\n", "\n", "def list_mem(length, size_func=flatsize):\n", " \"\"\"Measure incremental memory increase of a growing list.\n", " \"\"\"\n", " my_list= []\n", " mem = [size_func(my_list)]\n", " for elem in xrange(length):\n", " my_list.append(elem)\n", " mem.append(size_func(my_list))\n", " return mem\n", "\n", "SIZE = 1000\n", "SHOW = 20" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 94 }, { "cell_type": "code", "collapsed": false, "input": [ "plot(list_mem(SIZE, size_func=flatsize))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 95, "text": [ "[]" ] }, { "metadata": {}, "output_type": "display_data", "png": "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\n", "text": [ "" ] } ], "prompt_number": 95 }, { "cell_type": "code", "collapsed": false, "input": [ "plot(list_mem(SIZE, size_func=asizeof))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 96, "text": [ "[]" ] }, { "metadata": {}, "output_type": "display_data", "png": "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\n", "text": [ "" ] } ], "prompt_number": 96 }, { "cell_type": "code", "collapsed": false, "input": [ "plot(list_mem(SIZE, size_func=sys.getsizeof))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 97, "text": [ "[]" ] }, { "metadata": {}, "output_type": "display_data", "png": "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\n", "text": [ "" ] } ], "prompt_number": 97 }, { "cell_type": "markdown", "metadata": {}, "source": [ "- `sys.getsizeof` is the same thing as `pympler.flatsize`." ] }, { "cell_type": "code", "collapsed": false, "input": [ "%load optimizing/measuring/list_alloc_steps.py" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 102 }, { "cell_type": "code", "collapsed": false, "input": [ "# file: list_alloc_steps.py\n", "\n", "\"\"\"Measure the number of memory allocation steps for a list.\n", "\"\"\"\n", "\n", "import sys\n", "\n", "from pympler.asizeof import flatsize\n", "\n", "\n", "def list_steps(lenght, size_func=sys.getsizeof):\n", " \"\"\"Measure the number of memory alloaction steps for a list.\n", " \"\"\"\n", " my_list = []\n", " steps = 0\n", " int_size = size_func(int())\n", " old_size = size_func(my_list)\n", " for elem in xrange(lenght):\n", " my_list.append(elem)\n", " new_size = sys.getsizeof(my_list)\n", " if new_size - old_size > int_size:\n", " steps += 1\n", " old_size = new_size\n", " return steps\n", "\n", "\n", "if __name__ == '__main__':\n", " print 'Using sys.getsizeof:'\n", " for size in [10, 100, 1000, 10000, int(1e5), int(1e6), int(1e7)]:\n", " print '%10d: %3d' % (size, list_steps(size))\n", " print 'Using pympler.asizeof.flatsize:'\n", " for size in [10, 100, 1000, 10000, int(1e5), int(1e6), int(1e7)]:\n", " print '%10d: %3d' % (size, list_steps(size, flatsize))\n" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "!python optimizing/measuring/list_alloc_steps.py" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Using sys.getsizeof:\r\n", " 10: 3\r\n", " 100: 10\r\n", " 1000: 27\r\n", " 10000: 46\r\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ " 100000: 65\r\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ " 1000000: 85\r\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ " 10000000: 104\r\n", "Using pympler.asizeof.flatsize:\r\n", " 10: 3\r\n", " 100: 10\r\n", " 1000: 27\r\n", " 10000: 46\r\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ " 100000: 65\r\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ " 1000000: 85\r\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ " 10000000: 104\r\n" ] } ], "prompt_number": 103 }, { "cell_type": "markdown", "metadata": {}, "source": [ "There's a line memory profiler, look in the handout." ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] } ], "metadata": {} } ] }