Skip to content

Tracing Pony Programs

The Pony runtime records actor, scheduler, and GC events as trace data. Traces can be written to a file in the background or kept in per-thread in-memory ring buffers (“flight recorder” mode) that dump to stderr on a crash signal (Linux and macOS) or fault (Windows).

Traces are written in Chromium trace JSON format and can be viewed with the Perfetto trace viewer.

When no tracing categories are enabled, the runtime checks a single boolean at each trace point and skips the call. The overhead is not measurable.

Categories

Categories control which kinds of events the runtime records. All categories are disabled by default.

Category Events
scheduler Basic scheduler events
scheduler_messaging Inter-scheduler messaging events
scheduler_stealing Scheduler work-stealing events
actor Actor lifecycle and scheduling events
actor_behavior Actor behavior run events
actor_gc Actor garbage collection and GC threshold change events
actor_state_change Actor state change and batch size change events
runtime Runtime lifecycle events (init, start, shutdown)
systematic_testing Systematic testing events
systematic_testing_details Detailed systematic testing events
cycle_detector Actor events for the cycle detector only

Actor event categories (actor, actor_behavior, actor_gc, actor_state_change) trace all actors when enabled. cycle_detector enables actor events for the cycle detector only, without enabling them for every actor.

Enabling tracing from the command line

Set categories at startup with --ponytracingcategories:

./my_program --ponytracingcategories='actor,scheduler'

See the Tracing Options reference for the full flag list.

Controlling tracing from code

The runtime_tracing standard library package toggles categories while a program is running. No trace output file is created until the first call that enables a category, so programs that never call the API pay no I/O cost.

Category operations

  • RuntimeTracing.enable_categories — add the listed categories to the active set.
  • RuntimeTracing.disable_categories — remove the listed categories from the active set.
  • RuntimeTracing.set_categories — replace the active set with exactly the listed categories. Pass an empty collection to disable all.

Each operation returns a TracingResult: TracingOk on success, TracingNotAvailable if the caller is not on a scheduler thread, or TracingLogFileError if the trace output file cannot be opened.

All operations require a RuntimeTracingAuth, obtained from AmbientAuth.

Specifying categories

Categories are passed as a collection of primitives — typically an array literal:

RuntimeTracing.enable_categories(
  auth, [SchedulerTracing; ActorBehaviorTracing])

The category primitives are: SchedulerTracing, SchedulerMessagingTracing, SchedulerStealingTracing, ActorTracing, ActorBehaviorTracing, ActorGCTracing, ActorStateChangeTracing, RuntimeLifecycleTracing, SystematicTestingTracing, SystematicTestingDetailsTracing, and CycleDetectorTracing.

Example

This program enables tracing at startup, does some work, narrows the active categories, and then disables tracing:

use "runtime_tracing"

actor Worker
  let _env: Env

  new create(env: Env) =>
    _env = env
    do_work()

  be do_work() =>
    _env.out.print("Worker running")

actor Main
  new create(env: Env) =>
    let auth = RuntimeTracingAuth(env.root)

    // Enable scheduler and actor behavior tracing.
    match RuntimeTracing.enable_categories(
      auth, [SchedulerTracing; ActorBehaviorTracing])
    | TracingOk => env.out.print("tracing enabled")
    | TracingNotAvailable => env.out.print("not on a scheduler thread")
    | TracingLogFileError => env.out.print("could not open trace file")
    end

    // Spawn a worker — its behavior run will appear in the trace.
    Worker(env)

    // Narrow to just actor categories.
    RuntimeTracing.set_categories(
      auth,
      [ ActorTracing; ActorBehaviorTracing
        ActorGCTracing; ActorStateChangeTracing ])

    // Turn off all tracing.
    RuntimeTracing.set_categories(auth, [])

Run with tracing output flags if you want a custom output path (the defaults — JSON format, ponytrace.json — work without any flags):

./my_program --ponytracingoutput=my-trace.json

Setting tracing defaults from code

Tracing configuration can be set before the runtime starts via @runtime_override_defaults on the Main actor. This sets initial values for all tracing flags. Command-line arguments still override them.

actor Main
  new create(env: Env) =>
    env.out.print("Hello, world.")

  fun @runtime_override_defaults(rto: RuntimeOptions) =>
    rto.ponytracingcategories = "scheduler,actor_behavior".cstring()

See Programmatic Overrides for more on @runtime_override_defaults.

See also

  • Runtime Options: Tracing Options — full reference for all --ponytracing* command-line flags
  • Profiling Pony Programs — CPU profiling with perf, Instruments, and Callgrind. Different from runtime tracing: profiling shows where CPU time went, while tracing records runtime events like actor scheduling and GC.