Skip to main content

Time a block of code.

Project description

A function-decorator and a context-manager (with-statement) to time a block of code.

If your program is executing a lengthy operation, it’s good UI to let the user know what’s going on, rather than just silently chomping along. The user will have insight on what the process is stuck on and can decide if that was expected or not. This library lets the programmer tag some functions with a decorator or with-statement that logs when the function starts and finishes executing.

The user won’t want to see every function, but judiciously labeling a few top-level blocks with human-readable strings makes the program’s running times more understandable.

Logging the start and end can also be useful for high-level macro-optimization. line_profiler will measure every line, which comes with overhead and lots more data. Most lines are not the bottleneck, so this is just adding hay to the haystack and the performance overhead. line_profiler is good for micro-optimization when you already know where the bottleneck is; this package is good for learning what high-level operation is the bottleneck.

Quickstart

$ pip install charmonium.time_block
>>> import charmonium.time_block as ch_time_block
>>> import time
>>>
>>> def main():
...     with ch_time_block.ctx("downloading data"):
...         time.sleep(0.2)
...
>>> main()
downloading data: running
downloading data: finished in now

Equivalent a decorator:

>>> @ch_time_block.decor()
... def download_data():
...     time.sleep(0.2)
...
>>> download_data()
download_data: running
download_data: finished in now

Like function profiling, but unlike other block-loggers, this package maintains a call stack of declared blocks (not every function). This “perforated stack” lets the programmer explicitly what gets logged to the user. In particular, the description field allows one to customize the representation of that stack frame, and the comment field allows one to add a message just at the start, such as the problem-size.

>>> @ch_time_block.decor(
...     # fn params are available for use in the format string
...     description="delete-{x}",
...     comment="({x} nodes)",
... )
... def delete_nodes(x):
...     with ch_time_block.ctx(
...         description=f"finder-{x}",
...         comment=f"({x} nodes)",
...     ):
...         time.sleep(0.1)
...
>>> delete_nodes(32)
delete-32: running
delete-32 > finder-32: running
delete-32 > finder-32: finished in now
delete-32: finished in now

Unlike external profiling, this package reports in realtime to logger (destination customizable). This is intended to let the user know what the code is doing right now.

Since this plugs into Python’s logger infrastructure, this can feed a pipeline that checks the application health.

This records process’s increase in memory usage (relatively cross-platform method using psutil) when do_gc=True, which gives a rough estimate of the memory leaked by the block. If a function consistently uses memory that doesn’t get freed when the function returns, it may indicate a memory leak. In high-level graph processing code, this is helpful to know _which_ transformation is eating up all of RAM.

>>> variable = []
>>> @ch_time_block.decor()
... def main():
...     # Oops, leaking memory in global variable
...     variable.append("abc" * 16384)
...
>>> main()
main: running
main: finished in now, leaked ...KiB

TODO

  • Explain iter, iter no elements, and async variants

  • Describe workflow

  • Note on performance/coarseness

    • Have global disable

    • Have context disable?

  • Documentation explains two ways of getting the stats: event-based and batch

    • Print, structlog, logging, rich backends

      • Should be very easy to get a print; then ensure doctests work.

  • Integration with other profilers

  • There should be an easy integration with Typer/Click and with global/atexit

  • Persistence

    • Save at final frame

    • Use hash of frame func + module version + global version

  • Frames have optional data

    • Could have size vector

      • Could implement global progress bar

  • Show the active awaitables?

  • Can we do async_ctx? Probably not. If not, explain why in README

    • Should we be an async event loop? Probably not.

  • Use term scope timer in documentation

  • Differentiators: print, time async, time iters, includes memory

  • Plug in to existing profile visualizers. Make a flame graph.

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

charmonium_time_block-1.0.0.tar.gz (13.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

charmonium_time_block-1.0.0-py3-none-any.whl (14.4 kB view details)

Uploaded Python 3

File details

Details for the file charmonium_time_block-1.0.0.tar.gz.

File metadata

  • Download URL: charmonium_time_block-1.0.0.tar.gz
  • Upload date:
  • Size: 13.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.4.1 CPython/3.13.13 Linux/6.18.33

File hashes

Hashes for charmonium_time_block-1.0.0.tar.gz
Algorithm Hash digest
SHA256 54e48376601a4247637f6d74d84d94484432efaa0b90ba68b9882afbed4f67af
MD5 274c00f204bc74b4c39225938d1fc9a8
BLAKE2b-256 443b32c7816259377df85bf330e552411556af734b50168797bd5a544b669616

See more details on using hashes here.

File details

Details for the file charmonium_time_block-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for charmonium_time_block-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 47544ebfc934ea4558fa7c51e056b745b44d31297f2eaf41add787c7452ab092
MD5 8536e325422cd57477116432f6e09875
BLAKE2b-256 57cc2a2274720f9b4af8f12e37bbda79fe109bf2096b2aa6409dd3f75aaf4d91

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page