File: example_kernprof.rst

package info (click to toggle)
python-line-profiler 5.0.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,256 kB
  • sloc: python: 8,119; sh: 810; ansic: 297; makefile: 14
file content (383 lines) | stat: -rw-r--r-- 12,074 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
``kernprof`` invocations
========================

The module (and installed script) :py:mod:`kernprof` can be used to run
and profile Python code in various forms.

For the following, we assume that we have:

* the below file ``fib.py`` in the current directory, and
* :py:mod:`line_profiler` and :py:mod:`kernprof` installed.

.. code:: python

    import functools
    import sys
    from argparse import ArgumentParser
    from typing import Callable, Optional, Sequence


    @functools.lru_cache()
    def fib(n: int) -> int:
        return _run_fib(fib, n)


    def fib_no_cache(n: int) -> int:
        return _run_fib(fib_no_cache, n)


    def _run_fib(fib: Callable[[int], int], n: int) -> int:
        if n < 0:
            raise ValueError(f'{n = !r}: expected non-negative integer')
        if n < 2:
            return 1
        prev_prev = fib(n - 2)
        prev = fib(n - 1)
        return prev_prev + prev


    def main(args: Optional[Sequence[str]] = None) -> None:
        parser = ArgumentParser()
        parser.add_argument('n', nargs='+', type=int)
        parser.add_argument('--verbose', action='store_true')
        parser.add_argument('--no-cache', action='store_true')
        arguments = parser.parse_args(args)

        pattern = 'fib({!r}) = {!r}' if arguments.verbose else '{1!r}'
        func = fib_no_cache if arguments.no_cache else fib

        for n in arguments.n:
            result = func(n)
            print(pattern.format(n, result))


    if __name__ == '__main__':
        main()


Script execution
----------------

In the most basic form, one passes the path to the executed script and
its arguments to ``kernprof``:

.. code:: bash

    kernprof --prof-mod fib.py --line-by-line --view \
        fib.py --verbose 10 20 30

.. raw:: html

    <details>
    <summary>Output (click to expand)</summary>

.. code::

    fib(10) = 89
    fib(20) = 10946
    fib(30) = 1346269
    Wrote profile results to fib.py.lprof
    Timer unit: 1e-06 s

    Total time: 5.6e-05 s
    File: fib.py
    Function: fib at line 7

    Line #      Hits         Time  Per Hit   % Time  Line Contents
    ==============================================================
         7                                           @functools.lru_cache()
         8                                           def fib(n: int) -> int:
         9        31         56.0      1.8    100.0      return _run_fib(fib, n)

    Total time: 0 s
    File: fib.py
    Function: fib_no_cache at line 12

    Line #      Hits         Time  Per Hit   % Time  Line Contents
    ==============================================================
        12                                           def fib_no_cache(n: int) -> int:
        13                                               return _run_fib(fib_no_cache, n)

    Total time: 3.8e-05 s
    File: fib.py
    Function: _run_fib at line 16

    Line #      Hits         Time  Per Hit   % Time  Line Contents
    ==============================================================
        16                                           def _run_fib(fib: Callable[[int], int], n: int) -> int:
        17        31          3.0      0.1      7.9      if n < 0:
        18                                                   raise ValueError(f'{n = !r}: expected non-negative integer')
        19        31          2.0      0.1      5.3      if n < 2:
        20         2          0.0      0.0      0.0          return 1
        21        29         18.0      0.6     47.4      prev_prev = fib(n - 2)
        22        29         12.0      0.4     31.6      prev = fib(n - 1)
        23        29          3.0      0.1      7.9      return prev_prev + prev

    Total time: 0.000486 s
    File: fib.py
    Function: main at line 26

    Line #      Hits         Time  Per Hit   % Time  Line Contents
    ==============================================================
        26                                           def main(args: Optional[Sequence[str]] = None) -> None:
        27         1        184.0    184.0     37.9      parser = ArgumentParser()
        28         1         17.0     17.0      3.5      parser.add_argument('n', nargs='+', type=int)
        29         1         16.0     16.0      3.3      parser.add_argument('--verbose', action='store_true')
        30         1         14.0     14.0      2.9      parser.add_argument('--no-cache', action='store_true')
        31         1        144.0    144.0     29.6      arguments = parser.parse_args(args)
        32                                           
        33         1          0.0      0.0      0.0      pattern = 'fib({!r}) = {!r}' if arguments.verbose else '{1!r}'
        34         1          0.0      0.0      0.0      func = fib_no_cache if arguments.no_cache else fib
        35                                           
        36         4          0.0      0.0      0.0      for n in arguments.n:
        37         3         91.0     30.3     18.7          result = func(n)
        38         3         20.0      6.7      4.1          print(pattern.format(n, result))

.. raw:: html

    </details>
    <p>


.. _kernprof-script-note:
.. note::

   Instead of passing the ``--view`` flag to ``kernprof`` to view the
   profiling results immediately, sometimes it can be more convenient to
   just generate the profiling results and view them later by running
   the :py:mod:`line_profiler` module (``python -m line_profiler``).


Module execution
----------------

It is also possible to use ``kernprof -m`` to run installed modules and
packages:

.. code:: bash

    PYTHONPATH="${PYTHONPATH}:${PWD}" \
        kernprof --prof-mod fib --line-by-line --view -m \
        fib --verbose 10 20 30

.. raw:: html

    <details>
    <summary>Output (click to expand)</summary>

.. code::

    fib(10) = 89
    fib(20) = 10946
    fib(30) = 1346269
    Wrote profile results to fib.lprof
    ...

