Profile specific bytecode operations in a target script
Project description
heavyops
heavyops allows you to identify performance bottlenecks related to specific bytecode instructions.
Example use case: side effects of closures
When a variable is captured by a closure, Python creates a cell object to hold the variable. This can lead to performance overhead. By tracking LOAD_DEREF instructions, you can identify functions that use closures and refactor them if necessary. For example:
class Foo:
def __init__(self, lo, hi):
self.lo = lo
self.hi = hi
def intersects(self, other):
if isinstance(other, Foo):
return self.lo < other.hi and other.lo < self.hi
elif isinstance(other, list):
# the following captures 'self' in a closure for the generator expression
return any(self.intersects(item) for item in other)
else:
return False
for i in range(1000):
Foo(1, 4).intersects(Foo(2, 5))
Even though the generator expression is not in a hot path, it captures self, leading to the creation of a cell object for self and the use of LOAD_DEREF instructions in the hot path:
$ python3 -m heavyops example.py
3,814 / 94,467 tracked instructions
COUNT | INSTRUCTION
--------------------------------------------------
2,662 | LOAD_DEREF
512 | MAKE_FUNCTION
...
COUNT | LOCATION
--------------------------------------------------
1,000 | example.py:8 intersects LOAD_DEREF
1,000 | example.py:8 intersects LOAD_DEREF
...
This can be fixed by avoiding the generator expression, for example by using a for loop:
class Foo:
def __init__(self, lo, hi):
self.lo = lo
self.hi = hi
def intersects(self, other):
if isinstance(other, Foo):
return self.lo < other.hi and other.lo < self.hi
elif isinstance(other, list):
for item in other:
if self.intersects(item):
return True
return False
Usage
After installation an executable heavyops is available. Simply run it with the target script and its arguments:
heavyops [options] target_script.py [script_args...]
or as a module:
python3 -m heavyops [options] target_script.py [script_args...]
By default, it will report the following instructions:
MAKE_FUNCTIONBUILD_TUPLEBUILD_LISTBUILD_SETBUILD_MAPLOAD_DEREF
You can customize the instructions to track using on or more -i / --instructions flags.
heavyops -i MAKE_FUNCTION -i BUILD_LIST my_app arg1 arg2
You can restrict tracking to specific files using the -f / --file flag:
heavyops -f 'specific_file.py' my_app arg1 arg2
Project details
Release history Release notifications | RSS feed
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 heavyops-0.1.0.tar.gz.
File metadata
- Download URL: heavyops-0.1.0.tar.gz
- Upload date:
- Size: 3.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c8ca8cf6d220aac565acada9e45fde76564cc492b1aacba8e2394d9647ec89e8
|
|
| MD5 |
731f7a8179402c3e02ec442e41bbb232
|
|
| BLAKE2b-256 |
b6d863257383c72f0056640fce94cb43564753e750970506948081744263c6e5
|
File details
Details for the file heavyops-0.1.0-py3-none-any.whl.
File metadata
- Download URL: heavyops-0.1.0-py3-none-any.whl
- Upload date:
- Size: 3.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4110dc678d5dcdb7db7d5b0b9dfcf816f3b7e6fee5dc56a2e549b16d515dfb70
|
|
| MD5 |
32a57f190df33f38fa69ca4f45ae027b
|
|
| BLAKE2b-256 |
27e115821fad203e77f643f9f3d4077eccc6a1b30a055ddbed73d42f2ec6ef97
|