Skip to content

ppy_runtime

ppy_runtime holds what a built artifact needs at launch, and nothing more. It never imports ppy_compiler.

A compiled application depends on the interpreter, this runtime, its native library, and its manifest. It keeps working with the compiler uninstalled.

Launching

ppy_runtime.launch

Run a built artifact: load, bind, execute -- and never compile.

This is the whole runtime path of an AOT build. It reads the manifest, opens the native library, rebuilds the guarded bindings from the recorded ABI, loads the generated Python the build wrote, and runs the entry module. No parsing, no analysis, no LLVM: those all happened at build time.

PrebuiltBinder(manifest, library)

Bases: LibraryBinder

Serves the entries a manifest recorded, out of one shared library.

region(module, function, fallback)

Serve a compiled ATen region out of the extension the build shipped.

generated_modules(manifest)

The generated Python modules a manifest names, read off disk.

ppy_runtime.manifest

Loading the binding manifest: the artifact's contract with this runtime.

The manifest is data a build wrote once; loading it must stay cheap and must never reconstruct compiler state. Validation is schema, ABI version, interpreter compatibility, and file presence -- nothing that reads source.

ManifestError

Bases: RuntimeError

The artifact cannot be run, with the reason and the remedy.

RegionLibrary(library, entries) dataclass

One generated module's compiled ATen regions: the extension holding them, and the C++ symbol that serves each function.

host_runs(target)

Whether this machine is the one target names, by architecture and OS.

The runtime has no LLVM to ask, so it compares the words a triple is made of with what the platform says of itself.

Binding and the ABI

ppy_runtime.binding

Python-ABI trampolines for natively lowered functions (spec 16.4, 25.3).

Runtime-only: a built artifact binds through this module with no compiler installed. JIT specialization is an optional hook the compiler passes in, and its machinery is imported only when it is actually used.

SanitizerFailure

Bases: RuntimeError

A --sanitize check failed in native code; the message names the kind and the function.

GuardFailed

Bases: Exception

A runtime guard rejected an argument, so the Python path must run.

NativeBinding(signature, wrapper, fallback, calls=0, fallbacks=0, specialized_calls=0, fast_entry=None, owner=None, selectors=list(), registered=0, key_counts=dict(), observations=0, observing=False) dataclass

A guarded native entry point with a Python fallback.

observation_wanted(specializer, policy, info)

Whether this function still wants Python watching for specialization.

value_class_types(signature, fallback)

The runtime classes a generated wrapper guards value parameters on.

Resolved from the defining module, so a class the wrapper cannot see means no fast entry rather than a wrong one.

remember(entry, signature)

Record that entry, a generated C entry point, runs signature natively.

signature_of(function)

The native signature calling function runs under here, or None when the call is Python's: the wrapper's attribute, or the adopted C entry point.

adopt(signature, entry, fallback, *, owner=None)

Adopt a generated wrapper that already holds its Python fallback in C.

Nothing stands between the caller and the C entry point, so per-call statistics are not collected on this path.

bind(signature, address, fallback, *, specializer=None, policy=None, info=None, fast_entry=None, owner=None, register=None)

Build the Python-callable wrapper for one native function.

ctypes.CFUNCTYPE releases the GIL around the foreign call, which is what a native region touching no Python objects is allowed to do (spec 16.6).

When the function asked for it, repeated argument shapes are compiled into guarded specializations and selected here (spec 16.9).

ppy_runtime.abi

The PPY native ABI, as data: what a compiled artifact promises (spec 16.4).

This is the contract a binding manifest serializes and a runtime rebuilds. Nothing here may depend on the compiler: the same dataclasses describe a function to the lowering that emits it and to the runtime that calls it years later.

NativeParam(name, kind, element='', elements=(), fields=(), class_name='') dataclass

One source-level parameter and the ABI atoms it expands to.

is_pointer property

A ppy.native.ptr[T]: one machine address, no Python boundary.

is_handle property

A ppy.Vec or another collection: its runtime handle, no Python boundary.

is_borrowed property

A ppy.Buffer[T] is borrowed in place; a list is copied out.

A Python list holds boxed elements, so there is no contiguous array to point at. A buffer-protocol object already has one (spec 6.4, 13.8).

NativeSignature(qualname, symbol, parameters, returns, releases_gil=False, cpu_features=(), future='') dataclass

The PPY native ABI for one function (spec 16.4).

Runtimes native code calls into

ppy_runtime.arrow

Arrow arrays across the native boundary: the C Data Interface, without a copy.

An Arrow array is handed to native code as the ArrowArray struct the Arrow C Data Interface defines -- length, null count, offset, and the buffers -- which arrow.import in the IR reads directly. No PyObject crosses the boundary (spec 54). The producer keeps ownership: the struct's release callback is called when the borrow ends, and never twice.

