GithubHelp home page GithubHelp logo

nschloe / tuna Goto Github PK

View Code? Open in Web Editor NEW
1.3K 7.0 33.0 5.61 MB

:fish: Python profile viewer

License: GNU General Public License v3.0

Python 71.28% HTML 6.02% JavaScript 19.12% CSS 3.58%
python pypi profile browser profiler

tuna's Introduction

tuna

Performance analysis for Python.

PyPi Version PyPI pyversions GitHub stars Downloads

Discord

gh-actions Code style: black code style: prettier

tuna is a modern, lightweight Python profile viewer inspired by SnakeViz. It handles runtime and import profiles, has minimal dependencies, uses d3 and bootstrap, and avoids certain errors present in SnakeViz (see below) and is faster, too.

Create a runtime profile with

python -mcProfile -o program.prof yourfile.py

or an import profile with

python -X importtime yourfile.py 2> import.log

and show it with

tuna program.prof

Why tuna doesn't show the whole call tree

The whole timed call tree cannot be retrieved from profile data. Python developers made the decision to only store parent data in profiles because it can be computed with little overhead. To illustrate, consider the following program.

import time


def a(t0, t1):
    c(t0)
    d(t1)


def b():
    a(1, 4)


def c(t):
    time.sleep(t)


def d(t):
    time.sleep(t)


if __name__ == "__main__":
    a(4, 1)
    b()

The root process (__main__) calls a() which spends 4 seconds in c() and 1 second in d(). __main__ also calls b() which calls a(), this time spending 1 second in c() and 4 seconds in d(). The profile, however, will only store that c() spent a total of 5 seconds when called from a(), and likewise d(). The information that the program spent more time in c() when called in root -> a() -> c() than when called in root -> b() -> a() -> c() is not present in the profile.

tuna only displays the part of the timed call tree that can be deduced from the profile. SnakeViz, on the other hand, tries to construct the entire call tree, but ends up providing lots of wrong timings.

SnakeViz output. Wrong. tuna output. Only shows what can be retrieved from the profile.

Installation

tuna is available from the Python Package Index, so simply do

pip install tuna

to install.

Testing

To run the tuna unit tests, check out this repository and type

pytest

IPython magics

tuna includes a tuna line / cell magic which can be used as a drop-in replacement for the prun magic. Simply run %load_ext tuna to load the magic and then call it like %tuna sleep(3) or

%%tuna
sleep(3)

prun is still used to do the actual profiling and then the results are displayed in the notebook.

Development

After forking and cloning the repository, make sure to run make dep to install additional dependencies (bootstrap and d3) which aren't stored in the repo.

License

This software is published under the GPLv3 license.

tuna's People

Contributors

bobotig avatar dependabot[bot] avatar eric-wieser avatar galaxysnail avatar hmaarrfk avatar klauer avatar luccaportes avatar mimischi avatar mohammad7t avatar neighthan avatar nschloe avatar renovate-bot avatar renovate[bot] avatar tailhook avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

tuna's Issues

Cant read Profile done with importtime

$ tuna profile.data 
Traceback (most recent call last):
  File "/Users/Thomas/.local/miniconda3/envs/4cast_37/bin/tuna", line 11, in <module>
    sys.exit(main())
  File "/Users/Thomas/.local/miniconda3/envs/4cast_37/lib/python3.7/site-packages/tuna/cli.py", line 33, in main
    start_server(args.infile, args.browser)
  File "/Users/Thomas/.local/miniconda3/envs/4cast_37/lib/python3.7/site-packages/tuna/main.py", line 172, in start_server
    data = read(prof_filename)
  File "/Users/Thomas/.local/miniconda3/envs/4cast_37/lib/python3.7/site-packages/tuna/main.py", line 28, in read
    return read_import_profile(filename)
  File "/Users/Thomas/.local/miniconda3/envs/4cast_37/lib/python3.7/site-packages/tuna/main.py", line 125, in read_import_profile
    self_time = int(items[0])
ValueError: invalid literal for int() with base 10: 'self [us]'

File profile.dat starts with

