Skip to content

Commit e0a5e7d

Browse files
committed
More docs
docs/source/manual/examples/example_kernprof.rst New page for decumenting various `kernprof` docs/source/manual/examples/index.rst kernprof.py::__doc__ Added links to the above
1 parent eb451de commit e0a5e7d

File tree

3 files changed

+290
-0
lines changed

3 files changed

+290
-0
lines changed
Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
``kernprof`` invocations
2+
========================
3+
4+
The module (and installed script) :py:mod:`kernprof` can be used to run
5+
and profile Python code in various forms.
6+
7+
For the following, we assume that we have:
8+
9+
* the below file ``fib.py`` in the current directory,
10+
* the current directory in ``${PYTHONPATH}``, and
11+
* :py:mod:`line_profiler` and :py:mod:`kernprof` installed.
12+
13+
.. code:: python
14+
15+
import functools
16+
import sys
17+
from argparse import ArgumentParser
18+
from typing import Callable, Optional, Sequence
19+
20+
21+
@functools.lru_cache()
22+
def fib(n: int) -> int:
23+
return _run_fib(fib, n)
24+
25+
26+
def fib_no_cache(n: int) -> int:
27+
return _run_fib(fib_no_cache, n)
28+
29+
30+
def _run_fib(fib: Callable[[int], int], n: int) -> int:
31+
if n < 0:
32+
raise ValueError(f'{n = !r}: expected non-negative integer')
33+
if n < 2:
34+
return 1
35+
prev_prev = fib(n - 2)
36+
prev = fib(n - 1)
37+
return prev_prev + prev
38+
39+
40+
def main(args: Optional[Sequence[str]] = None) -> None:
41+
parser = ArgumentParser()
42+
parser.add_argument('n', nargs='+', type=int)
43+
parser.add_argument('--verbose', action='store_true')
44+
parser.add_argument('--no-cache', action='store_true')
45+
arguments = parser.parse_args(args)
46+
47+
pattern = 'fib({!r}) = {!r}' if arguments.verbose else '{1!r}'
48+
func = fib_no_cache if arguments.no_cache else fib
49+
50+
for n in arguments.n:
51+
result = func(n)
52+
print(pattern.format(n, result))
53+
54+
55+
if __name__ == '__main__':
56+
main()
57+
58+
59+
Script execution
60+
----------------
61+
62+
In the most basic form, one passes the path to the executed script and
63+
its arguments to ``kernprof``:
64+
65+
.. code:: console
66+
67+
$ kernprof --prof-mod fib.py --line-by-line --view \
68+
> fib.py --verbose 10 20 30
69+
fib(10) = 89
70+
fib(20) = 10946
71+
fib(30) = 1346269
72+
Wrote profile results to fib.py.lprof
73+
Timer unit: 1e-06 s
74+
75+
Total time: 5.6e-05 s
76+
File: fib.py
77+
Function: fib at line 7
78+
79+
Line # Hits Time Per Hit % Time Line Contents
80+
==============================================================
81+
7 @functools.lru_cache()
82+
8 def fib(n: int) -> int:
83+
9 31 56.0 1.8 100.0 return _run_fib(fib, n)
84+
85+
Total time: 0 s
86+
File: fib.py
87+
Function: fib_no_cache at line 12
88+
89+
Line # Hits Time Per Hit % Time Line Contents
90+
==============================================================
91+
12 def fib_no_cache(n: int) -> int:
92+
13 return _run_fib(fib_no_cache, n)
93+
94+
Total time: 3.8e-05 s
95+
File: fib.py
96+
Function: _run_fib at line 16
97+
98+
Line # Hits Time Per Hit % Time Line Contents
99+
==============================================================
100+
16 def _run_fib(fib: Callable[[int], int], n: int) -> int:
101+
17 31 3.0 0.1 7.9 if n < 0:
102+
18 raise ValueError(f'{n = !r}: expected non-negative integer')
103+
19 31 2.0 0.1 5.3 if n < 2:
104+
20 2 0.0 0.0 0.0 return 1
105+
21 29 18.0 0.6 47.4 prev_prev = fib(n - 2)
106+
22 29 12.0 0.4 31.6 prev = fib(n - 1)
107+
23 29 3.0 0.1 7.9 return prev_prev + prev
108+
109+
Total time: 0.000486 s
110+
File: fib.py
111+
Function: main at line 26
112+
113+
Line # Hits Time Per Hit % Time Line Contents
114+
==============================================================
115+
26 def main(args: Optional[Sequence[str]] = None) -> None:
116+
27 1 184.0 184.0 37.9 parser = ArgumentParser()
117+
28 1 17.0 17.0 3.5 parser.add_argument('n', nargs='+', type=int)
118+
29 1 16.0 16.0 3.3 parser.add_argument('--verbose', action='store_true')
119+
30 1 14.0 14.0 2.9 parser.add_argument('--no-cache', action='store_true')
120+
31 1 144.0 144.0 29.6 arguments = parser.parse_args(args)
121+
32
122+
33 1 0.0 0.0 0.0 pattern = 'fib({!r}) = {!r}' if arguments.verbose else '{1!r}'
123+
34 1 0.0 0.0 0.0 func = fib_no_cache if arguments.no_cache else fib
124+
35
125+
36 4 0.0 0.0 0.0 for n in arguments.n:
126+
37 3 91.0 30.3 18.7 result = func(n)
127+
38 3 20.0 6.7 4.1 print(pattern.format(n, result))
128+
129+
.. _kernprof-script-note:
130+
.. note::
131+
132+
Instead of passing the ``--view`` flag to ``kernprof`` to view the
133+
profiling results immediately, sometimes it can be more convenient to
134+
just generate the profiling results and view them later by running
135+
the :py:mod:`line_profiler` module (``python -m line_profiler``).
136+
137+
138+
Module execution
139+
----------------
140+
141+
It is also possible to use ``kernprof -m`` to run installed modules and
142+
packages:
143+
144+
.. code:: console
145+
146+
$ kernprof --prof-mod fib --line-by-line --view -m \
147+
> fib --verbose 10 20 30
148+
fib(10) = 89
149+
fib(20) = 10946
150+
fib(30) = 1346269
151+
Wrote profile results to fib.lprof
152+
...
153+
154+
.. _kernprof-m-note:
155+
.. note::
156+
157+
As with ``python -m``, the ``-m`` option terminates further parsing
158+
of arguments by ``kernprof`` and passes them all to the argument
159+
thereafter (the run module).
160+
If there isn't one, an error is raised:
161+
162+
.. code:: console
163+
164+
$ kernprof -m
165+
Traceback (most recent call last):
166+
...
167+
ValueError: argument expected for the -m option
168+
169+
170+
Literal-code execution
171+
----------------------
172+
173+
Like how ``kernprof -m`` parallels ``python -m``, ``kernprof -c`` can be
174+
used to run and profile literal snippets supplied on the command line
175+
like ``python -c``:
176+
177+
.. code:: console
178+
179+
$ code="import sys; "
180+
$ code+="from fib import _run_fib, fib_no_cache as fib; "
181+
$ code+="for n in sys.argv[1:]: print(f'fib({n})', '=', fib(int(n)))"
182+
$ kernprof --prof-mod fib._run_fib --line-by-line --view -c "${code}" 10 20
183+
fib(10) = 89
184+
fib(20) = 10946
185+
Wrote profile results to <...>/kernprof-command-imuhz89_.lprof
186+
Timer unit: 1e-06 s
187+
188+
Total time: 0.007666 s
189+
File: <...>/fib.py
190+
Function: _run_fib at line 16
191+
192+
Line # Hits Time Per Hit % Time Line Contents
193+
==============================================================
194+
16 def _run_fib(fib: Callable[[int], int], n: int) -> int:
195+
17 22068 1656.0 0.1 20.6 if n < 0:
196+
18 raise ValueError(f'{n = !r}: expected non-negative integer')
197+
19 22068 1663.0 0.1 20.7 if n < 2:
198+
20 11035 814.0 0.1 10.1 return 1
199+
21 11033 1668.0 0.2 20.7 prev_prev = fib(n - 2)
200+
22 11033 1477.0 0.1 18.4 prev = fib(n - 1)
201+
23 11033 770.0 0.1 9.6 return prev_prev + prev
202+
203+
.. note::
204+
205+
* As with ``python -c``, the ``-c`` option terminates further
206+
parsing of arguments by ``kernprof`` and passes them all to the
207+
argument thereafter (the executed code).
208+
If there isn't one, an error is raised as
209+
:ref:`above <kernprof-m-note>` with ``kernprof -m``.
210+
* .. _kernprof-c-note:
211+
Since the temporary file containing the executed code will not
212+
exist beyond the ``kernprof`` process, profiling results
213+
pertaining to targets (function definitions) local to said code
214+
:ref:`will not be accessible later <kernprof-script-note>` by
215+
``python -m line_profiler`` and has to be ``--view``-ed
216+
immediately:
217+
218+
.. code:: console
219+
220+
$ read -d '' -r code <<-'!'
221+
> from fib import fib
222+
>
223+
> def my_func(n=50):
224+
> result = fib(n)
225+
> print(n, '->', result)
226+
>
227+
> my_func()
228+
> !
229+
$ kernprof -lv -c "${code}"
230+
50 -> 20365011074
231+
Wrote profile results to <...>/kernprof-command-ni6nis6t.lprof
232+
Timer unit: 1e-06 s
233+
234+
Total time: 3.8e-05 s
235+
File: <...>/kernprof-command.py
236+
Function: my_func at line 3
237+
238+
Line # Hits Time Per Hit % Time Line Contents
239+
==============================================================
240+
3 def my_func(n=50):
241+
4 1 26.0 26.0 68.4 result = fib(n)
242+
5 1 12.0 12.0 31.6 print(n, '->', result)
243+
244+
$ python -m line_profiler kernprof-command-ni6nis6t.lprof
245+
Timer unit: 1e-06 s
246+
247+
Total time: 3.6e-05 s
248+
249+
Could not find file <...>/kernprof-command.py
250+
Are you sure you are running this program from the same directory
251+
that you ran the profiler from?
252+
Continuing without the function's contents.
253+
254+
Line # Hits Time Per Hit % Time Line Contents
255+
==============================================================
256+
3
257+
4 1 26.0 26.0 72.2
258+
5 1 10.0 10.0 27.8
259+
260+
261+
Executing code read from ``stdin``
262+
----------------------------------
263+
264+
It is also possible to read, run, and profile code from ``stdin``, by
265+
passing ``-`` to ``kernprof`` in place of a filename:
266+
267+
.. code:: console
268+
269+
$ kernprof --prof-mod fib._run_fib --line-by-line --view - 10 20 <<-'!'
270+
> import sys
271+
> from fib import _run_fib, fib_no_cache as fib
272+
> for n in sys.argv[1:]:
273+
> print(f"fib({n})", "=", fib(int(n)))
274+
> !
275+
fib(10) = 89
276+
fib(20) = 10946
277+
Wrote profile results to <...>/kernprof-stdin-kntk2lo1.lprof
278+
...
279+
280+
.. note::
281+
282+
Since the temporary file containing the executed code will not exist
283+
beyond the ``kernprof`` process, profiling results pertaining to
284+
targets (function definitions) local to said code will not be
285+
accessible later and has to be ``--view``-ed immediately
286+
(see :ref:`above note <kernprof-c-note>` on ``kernprof -c``).

docs/source/manual/examples/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ Examples of line profiler usage:
55

66
+ `Basic Usage <../../index.html#line-profiler-basic-usage>`_
77

8+
+ `kernprof invocations <example_kernprof.rst>`_
9+
810
+ `Auto Profiling <../../auto/line_profiler.autoprofile.html#auto-profiling>`_
911

1012
+ `Explicit Profiler <../../auto/line_profiler.explicit_profiler.html#module-line_profiler.explicit_profiler>`_

kernprof.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ def main():
5050
* ``kernprof <options> - <args to code>`` parallels ``python -`` and
5151
executes literal code passed via the ``stdin``.
5252
53+
See also :doc:`kernprof invocations </manual/examples/example_kernprof>`.
54+
5355
For more details and options, refer to the CLI help.
5456
To view kernprof help run:
5557

0 commit comments

Comments
 (0)