from ppy_runtime.arrow import exported

with exported(array) as struct:      # the address of an ArrowArray
    native(struct, ...)

ArrowArray

Bases: Structure

struct ArrowArray of the Arrow C Data Interface.

ArrowSchema

Bases: Structure

struct ArrowSchema of the Arrow C Data Interface.

release(struct)

Give the producer its memory back, once; a released struct is inert.

exported(array)

Borrow array (a pyarrow.Array) as an ArrowArray struct: its address.

The array's buffers are shared, not copied; the struct is released when the block ends, whatever happened inside it.

ppy_runtime.aio

The native async runtime's Python face: its library, its futures, and how they run (spec 77).

The runtime is one C file beside this module. It is compiled once, on first use, with the C compiler the machine has, into the user's cache, and loaded into the process; compiled code the JIT makes and a built artifact both reach the same functions, so a future one side started the other can drive. Without a compiler, or off Linux, there is no runtime: available() says so, reason() says why, and every coroutine runs under asyncio.

NativeGuardFailed

Bases: RuntimeError

A guard failed inside a native coroutine, where nothing can fall back.

A compiled coroutine that has already slept or spoken on a socket cannot hand the work back to its Python definition; the honest answer is this error, naming the function. --safeguards off or a body the prover clears keeps the guard out of the coroutine.

Runtime(library)

ppy_aio_* through ctypes, on whichever library holds them.

NativeFuture(handle, kind, runtime_, function='')

What a natively compiled async def hands back when called: a future the runtime owns.

ppy.aio.run drives the loop until it completes; awaited from asyncio, it steps the native loop between the Python loop's turns. Its value is read once.

start()

Run this coroutine from the loop's next turn on, without waiting for it.

result()

Run the loop until this future completes, and its value.

compiler()

The C compiler that builds the runtime: CC, else the first of cc, gcc, clang.

reason()

Why the runtime is unavailable here; empty when it is.

library_path()

The compiled runtime, built into the cache on first use; None with the reason kept.

runtime()

The process's runtime, on the library library_path built; None without one.

runtime_for(owner)

The runtime a native function's own library carries, else the process's.

ppy_runtime.cuda

Launching a compiled kernel: the CUDA driver through ctypes, no toolkit needed (spec 75).

The build stages a kernel as PTX with the kinds of its parameters; a Kernel loads it into the device's primary context once and launches it. Scalars are passed by value; a native pointer's whole array goes to the device before the launch and comes back after it when the pointer is mutable, so a launch means exactly what the reference launch means, only on the device. Memory made by cuda.device_alloc already lives there: its address is passed and nothing is copied. A machine without the driver, or without a device, has no kernel to bind: the reference runs instead, and the binding says why.

CudaError

Bases: RuntimeError

The driver refused: the message carries its error string.

Driver(library)

The CUDA driver, loaded once, with the first device's primary context.

Kernel(function, symbol, ptx, params, threads=0)

One compiled kernel: its PTX, its symbol, and the kinds of its parameters.

launch(grid, block, arguments)

Run the kernel over grid blocks of block threads with arguments, and wait.

driver()

The driver, loaded on first use; None where there is none, or PPY_NO_CUDA is set.

kernel_binding(function, payload, fallback)

The staged kernel behind function, for ppy.cuda.launch to find.

Called directly, a kernel runs its own definition, as it would under CPython; launched, it runs on the device. Without a driver the binding is the fallback and says why.

ppy_runtime.xla

Running a compiled ppy.xla function: the payload the build staged, on a device.

The payload is what the compiler wrote for an @ppy.xla.jit function: the StableHLO module and the kinds of its parameters and results. runtime_call turns it into a callable that places the arguments on the device, runs the executable, and hands back Python values -- a float for a float, an array for a tensor -- so the program sees what the Python path would have given it (spec 64, 65, 66).

available()

Are the XLA bindings and JAX's buffer placement importable? (No import happens.)

runtime_call(payload)

A callable running the compiled function payload describes.

Staged artifacts

ppy_runtime.exported

Calling a build-time exported graph region (spec 21.3, 21.4).

bind_exported(function, payload, fallback)

Rehydrate an exported computation, falling back to the staged function.

The exported artifact carries its own StableHLO and calling metadata, so invoking it does not re-trace the Python source. Shapes outside the exported signature fall back, which is what shape polymorphism does not cover (spec 21.5).

ppy_runtime.regions

Guarded dispatch into a compiled ATen region (spec 20.6).

bind_region(function, compiled, fallback)

Wrap a compiled region in the guards its curated domain requires.

Every at:: call inside the region goes through the dispatcher, so autograd and device selection need no guard. What does need one is the Python override machinery the region bypasses (spec 20.6).