import time: self [us] | cumulative | imported package
import time:       151 |        151 | zipimport
import time:       685 |        685 | _frozen_importlib_external
import time:        81 |         81 |     _codecs
import time:       619 |        700 |   codecs
import time:       495 |        495 |   encodings.aliases

Run failed on Mac OS Monterey M1 Chip

I tried running a python script using tuna by the command python -mcProfile -o program.prof main.py. I failed running and yeilded the following error.

    from winsound import SND_LOOP
ModuleNotFoundError: No module named 'winsound'

Support fluid-width browser windows

It seems a shame to have a wide monitor, but have tuna only use the narrow center of it.

Setting class="container-fluid" is just the tip of the iceberg here.

Most of my patches so far have come about as a result of looking into this, and getting a better mental model for d3js

pytest integration

This would be awesome if tuna could plug with pytest. The same way tuna has ipython magic, a --tuna option in pytest would be very convenient.
What do you think?

Exception occurred when running tuna program.prof

When I run tuna program.prof, I get the following exception along with many more warnings. I'm running tuna on Windows 10. Here's part of the log:

----------------------------------------
127.0.0.1 - - [26/Apr/2020 09:35:18] "GET /static/favicon256.png HTTP/1.1" 200 -
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 59291)
Traceback (most recent call last):
  File "C:\Users\Amin\Anaconda3\envs\py36\lib\socketserver.py", line 320, in _handle_request_noblock
    self.process_request(request, client_address)
  File "C:\Users\Amin\Anaconda3\envs\py36\lib\socketserver.py", line 351, in process_request
    self.finish_request(request, client_address)
  File "C:\Users\Amin\Anaconda3\envs\py36\lib\socketserver.py", line 364, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "C:\Users\Amin\Anaconda3\envs\py36\lib\socketserver.py", line 724, in __init__
    self.handle()
  File "C:\Users\Amin\Anaconda3\envs\py36\lib\http\server.py", line 418, in handle
    self.handle_one_request()
  File "C:\Users\Amin\Anaconda3\envs\py36\lib\http\server.py", line 406, in handle_one_request
    method()
  File "C:\Users\Amin\Anaconda3\envs\py36\lib\site-packages\tuna\main.py", line 229, in do_GET
    mimetype, _ = mimetypes.guess_type(filepath)
  File "C:\Users\Amin\Anaconda3\envs\py36\lib\mimetypes.py", line 291, in guess_type
    return _db.guess_type(url, strict)
  File "C:\Users\Amin\Anaconda3\envs\py36\lib\mimetypes.py", line 116, in guess_type
    scheme, url = urllib.parse.splittype(url)
  File "C:\Users\Amin\Anaconda3\envs\py36\lib\urllib\parse.py", line 974, in splittype
    match = _typeprog.match(url)
TypeError: expected string or bytes-like object
----------------------------------------

favicon.ico missing error

I'm running in Firefox 60. The server shows the following error:

FileNotFoundError: [Errno 2] No such file or directory: '/remote/YYYY/miniconda3/envs/XXX/lib/python3.7/site-packages/tuna/web/favicon.ico'

I am not sure what impact it has but I can't see the chart.

Uncaught StopIteration exception

Just installed tuna and it doesn't seem to be working on my machine.

> pip install tuna
> python -m cProfile -o stat.prof myscript.py
> tuna stat.prof
Traceback (most recent call last):
  File "c:\users\kevin.rose\appdata\local\continuum\anaconda2\envs\sdk-v2.2\lib\runpy.py", line 174, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "c:\users\kevin.rose\appdata\local\continuum\anaconda2\envs\sdk-v2.2\lib\runpy.py", line 72, in _run_code
    exec code in run_globals
  File "C:\Users\kevin.rose\AppData\Local\Continuum\Anaconda2\envs\sdk-v2.2\Scripts\tuna.exe\__main__.py", line 9, in <module>
  File "c:\users\kevin.rose\appdata\local\continuum\anaconda2\envs\sdk-v2.2\lib\site-packages\tuna\cli.py", line 13, in main
    start_server(args.infile, args.browser)
  File "c:\users\kevin.rose\appdata\local\continuum\anaconda2\envs\sdk-v2.2\lib\site-packages\tuna\main.py", line 156, in start_server
    data = read(prof_filename)
  File "c:\users\kevin.rose\appdata\local\continuum\anaconda2\envs\sdk-v2.2\lib\site-packages\tuna\main.py", line 22, in read
    return read_import_profile(filename)
  File "c:\users\kevin.rose\appdata\local\continuum\anaconda2\envs\sdk-v2.2\lib\site-packages\tuna\main.py", line 110, in read_import_profile
    line = next(import_lines)
