monitor

package
v0.11.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 7, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Index

Constants

View Source
const (
	LocalEvents     = 11
	UngroupedEvents = 16
	Events          = 19
)

Event-count constants. CPython distinguishes three counts: LocalEvents covers the events that fire from instrumented bytecode (those need a per-codeunit tools table); UngroupedEvents counts every "real" event before the BRANCH_* split; Events is the total count including the derived BRANCH event.

CPython: Include/internal/pycore_instruments.h:70-76

View Source
const MaxToolID = 8

MaxToolID is the upper bound on tool slot indices. CPython packs the active-tool bitmask into a single uint8 per event, so the table cannot grow past 8 without a wider type.

CPython: Include/internal/pycore_instruments.h:70 PY_MONITORING_TOOL_IDS

View Source
const NoLine = -2

NoLine is the sentinel stored in the line table when a codeunit has no source line. CPython: Python/instrumentation.c:294 NO_LINE.

Variables

View Source
var Disable = newSentinel()

Disable is the singleton callbacks return to ask the runtime to stop firing this event for this code object. The fire-event entry points compare returned values for identity.

CPython: Python/instrumentation.c:70 _PyInstrumentation_DISABLE

View Source
var Missing = newSentinel()

Missing is the singleton handed to a callback when the requested value is not available (for example, a return value during PY_THROW).

CPython: Python/instrumentation.c:72 _PyInstrumentation_MISSING

Functions

func BuildSysMonitoring

func BuildSysMonitoring(interp *InterpState) *objects.Module

BuildSysMonitoring returns a *Module populated with the PEP 669 API methods, the DISABLE / MISSING sentinels, and the events namespace. The methods close over interp so the caller does not have to thread a thread-state argument through every Python-level invocation.

CPython: Python/instrumentation.c:2529 _Py_CreateMonitoringObject

func CheckToolID

func CheckToolID(tool Tool) error

CheckToolID reports whether tool is a valid index. Mirrors the CPython argument check used by the sys.monitoring entry points before they touch InterpState.

CPython: Python/instrumentation.c:2126 check_valid_tool

func DeInstrument

func DeInstrument(op compile.Opcode) compile.Opcode

DeInstrument maps INSTRUMENTED_<X> back to <X>, or returns op unchanged if it has no instrumented form.

CPython: Python/instrumentation.c:113 DE_INSTRUMENT

func EnterScope

func EnterScope(interp *InterpState, states []MonState, version *uint32, eventTypes []Event)

EnterScope refreshes the MonState slots from interp.Monitors when the cached version is stale. The eval loop holds the cached version per stack frame so a fresh instrument pass propagates without touching every active state on every event.

CPython: Python/instrumentation.c:2643 PyMonitoring_EnterScope

func ExitScope

func ExitScope()

ExitScope is currently a no-op. CPython keeps the symbol for symmetry; gopy mirrors the shape so callers do not have to special case it.

CPython: Python/instrumentation.c:2660 PyMonitoring_ExitScope

func FireBranchLeft

func FireBranchLeft(interp *InterpState, state *MonState, codelike objects.Object, offset int32, target objects.Object) error

FireBranchLeft fires BRANCH_LEFT.

CPython: Python/instrumentation.c:2764 _PyMonitoring_FireBranchLeftEvent

func FireBranchRight

func FireBranchRight(interp *InterpState, state *MonState, codelike objects.Object, offset int32, target objects.Object) error

FireBranchRight fires BRANCH_RIGHT.

CPython: Python/instrumentation.c:2754 _PyMonitoring_FireBranchRightEvent

func FireCRaise

func FireCRaise(interp *InterpState, state *MonState, codelike objects.Object, offset int32, exc objects.Object) error

FireCRaise fires C_RAISE.

CPython: Python/instrumentation.c:2837 _PyMonitoring_FireCRaiseEvent

func FireCReturn

func FireCReturn(interp *InterpState, state *MonState, codelike objects.Object, offset int32, retval objects.Object) error

FireCReturn fires C_RETURN.

