Documentation
¶
Index ¶
- Constants
- Variables
- func BuildSysMonitoring(interp *InterpState) *objects.Module
- func CheckToolID(tool Tool) error
- func DeInstrument(op compile.Opcode) compile.Opcode
- func EnterScope(interp *InterpState, states []MonState, version *uint32, eventTypes []Event)
- func ExitScope()
- func FireBranchLeft(interp *InterpState, state *MonState, codelike objects.Object, offset int32, ...) error
- func FireBranchRight(interp *InterpState, state *MonState, codelike objects.Object, offset int32, ...) error
- func FireCRaise(interp *InterpState, state *MonState, codelike objects.Object, offset int32, ...) error
- func FireCReturn(interp *InterpState, state *MonState, codelike objects.Object, offset int32, ...) error
- func FireCall(interp *InterpState, state *MonState, codelike objects.Object, offset int32, ...) error
- func FireExceptionHandled(interp *InterpState, state *MonState, codelike objects.Object, offset int32, ...) error
- func FireInstruction(interp *InterpState, state *MonState, codelike objects.Object, offset int32) error
- func FireJump(interp *InterpState, state *MonState, codelike objects.Object, offset int32, ...) error
- func FireLine(interp *InterpState, state *MonState, codelike objects.Object, offset int32, ...) error
- func FirePyResume(interp *InterpState, state *MonState, codelike objects.Object, offset int32) error
- func FirePyReturn(interp *InterpState, state *MonState, codelike objects.Object, offset int32, ...) error
- func FirePyStart(interp *InterpState, state *MonState, codelike objects.Object, offset int32) error
- func FirePyThrow(interp *InterpState, state *MonState, codelike objects.Object, offset int32, ...) error
- func FirePyUnwind(interp *InterpState, state *MonState, codelike objects.Object, offset int32, ...) error
- func FirePyYield(interp *InterpState, state *MonState, codelike objects.Object, offset int32, ...) error
- func FireRaise(interp *InterpState, state *MonState, codelike objects.Object, offset int32, ...) error
- func FireReraise(interp *InterpState, state *MonState, codelike objects.Object, offset int32, ...) error
- func FireStopIteration(interp *InterpState, state *MonState, codelike objects.Object, offset int32, ...) error
- func Instrument(code *objects.Code, interp *InterpState) error
- func InstrumentedFor(op compile.Opcode) compile.Opcode
- func IsDisable(o objects.Object) bool
- func IsInstrumented(op compile.Opcode) bool
- func IsInstrumentedEvent(ev Event) bool
- func IsMissing(o objects.Object) bool
- func LineForOffset(code *objects.Code, i int) int
- func OpcodeHasEvent(op compile.Opcode) bool
- type CoMonitoringData
- type Event
- type EventSet
- type GlobalMonitors
- type InterpState
- func (s *InterpState) Callback(tool Tool, ev Event) objects.Object
- func (s *InterpState) ClearToolID(tool Tool) error
- func (s *InterpState) FreeToolID(tool Tool) error
- func (s *InterpState) GetEvents(tool Tool) EventSet
- func (s *InterpState) GetLocalEvents(code *objects.Code, tool Tool) (EventSet, error)
- func (s *InterpState) GlobalVersion() uint32
- func (s *InterpState) IsToolInUse(tool Tool) bool
- func (s *InterpState) RegisterCallback(tool Tool, ev Event, callable objects.Object) (objects.Object, error)
- func (s *InterpState) RestartEvents()
- func (s *InterpState) SetEvents(tool Tool, events EventSet) error
- func (s *InterpState) SetLocalEvents(code *objects.Code, tool Tool, events EventSet) error
- func (s *InterpState) ToolName(tool Tool) objects.Object
- func (s *InterpState) UseToolID(tool Tool, name objects.Object) error
- type LineDispatch
- type LineInstrumentationData
- type LocalMonitors
- type MonState
- type Tool
Constants ¶
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
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
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 ¶
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
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 ¶
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 ¶
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 ¶
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 ¶
InstrumentedFor returns the INSTRUMENTED_<X> variant of op, or zero if none exists.
CPython: Python/instrumentation.c:135 INSTRUMENTED_OPCODES
func IsInstrumented ¶
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 ¶
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 LineForOffset ¶
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 ¶
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 ¶
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
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 ¶
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 ¶
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
type LineDispatch ¶
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 ¶
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