StopIteration

I fixed this with a one-liner updating the read function of main.py to except not only TunaError, but StopIteration as well:

def read(filename):
    _, ext = os.path.splitext(filename)
    try:
        return read_import_profile(filename)
    except (TunaError, StopIteration):
        pass

    # runtime profile
    return read_runtime_profile(filename)

but that was a wild shot in the dark, not sure if the solution would work elsewhere.

AssertionError (line 98, in _shelf)

Traceback (most recent call last):
  File "/home/jzzeng/anaconda3/envs/reacnetgenerator/bin/tuna", line 10, in <module>
    sys.exit(main())
  File "/home/jzzeng/anaconda3/envs/reacnetgenerator/lib/python3.7/site-packages/tuna/cli.py", line 31, in main
    start_server(args.infile, args.browser, args.port)
  File "/home/jzzeng/anaconda3/envs/reacnetgenerator/lib/python3.7/site-packages/tuna/main.py", line 185, in start_server
    data = read(prof_filename)
  File "/home/jzzeng/anaconda3/envs/reacnetgenerator/lib/python3.7/site-packages/tuna/main.py", line 26, in read
    return read_import_profile(filename)
  File "/home/jzzeng/anaconda3/envs/reacnetgenerator/lib/python3.7/site-packages/tuna/main.py", line 165, in read_import_profile
    lst, k = _shelf(entries[::-1], 0)
  File "/home/jzzeng/anaconda3/envs/reacnetgenerator/lib/python3.7/site-packages/tuna/main.py", line 99, in _shelf
    out[-1]["children"], k = _shelf(lst, k)
  File "/home/jzzeng/anaconda3/envs/reacnetgenerator/lib/python3.7/site-packages/tuna/main.py", line 99, in _shelf
    out[-1]["children"], k = _shelf(lst, k)
  File "/home/jzzeng/anaconda3/envs/reacnetgenerator/lib/python3.7/site-packages/tuna/main.py", line 98, in _shelf
    assert level == reference_level + 1
AssertionError

reacnetgenerator_importtime.log

Broken Pipe

Quick question, was getting a broken pipe message when running the tuna command. The tab opens up in browser but is unable to connect. Any idea on the cause?

Exception happened during processing of request from ('127.0.0.1', 63304)
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/socketserver.py", line 316, in _handle_request_noblock
    self.process_request(request, client_address)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/socketserver.py", line 347, in process_request
    self.finish_request(request, client_address)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/socketserver.py", line 360, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/socketserver.py", line 720, in __init__
    self.handle()
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/http/server.py", line 427, in handle
    self.handle_one_request()
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/http/server.py", line 415, in handle_one_request
    method()
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/tuna/main.py", line 64, in do_GET
    self.wfile.write(content)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/socketserver.py", line 799, in write
    self._sock.sendall(b)
BrokenPipeError: [Errno 32] Broken pipe

Running on MacOS Catalina, Python 3.8 and Chrome

assert mimetype is not None

Error / tuna 0.5.11 / installed with pip

When called with invalid URL, instead of a clean 404, we get

Exception occurred during processing of request from ('192.168.64.1', 62031)
Traceback (most recent call last):
  File "/usr/lib/python3.9/socketserver.py", line 316, in _handle_request_noblock
    self.process_request(request, client_address)
  File "/usr/lib/python3.9/socketserver.py", line 347, in process_request
    self.finish_request(request, client_address)
  File "/usr/lib/python3.9/socketserver.py", line 360, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/lib/python3.9/socketserver.py", line 720, in __init__
    self.handle()
  File "/usr/lib/python3.9/http/server.py", line 427, in handle
    self.handle_one_request()
  File "/usr/lib/python3.9/http/server.py", line 415, in handle_one_request
    method()
  File "/opt/scodoc/venv/lib/python3.9/site-packages/tuna/main.py", line 59, in do_GET
    assert mimetype is not None
