upstream: https://github.com/janestreet/memtrace
at main 302 lines 9.3 kB view raw
1(** Encoder and decoder for Memtrace traces. *) 2 3(** {1 Time} *) 4 5(** Timestamps. *) 6module Timestamp : sig 7 type t 8 9 val now : unit -> t 10 (** [now ()] is the current timestamp. *) 11 12 val of_int64 : int64 -> t 13 (** [of_int64 us] is a timestamp from microseconds since the Unix epoch. *) 14 15 val to_int64 : t -> int64 16 (** [to_int64 t] is [t] as microseconds since the Unix epoch. *) 17 18 val to_float : t -> float 19 (** [to_float t] is [t] in the Unix module's float format. *) 20 21 val of_float : float -> t 22 (** [of_float f] is a timestamp from the Unix module's float format. *) 23end 24 25(** Time deltas measured from the start of the trace. *) 26module Timedelta : sig 27 type t 28 29 val to_int64 : t -> int64 30 (** [to_int64 t] is [t] as microseconds since the start of the trace. *) 31 32 val offset : Timestamp.t -> t -> Timestamp.t 33 (** [offset base delta] is [base] offset by [delta]. *) 34end 35 36(** {1 Identifiers} *) 37 38(** Source locations in the traced program. *) 39module Location : sig 40 type t = { 41 filename : string; 42 line : int; 43 start_char : int; 44 end_char : int; 45 defname : string; 46 } 47 48 val to_string : t -> string 49 (** [to_string t] is a human-readable representation of [t]. *) 50 51 val unknown : t 52 (** [unknown] is a location representing an unknown source position. *) 53end 54 55(** Identifiers to represent allocations. *) 56module Obj_id : sig 57 type t = private int 58 59 module Tbl : Hashtbl.SeededS with type key = t 60 (** Hashtable keyed by object ID. *) 61 62 module Expert : sig 63 val of_int : int -> t 64 (** [of_int n] is an object ID from an integer. *) 65 end 66end 67 68(** Identifiers to represent domains. *) 69module Domain_id : sig 70 type t = private int 71 72 val main_domain : t 73 (** [main_domain] is the ID of the initial domain. *) 74 75 module Expert : sig 76 val of_int : int -> t 77 (** [of_int n] is a domain ID from an integer. *) 78 end 79end 80 81(** Codes for subsequences of locations in a backtrace. *) 82module Location_code : sig 83 type t = private int 84 85 module Tbl : Hashtbl.SeededS with type key = t 86 (** Hashtable keyed by location code. *) 87 88 module Expert : sig 89 val of_int : int -> t 90 (** [of_int n] is a location code from an integer. *) 91 end 92end 93 94(** Types of allocation. *) 95module Allocation_source : sig 96 type t = Minor | Major | External 97end 98 99(** {1 Events} *) 100 101(** Trace events. *) 102module Event : sig 103 type t = 104 | Alloc of { 105 obj_id : Obj_id.t; 106 (** An identifier for this allocation, used to refer to it in other 107 events. These identifiers are generated in allocation order. 108 109 Identifiers are not reused across domains. *) 110 length : int; 111 (** The ID of the domain on which this event occurred. 112 113 All events with the same obj_id will occur on the same domain, 114 unless that domain terminates before collecting this object (in 115 which case promotion or collection events may occur on an 116 arbitrary domain, but will always appear in order 117 Alloc-Promote-Collect for a given obj_id). 118 119 Events from different domains and different obj_ids may appear 120 out-of-order in a trace: timestamps and object identifiers are 121 only guaranteed to increase monotonically among events from a 122 single domain. Readers that require a global order of events 123 must merge the streams of events from different domains. *) 124 domain : Domain_id.t; 125 (** Length of the sampled allocation, in words, not including header 126 word. *) 127 nsamples : int; 128 (** Number of samples made in this allocation. At least 1. *) 129 source : Allocation_source.t; 130 (** How this object was initially allocated. *) 131 backtrace_buffer : Location_code.t array; 132 (** Backtrace of the allocation. The backtrace elements are stored 133 in order from caller to callee. The first element is the main 134 entrypoint and the last is the allocation. 135 136 NB: this is a mutable buffer, reused between events. Entries at 137 indices beyond [backtrace_length - 1] are not meaningful. If you 138 want to store backtraces, you must copy them using: 139 [Array.sub backtrace_buffer 0 backtrace_length]. *) 140 backtrace_length : int; (** Length of the backtrace. *) 141 common_prefix : int; 142 (** A prefix of this length has not changed since the last 143 allocation event that occurred on the same domain. *) 144 } 145 | Promote of Obj_id.t * Domain_id.t 146 | Collect of Obj_id.t * Domain_id.t 147 148 val domain : t -> Domain_id.t 149 (** [domain ev] is the domain on which [ev] occurred. *) 150 151 val to_string : (Location_code.t -> Location.t list) -> t -> string 152 (** [to_string lookup ev] is a human-readable representation of [ev]. *) 153end 154 155(** {1 Trace metadata} *) 156 157(** Global trace info. *) 158module Info : sig 159 type t = { 160 sample_rate : float; 161 word_size : int; 162 executable_name : string; 163 host_name : string; 164 ocaml_runtime_params : string; 165 pid : Int64.t; 166 initial_domain : Domain_id.t; 167 start_time : Timestamp.t; 168 context : string option; 169 } 170end 171 172(** {1 Writing traces} *) 173 174(** Writing traces. *) 175module Writer : sig 176 type t 177 178 exception Pid_changed 179 180 val create : Unix.file_descr -> ?getpid:(unit -> int64) -> Info.t -> t 181 (** [create fd info] is a trace writer to [fd]. *) 182 183 val domain : t -> Domain_id.t 184 (** [domain t] is the domain this writer writes events for. *) 185 186 val for_domain : t -> domain:Domain_id.t -> t 187 (** [for_domain t ~domain] is a writer for [domain] sharing [t]'s fd. *) 188 189 (** All of the functions below may raise Unix_error if writing to the file 190 descriptor fails, or Pid_changed if getpid returns a different value. *) 191 192 val put_alloc : 193 t -> 194 Timestamp.t -> 195 length:int -> 196 nsamples:int -> 197 source:Allocation_source.t -> 198 callstack:Location_code.t array -> 199 decode_callstack_entry:(Location_code.t -> Location.t list) -> 200 Obj_id.t 201 (** [put_alloc t time ~length ~nsamples ~source ~callstack 202 ~decode_callstack_entry] writes an allocation event. *) 203 204 val put_alloc_with_raw_backtrace : 205 t -> 206 Timestamp.t -> 207 length:int -> 208 nsamples:int -> 209 source:Allocation_source.t -> 210 callstack:Printexc.raw_backtrace -> 211 Obj_id.t 212 (** [put_alloc_with_raw_backtrace t time ~length ~nsamples ~source ~callstack] 213 writes an allocation event using a raw backtrace. *) 214 215 val put_alloc_backtrace_suffix : 216 t -> 217 Timestamp.t -> 218 length:int -> 219 nsamples:int -> 220 source:Allocation_source.t -> 221 callstack:Printexc.raw_backtrace -> 222 drop_slots:int -> 223 Obj_id.t 224 (** [put_alloc_backtrace_suffix t time ~length ~nsamples ~source ~callstack 225 ~drop_slots] writes an allocation, dropping the first [drop_slots] 226 backtrace entries. *) 227 228 val put_collect : t -> Timestamp.t -> Obj_id.t -> unit 229 (** [put_collect t time obj_id] writes a collection event. *) 230 231 val put_promote : t -> Timestamp.t -> Obj_id.t -> unit 232 (** [put_promote t time obj_id] writes a promotion event. *) 233 234 val flush : t -> unit 235 (** [flush t] flushes currently buffered events. The file descriptor is not 236 closed, and more events may be written after flush. *) 237 238 val close : t -> unit 239 (** [close t] flushes and closes the underlying file descriptor. *) 240 241 module Multiplexed_domains : sig 242 type t 243 (** A set of per-domain writers, allowing events from different domains to 244 be multiplexed into a single stream. *) 245 246 val create : Unix.file_descr -> ?getpid:(unit -> int64) -> Info.t -> t 247 (** [create fd info] is a multiplexed writer to [fd]. *) 248 249 val put_event : 250 t -> 251 decode_callstack_entry:(Location_code.t -> Location.t list) -> 252 Timestamp.t -> 253 Event.t -> 254 unit 255 (** [put_event t ~decode_callstack_entry time ev] writes [ev]. *) 256 257 val next_alloc_id : t -> domain:Domain_id.t -> Obj_id.t 258 (** [next_alloc_id t ~domain] is the next allocation ID for [domain]. *) 259 260 val flush : t -> unit 261 (** [flush t] flushes all per-domain writers. *) 262 end 263end 264 265(** {1 Reading traces} *) 266 267(** Reading traces. *) 268module Reader : sig 269 type t 270 271 val create : Unix.file_descr -> t 272 (** [create fd] is a trace reader from [fd]. *) 273 274 val info : t -> Info.t 275 (** [info t] is the trace metadata. *) 276 277 val lookup_location_code : t -> Location_code.t -> Location.t list 278 (** [lookup_location_code t code] resolves [code] to source locations. *) 279 280 val iter : 281 t -> ?parse_backtraces:bool -> (Timedelta.t -> Event.t -> unit) -> unit 282 (** [iter t f] calls [f] for each event in the trace. *) 283 284 val open_ : filename:string -> t 285 (** [open_ ~filename] opens a trace file. *) 286 287 val size_bytes : t -> int64 288 (** [size_bytes t] is the size of the trace in bytes. *) 289 290 val close : t -> unit 291 (** [close t] closes the reader. *) 292end 293 294(** {1:private Private} *) 295 296module Private : sig 297 val set_tracer_module : string -> unit 298 (** [set_tracer_module name] sets the module name for backtrace filtering. *) 299 300 val obj_ids_per_chunk : int Atomic.t 301 (** For testing: number of object IDs per chunk. *) 302end