CPython: Python/instrumentation.c:2774 _PyMonitoring_FireCReturnEvent

func FireCall

func FireCall(interp *InterpState, state *MonState, codelike objects.Object, offset int32, callable, arg0 objects.Object) error

FireCall fires CALL.

CPython: Python/instrumentation.c:2708 _PyMonitoring_FireCallEvent

func FireExceptionHandled

func FireExceptionHandled(interp *InterpState, state *MonState, codelike objects.Object, offset int32, exc objects.Object) error

FireExceptionHandled fires EXCEPTION_HANDLED.

CPython: Python/instrumentation.c:2865 _PyMonitoring_FireExceptionHandledEvent

func FireInstruction

func FireInstruction(interp *InterpState, state *MonState, codelike objects.Object, offset int32) error

FireInstruction fires INSTRUCTION.

CPython: Python/instrumentation.c instruments PER_INSTRUCTION via the same fire path; the standalone entry exists in gopy because the dispatch fan-out lives on the Go side.

func FireJump

func FireJump(interp *InterpState, state *MonState, codelike objects.Object, offset int32, target objects.Object) error

FireJump fires JUMP.

CPython: Python/instrumentation.c:2734 _PyMonitoring_FireJumpEvent

func FireLine

func FireLine(interp *InterpState, state *MonState, codelike objects.Object, offset int32, lineno int) error

FireLine fires LINE. Unlike the other entry points the offset is replaced by the line number on the way out.

CPython: Python/instrumentation.c:2718 _PyMonitoring_FireLineEvent

func FirePyResume

func FirePyResume(interp *InterpState, state *MonState, codelike objects.Object, offset int32) error

FirePyResume fires PY_RESUME.

CPython: Python/instrumentation.c:2677 _PyMonitoring_FirePyResumeEvent

func FirePyReturn

func FirePyReturn(interp *InterpState, state *MonState, codelike objects.Object, offset int32, retval objects.Object) error

FirePyReturn fires PY_RETURN.

CPython: Python/instrumentation.c:2688 _PyMonitoring_FirePyReturnEvent

func FirePyStart

func FirePyStart(interp *InterpState, state *MonState, codelike objects.Object, offset int32) error

FirePyStart fires PY_START.

CPython: Python/instrumentation.c:2668 _PyMonitoring_FirePyStartEvent

func FirePyThrow

func FirePyThrow(interp *InterpState, state *MonState, codelike objects.Object, offset int32, exc objects.Object) error

FirePyThrow fires PY_THROW with the currently-raised exception.

CPython: Python/instrumentation.c:2809 _PyMonitoring_FirePyThrowEvent

func FirePyUnwind

func FirePyUnwind(interp *InterpState, state *MonState, codelike objects.Object, offset int32, exc objects.Object) error

FirePyUnwind fires PY_UNWIND.

CPython: Python/instrumentation.c:2879 _PyMonitoring_FirePyUnwindEvent

func FirePyYield

func FirePyYield(interp *InterpState, state *MonState, codelike objects.Object, offset int32, retval objects.Object) error

FirePyYield fires PY_YIELD.

CPython: Python/instrumentation.c:2698 _PyMonitoring_FirePyYieldEvent

func FireRaise

func FireRaise(interp *InterpState, state *MonState, codelike objects.Object, offset int32, exc objects.Object) error

FireRaise fires RAISE.

CPython: Python/instrumentation.c:2823 _PyMonitoring_FireRaiseEvent

func FireReraise

func FireReraise(interp *InterpState, state *MonState, codelike objects.Object, offset int32, exc objects.Object) error

FireReraise fires RERAISE.

CPython: Python/instrumentation.c:2851 _PyMonitoring_FireReraiseEvent

func FireStopIteration

func FireStopIteration(interp *InterpState, state *MonState, codelike objects.Object, offset int32, value objects.Object) error