AssertionError

Crash when the favicon does not exists

Hello, thank you for creating this module, I'm going to try to make my import faster using it :)

I got the following error while monkey testing the server:

Exception happened during processing of request from ('127.0.0.1', 45132)
Traceback (most recent call last):
  File "/usr/lib/python3.8/socketserver.py", line 316, in _handle_request_noblock
    self.process_request(request, client_address)
  File "/usr/lib/python3.8/socketserver.py", line 347, in process_request
    self.finish_request(request, client_address)
  File "/usr/lib/python3.8/socketserver.py", line 360, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/lib/python3.8/socketserver.py", line 747, in __init__
    self.handle()
  File "/usr/lib/python3.8/http/server.py", line 427, in handle
    self.handle_one_request()
  File "/usr/lib/python3.8/http/server.py", line 415, in handle_one_request
    method()
  File "/home/pierre/pylint/venv/lib/python3.8/site-packages/tuna/main.py", line 63, in do_GET
    with open(filepath, "rb") as fh:
FileNotFoundError: [Errno 2] No such file or directory: '/home/pierre/pylint/venv/lib/python3.8/site-packages/tuna/web/favicon.ico'

How to properly close tuna

Hello, I just discovered tuna and found it quite useful, but I'm wondering how to properly close it after reviewing the import profile (e.g., tuna import.log)? The only ways that worked so far are Ctrl + C to kill the program, thanks!

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/tests.yml
  • actions/checkout v3
  • pre-commit/action v3.0.0
  • actions/setup-python v4
  • actions/checkout v3
  • codecov/codecov-action v3
npm
package.json
  • bootstrap 5.2.3
  • d3 7.8.2
  • prettier 2.8.3
pep621
pyproject.toml
  • setuptools >=42
setup-cfg
setup.cfg

  • Check this box to trigger a request for Renovate to run again on this repository

Can tuna generate static dir?

From what I can see tuna generates static index.html from the profile data and serves it along with other static files like stylesheets.

So can it just generate files and put it on disk? My use case is to generate some profile on a CI system and serve it online via S3 or other static file server. Another use case is to share profile to someone online without keeping my laptop running.

What do you think?

Add disclaimer: Tuna cannot deal with captured output of every type of terminal

Hi,

Thanks for making this very useful package. I was trying to read the output generated with:

python -X importtime import_numpy.py 2> import_numpy.log

I'm working on a Windows machine, and I normally use Powershell. However tuna wasn't able to read the log file written by it.
It threw me the following Warnings for every line in the file:

WARNING:root:Didn't recognize and skipped line import time: 1269 | 18898 | numpy._version
WARNING:root:Didn't recognize and skipped line ``

When I ran the same command in the classic cmd.exe, tuna had no issues reading the captured output.

Apparently Powershell wrote to a file encoded in "UTF-16 LE BOM" and uses CR LF, whereas cmd.exe wrote to a file encoded in UTF-8 and uses Unix style LF.

I don't think tuna should be able to deal with output generated by every kind of terminal, because this is difficult to maintain: Who knows what the developers of some hypothetical superturboshell decide to encode their files to.

But is probably good to add this as a known issue to the documentation.

For reference:

import_numpy_cmd.log
import_numpy_powershell.log

IPython magics broken in tuna >=5.0

First, ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ , this is an amazingly useful profiling tool. Thanks!

The ipython magics are broken in release 5.0+ with the browser console traceback of:

Uncaught TypeError: Cannot read property 'addEventListener' of null
    at HTMLElement.render (about:srcdoc:132)
    at HTMLElement.connectedCallback (about:srcdoc:112)
    at about:srcdoc:270

This is being raised after failing to resolve the "resetZoomButton" added in #87 at https://github.com/nschloe/tuna/blob/v0.5.3/tuna/web/static/icicle.js#L27-L30

