Browse Source

Rewrite of Profiling

pull/109/merge
Jure Šorn 1 year ago
parent
commit
ad00805ce2
5 changed files with 109 additions and 94 deletions
  1. 75
      README.md
  2. 83
      index.html
  3. 39
      parse.js
  4. 4
      pdf/index_for_pdf.html
  5. 2
      pdf/index_for_pdf_print.html

75
README.md

@ -1935,14 +1935,14 @@ with <conn>.begin(): ... # Exits the block with commit or
```
```text
+------------+--------------+-----------+----------------------------------+
| Dialect | pip3 install | import | Dependencies |
+------------+--------------+-----------+----------------------------------+
| mysql | mysqlclient | MySQLdb | www.pypi.org/project/mysqlclient |
| postgresql | psycopg2 | psycopg2 | www.pypi.org/project/psycopg2 |
| mssql | pyodbc | pyodbc | www.pypi.org/project/pyodbc |
| oracle | oracledb | oracledb | www.pypi.org/project/oracledb |
+------------+--------------+-----------+----------------------------------+
+------------+--------------+----------+----------------------------------+
| Dialect | pip3 install | import | Dependencies |
+------------+--------------+----------+----------------------------------+
| mysql | mysqlclient | MySQLdb | www.pypi.org/project/mysqlclient |
| postgresql | psycopg2 | psycopg2 | www.pypi.org/project/psycopg2 |
| mssql | pyodbc | pyodbc | www.pypi.org/project/pyodbc |
| oracle | oracledb | oracledb | www.pypi.org/project/oracledb |
+------------+--------------+----------+----------------------------------+
```
@ -2591,49 +2591,48 @@ duration_in_seconds = perf_counter() - start_time
### Timing a Snippet
```python
>>> from timeit import timeit
>>> timeit("''.join(str(i) for i in range(100))",
... number=10000, globals=globals(), setup='pass')
0.34986
>>> timeit('list(range(10000))', number=1000, globals=globals(), setup='pass')
0.19373
```
### Profiling by Line
```python
# $ pip3 install line_profiler memory_profiler
```text
$ pip3 install line_profiler
$ echo "
@profile
def main():
a = [*range(10000)]
b = {*range(10000)}
main()
```
```text
a = list(range(10000))
b = set(range(10000))
main()" > test.py
$ kernprof -lv test.py
Line # Hits Time Per Hit % Time Line Contents
=======================================================
1 @profile
2 def main():
3 1 955.0 955.0 43.7 a = [*range(10000)]
4 1 1231.0 1231.0 56.3 b = {*range(10000)}
$ python3 -m memory_profiler test.py
Line # Mem usage Increment Line Contents
=======================================================
1 37.668 MiB 37.668 MiB @profile
2 def main():
3 38.012 MiB 0.344 MiB a = [*range(10000)]
4 38.477 MiB 0.465 MiB b = {*range(10000)}
3 1 219.0 219.0 31.1 a = list(range(10000))
4 1 487.0 487.0 68.9 b = set(range(10000))
```
### Call Graph
#### Generates a PNG image of the call graph with highlighted bottlenecks:
```python
# $ pip3 install pycallgraph2; apt/brew install graphviz
import pycallgraph2 as cg, datetime
### Call and Flame Graphs
```bash
$ pip3 install gprof2dot snakeviz
$ apt/brew install graphviz
$ python3 -m cProfile -o test.prof test.py
$ gprof2dot -f pstats test.prof | dot -Tpng -o test.png; xdg-open/open test.png
$ snakeviz test.prof
```
filename = f'profile-{datetime.datetime.now():%Y%m%d_%H%M%S}.png'
drawer = cg.output.GraphvizOutput(output_file=filename)
with cg.PyCallGraph(drawer):
<code_to_be_profiled>
### Sampling and Memory Profilers
```text
+--------------+-------------------------------+------------+----------+------+
| pip3 install | How to run | Target | Type | Live |
+--------------+-------------------------------+------------+----------+------+
| py-spy | py-spy top -- python3 test.py | CPU | Sampling | Yes |
| pyinstrument | pyinstrument test.py | CPU | Sampling | No |
| scalene | scalene test.py | CPU+Memory | Sampling | No |
| memray | memray run --live test.py | Memory | Tracing | Yes |
| filprofiler | fil-profile run test.py | Memory | Tracing | No |
+--------------+-------------------------------+------------+----------+------+
```

83
index.html

@ -54,7 +54,7 @@
<body>
<header>
<aside>June 9, 2023</aside>
<aside>June 30, 2023</aside>
<a href="https://gto76.github.io" rel="author">Jure Šorn</a>
</header>
@ -1609,14 +1609,14 @@ CompletedProcess(args=[<span class="hljs-string">'bc'</span>, <span class="hljs-
<span class="hljs-keyword">with</span> &lt;conn&gt;.begin(): ... <span class="hljs-comment"># Exits the block with commit or rollback.</span>
</code></pre></div>
<pre><code class="text language-text">┏━━━━━━━━━━━━┯━━━━━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Dialect │ pip3 install │ import │ Dependencies
┠────────────┼──────────────┼──────────┼──────────────────────────────────┨
┃ mysql │ mysqlclient │ MySQLdb │ www.pypi.org/project/mysqlclient ┃
┃ postgresql │ psycopg2 │ psycopg2 │ www.pypi.org/project/psycopg2 ┃
┃ mssql │ pyodbc │ pyodbc │ www.pypi.org/project/pyodbc ┃
┃ oracle │ oracledb │ oracledb │ www.pypi.org/project/oracledb ┃
┗━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
<pre><code class="text language-text">┏━━━━━━━━━━━━┯━━━━━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Dialect │ pip3 install │ import │ Dependencies
┠────────────┼──────────────┼──────────┼──────────────────────────────────┨
┃ mysql │ mysqlclient │ MySQLdb │ www.pypi.org/project/mysqlclient ┃
┃ postgresql │ psycopg2 │ psycopg2 │ www.pypi.org/project/psycopg2 ┃
┃ mssql │ pyodbc │ pyodbc │ www.pypi.org/project/pyodbc ┃
┃ oracle │ oracledb │ oracledb │ www.pypi.org/project/oracledb ┃
┗━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
</code></pre>
<div><h2 id="bytes"><a href="#bytes" name="bytes">#</a>Bytes</h2><p><strong>Bytes object is an immutable sequence of single bytes. Mutable version is called bytearray.</strong></p><pre><code class="python language-python hljs">&lt;bytes&gt; = <span class="hljs-string">b'&lt;str&gt;'</span> <span class="hljs-comment"># Only accepts ASCII characters and \x00-\xff.</span>
&lt;int&gt; = &lt;bytes&gt;[&lt;index&gt;] <span class="hljs-comment"># Returns an int in range from 0 to 255.</span>
@ -2124,44 +2124,43 @@ duration_in_seconds = perf_counter() - start_time
</code></pre></div>
<div><h3 id="timingasnippet">Timing a Snippet</h3><pre><code class="python language-python hljs"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">from</span> timeit <span class="hljs-keyword">import</span> timeit
<span class="hljs-meta">&gt;&gt;&gt; </span>timeit(<span class="hljs-string">"''.join(str(i) for i in range(100))"</span>,
<span class="hljs-meta">... </span> number=<span class="hljs-number">10000</span>, globals=globals(), setup=<span class="hljs-string">'pass'</span>)
<span class="hljs-number">0.34986</span>
</code></pre></div>
<div><h3 id="profilingbyline">Profiling by Line</h3><pre><code class="python language-python hljs"><span class="hljs-comment"># $ pip3 install line_profiler memory_profiler</span>
<span class="hljs-meta">@profile</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>:</span>
a = [*range(<span class="hljs-number">10000</span>)]
b = {*range(<span class="hljs-number">10000</span>)}
main()
</code></pre></div>
<pre><code class="text language-text">$ kernprof -lv test.py
<span class="hljs-meta">&gt;&gt;&gt; </span>timeit(<span class="hljs-string">'list(range(10000))'</span>, number=<span class="hljs-number">1000</span>, globals=globals(), setup=<span class="hljs-string">'pass'</span>)
<span class="hljs-number">0.19373</span>
</code></pre></div>
<div><h3 id="profilingbyline">Profiling by Line</h3><pre><code class="text language-text">$ pip3 install line_profiler
$ echo "
@profile
def main():
a = list(range(10000))
b = set(range(10000))
main()" &gt; test.py
$ kernprof -lv test.py
Line # Hits Time Per Hit % Time Line Contents
=======================================================
1 @profile
2 def main():
3 1 955.0 955.0 43.7 a = [*range(10000)]
4 1 1231.0 1231.0 56.3 b = {*range(10000)}
$ python3 -m memory_profiler test.py
Line # Mem usage Increment Line Contents
=======================================================
1 37.668 MiB 37.668 MiB @profile
2 def main():
3 38.012 MiB 0.344 MiB a = [*range(10000)]
4 38.477 MiB 0.465 MiB b = {*range(10000)}
</code></pre>
<div><h3 id="callgraph">Call Graph</h3><div><h4 id="generatesapngimageofthecallgraphwithhighlightedbottlenecks">Generates a PNG image of the call graph with highlighted bottlenecks:</h4><pre><code class="python language-python hljs"><span class="hljs-comment"># $ pip3 install pycallgraph2; apt/brew install graphviz</span>
<span class="hljs-keyword">import</span> pycallgraph2 <span class="hljs-keyword">as</span> cg, datetime
3 1 219.0 219.0 31.1 a = list(range(10000))
4 1 487.0 487.0 68.9 b = set(range(10000))
</code></pre></div>
filename = <span class="hljs-string">f'profile-<span class="hljs-subst">{datetime.datetime.now():%Y%m%d_%H%M%S}</span>.png'</span>
drawer = cg.output.GraphvizOutput(output_file=filename)
<span class="hljs-keyword">with</span> cg.PyCallGraph(drawer):
&lt;code_to_be_profiled&gt;
</code></pre></div></div>
<div><h3 id="callandflamegraphs">Call and Flame Graphs</h3><pre><code class="bash language-bash hljs">$ pip3 install gprof2dot snakeviz
$ apt/brew install graphviz
$ python3 -m cProfile -o test.prof test.py
$ gprof2dot -f pstats test.prof | dot -Tpng -o test.png; xdg-open/open test.png
$ snakeviz test.prof
</code></pre></div>
<div><h3 id="samplingandmemoryprofilers">Sampling and Memory Profilers</h3><pre><code class="text language-text">┏━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━┓
┃ pip3 install │ How to run │ Target │ Type │ Live ┃
┠──────────────┼───────────────────────────────┼────────────┼──────────┼──────┨
┃ py-spy │ py-spy top -- python3 test.py │ CPU │ Sampling │ Yes ┃
┃ pyinstrument │ pyinstrument test.py │ CPU │ Sampling │ No ┃
┃ scalene │ scalene test.py │ CPU+Memory │ Sampling │ No ┃
┃ memray │ memray run --live test.py │ Memory │ Tracing │ Yes ┃
┃ filprofiler │ fil-profile run test.py │ Memory │ Tracing │ No ┃
┗━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━┛
</code></pre></div>
<div><h2 id="numpy"><a href="#numpy" name="numpy">#</a>NumPy</h2><p><strong>Array manipulation mini-language. It can run up to one hundred times faster than the equivalent Python code. An even faster alternative that runs on a GPU is called CuPy.</strong></p><pre><code class="python language-python hljs"><span class="hljs-comment"># $ pip3 install numpy</span>
<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np
@ -2934,7 +2933,7 @@ $ pyinstaller script.py --add-data '&lt;path&gt;:.' <span class="hljs-comment">
<footer>
<aside>June 9, 2023</aside>
<aside>June 30, 2023</aside>
<a href="https://gto76.github.io" rel="author">Jure Šorn</a>
</footer>

39
parse.js

@ -460,19 +460,19 @@ const DIAGRAM_9_B =
"┗━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━┛\n";
const DIAGRAM_95_A =
"+------------+--------------+-----------+----------------------------------+\n" +
"| Dialect | pip3 install | import | Dependencies |\n" +
"+------------+--------------+-----------+----------------------------------+\n";
'+------------+--------------+----------+----------------------------------+\n' +
'| Dialect | pip3 install | import | Dependencies |\n' +
'+------------+--------------+----------+----------------------------------+\n';
const DIAGRAM_95_B =
"┏━━━━━━━━━━━━┯━━━━━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n" +
"┃ Dialect │ pip3 install │ import │ Dependencies ┃\n" +
"┠────────────┼──────────────┼──────────┼──────────────────────────────────┨\n" +
"┃ mysql │ mysqlclient │ MySQLdb │ www.pypi.org/project/mysqlclient ┃\n" +
"┃ postgresql │ psycopg2 │ psycopg2 │ www.pypi.org/project/psycopg2 ┃\n" +
"┃ mssql │ pyodbc │ pyodbc │ www.pypi.org/project/pyodbc ┃\n" +
"┃ oracle │ oracledb │ oracledb │ www.pypi.org/project/oracledb ┃\n" +
"┗━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n";
'┏━━━━━━━━━━━━┯━━━━━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n' +
'┃ Dialect │ pip3 install │ import │ Dependencies ┃\n' +
'┠────────────┼──────────────┼──────────┼──────────────────────────────────┨\n' +
'┃ mysql │ mysqlclient │ MySQLdb │ www.pypi.org/project/mysqlclient ┃\n' +
'┃ postgresql │ psycopg2 │ psycopg2 │ www.pypi.org/project/psycopg2 ┃\n' +
'┃ mssql │ pyodbc │ pyodbc │ www.pypi.org/project/pyodbc ┃\n' +
'┃ oracle │ oracledb │ oracledb │ www.pypi.org/project/oracledb ┃\n' +
'┗━━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n';
const DIAGRAM_10_A =
'+-------------+-------------+\n' +
@ -508,6 +508,22 @@ const DIAGRAM_11_B =
'┃ str │ ┃\n' +
'┗━━━━━━━━━━━━━┷━━━━━━━━━━━━━┛\n';
const DIAGRAM_115_A =
'+--------------+-------------------------------+------------+----------+------+\n' +
'| pip3 install | How to run | Target | Type | Live |\n' +
'+--------------+-------------------------------+------------+----------+------+\n';
const DIAGRAM_115_B =
'┏━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━┓\n' +
'┃ pip3 install │ How to run │ Target │ Type │ Live ┃\n' +
'┠──────────────┼───────────────────────────────┼────────────┼──────────┼──────┨\n' +
'┃ py-spy │ py-spy top -- python3 test.py │ CPU │ Sampling │ Yes ┃\n' +
'┃ pyinstrument │ pyinstrument test.py │ CPU │ Sampling │ No ┃\n' +
'┃ scalene │ scalene test.py │ CPU+Memory │ Sampling │ No ┃\n' +
'┃ memray │ memray run --live test.py │ Memory │ Tracing │ Yes ┃\n' +
'┃ filprofiler │ fil-profile run test.py │ Memory │ Tracing │ No ┃\n' +
'┗━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━┛\n';
const DIAGRAM_12_A =
'+-----------+-----------+------+-----------+\n' +
'| sampwidth | min | zero | max |\n' +
@ -740,6 +756,7 @@ function updateDiagrams() {
$(`code:contains(${DIAGRAM_95_A})`).html(DIAGRAM_95_B);
$(`code:contains(${DIAGRAM_10_A})`).html(DIAGRAM_10_B);
$(`code:contains(${DIAGRAM_11_A})`).html(DIAGRAM_11_B);
$(`code:contains(${DIAGRAM_115_A})`).html(DIAGRAM_115_B);
$(`code:contains(${DIAGRAM_12_A})`).html(DIAGRAM_12_B).removeClass("text").removeClass("language-text").addClass("python");
$(`code:contains(${DIAGRAM_13_A})`).html(DIAGRAM_13_B).removeClass("text").removeClass("language-text").addClass("python");
$(`code:contains(${DIAGRAM_14_A})`).parent().remove();

4
pdf/index_for_pdf.html

@ -51,7 +51,7 @@
<strong>filter function, <a href="#mapfilterreduce">11</a></strong><br>
<strong>flask library, <a href="#web">36</a></strong><br>
<strong>floats, <a href="#abstractbaseclasses">4</a>, <a href="#floats">6</a>, <a href="#types">7</a></strong><br>
<strong>format, <a href="#format">6</a>-<a href="#comparisonofpresentationtypes">7</a>, <a href="#callgraph">37</a></strong><br>
<strong>format, <a href="#format">6</a>-<a href="#comparisonofpresentationtypes">7</a></strong><br>
<strong>functools module, <a href="#mapfilterreduce">11</a>, <a href="#partial">12</a>, <a href="#debuggerexample">13</a>, <a href="#sortable">16</a></strong><br>
<strong>futures, <a href="#threadpoolexecutor">30</a></strong> </p>
<h3 id="g">G</h3>
@ -103,7 +103,7 @@
<strong>pillow library, <a href="#image">39</a>-<a href="#animation">40</a></strong><br>
<strong>plotting, <a href="#plot">34</a>, <a href="#dataframeencodedecodeplot">46</a>, <a href="#plotly">47</a>-<a href="#displaysamultiaxislinechartoftotalcoronaviruscasesandchangesinpricesofbitcoindowjonesandgold">48</a></strong><br>
<strong>print function, <a href="#print">22</a></strong><br>
<strong>profiling, <a href="#profiling">36</a>-<a href="#timingasnippet">37</a></strong><br>
<strong>profiling, <a href="#profiling">36</a>-<a href="#profilingbyline">37</a></strong><br>
<strong>progress bar, <a href="#progressbar">34</a></strong><br>
<strong>property decorator, <a href="#property">15</a></strong><br>
<strong>pygame library, <a href="#pygame">42</a>-<a href="#basicmariobrothersexample">43</a></strong> </p>

2
pdf/index_for_pdf_print.html

@ -51,7 +51,7 @@
<strong>filter function, 11</strong><br>
<strong>flask library, 36</strong><br>
<strong>floats, 4, 6, 7</strong><br>
<strong>format, 6-7, 37</strong><br>
<strong>format, 6-7</strong><br>
<strong>functools module, 11, 12, 13, 16</strong><br>
<strong>futures, 30</strong> </p>
<h3 id="g">G</h3>

Loading…
Cancel
Save