upstream: https://github.com/janestreet/memtrace
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