It's not entirely clear to me why the strategy used in the magics doesn't work here, but I believe it may be because an object is specified by ID in the tuna javascript but then isn't present in the IFrame generated by the magic?

I've uploaded a full repro to nbviewer:
https://nbviewer.jupyter.org/gist/asford/35eebdaba46cb3e513565d6fc8440763

It should be possible to open this viewer to view the error traceback in the browser developer console.

crash when parsing profile

code:
fatmodule.py:

import time
#mimics a module which takes a long time to import
time.sleep(1)

demo2.py:

import time

def b():
    import fatmodule
    time.sleep(.1)

b()
python3 -m cProfile -o prof2 ./demo2.py
tuna2 prof2
Traceback (most recent call last):
  File "/home/bart/.local/bin/tuna", line 8, in <module>
    sys.exit(main())
  File "/home/bart/.local/lib/python3.8/site-packages/tuna/cli.py", line 32, in main
    start_server(args.infile, args.browser, args.port)
  File "/home/bart/.local/lib/python3.8/site-packages/tuna/main.py", line 44, in start_server
    data = read(prof_filename)
  File "/home/bart/.local/lib/python3.8/site-packages/tuna/main.py", line 23, in read
    return read_runtime_profile(filename)
  File "/home/bart/.local/lib/python3.8/site-packages/tuna/_runtime_profile.py", line 88, in read_runtime_profile
    "children": [populate(root, None) for root in roots],
  File "/home/bart/.local/lib/python3.8/site-packages/tuna/_runtime_profile.py", line 88, in <listcomp>
    "children": [populate(root, None) for root in roots],
  File "/home/bart/.local/lib/python3.8/site-packages/tuna/_runtime_profile.py", line 47, in populate
    c = [populate(child, key) for child in children[key]]
  File "/home/bart/.local/lib/python3.8/site-packages/tuna/_runtime_profile.py", line 47, in <listcomp>
    c = [populate(child, key) for child in children[key]]
  File "/home/bart/.local/lib/python3.8/site-packages/tuna/_runtime_profile.py", line 47, in populate
    c = [populate(child, key) for child in children[key]]
...
RecursionError: maximum recursion depth exceeded in comparison

prof2.gz

Tuna badly struggles on large files

I'm working a relatively large cProfile dump while analyzing startup of a django application. The profile file size is 9.4MB. Snakeviz is able to load this, though it can't visualize at a depth of more than 5 calls. Tuna just fails to load a file of this size. It looks like this is probably a result of eager-loading the entire profiling data set.

Static assets not included?

Hi, I just tried pip install -U tuna and it seems that the web folder was not included in my install. I think for some reason the package data are not being installed.

Tuna relies on sklearn that is deprecated

The 'sklearn' PyPI package is deprecated, use 'scikit-learn'
rather than 'sklearn' for pip commands.

Here is how to fix this error in the main use cases:

  • use 'pip install scikit-learn' rather than 'pip install sklearn'
  • replace 'sklearn' by 'scikit-learn' in your pip requirements files
    (requirements.txt, setup.py, setup.cfg, Pipfile, etc ...)
  • if the 'sklearn' package is used by one of your dependencies,
    it would be great if you take some time to track which package uses
    'sklearn' instead of 'scikit-learn' and report it to their issue tracker
  • as a last resort, set the environment variable
    SKLEARN_ALLOW_DEPRECATED_SKLEARN_PACKAGE_INSTALL=True to avoid this error

More information is available at
https://github.com/scikit-learn/sklearn-pypi-package

If the previous advice does not cover your use case, feel free to report it at
https://github.com/scikit-learn/sklearn-pypi-package/issues/new

almost empty profile?

I generated the profile on a arm device (running debian jessie), using python3.4 and the command from your readme: python3 -mcProfile -o /tmp/program.prof .

When I analyse the profile on my dev machine (debian testing, tuna v0.3.6), I get only 3 entries in the profile:

root0.000 s (100.0%)
~::0::<method 'disable' of '_lsprof.Profiler' objects>0.000 s (100.0%)
~::0::<method 'disable' of '_lsprof.Profiler' objects>::self0.000 s (100.0%)

