PyHaste

Python code speed analyzer


Keywords
performance, measuring, benchmark, benchmarking, analyzer
License
BSD-3-Clause
Install
pip install PyHaste==1.1.2

Documentation

PyHaste

GitHub Workflow Status Code style: ruff Pre-commit PyPI PyPI - Python Version License: BSD 3-Clause

Python code speed analyzer.

PyHaste screenshot

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

Usage

To measure your code, pyhaste exports a measure context manager, give it a 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% β”‚         β”‚       β”‚          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

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.

"Buy Me A Coffee"