Metadata-Version: 2.4
Name: timing
Version: 0.6.1.dev4+git5b791be1
Summary: Simplify logging of timings of selected parts of an application.
Home-page: https://github.com/mbdevpl/timing
Download-URL: 
Author: Mateusz Bysiek
Author-email: mateusz.bysiek@gmail.com
Maintainer: Mateusz Bysiek
Maintainer-email: mateusz.bysiek@gmail.com
License-Expression: Apache-2.0
Keywords: timing,timer,time measurement,profiling,reproducibility
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Natural Language :: English
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: System :: Benchmark
Classifier: Topic :: System :: Logging
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/x-rst; charset=UTF-8
License-File: LICENSE
License-File: NOTICE
Requires-Dist: numpy~=2.2
Requires-Dist: version-query~=1.6
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license-file
Dynamic: license-expression
Dynamic: maintainer
Dynamic: maintainer-email
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

.. role:: python(code)
    :language: python


======
timing
======

Simplify logging of timings of selected parts of an application.

.. image:: https://img.shields.io/pypi/v/timing.svg
    :target: https://pypi.org/project/timing
    :alt: package version from PyPI

.. image:: https://github.com/mbdevpl/timing/actions/workflows/python.yml/badge.svg?branch=main
    :target: https://github.com/mbdevpl/timing/actions
    :alt: build status from GitHub

.. image:: https://codecov.io/gh/mbdevpl/timing/branch/main/graph/badge.svg
    :target: https://codecov.io/gh/mbdevpl/timing
    :alt: test coverage from Codecov

.. image:: https://api.codacy.com/project/badge/Grade/5dba9ea9f47e4e86aeed6eddfce42640
    :target: https://app.codacy.com/gh/mbdevpl/timing
    :alt: grade from Codacy

.. image:: https://img.shields.io/github/license/mbdevpl/timing.svg
    :target: https://github.com/mbdevpl/timing/blob/v0.6.1.dev4+git5b791be1/NOTICE
    :alt: license

.. contents::
    :backlinks: none


How to use
==========

Recommended initialization is as follows.

.. code:: python

    import timing

    _TIME = timing.get_timing_group(__name__)  # type: timing.TimingGroup


This follows the conventions of :python:`logging` module.

.. code:: python

    import logging

    _LOG = logging.getLogger(__name__)

Any name can be used instead of :python:`__name__`.
However, if names of format :python:`module.sub.sub_sub` are used, this will create a timing
hierarchy where each timing data is stored in its proper location and can be queried easier.

The resulting :python:`_TIME` object is used to create individual timers,
and will handle storing results in cache, which later can be used to obtain timing statistics.

You can obtain the timer object directly via :python:`start(name)` method.
You'll need to manually call :python:`stop()` in this case.

.. code:: python

   timer = _TIME.start('spam')  # type: timing.Timing
   spam()
   more_spam()
   timer.stop()


You can also obtain the timer object indirectly via :python:`measure(name)` context manager.
The context manager will take care of calling :python:`stop()` at the end.

.. code:: python

    with _TIME.measure('ham') as timer:  # type: timing.Timing
        ham()
        more_ham()


And if you want to time many repetitions of the same action (e.g. for statistical significance)
you can use :python:`measure_many(name[, samples][, threshold])` generator.

You can decide how many times you want to measure via :python:`samples` parameter
and how many seconds at most you want to spend on measurements via :python:`threshold` parameter

.. code:: python

    for timer in _TIME.measure_many('eggs', samples=1000):  # type: timing.Timing
        eggs()
        more_eggs()

    for timer in _TIME.measure_many('bacon', threshold=0.5):  # type: timing.Timing
        bacon()
        more_bacon()

    for timer in _TIME.measure_many('tomatoes', samples=500, threshold=0.5):  # type: timing.Timing
        tomatoes()
        more_tomatoes()


Also, you can use :python:`measure` and :python:`measure(name)` as decorator.
In this scenario you cannot access the timings directly, but the results will be stored
in the timing group object, as well as in the global cache unless you configure the timing
to not use the cache.

.. code:: python

    import timing

    _TIME = timing.get_timing_group(__name__)

    @_TIME.measure
    def recipe():
        ham()
        eggs()
        bacon()

    @_TIME.measure('the_best_recipe')
    def bad_recipe():
        spam()
        spam()
        spam()


Then, after calling each function the results can be accessed through :python:`summary` property.

.. code:: python

    recipe()
    bad_recipe()
    bad_recipe()

    assert _TIME.summary['recipe']['samples'] == 1
    assert _TIME.summary['the_best_recipe']['samples'] == 2


The :python:`summary` property is dynamically computed on first access. Subsequent accesses
will not recompute the values, so if you need to access the updated results,
call the :python:`summarize()` method.

.. code:: python

    recipe()
    assert _TIME.summary['recipe']['samples'] == 1

    bad_recipe()
    bad_recipe()
    assert _TIME.summary['the_best_recipe']['samples'] == 2  # will fail
    _TIME.summarize()
    assert _TIME.summary['the_best_recipe']['samples'] == 2  # ok


Further API and documentation are in development.


See these examples in action in `examples.ipynb <https://github.com/mbdevpl/timing/blob/v0.6.1.dev4+git5b791be1/examples.ipynb>`_ notebook.


Requirements
============

Python version 3.11 or later.

Python libraries as specified in `requirements.txt <https://github.com/mbdevpl/timing/blob/v0.6.1.dev4+git5b791be1/requirements.txt>`_.

Building and running tests additionally requires packages listed in `requirements_test.txt <https://github.com/mbdevpl/timing/blob/v0.6.1.dev4+git5b791be1/requirements_test.txt>`_.

Tested on Linux, macOS and Windows.