.. raw:: html

    </details>
    <p>

.. _kernprof-m-note:
.. note::

    As with ``python -m``, the ``-m`` option terminates further parsing
    of arguments by ``kernprof`` and passes them all to the argument
    thereafter (the run module).
    If there isn't one, an error is raised:

    .. code:: bash

        kernprof -m

    .. raw:: html

        <details>
        <summary>Output (click to expand)</summary>

    .. code:: pycon

        Traceback (most recent call last):
          ...
        ValueError: argument expected for the -m option

    .. raw:: html

        </details>


Literal-code execution
----------------------

Like how ``kernprof -m`` parallels ``python -m``, ``kernprof -c`` can be
used to run and profile literal snippets supplied on the command line
like ``python -c``:

.. code:: bash

    PYTHONPATH="${PYTHONPATH}:${PWD}" \
        kernprof --prof-mod fib._run_fib --line-by-line --view -c "
        import sys
        from fib import _run_fib, fib_no_cache as fib
        for n in sys.argv[1:]:
            print(f'fib({n})', '=', fib(int(n)))
        " 10 20

.. raw:: html

    <details>
    <summary>Output (click to expand)</summary>

.. code::

    fib(10) = 89
    fib(20) = 10946
    Wrote profile results to <...>/kernprof-command-imuhz89_.lprof
    Timer unit: 1e-06 s

    Total time: 0.007666 s
    File: <...>/fib.py
    Function: _run_fib at line 16

    Line #      Hits         Time  Per Hit   % Time  Line Contents
    ==============================================================
        16                                           def _run_fib(fib: Callable[[int], int], n: int) -> int:
        17     22068       1656.0      0.1     20.6      if n < 0:
        18                                                   raise ValueError(f'{n = !r}: expected non-negative integer')
        19     22068       1663.0      0.1     20.7      if n < 2:
        20     11035        814.0      0.1     10.1          return 1
        21     11033       1668.0      0.2     20.7      prev_prev = fib(n - 2)
        22     11033       1477.0      0.1     18.4      prev = fib(n - 1)
        23     11033        770.0      0.1      9.6      return prev_prev + prev

.. raw:: html

    </details>
    <p>

.. note::

    * As with ``python -c``, the ``-c`` option terminates further
      parsing of arguments by ``kernprof`` and passes them all to the
      argument thereafter (the executed code).
      If there isn't one, an error is raised as
      :ref:`above <kernprof-m-note>` with ``kernprof -m``.
    * .. _kernprof-c-note:
      Since the temporary file containing the executed code will not
      exist beyond the ``kernprof`` process, profiling results
      pertaining to targets (function definitions) local to said code
      :ref:`will not be accessible later <kernprof-script-note>` by
      ``python -m line_profiler`` and has to be ``--view``-ed
      immediately:

      .. code:: bash

          PYTHONPATH="${PYTHONPATH}:${PWD}" \
              kernprof --line-by-line --view -c "
              from fib import fib

              def my_func(n=50):
                  result = fib(n)
                  print(n, '->', result)

              my_func()"

      .. raw:: html

          <details>
          <summary>Output (click to expand)</summary>

      .. code::

          50 -> 20365011074
          Wrote profile results to <...>/kernprof-command-ni6nis6t.lprof
          Timer unit: 1e-06 s

          Total time: 3.8e-05 s
          File: <...>/kernprof-command.py
          Function: my_func at line 3

          Line #      Hits         Time  Per Hit   % Time  Line Contents
          ==============================================================
               3                                           def my_func(n=50):
               4         1         26.0     26.0     68.4      result = fib(n)
               5         1         12.0     12.0     31.6      print(n, '->', result)

      .. raw:: html

          </details>
          <p>

      .. code:: bash

          python -m line_profiler kernprof-command-ni6nis6t.lprof

      .. raw:: html

          <details>
          <summary>Output (click to expand)</summary>

      .. code::

          Timer unit: 1e-06 s
          
          Total time: 3.6e-05 s
          
          Could not find file <...>/kernprof-command.py
          Are you sure you are running this program from the same directory
          that you ran the profiler from?
          Continuing without the function's contents.

          Line #      Hits         Time  Per Hit   % Time  Line Contents
          ==============================================================
               3                                           
               4         1         26.0     26.0     72.2  
               5         1         10.0     10.0     27.8  

      .. raw:: html

          </details>


Executing code read from ``stdin``
----------------------------------

It is also possible to read, run, and profile code from ``stdin``, by
passing ``-`` to ``kernprof`` in place of a filename:

.. code:: bash

    {
        # This example doesn't make much sense on its own, but just
        # imagine if this is a command generating code dynamically
        echo 'import sys'
        echo 'from fib import _run_fib, fib_no_cache as fib'
        echo 'for n in sys.argv[1:]:'
        echo '    print(f"fib({n})", "=", fib(int(n)))'
    } | PYTHONPATH="${PYTHONPATH}:${PWD}" \
        kernprof --prof-mod fib._run_fib --line-by-line --view - 10 20

.. raw:: html

    <details>
    <summary>Output (click to expand)</summary>

.. code::

    fib(10) = 89
    fib(20) = 10946
    Wrote profile results to <...>/kernprof-stdin-kntk2lo1.lprof
    ...

.. raw:: html

    </details>
    <p>

.. note::

    Since the temporary file containing the executed code will not exist
    beyond the ``kernprof`` process, profiling results pertaining to
    targets (function definitions) local to said code will not be
    accessible later and has to be ``--view``-ed immediately
    (see :ref:`above note <kernprof-c-note>` on ``kernprof -c``).