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.3.0.tar.gz (4.6 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.3.0-py3-none-any.whl (5.1 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for heavyops-0.3.0.tar.gz
Algorithm Hash digest
SHA256 c3920c3b98f2bc1b76eb01b38cc366a85deea7e90f0a9d25102af9006631979f
MD5 cc18c0eceee36bc15504c34a3c9c283b
BLAKE2b-256 0bd5fefd496155b87e44953c62c4d8a9af1124c59dafae27de03e17b3a06aa25

See more details on using hashes here.

File details

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

File metadata

  • Download URL: heavyops-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 5.1 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.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 df5d9291880e1629a7555d5bd173f1853a42f339ac713ff56c5d6bb1344fa274
MD5 7d5564b2a85eb39b73da10cd36782ea2
BLAKE2b-256 71496542fadb0b2a69671e23f4df32d0e5837773f031b28850860e6a3d20fe9d

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