Unicode decode error

tuna cannot parse a cProfile dump file. This is a stack trace:

$ tuna cprofile.dat
Traceback (most recent call last):
  File "~/.virtualenvs/profiling/bin/tuna", line 11, in <module>
    sys.exit(main())
  File "~/.virtualenvs/profiling/lib/python3.6/site-packages/tuna/cli.py", line 13, in main
    start_server(args.infile, args.browser)
  File "~/.virtualenvs/profiling/lib/python3.6/site-packages/tuna/main.py", line 134, in start_server
    data = read(prof_filename)
  File "~/.virtualenvs/profiling/lib/python3.6/site-packages/tuna/main.py", line 21, in read
    return read_import_profile(filename)
  File "~/.virtualenvs/profiling/lib/python3.6/site-packages/tuna/main.py", line 93, in read_import_profile
    assert next(import_lines) == "self [us] | cumulative | imported package"
  File "~/.virtualenvs/profiling/lib/python3.6/site-packages/tuna/main.py", line 89, in <genexpr>
    line[len("import time: ") :].rstrip()
  File "~/.virtualenvs/profiling/lib/python3.6/codecs.py", line 321, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfb in position 0: invalid start byte

Alternate port

If I want to compare two files, I might open tuna twice. But I get OSError: [Errno 98] Address already in use. It would be nice it if it a) picked some other (random, possibly) port and b) had a CLI flag to pick a specific port.

Visualization in Tuna

As it stands Tuna is a great tool. However it find it has some user interface deficiencies. I'll use this as an example

image

  • Every box is blue except some gray ones. This is... just annoying and makes it harder to navigate, or quickly recognize similar calls. A color scheme will improve how fast the user can process the info served to him. The UI also does not highlight calls to the same scripts from different functions
  • Also I don't know why some boxes are blue and some gray. It's probably documented somewhere, and intuitively it's related to depth, but it's not immediately obvious to the user. This is minor though
  • The UI insists in trying to show text in places it does not fit. You end up with small boxes that have stuff like "...py::165..." written in them because the string does not fit. IMO it'd be better to just hide these strings like snakeviz does
  • Navigating function calls is painful. Say I zoom into rl_algo.py on the left. To zoom back out, I need to click on the slab on top of it (its parent function) then go on clicking until I get to root. This is seriously annoying and slows me down if I'm examining the deeper calls. This is easily my biggest gripe with the current UI after color
  • There's no access to the actual profile data like in snakeviz. Its search + filtering + visualization of the data is immensely useful.

That's some of the issues I have with it. That's not to bash Tuna. Thank you for making a tool that accurately shows exec times. But I think you'd be best served by emulating snakeviz's visualization and building from there (e.g. adding a browser that lets me quickly access other profiles in this or nearby folders). As it stands yours lacks features that snakeviz implements and that makes life orders of magnitude simpler for a user.

render function signature changed

out.write(render(data))

The render function signature was changed in the last commit to render(data, filename), but this call uses the old signature.
Would it be better to provide a default value for filename in render or to add a filename here?

running tuna multiple times fails

I started tuna once (to see state before change) and then again (to see state after change)

It resulted in

Traceback (most recent call last):
  File "/home/mateusz/.local/bin/tuna", line 10, in <module>
    sys.exit(main())
  File "/home/mateusz/.local/lib/python3.5/site-packages/tuna/cli.py", line 33, in main
    start_server(args.infile, args.browser, args.port)
  File "/home/mateusz/.local/lib/python3.5/site-packages/tuna/main.py", line 212, in start_server
    httpd = HTTPServer(("", port), StaticServer)
  File "/usr/lib/python3.5/socketserver.py", line 440, in __init__
    self.server_bind()
  File "/usr/lib/python3.5/http/server.py", line 138, in server_bind
    socketserver.TCPServer.server_bind(self)
  File "/usr/lib/python3.5/socketserver.py", line 454, in server_bind
    self.socket.bind(self.server_address)
OSError: [Errno 98] Address already in use

Add filename to html title

Hi, do you think it is a good idea to add the filename of the profile log to the title of the HTML page?