FireStopIteration fires STOP_ITERATION. The caller passes the StopIteration value (the iterator's return value); CPython sets it as the current exception before firing and restores afterwards.

CPython: Python/instrumentation.c:2893 _PyMonitoring_FireStopIterationEvent

func Instrument

func Instrument(code *objects.Code, interp *InterpState) error

Instrument walks code's bytecode and installs the INSTRUMENTED_<X> opcodes for every (event, offset) where a tool has subscribed. Returns nil on success. The walk is idempotent: re-running with the same monitor state is a no-op aside from refreshing the version.

CPython: Python/instrumentation.c:1923 _Py_Instrument

func InstrumentedFor

func InstrumentedFor(op compile.Opcode) compile.Opcode

InstrumentedFor returns the INSTRUMENTED_<X> variant of op, or zero if none exists.

CPython: Python/instrumentation.c:135 INSTRUMENTED_OPCODES

func IsDisable

func IsDisable(o objects.Object) bool

IsDisable reports whether o is the Disable sentinel.

func IsInstrumented

func IsInstrumented(op compile.Opcode) bool

IsInstrumented reports whether op is one of the INSTRUMENTED_<X> variants. Used by the shadow walk to decide whether to write a fresh INSTRUMENTED_<X> opcode or leave the slot alone.

CPython: Python/instrumentation.c:184 is_instrumented

func IsInstrumentedEvent

func IsInstrumentedEvent(ev Event) bool

IsInstrumentedEvent returns true for events that originate from instrumented bytecode (the local-events range). Mirrors the PY_MONITORING_IS_INSTRUMENTED_EVENT macro.

CPython: Include/cpython/monitoring.h:20 PY_MONITORING_IS_INSTRUMENTED_EVENT

func IsMissing

func IsMissing(o objects.Object) bool

IsMissing reports whether o is the Missing sentinel.

func LineForOffset

func LineForOffset(code *objects.Code, i int) int

LineForOffset returns the source line number that codeunit i in code maps to via PEP 626 location data, or -1 when the entry has no line information.

func OpcodeHasEvent

func OpcodeHasEvent(op compile.Opcode) bool

OpcodeHasEvent reports whether op fires a monitoring event. Mirrors the predicate the instrument pass uses to skip non-event opcodes.

CPython: Python/instrumentation.c:180 opcode_has_event

Types

type CoMonitoringData

type CoMonitoringData struct {
	// LocalMonitors records the tools currently observing each
	// local event for this code.
	LocalMonitors LocalMonitors
	// ActiveMonitors is the union of LocalMonitors and the
	// per-interpreter GlobalMonitors at the time of the last
	// instrument pass. Read on the hot path to skip the global
	// table dereference.
	ActiveMonitors LocalMonitors
	// Tools is the per-codeunit bitmask used by the fire-event
	// entry points to find which tools want to be notified at the
	// current instr offset. Length matches the bytecode in
	// codeunits when allocated; nil otherwise.
	Tools []uint8
	// ToolVersions tracks the per-tool monitoring version that was
	// active when the instrument pass ran. The shadow walk
	// re-instruments the code when these drift.
	ToolVersions [MaxToolID]uintptr
	// Lines / LineTools back the line-event arms.
	Lines     *LineInstrumentationData
	LineTools []uint8
	// PerInstructionOpcodes / PerInstructionTools back the
	// per-instruction event arm. These hold the underlying
	// (de-instrumented) opcodes the dispatcher should restore to
	// when the per-instruction tools are removed.
	PerInstructionOpcodes []uint8
	PerInstructionTools   []uint8
}

CoMonitoringData holds the per-code instrumentation state. Keep it nil on code objects that have never been instrumented; allocate it lazily in _Py_Instrument.

CPython: Include/internal/pycore_instruments.h:100 _PyCoMonitoringData

func CoMonitoring

func CoMonitoring(code *objects.Code) *CoMonitoringData

CoMonitoring returns the existing CoMonitoringData for code or nil if no instrument pass has run yet.

func EnsureCoMonitoringData

func EnsureCoMonitoringData(code *objects.Code) *CoMonitoringData

EnsureCoMonitoringData allocates code.MonitoringData on first use and returns the concrete pointer. Subsequent calls reuse the existing instance. Mirrors CPython's allocate_instrumentation_data.

CPython: Python/instrumentation.c:1828 allocate_instrumentation_data

type Event

type Event uint8

Event is one of the PEP 669 monitoring event IDs.

CPython: Include/cpython/monitoring.h:8 PY_MONITORING_EVENT_*

const (
	EventPyStart       Event = 0
	EventPyResume      Event = 1
	EventPyReturn      Event = 2
	EventPyYield       Event = 3
	EventCall          Event = 4
	EventLine          Event = 5
	EventInstruction   Event = 6
	EventJump          Event = 7
	EventBranchLeft    Event = 8
	EventBranchRight   Event = 9
	EventStopIteration Event = 10
)

Local events fire from instrumented bytecode.

CPython: Include/cpython/monitoring.h:8-18

const (
	EventRaise            Event = 11
	EventExceptionHandled Event = 12
	EventPyUnwind         Event = 13
	EventPyThrow          Event = 14
	EventReraise          Event = 15
)

Other events, mainly raised on exception flow.

CPython: Include/cpython/monitoring.h:25-29

const (
	EventCReturn Event = 16
	EventCRaise  Event = 17
	EventBranch  Event = 18 // deprecated in 3.14, but still wired
)

Ancillary events.

CPython: Include/cpython/monitoring.h:34-36

func EventForOpcode

func EventForOpcode(op compile.Opcode) Event

EventForOpcode returns the event ID op fires, or -1 for none.

CPython: Python/instrumentation.c:74 EVENT_FOR_OPCODE

type EventSet

type EventSet uint32

EventSet is a bitmask of event IDs. Tool registration takes one of these so a tool can opt into multiple events in one call.

CPython: Include/internal/pycore_instruments.h:15 _PyMonitoringEventSet

func (EventSet) Has

func (s EventSet) Has(ev Event) bool

Has reports whether ev is in the set.

func (EventSet) With

func (s EventSet) With(ev Event) EventSet

With returns a copy of s with ev added.

func (EventSet) Without

func (s EventSet) Without(ev Event) EventSet

Without returns a copy of s with ev removed.

type GlobalMonitors

type GlobalMonitors struct {
	Tools [UngroupedEvents]uint8
}

GlobalMonitors carries the tool bitmask per ungrouped event for the whole interpreter. The grouped BRANCH event is split into BRANCH_LEFT / BRANCH_RIGHT before reaching this table, so the shape matches CPython's count of 16 "real" events.

CPython: Include/internal/pycore_instruments.h:83 _Py_GlobalMonitors

func (*GlobalMonitors) IsActive

func (g *GlobalMonitors) IsActive(ev Event) bool

IsActive reports whether any tool is registered for ev.

type InterpState

type InterpState struct {
	// Monitors is the per-interpreter event mask, indexed by event.
	// Each entry is a uint8 with one bit per tool. The instrument
	// pass unions this with each code object's local monitors to
	// compute ActiveMonitors.
	//
	// CPython: Include/internal/pycore_interp_structs.h:948
	Monitors GlobalMonitors

	// Callables[tool][event] is the user callback registered for
	// that slot, or nil if no tool has registered there.
	//
	// CPython: Include/internal/pycore_interp_structs.h:953
	Callables [MaxToolID][Events]objects.Object

	// ToolNames[tool] is the human-readable identifier the user
	// passed to sys.monitoring.use_tool_id. nil for free slots.
	//
	// CPython: Include/internal/pycore_interp_structs.h:954
	ToolNames [MaxToolID]objects.Object

	// ToolVersions[tool] is bumped every time the tool's set of
	// registered events changes. The shadow walk caches the version
	// it last saw on each code object so it only re-instruments
	// when something changed.
	//
	// CPython: Include/internal/pycore_interp_structs.h:955
	ToolVersions [MaxToolID]uintptr

	// SysProfilingThreads counts the threads with a c_profilefunc
	// installed; SysTracingThreads counts c_tracefunc threads. The
	// instrumentation runtime uses them to short-circuit the legacy
	// sys.setprofile / sys.settrace shims when no thread has them
	// enabled.
	//
	// CPython: Include/internal/pycore_interp_structs.h:951-952
	SysProfilingThreads int
	SysTracingThreads   int

	// SysProfileOnce gates the one-shot install of the legacy
	// sys.setprofile event handlers; SysTraceOnce does the same for
	// sys.settrace. CPython spells these as _PyOnceFlag fields on
	// PyInterpreterState. The first SetProfile / SetTrace caller
	// runs the install, every subsequent caller skips it.
	//
	// CPython: Include/internal/pycore_interp_structs.h
	//          sys_profile_once_flag / sys_trace_once_flag
	SysProfileOnce sync.Once
	SysTraceOnce   sync.Once
	// contains filtered or unexported fields
}

InterpState is the per-interpreter monitoring slab. Allocate one on interpreter construction and reach it from the eval loop, the instrument pass, and the sys.monitoring builtin.

CPython: Include/internal/pycore_interp_structs.h:948 monitors

func NewInterpState

func NewInterpState() *InterpState

NewInterpState allocates a zero-valued InterpState. All slots start empty: no tool has claimed an ID, no callbacks are registered, and the global event mask is zero.

func (*InterpState) Callback

func (s *InterpState) Callback(tool Tool, ev Event) objects.Object

Callback returns the callable registered for (tool, event), or nil if the slot is empty. The fire-event entry points read this on every event.

func (*InterpState) ClearToolID

func (s *InterpState) ClearToolID(tool Tool) error

ClearToolID is the public entry point. Mirrors CPython's monitoring.clear_tool_id, which is a no-op on unclaimed slots.

CPython: Python/instrumentation.c:2174 monitoring_clear_tool_id_impl

func (*InterpState) FreeToolID

func (s *InterpState) FreeToolID(tool Tool) error

FreeToolID releases a tool slot, clearing every callback and event registration that pinned to it. Mirrors CPython's free_tool_id, which calls _PyMonitoring_ClearToolId before nulling the name.

CPython: Python/instrumentation.c:2202 monitoring_free_tool_id_impl

func (*InterpState) GetEvents

func (s *InterpState) GetEvents(tool Tool) EventSet

GetEvents returns the event mask currently registered for tool.

CPython: Python/instrumentation.c:281 get_events

func (*InterpState) GetLocalEvents

func (s *InterpState) GetLocalEvents(code *objects.Code, tool Tool) (EventSet, error)

GetLocalEvents returns the local event mask for tool on code, or 0 if no instrument data has been allocated yet.

CPython: Python/instrumentation.c:2065 _PyMonitoring_GetLocalEvents

func (*InterpState) GlobalVersion

func (s *InterpState) GlobalVersion() uint32

GlobalVersion returns the current instrumentation version.

CPython: Python/instrumentation.c:1014 global_version

func (*InterpState) IsToolInUse

func (s *InterpState) IsToolInUse(tool Tool) bool

IsToolInUse reports whether the slot has been claimed by use_tool_id. The instrument pass checks this before reading any other per-tool field.

CPython: Python/instrumentation.c:2126 check_valid_tool (companion)

func (*InterpState) RegisterCallback

func (s *InterpState) RegisterCallback(tool Tool, ev Event, callable objects.Object) (objects.Object, error)

RegisterCallback installs callable for the (tool, event) slot and returns the previous callable, or nil if none was registered. Pass nil for callable to clear the slot. The branch event splits into BranchLeft and BranchRight; CPython wraps it with a synthetic dispatcher before storing, gopy mirrors the same split but stores the user callable directly because the legacy branch handler type has not been ported yet.

CPython: Python/instrumentation.c:3018 _PyMonitoring_RegisterCallback

func (*InterpState) RestartEvents

func (s *InterpState) RestartEvents()

RestartEvents bumps the global monitoring version twice: once into the new last_restart_version and again so live code objects that see this version know to re-instrument from scratch instead of diffing.

CPython: Python/instrumentation.c:2436 monitoring_restart_events_impl

func (*InterpState) SetEvents

func (s *InterpState) SetEvents(tool Tool, events EventSet) error

SetEvents replaces tool's event mask. Bumps the global version when the mask actually changed so the shadow walk re-instruments dependent code. The caller (sys.monitoring.set_events) is responsible for the world-stop CPython does around this; gopy is single-interpreter and does not yet stop the world.

CPython: Python/instrumentation.c:2004 _PyMonitoring_SetEvents

func (*InterpState) SetLocalEvents

func (s *InterpState) SetLocalEvents(code *objects.Code, tool Tool, events EventSet) error

SetLocalEvents installs the local event mask for tool on code. Errors if the tool is not in use. Returns nil on success and bumps the per-tool version so the shadow walk re-instruments code on next run.

CPython: Python/instrumentation.c:2033 _PyMonitoring_SetLocalEvents

func (*InterpState) ToolName

func (s *InterpState) ToolName(tool Tool) objects.Object

ToolName returns the registered tool name, or nil if the slot is free.

func (*InterpState) UseToolID

func (s *InterpState) UseToolID(tool Tool, name objects.Object) error

UseToolID claims tool for name. Errors if the slot is already in use. Returns nil and stores the name on success.

CPython: Python/instrumentation.c:2147 monitoring_use_tool_id_impl

type LineDispatch

type LineDispatch struct {
	OriginalOpcode compile.Opcode
	Line           int
}

LineDispatch carries the result of a fired line event back to the dispatcher. OriginalOpcode is the opcode the dispatcher should run in place of INSTRUMENTED_LINE.

func CallInstrumentationLine

func CallInstrumentationLine(interp *InterpState, code *objects.Code, instr int, prevInstr int) (LineDispatch, error)

CallInstrumentationLine fires LINE for the (code, instr) pair when the instr offset starts a new line and at least one tool subscribes, then returns the original opcode the dispatcher should execute in INSTRUMENTED_LINE's place.

CPython: Python/instrumentation.c:1297 _Py_call_instrumentation_line

type LineInstrumentationData

type LineInstrumentationData struct {
	BytesPerEntry uint8
	Data          []byte
}

LineInstrumentationData is the per-codeunit auxiliary table used by line events. CPython stores variable-width entries inline; gopy uses a flat byte slice indexed by codeunit because the deltas are small and we don't need the union-y layout.

CPython: Include/internal/pycore_instruments.h:91 _PyCoLineInstrumentationData

type LocalMonitors

type LocalMonitors struct {
	Tools [LocalEvents]uint8
}

LocalMonitors carries the tool bitmask per local-event slot for a single code object. tools[ev] is a uint8 with one bit per tool (ToolDebugger ... ToolSysTrace).

CPython: Include/internal/pycore_instruments.h:79 _Py_LocalMonitors

func (*LocalMonitors) IsActive

func (l *LocalMonitors) IsActive(ev Event) bool

IsActive reports whether any tool is registered for ev on this code.

type MonState

type MonState struct {
	Active uint8
}

MonState is the per-event tool bitmask the fire-event entry points read on every call. The instrument pass refreshes it via EnterScope when the interpreter's global monitoring version drifts.

CPython: Include/internal/pycore_instruments.h _PyMonitoringState

type Tool

type Tool uint8

Tool is a 0..MaxToolID-1 index used to key per-tool callbacks.

const (
	ToolDebugger  Tool = 0
	ToolCoverage  Tool = 1
	ToolProfiler  Tool = 2
	ToolOptimizer Tool = 5
)

Reserved tool IDs from PEP 669.

CPython: Include/internal/pycore_instruments.h:20-23

const (
	ToolSysProfile Tool = 6
	ToolSysTrace   Tool = 7
)

Internal tool IDs CPython uses to back sys.setprofile and sys.settrace. These do not appear in user-visible APIs but the instrumentation runtime treats them like any other tool slot.

CPython: Include/internal/pycore_instruments.h:26-27

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL