Skip to main content

Profile specific bytecode operations in a target script

Project description

heavyops

heavyops identifies performance bottlenecks related to specific bytecode instructions.

Use it to find redundant object allocations, unexpected side effects of closures, and other inefficiencies in your Python code.

The project is based on sys.monitoring.

Installation

$ pip install heavyops

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_FUNCTION
  • BUILD_TUPLE
  • BUILD_LIST
  • BUILD_SET
  • BUILD_MAP
  • LOAD_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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

heavyops-0.2.0.tar.gz (4.4 kB view details)

Uploaded Source

Built Distribution

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

heavyops-0.2.0-py3-none-any.whl (4.9 kB view details)

Uploaded Python 3

File details

Details for the file heavyops-0.2.0.tar.gz.

File metadata

  • Download URL: heavyops-0.2.0.tar.gz
  • Upload date:
  • Size: 4.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for heavyops-0.2.0.tar.gz
Algorithm Hash digest
SHA256 d1d57b228fbe8b19a585b8e6b2963cefe55db1df42e9291d7ea036bf56dc39cf
MD5 806d264af0071cc5013dc38a049cf6ec
BLAKE2b-256 cc4fa93a48bb2a34d326a67c621d2bbd08003985b1d356f33a4456de47d28787

See more details on using hashes here.

File details

Details for the file heavyops-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: heavyops-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 4.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for heavyops-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ac2c97cc743af25b6336b8894b906a6ee6def523e9c0b6e55aec34c2c8b70d7f
MD5 5372495eaa58f625c9b572a6e7e7d3a4
BLAKE2b-256 dc7851ad7459da6264a8c8b31039c51d01f30fb2a0ecbc8a0f94bedd9c1541ea

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