It would be useful when analyzing multiple files at the same time. Now it gets very confusing:

image

I thought it could be something like "tuna - filename".

I can do that if you agree.

Look for tracebacks in the log file

Right now I get a failure of assert len(items) == 3 if the profile data from python ends up with a traceback within it. It would be nice if the error message were clearer.

Feature request: Watch for file change

First off, really really love this project.

Just a small feature request if possible. Tuna helps me a ton with profile long import times, but it would be awesome if it could watch for changes to the log file that is being generated. Currently the workflow is:

  • python -x ...
  • tuna file.log
  • ctrl + c for tuna
  • repeat the process.

It would be super if tuna could watch the log file and perhaps auto refresh the browser.

Thanks!

Call stack depth is limited?

Hi there, Thanks for making this software available!

It seems like it could be really helpful to me, but when I tried running it on a pstats file, I couldn't see the info I wanted. Only 14 rows were shown, even though profile contains 20 or more. Is there a way to work around this?

stats-14-14-29.log

What itch does Tuna scratch?

The readme says Tuna is inspired by the awesome SnakeViz, which in turn was inspired by RunSnakeRun. I'm new to the territory and don't know anything about any of these. After a brief look at each I can see why SnakeViz exists; RunSnakeRun hasn't been updated for several years and it's graphical presentation looks pre-schoolish to current eyes. I don't see something similar for Tuna v SnakeViz, which has a community, good presentation, and development activity over time. In other words, what itch does Tuna scratch? (Genuinely curious).

Question: Using Window Title for foobar2000, any way I can send playback time and song duration to Tuna?

I'm using foobar2000 along with the YouTube Source plugin in order to play songs from YouTube in there, and I've formatted my foobar2000 Window Title so it will say " - - /" and was wondering if there is any way to send the playback time and song duration info to Tuna to use with the progress bar source etc.

As it stands, right now the Tuna text source will show the full title bar but what I am hoping for is to cut the playback time and song duration out of the title and have it be used in the progress bar source.

Unable to read prof file from WSGI Application Profiler

When I run "tuna <profile_output>.prof" I get the following:

Traceback (most recent call last):
  File "/Users/stephen/www/profiling/venv3/bin/tuna", line 11, in <module>
    sys.exit(main())
  File "/Users/stephen/www/profiling/venv3/lib/python3.6/site-packages/tuna/cli.py", line 33, in main
    start_server(args.infile, args.browser)
  File "/Users/stephen/www/profiling/venv3/lib/python3.6/site-packages/tuna/main.py", line 172, in start_server
    data = read(prof_filename)
  File "/Users/stephen/www/profiling/venv3/lib/python3.6/site-packages/tuna/main.py", line 33, in read
    return read_runtime_profile(filename)
  File "/Users/stephen/www/profiling/venv3/lib/python3.6/site-packages/tuna/main.py", line 37, in read_runtime_profile
    stats = pstats.Stats(prof_filename)
  File "/usr/local/Cellar/python/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/pstats.py", line 72, in __init__
    self.init(arg)
  File "/usr/local/Cellar/python/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/pstats.py", line 86, in init
    self.load_stats(arg)
  File "/usr/local/Cellar/python/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/pstats.py", line 100, in load_stats
    self.stats = marshal.load(f)
ValueError: bad marshal data (unknown type code)

Also, the same files load fine in SnakeViz, but obviously I'm interested in the advanced features of Tuna.

Python v3.6.1
MacOS 10.13.5

Any suggestions would be greatly appreciated.

Missing apple-touch-icon-precomposed.png and apple-touch-icon.png

Thank you for making tuna!

When I run it on MacOS and Safari in Python 3.11 env with Conda installation I get the following errors in the console about two missing files.

Seems to display and work fine though. If it's easy to fix maybe you could? Or if it's irrelevant just close?

