Skip to main content

Simple profile decorators to monitor execution time and memory usage.

Project description

simple-profile

Simple decorators to profile the memory usage and execution time.

Installation

pip install simple-profile

Decorators

Decorator Description
@simple_profile() Profiles the peak memory usage and the average execution time of a function.
@memory_profile() Profiles only the peak memory usage of a function.
@time_profile() Profiles only the average execution time of a function.

Usage

1. Profile a function

The @simple_profile() decorator allows to log the peak memory usage and the average execution time of each function call.
By default, memory usage and execution time are logged in the most suitable units, but it is possible to change the units.

from simple_profile import simple_profile

@simple_profile()
def my_function():
    return [2 * i for i in range(10)]

my_function()

Output:

my_function | 432 B | 445.2 ns

2. Profile only the memory usage of a function

The @memory_profile() decorator allows to log the peak memory usage of each function call.
This is done using the tracemalloc module provided by Python.

from simple_profile import memory_profile

@memory_profile()
def my_function():
    return [2 * i for i in range(10)]

my_function()

Output:

my_function | 432 B

3. Profile only the execution time of a function

The @time_profile() decorator allows to log the average execution time of each function call.
This is done using the timeit module provided by Python.
By default, each function call is repeated 1,000,000 times to get a reliable measurement, but it is possible to change this value.

from simple_profile import time_profile

@time_profile()
def my_function():
    return [2 * i for i in range(10)]

my_function()

Output:

my_function | 439.3 ns

4. Change the number of iterations

It is possible to change the number of times a function call is repeated when profiling the execution time.
To do this, you can set the iterations argument of the simple_profile() and time_profile() decorators.

from simple_profile import simple_profile

@simple_profile(iterations=100)
def pi(n):
    result = 0
    d = 1
    for i in range(1, n):
        a = 2 * (i % 2) - 1
        result += 4 * a / d
        d += 2
    return result

pi(100)

Output:

pi | 168 B | 6.461 µs

5. Change the time and memory units

It is also possible to change the time and memory units used in the logs.
To do this, you can set the unit argument of the memory_profile() and time_profile() decorators.
For the simple_profile() decorator, you can set the time_unit and memory_unit arguments.

from simple_profile import simple_profile, MemoryUnit, TimeUnit

@simple_profile(memory_unit=MemoryUnit.KILOBYTES, time_unit=TimeUnit.MILLISECONDS)
def exponential(x, n):
    result = 1.0
    for i in range(n, 0, -1):
        result = 1 + x * result / i
    return result

exponential(8, 100)

Output:

exponential | 0.168 kB | 0.005429 ms

6. Change the time and memory precision

Moreover, it is possible to change the precision of memory and time values.
To do this, you can define the number of significant digits you want in the precision argument of any decorator provided by this package.
For the simple_profile() decorator, you can set the time_precision and memory_precision arguments for more granular control.

from simple_profile import simple_profile

@simple_profile(precision=10)
def average(lst):
    return sum(lst) / len(lst)

average([25, 12, 18, 88, 64, 55, 22])

Output:

average | 120 B | 176.6314 ns

7. Log the arguments and the result

Furthermore, it is possible to log the arguments and the result of each function call.
Indeed, this can be useful to better profile a function and analyze its behavior.

from simple_profile import simple_profile

@simple_profile(print_args=True, print_result=True)
def greeting_message(name, coins):
    return "Hello {}! You have {} coins.".format(name, coins)

greeting_message("John", coins=5)

Output:

greeting_message | John, coins=5 | Hello John! You have 5 coins. | 521 B | 350.1 ns

8. Set a custom name for a function

Additionally, it is possible to define a custom descriptive name for each function.
To do this, you can set the name argument of any decorator provided by this package.

from simple_profile import simple_profile

@simple_profile(name="Naive method")
def factorial(n):
    result = 1
    for i in range(1, n + 1):
        result *= i
    return result

factorial(10)

Output:

Naive method | 160 B | 411.3 ns

9. Compare multiple functions

from simple_profile import simple_profile

@simple_profile(name="List comprehension")
def my_function(n):
    return [pow(2, i) for i in range(n)]


@simple_profile(name="For loop")
def my_function_2(n):
    lst = []
    for i in range(n):
        lst.append(pow(2, i))
    return lst

my_function(10)
my_function_2(10)

Output:

List comprehension | 464 B | 666.8 ns
For loop | 312 B | 650.7 ns

10. Profile a recursive function

The decorators work seamlessly with recursive functions.
Only one profiling message is logged per function call even if the function is recursive.

from simple_profile import simple_profile

@simple_profile(print_args=True, print_result=True, iterations=100)
def fibonacci(n):
    if n <= 1:
        return n
    else:
        return fibonacci(n - 1) + fibonacci(n - 2)

fibonacci(10)

Output:

fibonacci | 10 | 55 | 1.648 kB | 21.04 µs

11. Enable garbage collection during measurements

By default, garbage collection is temporarily turned off to make measurements more comparable, but it is possible to enable it if you prefer.
To do this, you can set the enable_gc argument of the simple_profile() and time_profile() decorators to True.

from simple_profile import simple_profile

@simple_profile(name="Without GC")
def my_function():
    return [oct(i) for i in range(10)]

@simple_profile(name="With GC", enable_gc=True)
def my_function_2():
    return [oct(i) for i in range(10)]

my_function()
my_function_2()

Output:

Without GC | 954 B | 666.5 ns
With GC | 954 B | 669.2 ns

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

simple_profile-1.1.2.tar.gz (19.3 kB view details)

Uploaded Source

Built Distribution

simple_profile-1.1.2-py3-none-any.whl (19.2 kB view details)

Uploaded Python 3

File details

Details for the file simple_profile-1.1.2.tar.gz.

File metadata

  • Download URL: simple_profile-1.1.2.tar.gz
  • Upload date:
  • Size: 19.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.2.2 CPython/3.11.0 Windows/10

File hashes

Hashes for simple_profile-1.1.2.tar.gz
Algorithm Hash digest
SHA256 9548512379b38391729f31b7656049ac67b4113279c97fd77d7ac2099933519c
MD5 a2f3a62c69a2d7a83f72a41272bdc1e7
BLAKE2b-256 64367899a1ab16f660c2c948be11e4835b87dc41ac1fe17c004f19fe46e9ecca

See more details on using hashes here.

File details

Details for the file simple_profile-1.1.2-py3-none-any.whl.

File metadata

  • Download URL: simple_profile-1.1.2-py3-none-any.whl
  • Upload date:
  • Size: 19.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.2.2 CPython/3.11.0 Windows/10

File hashes

Hashes for simple_profile-1.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 cbc59dcfed821dd08e31a847c216d6f43b0331b38c779d10b55778e6dcf37ea9
MD5 d118d3119835e800e713e6d9bbef9c98
BLAKE2b-256 f467d27351a077b024d137cfdbc8888cffcdd0b25ffb9d58ff302eae7b4dded5

See more details on using hashes here.

Supported by

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