feat: jupyter support, using cell magic
This commit is contained in:
parent
89d953ee59
commit
d6796cec11
51
README.md
51
README.md
@ -18,6 +18,57 @@ Open the result.html, and identify the problem (GIL visible, possible low instru
|
||||
|
||||
|
||||
The dark red `S(GIL)` blocks indicate the threads/processes are in a waiting state due to the GIL, dark orange `S` is a due to other reasons (like `time.sleep(...)`). The regular pattern is due to Python switching threads after [`sys.getswitchinterval`](https://docs.python.org/3/library/sys.html#sys.getswitchinterval) (0.005 seconds)
|
||||
|
||||
# Usage - Jupyter notebook
|
||||
|
||||
First, load the magics
|
||||
```
|
||||
%load_ext per4m.cellmagic
|
||||
```
|
||||
|
||||
Run a cell with the `%%giltrace` cell magic.
|
||||
```
|
||||
%%giltrace
|
||||
import threading
|
||||
import time
|
||||
import time
|
||||
|
||||
|
||||
def run():
|
||||
total = 0
|
||||
for i in range(1_000_000):
|
||||
total += i
|
||||
return total
|
||||
|
||||
|
||||
thread1 = threading.Thread(target=run)
|
||||
thread2 = threading.Thread(target=run)
|
||||
thread1.start()
|
||||
thread2.start()
|
||||
time.sleep(0.2)
|
||||
for thread in [thread1, thread2]:
|
||||
thread.join()
|
||||
```
|
||||
Output:
|
||||
```
|
||||
Saving report to /tmp/tmp2rwf1xq3/viztracer.json ...
|
||||
Dumping trace data to json, total entries: 89, estimated json file size: 10.4KiB
|
||||
Report saved.
|
||||
|
||||
[ perf record: Woken up 8 times to write data ]
|
||||
[ perf record: Captured and wrote 2,752 MB /tmp/tmp2rwf1xq3/perf.data (415 samples) ]
|
||||
|
||||
Wait for perf to finish...
|
||||
Saving report to /home/maartenbreddels/github/maartenbreddels/per4m/result.html ...
|
||||
Dumping trace data to json, total entries: 167, estimated json file size: 19.6KiB
|
||||
Generating HTML report
|
||||
Report saved.
|
||||
Download result.html
|
||||
Open result.html in new tab (might not work due to security issue)
|
||||
```
|
||||
|
||||
Click the download link to get the results.
|
||||
|
||||
# Usage - manual
|
||||
|
||||
## Step 1
|
||||
|
41
per4m/cellmagic.py
Normal file
41
per4m/cellmagic.py
Normal file
@ -0,0 +1,41 @@
|
||||
import os
|
||||
import tempfile
|
||||
import viztracer
|
||||
from viztracer.report_builder import ReportBuilder
|
||||
from IPython.display import HTML, display
|
||||
|
||||
from IPython.core.magic import (cell_magic,
|
||||
magics_class,
|
||||
Magics,
|
||||
needs_local_scope,
|
||||
)
|
||||
|
||||
|
||||
from .giltracer import GilTracer
|
||||
|
||||
@magics_class
|
||||
class GilTraceMagic(Magics):
|
||||
@needs_local_scope
|
||||
@cell_magic
|
||||
def giltrace(self, line, cell, local_ns):
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
perf_path = os.path.join(temp_dir, 'perf.data')
|
||||
viz_path = os.path.join(temp_dir, 'viztracer.json')
|
||||
gil_path = os.path.join(temp_dir, 'giltracer.json')
|
||||
out_path = 'result.html'
|
||||
code = self.shell.transform_cell(cell)
|
||||
with GilTracer(perf_path, gil_path) as gt:
|
||||
with viztracer.VizTracer(output_file=viz_path):
|
||||
exec(code, local_ns, local_ns)
|
||||
builder = ReportBuilder([viz_path, gil_path])
|
||||
builder.save(output_file=out_path)
|
||||
|
||||
download = HTML(f'''<a href="{out_path}" download>Download {out_path}</a>''')
|
||||
view = HTML(f'''<a href="{out_path}" target="_blank" rel=”noopener noreferrer”>Open {out_path} in new tab</a> (might not work due to security issue)''')
|
||||
display(download, view)
|
||||
|
||||
def load_ipython_extension(ipython):
|
||||
"""
|
||||
Use `%load_ext per4m.cellmagic`
|
||||
"""
|
||||
ipython.register_magics(GilTraceMagic)
|
20
per4m/example2.py
Normal file
20
per4m/example2.py
Normal file
@ -0,0 +1,20 @@
|
||||
# same as example1, but without explicit viztracer calls
|
||||
import threading
|
||||
import time
|
||||
import time
|
||||
|
||||
|
||||
def run():
|
||||
total = 0
|
||||
for i in range(1_000_000):
|
||||
total += i
|
||||
return total
|
||||
|
||||
|
||||
thread1 = threading.Thread(target=run)
|
||||
thread2 = threading.Thread(target=run)
|
||||
thread1.start()
|
||||
thread2.start()
|
||||
time.sleep(0.2)
|
||||
for thread in [thread1, thread2]:
|
||||
thread.join()
|
Loading…
Reference in New Issue
Block a user