1 (**************************************************************************)
2 (* *)
3 (* OCaml *)
4 (* *)
5 (* Mark Shinwell and Leo White, Jane Street Europe *)
6 (* *)
7 (* Copyright 2015--2017 Jane Street Group LLC *)
8 (* *)
9 (* All rights reserved. This file is distributed under the terms of *)
10 (* the GNU Lesser General Public License version 2.1, with the *)
11 (* special exception on linking described in the file LICENSE. *)
12 (* *)
13 (**************************************************************************)
14
15 (** Access to the information recorded by the [Spacetime]
16 module. (It is intended that this module will be used by
17 post-processors rather than users wishing to understand their
18 programs.)
19 For 64-bit targets only.
20 This module may be used from any program, not just one compiled
21 with a compiler configured for Spacetime. *)
22
23 module Gc_stats : sig
24 type t
25
26 val minor_words : t -> int
27 val promoted_words : t -> int
28 val major_words : t -> int
29 val minor_collections : t -> int
30 val major_collections : t -> int
31 val heap_words : t -> int
32 val heap_chunks : t -> int
33 val compactions : t -> int
34 val top_heap_words : t -> int
35 end
36
37 module Annotation : sig
38 (** An annotation written into a value's header. These may be looked up
39 in a [Trace.t] (see below). *)
40 type t
41
42 (* CR-someday mshinwell: consider using tag and size to increase the
43 available space of annotations. Need to be careful of [Obj.truncate].
44 Could also randomise the tags on records.
45 *)
46
47 val to_int : t -> int
48 end
49
50 module Program_counter : sig
51 module OCaml : sig
52 type t
53
54 val to_int64 : t -> Int64.t
55 end
56
57 module Foreign : sig
58 type t
59
60 val to_int64 : t -> Int64.t
61 end
62
63 end
64
65 module Frame_table : sig
66 (* CR-someday mshinwell: move to [Gc] if dependencies permit? *)
67 (** A value of type [t] corresponds to the frame table of a running
68 OCaml program. The table is indexed by program counter address
69 (typically, but not always when using Spacetime, return addresses). *)
70 type t
71
72 (** Find the location, including any inlined frames, corresponding to the
73 given program counter address. Raises [Not_found] if the location
74 could not be resolved. *)
75 val find_exn : Program_counter.OCaml.t -> t -> Printexc.Slot.t list
76 end
77
78 module Function_entry_point : sig
79 type t
80
81 val to_int64 : t -> Int64.t
82 end
83
84 module Function_identifier : sig
85 type t
86 (* CR-soon mshinwell: same as [Function_entry_point] now *)
87 val to_int64 : t -> Int64.t
88 end
89
90 module Shape_table : sig
91 type t
92 end
93
94 module Trace : sig
95 (** A value of type [t] holds the dynamic call structure of the program
96 (i.e. which functions have called which other functions) together with
97 information required to decode profiling annotations written into
98 values' headers. *)
99 type t
100 type trace = t
101
102 type node
103 type ocaml_node
104 type foreign_node
105 type uninstrumented_node
106
107 module OCaml : sig
108 module Allocation_point : sig
109 (** A value of type [t] corresponds to an allocation point in OCaml
110 code. *)
111 type t
112
113 (** The program counter at (or close to) the allocation site. *)
114 val program_counter : t -> Program_counter.OCaml.t
115
116 (** The annotation written into the headers of boxed values allocated
117 at the given allocation site. *)
118 val annotation : t -> Annotation.t
119
120 (** The total number of words allocated at this point. *)
121 val num_words_including_headers : t -> int
122 end
123
124 module Direct_call_point : sig
125 (** A value of type ['target t] corresponds to a direct (i.e. known
126 at compile time) call point in OCaml code. ['target] is the type
127 of the node corresponding to the callee. *)
128 type 'target t
129
130 (** The program counter at (or close to) the call site. *)
131 val call_site : _ t -> Program_counter.OCaml.t
132
133 (** The address of the first instruction of the callee. *)
134 val callee : _ t -> Function_entry_point.t
135
136 (** The node corresponding to the callee. *)
137 val callee_node : 'target t -> 'target
138
139 (** The number of times the callee was called. Only available if the
140 compiler that recorded the Spacetime profile was configured with
141 "-with-spacetime-call-counts". [None] will be returned otherwise. *)
142 val call_count : _ t -> int option
143 end
144
145 module Indirect_call_point : sig
146 (** A value of type [t] corresponds to an indirect call point in OCaml
147 code. Each such value contains a list of callees to which the
148 call point has branched. *)
149 type t
150
151 (** The program counter at (or close to) the call site. *)
152 val call_site : t -> Program_counter.OCaml.t
153
154 module Callee : sig
155 type t
156
157 (** The address of the first instruction of the callee. *)
158 val callee : t -> Function_entry_point.t
159
160 (** The node corresponding to the callee. *)
161 val callee_node : t -> node
162
163 (** The number of times the callee was called. This returns [None] in
164 the same circumstances as [Direct_call_point.call_count], above. *)
165 val call_count : t -> int option
166
167 (** Move to the next callee to which this call point has branched.
168 [None] is returned when the end of the list is reached. *)
169 val next : t -> t option
170 end
171
172 (** The list of callees to which this indirect call point has
173 branched. *)
174 val callees : t -> Callee.t option
175 end
176
177 module Field : sig
178 (** A value of type [t] enables iteration through the contents
179 ("fields") of an OCaml node. *)
180 type t
181
182 type direct_call_point =
183 | To_ocaml of ocaml_node Direct_call_point.t
184 | To_foreign of foreign_node Direct_call_point.t
185 (* CR-soon mshinwell: once everything's finished, "uninstrumented"
186 should be able to go away. Let's try to do this after the
187 first release. *)
188 | To_uninstrumented of
189 uninstrumented_node Direct_call_point.t
190
191 type classification =
192 | Allocation of Allocation_point.t
193 | Direct_call of direct_call_point
194 | Indirect_call of Indirect_call_point.t
195
196 val classify : t -> classification
197 val next : t -> t option
198 end
199
200 module Node : sig
201 (** A node corresponding to an invocation of a function written in
202 OCaml. *)
203 type t = ocaml_node
204
205 val compare : t -> t -> int
206
207 (** A unique identifier for the function corresponding to this node. *)
208 val function_identifier : t -> Function_identifier.t
209
210 (** This function traverses a circular list. *)
211 val next_in_tail_call_chain : t -> t
212
213 val fields : t -> shape_table:Shape_table.t -> Field.t option
214 end
215 end
216
217 module Foreign : sig
218 module Allocation_point : sig
219 (** A value of type [t] corresponds to an allocation point in non-OCaml
220 code. *)
221 type t
222
223 val program_counter : t -> Program_counter.Foreign.t
224 val annotation : t -> Annotation.t
225 val num_words_including_headers : t -> int
226 end
227
228 module Call_point : sig
229 (** A value of type [t] corresponds to a call point from non-OCaml
230 code (to either non-OCaml code, or OCaml code via the usual
231 assembly veneer). Call counts are not available for such nodes. *)
232 type t
233
234 (** N.B. The address of the callee (of type [Function_entry_point.t]) is
235 not available. It must be recovered during post-processing. *)
236 val call_site : t -> Program_counter.Foreign.t
237 val callee_node : t -> node
238 end
239
240 module Field : sig
241 (** A value of type [t] enables iteration through the contents ("fields")
242 of a C node. *)
243 type t
244
245 type classification = private
246 | Allocation of Allocation_point.t
247 | Call of Call_point.t
248
249 val classify : t -> classification
250 val next : t -> t option
251 end
252
253 module Node : sig
254 (** A node corresponding to an invocation of a function written in C
255 (or any other language that is not OCaml). *)
256 type t = foreign_node
257
258 val compare : t -> t -> int
259
260 val fields : t -> Field.t option
261
262 end
263
264 end
265
266 module Node : sig
267 (** Either an OCaml or a foreign node; or an indication that this
268 is a branch of the graph corresponding to uninstrumented
269 code. *)
270 type t = node
271
272 val compare : t -> t -> int
273
274 type classification = private
275 | OCaml of OCaml.Node.t
276 | Foreign of Foreign.Node.t
277
278 val classify : t -> classification
279
280 val of_ocaml_node : OCaml.Node.t -> t
281 val of_foreign_node : Foreign.Node.t -> t
282
283 module Set : Set.S with type elt = t
284 module Map : Map.S with type key = t
285 end
286
287 (** Obtains the root of the graph for traversal. [None] is returned if
288 the graph is empty. *)
289 val root : t -> Node.t option
290 end
291
292 module Heap_snapshot : sig
293 type t
294 type heap_snapshot = t
295
296 module Entries : sig
297 (** An immutable array of the total number of blocks (= boxed
298 values) and the total number of words occupied by such blocks
299 (including their headers) for each profiling annotation in
300 the heap. *)
301 type t
302
303 val length : t -> int
304 val annotation : t -> int -> Annotation.t
305 val num_blocks : t -> int -> int
306 val num_words_including_headers : t -> int -> int
307
308 end
309
310 (** The timestamp of a snapshot. The units are as for [Sys.time]
311 (unless custom timestamps are being provided, cf. the [Spacetime] module
312 in the standard library). *)
313 val timestamp : t -> float
314
315 val gc_stats : t -> Gc_stats.t
316 val entries : t -> Entries.t
317 val words_scanned : t -> int
318 val words_scanned_with_profinfo : t -> int
319
320 module Total_allocation : sig
321 type t
322
323 val annotation : t -> Annotation.t
324 val num_words_including_headers : t -> int
325 val next : t -> t option
326 end
327
328 (** Total allocations across *all threads*. *)
329 (* CR-someday mshinwell: change the relevant variables to be thread-local *)
330 val total_allocations : t -> Total_allocation.t option
331
332 module Event : sig
333 type t
334
335 val event_name : t -> string
336 val timestamp : t -> float
337 end
338
339 module Series : sig
340 type t
341
342 (** At present, the [Trace.t] associated with a [Series.t] cannot be
343 garbage collected or freed. This should not be a problem, since
344 the intention is that a post-processor reads the trace and outputs
345 another format. *)
346 val read : path:string -> t
347
348 val time_of_writer_close : t -> float
349 val num_threads : t -> int
350
351 type trace_kind = Normal | Finaliser
352 val trace : t -> kind:trace_kind -> thread_index:int -> Trace.t option
353
354 val frame_table : t -> Frame_table.t
355 val shape_table : t -> Shape_table.t
356 val num_snapshots : t -> int
357 val snapshot : t -> index:int -> heap_snapshot
358 val events : t -> Event.t list
359
360 (** Returns [true] iff call count information was recorded in the
361 series. *)
362 val has_call_counts : t -> bool
363 end
364 end
365