(playpy) temp $ tuna import.log 
Starting httpd on port 8000
127.0.0.1 - - [06/Jan/2024 13:50:12] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [06/Jan/2024 13:50:12] "GET /static/tuna.css HTTP/1.1" 200 -
127.0.0.1 - - [06/Jan/2024 13:50:12] "GET /static/bootstrap.min.css HTTP/1.1" 200 -
127.0.0.1 - - [06/Jan/2024 13:50:12] "GET /static/d3.min.js HTTP/1.1" 200 -
127.0.0.1 - - [06/Jan/2024 13:50:12] "GET /static/icicle.js HTTP/1.1" 200 -
127.0.0.1 - - [06/Jan/2024 13:50:12] "GET /static/favicon256.png HTTP/1.1" 200 -
127.0.0.1 - - [06/Jan/2024 13:50:12] "GET /static/favicon256.png HTTP/1.1" 200 -
127.0.0.1 - - [06/Jan/2024 13:50:12] "GET /apple-touch-icon-precomposed.png HTTP/1.1" 200 -
----------------------------------------
Exception occurred during processing of request from ('127.0.0.1', 51187)
Traceback (most recent call last):
  File "/Users/cdeil/anaconda3/envs/playpy/lib/python3.11/socketserver.py", line 317, in _handle_request_noblock
    self.process_request(request, client_address)
  File "/Users/cdeil/anaconda3/envs/playpy/lib/python3.11/socketserver.py", line 348, in process_request
    self.finish_request(request, client_address)
  File "/Users/cdeil/anaconda3/envs/playpy/lib/python3.11/socketserver.py", line 361, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/Users/cdeil/anaconda3/envs/playpy/lib/python3.11/socketserver.py", line 755, in __init__
    self.handle()
  File "/Users/cdeil/anaconda3/envs/playpy/lib/python3.11/http/server.py", line 436, in handle
    self.handle_one_request()
  File "/Users/cdeil/anaconda3/envs/playpy/lib/python3.11/http/server.py", line 424, in handle_one_request
    method()
  File "/Users/cdeil/anaconda3/envs/playpy/lib/python3.11/site-packages/tuna/main.py", line 63, in do_GET
    with open(filepath, "rb") as fh:
         ^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '/Users/cdeil/anaconda3/envs/playpy/lib/python3.11/site-packages/tuna/web/apple-touch-icon-precomposed.png'
----------------------------------------
127.0.0.1 - - [06/Jan/2024 13:50:12] "GET /apple-touch-icon.png HTTP/1.1" 200 -
----------------------------------------
Exception occurred during processing of request from ('127.0.0.1', 51189)
Traceback (most recent call last):
  File "/Users/cdeil/anaconda3/envs/playpy/lib/python3.11/socketserver.py", line 317, in _handle_request_noblock
    self.process_request(request, client_address)
  File "/Users/cdeil/anaconda3/envs/playpy/lib/python3.11/socketserver.py", line 348, in process_request
    self.finish_request(request, client_address)
  File "/Users/cdeil/anaconda3/envs/playpy/lib/python3.11/socketserver.py", line 361, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/Users/cdeil/anaconda3/envs/playpy/lib/python3.11/socketserver.py", line 755, in __init__
    self.handle()
  File "/Users/cdeil/anaconda3/envs/playpy/lib/python3.11/http/server.py", line 436, in handle
    self.handle_one_request()
  File "/Users/cdeil/anaconda3/envs/playpy/lib/python3.11/http/server.py", line 424, in handle_one_request
    method()
  File "/Users/cdeil/anaconda3/envs/playpy/lib/python3.11/site-packages/tuna/main.py", line 63, in do_GET
    with open(filepath, "rb") as fh:
         ^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '/Users/cdeil/anaconda3/envs/playpy/lib/python3.11/site-packages/tuna/web/apple-touch-icon.png'

total execution time is wrong (handling of imports)

tuna helped me to pinpoint a performance issue in my program, thanks!
but I notced the total execution time is wrong.

I simplified it down tot this mini-program, essentially just a (big) import:
demo.py

import time

def b():
    import matplotlib
    time.sleep(.1)

b()

profiling:

time python3 -m cProfile -o prof ./demo.py

prof.gz

the profile and snakeviz show a total execution time of .281s
tuna shows 1.16s, i.e. x4
tuna is clearly wrong (time when generating the profile showed real:.382s)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.