Runtime_events(3)
π Runtime_events(3) β ring buffer-based runtime tracing π
okay so this is the Runtime_events page from the OCaml library manual, and it's literally the group chat for the OCaml runtime's tea β β ring-buffer tracing, bestie. Let's get into it.
πΈ NAME πΈ
Runtime_events β Runtime events - ring buffer-based runtime tracing
π Module π
Module Runtime_events
Module Runtime_events : sig end
β¨ Documentation β¨
okay so Runtime_events is the module that lets you enable and subscribe to tracing events from the Garbage Collector and other parts of the OCaml runtime. It's giving diagnostic/performance-monitoring main character energy π
β super useful for diagnostics or performance monitoring purposes.
You can use this module to subscribe to events for the current process or external processes asynchronously. No cap.
When enabled β either by setting the OCAML_RUNTIME_EVENTS_START environment variable or by calling Runtime_events.start β a file with the pid of the process and extension .events will be created. By default this is in the current directory, but it can be over-ridden by the OCAML_RUNTIME_EVENTS_DIR environment variable. Each domain maintains its own ring buffer in a section of the larger file into which it emits events. π¦
There is additionally a set of C APIs in runtime_events.h that can enable zero-impact monitoring of the current process or bindings for other languages. iconic.
The runtime events system's behaviour can be controlled by the following environment variables:
-OCAML_RUNTIME_EVENTS_STARTβ the manpage lists this env var with a leading dash; if set, it will cause the runtime events system to be started as part of the OCaml runtime initialization.-OCAML_RUNTIME_EVENTS_DIRβ sets the directory where the runtime events ring buffers will be located. If not present, the program's working directory will be used.-OCAML_RUNTIME_EVENTS_PRESERVEβ if set, this will prevent the OCaml runtime from removing its ring buffers when it terminates. This can help if you're monitoring very short running programs. lowkey a lifesaver for tiny programs π«Ά
π type runtime_counter π
type runtime_counter = β this is the type for counter events emitted by the runtime. Counter events are used to measure a quantity at a point in time or record the occurrence of an event. In the latter case their value will be one. periodt.
EV_C_FORCE_MINOR_ALLOC_SMALLβ triggering of a minor collection due to a full minor heap. Since 5.0EV_C_FORCE_MINOR_MAKE_VECTβ triggering of a minor collection due toArray.make. Since 5.0EV_C_FORCE_MINOR_SET_MINOR_HEAP_SIZEβ triggering of a minor collection due toGc.minor_heap_size. Since 5.0EV_C_FORCE_MINOR_MEMPROFβ triggering of a minor collection during memprof young sampling. Since 5.3EV_C_MINOR_PROMOTEDβ total bytes promoted from the minor heap of this Domain to the major heap in the last minor collection. Since 5.0EV_C_MINOR_ALLOCATEDβ total bytes allocated in the minor heap of this Domain in the last minor collection. Since 5.0EV_C_REQUEST_MAJOR_ALLOC_SHRβ major slice requested due to allocation in major heap. Since 5.0EV_C_REQUEST_MAJOR_ADJUST_GC_SPEEDβ major slice requested bycaml_adjust_gc_speed. Since 5.0EV_C_REQUEST_MINOR_REALLOC_REF_TABLEβ triggering of a minor collection due to ref table reallocation. Since 5.0EV_C_REQUEST_MINOR_REALLOC_EPHE_REF_TABLEβ triggering of a minor collection due to ephe_ref table reallocation. Since 5.0EV_C_REQUEST_MINOR_REALLOC_CUSTOM_TABLEβ triggering of a minor collection due to custom table reallocation. Since 5.0EV_C_MAJOR_HEAP_POOL_WORDSβ total words in a Domain's major heap pools. This is the sum of unallocated and live words in each pool. Since 5.1EV_C_MAJOR_HEAP_POOL_LIVE_WORDSβ current live words in a Domain's major heap pools. Since 5.1EV_C_MAJOR_HEAP_LARGE_WORDSβ total words of a Domain's major heap large allocations. A large allocation is an allocation larger than the largest sized pool. Since 5.1EV_C_MAJOR_HEAP_POOL_FRAG_WORDSβ words in a Domain's major heap pools lost to fragmentation. This is due to there not being a pool with the exact size of an allocation and a larger sized pool needing to be used. Since 5.1EV_C_MAJOR_HEAP_POOL_LIVE_BLOCKSβ live blocks of a Domain's major heap pools. Since 5.1EV_C_MAJOR_HEAP_LARGE_BLOCKSβ live blocks of a Domain's major heap large allocations. Since 5.1EV_C_MAJOR_HEAP_WORDSβ major heap size in words of a Domain. Since 5.3EV_C_MAJOR_ALLOCATED_WORDSβ allocations to the major heap of this Domain in words, since the last major slice. Since 5.3EV_C_MAJOR_ALLOCATED_WORKβ the amount of major GC 'work' needing to be done as a result of allocations to the major heap of this Domain in words, since the last major slice. Since 5.3EV_C_MAJOR_DEPENDENT_WORKβ the amount of major GC 'work' needing to be done as a result of dependent allocations to the major heap of this Domain in words, since the last major slice. Dependent memory is non-heap memory that depends on heap memory being collected in order to be freed. Since 5.3EV_C_MAJOR_EXTRA_WORKβ the amount of major GC 'work' needing to be done as a result of extra non-memory resources that are dependent on heap memory being collected in order to be freed. Since 5.3EV_C_MAJOR_WORK_COUNTERβ the global amount of major GC 'work' done by all domains since the program began. Since 5.3EV_C_MAJOR_ALLOC_COUNTERβ the global words of major GC allocations done by all domains since the program began. Since 5.3EV_C_MAJOR_SLICE_TARGETβ the target amount of global 'work' that should be done by all domains at the end of the major slice (seeEV_C_MAJOR_SLICE_COUNTER). Since 5.3EV_C_MAJOR_SLICE_BUDGETβ the budget in 'work' that a domain has to do during the major slice. Since 5.3EV_C_MINOR_ALLOCATED_WORDSβ total words allocated in the minor heap of this Domain in the last minor collection. Since 5.4EV_C_MINOR_PROMOTED_WORDSβ total words promoted from the minor heap of this Domain to the major heap in the last minor collection. Since 5.4
π¦ type runtime_phase π¦
type runtime_phase = β phase events, aka the "what is the runtime doing right now" vibes. here are all the constructors, bestie:
EV_EXPLICIT_GC_SETβ event spanning a call toGc.set. Since 5.0EV_EXPLICIT_GC_STATβ event spanning a call toGc.stat. Since 5.0EV_EXPLICIT_GC_MINORβ event spanning a call toGc.minor, which forces a minor collection. Since 5.0EV_EXPLICIT_GC_MAJORβ event spanning a call toGc.major, which forces a major collection. Since 5.0EV_EXPLICIT_GC_FULL_MAJORβ event spanning a call toGc.full_major, which forces a full major collection. Since 5.0EV_EXPLICIT_GC_COMPACTβ event spanning a call toGc.compact, which triggers a compaction. Since 5.0EV_MAJORβ event spanning any major GC work. Since 5.0EV_MAJOR_SWEEPβ event spanning the sweeping work of a major GC. Since 5.0EV_MAJOR_MARK_ROOTSβ event spanning the marking of roots in a major GC. Since 5.0EV_MAJOR_MEMPROF_ROOTSβ event spanning the marking of memprof roots in a major GC. Since 5.3EV_MAJOR_MARKβ event spanning the marking of the heap in a major GC. Since 5.0EV_MINORβ event spanning any minor GC work. Since 5.0EV_MINOR_LOCAL_ROOTSβ event spanning the scanning and major allocation of local roots during a minor GC. Since 5.0EV_MINOR_MEMPROF_ROOTSβ event spanning the scanning and promotion of memprof roots in a minor GC. Since 5.3EV_MINOR_MEMPROF_CLEANβ event spanning cleaning and updating of memprof structures at the end of a minor GC. Since 5.3EV_MINOR_FINALIZEDβ event spanning the running of finalisers for dead custom blocks at the end of a minor GC. Since 5.0EV_EXPLICIT_GC_MAJOR_SLICEβ event spanning a call toGc.major_slice. Since 5.0EV_FINALISE_UPDATE_FIRSTβ event spanning time spent in the first phase of finalisation at the end of a major GC cycle. Since 5.0EV_FINALISE_UPDATE_LASTβ event spanning time spent in the last phase of finalisation at the end of a major GC cycle. Since 5.0EV_INTERRUPT_REMOTEβ event spanning work triggered by an interrupt from another domain. This is usually a stop-the-world request. Since 5.0EV_MAJOR_EPHE_MARKβ event spanning the marking of ephemeron tables in a major GC. Since 5.0EV_MAJOR_EPHE_SWEEPβ event spanning the sweeping of ephemeron tables in a major GC. Since 5.0EV_MAJOR_FINISH_MARKINGβ event spanning work done at the end of marking in a major GC. Since 5.0EV_MAJOR_GC_CYCLE_DOMAINSβ event spanning work done at the end of a major GC cycle. This includes a minor collection. Since 5.0EV_MAJOR_GC_PHASE_CHANGEβ event spanning the change of phase in the major GC which involves a global barrier. Since 5.0EV_MAJOR_GC_STWβ event spanning the stop-the-world phase done at the end of a major GC cycle. Since 5.0EV_MAJOR_MARK_OPPORTUNISTICβ event spanning the work done during opportunistic marking in a major GC. Since 5.0EV_MAJOR_SLICEβ event spanning the work done during a major slice in a major GC. Since 5.0EV_MAJOR_FINISH_CYCLEβ event spanning attempts to drive all domains to the end of a major GC cycle. Since 5.0EV_MINOR_CLEARβ event spanning the cleaning of the minor heap and supporting structures at the end of a minor GC. Since 5.0EV_MINOR_FINALIZERS_OLDIFYβ event spanning the promotion of finalisers during a minor GC. Since 5.0EV_MINOR_GLOBAL_ROOTSβ event spanning the scanning and major allocation of global roots during a minor GC. Since 5.0EV_MINOR_LEAVE_BARRIERβ event spanning the time spent in the barrier at the end of a minor GC, waiting for all domains to finish their work. Since 5.0EV_STW_API_BARRIERβ event spanning the time spent waiting for all other domains to reach the stop-the-world entry barrier. Since 5.0EV_STW_HANDLERβ event spanning the time spent in the stop-the-world handler, including time spent in the stop-the-world callback itself.
The span roster is still rolling, and that previous variantβs comment wraps up with Since 5.0 before we hit the next batch. Buckle up, bestie:
EV_STW_LEADERβ the event spanning the time spent as the leader of a stop-the-world. Since 5.0EV_MAJOR_FINISH_SWEEPINGβ spans the time spent finishing sweeping when forced to as part of domain termination. Since 5.0EV_MAJOR_MEMPROF_CLEANβ spans the time spent cleaning memprof structures at the end of a major GC. Since 5.3EV_MINOR_FINALIZERS_ADMINβ spans finalisers book-keeping at the end of a minor GC. Since 5.0EV_MINOR_REMEMBERED_SETβ spans the scanning and major allocation of remembered sets during a minor GC. Since 5.0EV_MINOR_REMEMBERED_SET_PROMOTEβ spans the promotion of blocks in the remembered set and global roots during a minor GC. Since 5.0EV_MINOR_LOCAL_ROOTS_PROMOTEβ spans the promotion of local roots during a minor GC. Since 5.0EV_DOMAIN_CONDITION_WAITβ spans waiting inCondition.wait. Since 5.0EV_DOMAIN_RESIZE_HEAP_RESERVATIONβ spans resizing the domain heap reservation, as a result of minor heap size changes. Since 5.0EV_COMPACTβ spans compaction of the heap during a call toGc.compact. Since 5.2EV_COMPACT_EVACUATEβ spans evacuating major GC pools during a compaction. Since 5.2EV_COMPACT_FORWARDβ spans the walking of the heap to update changed pointers after an evacuation during a compaction. Since 5.2EV_COMPACT_RELEASEβ spans releasing the evacuated pools at the end of a compaction. Since 5.2EV_EMPTY_MINORβ spans a domain needing to empty its minor heap for a new allocation. This includes time spent trying to become stop-the-world leader. Since 5.4
That whole list is the type for span events emitted by the runtime. β¨
Then thereβs type lifecycle =, the lifecycle-event roster for Runtime_events and domains:
type lifecycle =
EV_RING_STARTβ event indicating that theRuntime_eventsring buffer has been started. Includes the PID of the process as an argument. Since 5.0EV_RING_STOPβ event indicating that theRuntime_eventsring buffer has been stopped. Since 5.0EV_RING_PAUSEβ event indicating that theRuntime_eventsring buffer has been paused. Since 5.0EV_RING_RESUMEβ event indicating that theRuntime_eventsring buffer has been resumed. Since 5.0EV_FORK_PARENTβ event indicating that a fork has occurred and the current domain is the parent. Includes the PID of the child as an argument. Since 5.0EV_FORK_CHILDβ event indicating that a fork has occurred and the current domain is the child. Since 5.0EV_DOMAIN_SPAWNβ event indicating that a new domain has been spawned. Includes the PID of the new domain as an argument. Since 5.0EV_DOMAIN_TERMINATEβ event indicating that a domain has terminated. Includes the PID of the domain as an argument. Since 5.0
Those are the lifecycle events for Runtime_events and domains. π
val lifecycle_name : lifecycle -> stringβ returns a string representation of a given lifecycle event type. πΈval runtime_phase_name : runtime_phase -> stringβ returns a string representation of a given runtime phase event type. πΈval runtime_counter_name : runtime_counter -> stringβ returns a string representation of a given runtime counter type. πΈtype cursorβ the type of the cursor used when consuming. πmodule Timestamp : sig endβ yes, itβs literally shaped like that in the source.module Type : sig endβ same energy.module User : sig endβ same energy.module Callbacks : sig endβ same energy.val start : unit -> unitβstart ()will start the collection of events in the runtime if not already started. Events can be consumed by creating a cursor withcreate_cursorand providing a set of callbacks to be called for each type of event. π₯val path : unit -> string optionβ if runtime events are being collected,path ()returnsSome pwherepis a path to the runtime events file. Otherwise, it returnsNone. πval pause : unit -> unitβpause ()will pause the collection of events in the runtime. Traces are collected if the program has calledRuntime_events.start ()or theOCAML_RUNTIME_EVENTS_STARTenvironment variable has been set. πval resume : unit -> unitβresume ()will resume the collection of events in the runtime. Traces are collected if the program has calledRuntime_events.start ()or theOCAML_RUNTIME_EVENTS_STARTenvironment variable has been set. πval create_cursor : (string * int) option -> cursorβcreate_cursor path_pidcreates a cursor to read from aruntime_events. Cursors can be created forruntime_eventsin and out of process. Aruntime_eventsring-buffer may have multiple cursors reading from it at any point in time, and a program may have multiple cursors open concurrently (for example if multiple consumers want different sets of events). Ifpath_pidisNonethen a cursor is created for the current process. Otherwise the pair contains a string path to the directory that contains thepid.eventsfile andint pidfor theruntime_eventsof an external process to monitor. π¦val free_cursor : cursor -> unitβ frees a previously createdruntime_eventscursor. π§val read_poll : cursor -> Callbacks.t -> int option -> intβread_poll cursor callbacks max_optioncalls the corresponding functions oncallbacksfor up tomax_optionevents read off the cursorβsruntime_eventsand returns the number of events read. π
Source/version: OCamldoc; date: 2026-06-22; footer page: Runtime_events(3). Thatβs the whole part 2, bestie β go consume those events responsibly ππ«Ά
π¦ where this page comes from
- arch rolling: ocaml 5.5.0-1 Β· LGPL2.1 AND custom: QPL-1.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms