Python code speed analyzer
Project description
PyHaste
Python code speed analyzer.
Monitor the performance of your scripts etc. tools and understand where time is spent.
Installation
It's a Python library, what do you expect?
pip install pyhaste
# OR
poetry add pyhaste
Normal usage
To measure your code, pyhaste exports a measure context manager, give it a name as an argument. Alternatively wrap functions in measure_wrap with the name as an argument. Once you want a report call report from pyhaste.
import time
from pyhaste import measure, report, measure_wrap
@measure_wrap("prepare_task")
def prepare_task():
time.sleep(0.1)
@measure_wrap("find_items")
def find_items():
return [1, 2, 3]
@measure_wrap("process_item")
def process_item(item):
time.sleep(item * 0.1)
with measure("task"):
prepare_task()
for item in find_items():
process_item(item)
time.sleep(0.01)
report()
────────────────────────── PyHaste report ───────────────────────────
┏━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━┳━━━━━━━━┳━━━━━━━┳━━━━━━━━━━┓
┃ Name ┃ Time ┃ Tot % ┃ Rel % ┃ Calls ┃ Per call ┃
┡━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━╇━━━━━━━━╇━━━━━━━╇━━━━━━━━━━┩
│ task │ 0.700 s │ 98.58% │ │ 1 │ 0.700 s │
│ task ›process_item │ 0.600 s │ 84.49% │ 85.70% │ 3 │ 0.200 s │
│ task ›prepare_task │ 0.100 s │ 14.09% │ 14.29% │ 1 │ 0.100 s │
│ Unmeasured │ 0.010 s │ 1.42% │ │ │ │
│ task ›find_items │ 0.000 s │ 0.00% │ 0.00% │ 1 │ 0.000 s │
├────────────────────┼─────────┼────────┼────────┼───────┼──────────┤
│ Total │ 0.710 s │ 100% │ │ │ │
└────────────────────┴─────────┴────────┴────────┴───────┴──────────┘
In case you need more complex analysis, you might benefit from pyhaste.Analyzer and creating your own instances, e.g. for measuring time spent on separate tasks in a longer running job:
import time
from random import uniform
from pyhaste import Analyzer
for item in [1, 2, 3]:
analyzer = Analyzer()
with analyzer.measure(f"process_item({item})"):
with analyzer.measure("db.find"):
time.sleep(uniform(0.04, 0.06) * item)
with analyzer.measure("calculate"):
with analyzer.measure("guestimate"):
with analyzer.measure("do_math"):
time.sleep(uniform(0.1, 0.15) * item)
with analyzer.measure("save"):
time.sleep(uniform(0.05, 0.075) * item)
time.sleep(uniform(0.01, 0.025) * item)
analyzer.report()
────────────────────────────────────────── PyHaste report ──────────────────────────────────────────
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━┓
┃ Name ┃ Time ┃ Tot % ┃ Rel % ┃ Calls ┃ Per call ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━┩
│ process_item(1) │ 0.232 s │ 92.26% │ │ 1 │ 0.232 s │
│ process_item(1) ›calculate │ 0.122 s │ 48.38% │ 52.44% │ 1 │ 0.122 s │
│ process_item(1) ›calculate ›guestimate │ 0.122 s │ 48.38% │ 100.00% │ 1 │ 0.122 s │
│ process_item(1) ›calculate ›guestimate ›do_math │ 0.122 s │ 48.37% │ 99.99% │ 1 │ 0.122 s │
│ process_item(1) ›save │ 0.058 s │ 23.23% │ 25.18% │ 1 │ 0.058 s │
│ process_item(1) ›db.find │ 0.052 s │ 20.64% │ 22.37% │ 1 │ 0.052 s │
│ Unmeasured │ 0.019 s │ 7.74% │ │ │ │
├─────────────────────────────────────────────────┼─────────┼────────┼─────────┼───────┼──────────┤
│ Total │ 0.251 s │ 100% │ │ │ │
└─────────────────────────────────────────────────┴─────────┴────────┴─────────┴───────┴──────────┘
────────────────────────────────────────── PyHaste report ──────────────────────────────────────────
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━┓
┃ Name ┃ Time ┃ Tot % ┃ Rel % ┃ Calls ┃ Per call ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━┩
│ process_item(2) │ 0.511 s │ 94.66% │ │ 1 │ 0.511 s │
│ process_item(2) ›calculate │ 0.288 s │ 53.38% │ 56.40% │ 1 │ 0.288 s │
│ process_item(2) ›calculate ›guestimate │ 0.288 s │ 53.38% │ 100.00% │ 1 │ 0.288 s │
│ process_item(2) ›calculate ›guestimate ›do_math │ 0.288 s │ 53.38% │ 99.99% │ 1 │ 0.288 s │
│ process_item(2) ›save │ 0.125 s │ 23.10% │ 24.41% │ 1 │ 0.125 s │
│ process_item(2) ›db.find │ 0.098 s │ 18.16% │ 19.19% │ 1 │ 0.098 s │
│ Unmeasured │ 0.029 s │ 5.34% │ │ │ │
├─────────────────────────────────────────────────┼─────────┼────────┼─────────┼───────┼──────────┤
│ Total │ 0.540 s │ 100% │ │ │ │
└─────────────────────────────────────────────────┴─────────┴────────┴─────────┴───────┴──────────┘
────────────────────────────────────────── PyHaste report ──────────────────────────────────────────
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━┓
┃ Name ┃ Time ┃ Tot % ┃ Rel % ┃ Calls ┃ Per call ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━┩
│ process_item(3) │ 0.749 s │ 93.21% │ │ 1 │ 0.749 s │
│ process_item(3) ›calculate │ 0.368 s │ 45.84% │ 49.18% │ 1 │ 0.368 s │
│ process_item(3) ›calculate ›guestimate │ 0.368 s │ 45.84% │ 100.00% │ 1 │ 0.368 s │
│ process_item(3) ›calculate ›guestimate ›do_math │ 0.368 s │ 45.84% │ 100.00% │ 1 │ 0.368 s │
│ process_item(3) ›save │ 0.217 s │ 27.07% │ 29.04% │ 1 │ 0.217 s │
│ process_item(3) ›db.find │ 0.163 s │ 20.29% │ 21.77% │ 1 │ 0.163 s │
│ Unmeasured │ 0.055 s │ 6.79% │ │ │ │
├─────────────────────────────────────────────────┼─────────┼────────┼─────────┼───────┼──────────┤
│ Total │ 0.803 s │ 100% │ │ │ │
└─────────────────────────────────────────────────┴─────────┴────────┴─────────┴───────┴──────────┘
Async usage and FastAPI example
Async Python causes some problems for following the stack, so we can't create these nested call stacks and relative calculations automatically. If you're ok with just making sure your names have the necessary degree of identification in some other way, you can use the async version by importing from pyhaste.async_analyzer. There's also an additional measure_wrap_async.
See pyhaste_async_demo.py and the FastAPI demo for usage examples.
If you've got good ideas on how we can reliably track the call stack context in async Python code please do share 🙂
Development
Issues and PRs are welcome!
Please open an issue first to discuss the idea before sending a PR so that you know if it would be wanted or needs re-thinking or if you should just make a fork for yourself.
For local development, make sure you install pre-commit, then run:
pre-commit install
poetry install
poetry run ptw .
poetry run python example.py
cd fastapi_example
poetry run python example.py
License
The code is released under the BSD 3-Clause license. Details in the LICENSE.md file.
Financial support
This project has been made possible thanks to Cocreators and Lietu. You can help us continue our open source work by supporting us on Buy me a coffee.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyhaste-1.1.4.tar.gz.
File metadata
- Download URL: pyhaste-1.1.4.tar.gz
- Upload date:
- Size: 6.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
09580275ffe96f053443e2651dd39aaf75abe68df152e4b49b8c4f1b1293b33a
|
|
| MD5 |
9b72bb1bf2d1aaf26044472997b9d9fe
|
|
| BLAKE2b-256 |
93da4905a2bd17ea06f936572040ce368e2a7b8ceae69c3aae05e35fbbb30b6d
|
Provenance
The following attestation bundles were made for pyhaste-1.1.4.tar.gz:
Publisher:
publish.yaml on cocreators-ee/pyhaste
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyhaste-1.1.4.tar.gz -
Subject digest:
09580275ffe96f053443e2651dd39aaf75abe68df152e4b49b8c4f1b1293b33a - Sigstore transparency entry: 582625539
- Sigstore integration time:
-
Permalink:
cocreators-ee/pyhaste@c5f017ee48acff9aa2a0a6d22baeb0d784fe7ff8 -
Branch / Tag:
refs/tags/1.1.4 - Owner: https://github.com/cocreators-ee
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@c5f017ee48acff9aa2a0a6d22baeb0d784fe7ff8 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pyhaste-1.1.4-py3-none-any.whl.
File metadata
- Download URL: pyhaste-1.1.4-py3-none-any.whl
- Upload date:
- Size: 7.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d39ae70cf5c89370a162cf245acd121e863089fdf73496052dec1da33e1abb9f
|
|
| MD5 |
a0ac95d69e4dd7b38fabfbfbd1c2664c
|
|
| BLAKE2b-256 |
04b20ff23bd0f8cac15c58978549b47449b9efad1b8b843e46ab9a2ac35e0617
|
Provenance
The following attestation bundles were made for pyhaste-1.1.4-py3-none-any.whl:
Publisher:
publish.yaml on cocreators-ee/pyhaste
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyhaste-1.1.4-py3-none-any.whl -
Subject digest:
d39ae70cf5c89370a162cf245acd121e863089fdf73496052dec1da33e1abb9f - Sigstore transparency entry: 582625549
- Sigstore integration time:
-
Permalink:
cocreators-ee/pyhaste@c5f017ee48acff9aa2a0a6d22baeb0d784fe7ff8 -
Branch / Tag:
refs/tags/1.1.4 - Owner: https://github.com/cocreators-ee
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@c5f017ee48acff9aa2a0a6d22baeb0d784fe7ff8 -
Trigger Event:
push
-
Statement type: