365 lines
11 KiB
OCaml
365 lines
11 KiB
OCaml
(**************************************************************************)
|
|
(* *)
|
|
(* OCaml *)
|
|
(* *)
|
|
(* Mark Shinwell and Leo White, Jane Street Europe *)
|
|
(* *)
|
|
(* Copyright 2015--2017 Jane Street Group LLC *)
|
|
(* *)
|
|
(* All rights reserved. This file is distributed under the terms of *)
|
|
(* the GNU Lesser General Public License version 2.1, with the *)
|
|
(* special exception on linking described in the file LICENSE. *)
|
|
(* *)
|
|
(**************************************************************************)
|
|
|
|
(** Access to the information recorded by the [Spacetime]
|
|
module. (It is intended that this module will be used by
|
|
post-processors rather than users wishing to understand their
|
|
programs.)
|
|
For 64-bit targets only.
|
|
This module may be used from any program, not just one compiled
|
|
with a compiler configured for Spacetime. *)
|
|
|
|
module Gc_stats : sig
|
|
type t
|
|
|
|
val minor_words : t -> int
|
|
val promoted_words : t -> int
|
|
val major_words : t -> int
|
|
val minor_collections : t -> int
|
|
val major_collections : t -> int
|
|
val heap_words : t -> int
|
|
val heap_chunks : t -> int
|
|
val compactions : t -> int
|
|
val top_heap_words : t -> int
|
|
end
|
|
|
|
module Annotation : sig
|
|
(** An annotation written into a value's header. These may be looked up
|
|
in a [Trace.t] (see below). *)
|
|
type t
|
|
|
|
(* CR-someday mshinwell: consider using tag and size to increase the
|
|
available space of annotations. Need to be careful of [Obj.truncate].
|
|
Could also randomise the tags on records.
|
|
*)
|
|
|
|
val to_int : t -> int
|
|
end
|
|
|
|
module Program_counter : sig
|
|
module OCaml : sig
|
|
type t
|
|
|
|
val to_int64 : t -> Int64.t
|
|
end
|
|
|
|
module Foreign : sig
|
|
type t
|
|
|
|
val to_int64 : t -> Int64.t
|
|
end
|
|
|
|
end
|
|
|
|
module Frame_table : sig
|
|
(* CR-someday mshinwell: move to [Gc] if dependencies permit? *)
|
|
(** A value of type [t] corresponds to the frame table of a running
|
|
OCaml program. The table is indexed by program counter address
|
|
(typically, but not always when using Spacetime, return addresses). *)
|
|
type t
|
|
|
|
(** Find the location, including any inlined frames, corresponding to the
|
|
given program counter address. Raises [Not_found] if the location
|
|
could not be resolved. *)
|
|
val find_exn : Program_counter.OCaml.t -> t -> Printexc.Slot.t list
|
|
end
|
|
|
|
module Function_entry_point : sig
|
|
type t
|
|
|
|
val to_int64 : t -> Int64.t
|
|
end
|
|
|
|
module Function_identifier : sig
|
|
type t
|
|
(* CR-soon mshinwell: same as [Function_entry_point] now *)
|
|
val to_int64 : t -> Int64.t
|
|
end
|
|
|
|
module Shape_table : sig
|
|
type t
|
|
end
|
|
|
|
module Trace : sig
|
|
(** A value of type [t] holds the dynamic call structure of the program
|
|
(i.e. which functions have called which other functions) together with
|
|
information required to decode profiling annotations written into
|
|
values' headers. *)
|
|
type t
|
|
type trace = t
|
|
|
|
type node
|
|
type ocaml_node
|
|
type foreign_node
|
|
type uninstrumented_node
|
|
|
|
module OCaml : sig
|
|
module Allocation_point : sig
|
|
(** A value of type [t] corresponds to an allocation point in OCaml
|
|
code. *)
|
|
type t
|
|
|
|
(** The program counter at (or close to) the allocation site. *)
|
|
val program_counter : t -> Program_counter.OCaml.t
|
|
|
|
(** The annotation written into the headers of boxed values allocated
|
|
at the given allocation site. *)
|
|
val annotation : t -> Annotation.t
|
|
|
|
(** The total number of words allocated at this point. *)
|
|
val num_words_including_headers : t -> int
|
|
end
|
|
|
|
module Direct_call_point : sig
|
|
(** A value of type ['target t] corresponds to a direct (i.e. known
|
|
at compile time) call point in OCaml code. ['target] is the type
|
|
of the node corresponding to the callee. *)
|
|
type 'target t
|
|
|
|
(** The program counter at (or close to) the call site. *)
|
|
val call_site : _ t -> Program_counter.OCaml.t
|
|
|
|
(** The address of the first instruction of the callee. *)
|
|
val callee : _ t -> Function_entry_point.t
|
|
|
|
(** The node corresponding to the callee. *)
|
|
val callee_node : 'target t -> 'target
|
|
|
|
(** The number of times the callee was called. Only available if the
|
|
compiler that recorded the Spacetime profile was configured with
|
|
"-with-spacetime-call-counts". [None] will be returned otherwise. *)
|
|
val call_count : _ t -> int option
|
|
end
|
|
|
|
module Indirect_call_point : sig
|
|
(** A value of type [t] corresponds to an indirect call point in OCaml
|
|
code. Each such value contains a list of callees to which the
|
|
call point has branched. *)
|
|
type t
|
|
|
|
(** The program counter at (or close to) the call site. *)
|
|
val call_site : t -> Program_counter.OCaml.t
|
|
|
|
module Callee : sig
|
|
type t
|
|
|
|
(** The address of the first instruction of the callee. *)
|
|
val callee : t -> Function_entry_point.t
|
|
|
|
(** The node corresponding to the callee. *)
|
|
val callee_node : t -> node
|
|
|
|
(** The number of times the callee was called. This returns [None] in
|
|
the same circumstances as [Direct_call_point.call_count], above. *)
|
|
val call_count : t -> int option
|
|
|
|
(** Move to the next callee to which this call point has branched.
|
|
[None] is returned when the end of the list is reached. *)
|
|
val next : t -> t option
|
|
end
|
|
|
|
(** The list of callees to which this indirect call point has
|
|
branched. *)
|
|
val callees : t -> Callee.t option
|
|
end
|
|
|
|
module Field : sig
|
|
(** A value of type [t] enables iteration through the contents
|
|
("fields") of an OCaml node. *)
|
|
type t
|
|
|
|
type direct_call_point =
|
|
| To_ocaml of ocaml_node Direct_call_point.t
|
|
| To_foreign of foreign_node Direct_call_point.t
|
|
(* CR-soon mshinwell: once everything's finished, "uninstrumented"
|
|
should be able to go away. Let's try to do this after the
|
|
first release. *)
|
|
| To_uninstrumented of
|
|
uninstrumented_node Direct_call_point.t
|
|
|
|
type classification =
|
|
| Allocation of Allocation_point.t
|
|
| Direct_call of direct_call_point
|
|
| Indirect_call of Indirect_call_point.t
|
|
|
|
val classify : t -> classification
|
|
val next : t -> t option
|
|
end
|
|
|
|
module Node : sig
|
|
(** A node corresponding to an invocation of a function written in
|
|
OCaml. *)
|
|
type t = ocaml_node
|
|
|
|
val compare : t -> t -> int
|
|
|
|
(** A unique identifier for the function corresponding to this node. *)
|
|
val function_identifier : t -> Function_identifier.t
|
|
|
|
(** This function traverses a circular list. *)
|
|
val next_in_tail_call_chain : t -> t
|
|
|
|
val fields : t -> shape_table:Shape_table.t -> Field.t option
|
|
end
|
|
end
|
|
|
|
module Foreign : sig
|
|
module Allocation_point : sig
|
|
(** A value of type [t] corresponds to an allocation point in non-OCaml
|
|
code. *)
|
|
type t
|
|
|
|
val program_counter : t -> Program_counter.Foreign.t
|
|
val annotation : t -> Annotation.t
|
|
val num_words_including_headers : t -> int
|
|
end
|
|
|
|
module Call_point : sig
|
|
(** A value of type [t] corresponds to a call point from non-OCaml
|
|
code (to either non-OCaml code, or OCaml code via the usual
|
|
assembly veneer). Call counts are not available for such nodes. *)
|
|
type t
|
|
|
|
(** N.B. The address of the callee (of type [Function_entry_point.t]) is
|
|
not available. It must be recovered during post-processing. *)
|
|
val call_site : t -> Program_counter.Foreign.t
|
|
val callee_node : t -> node
|
|
end
|
|
|
|
module Field : sig
|
|
(** A value of type [t] enables iteration through the contents ("fields")
|
|
of a C node. *)
|
|
type t
|
|
|
|
type classification = private
|
|
| Allocation of Allocation_point.t
|
|
| Call of Call_point.t
|
|
|
|
val classify : t -> classification
|
|
val next : t -> t option
|
|
end
|
|
|
|
module Node : sig
|
|
(** A node corresponding to an invocation of a function written in C
|
|
(or any other language that is not OCaml). *)
|
|
type t = foreign_node
|
|
|
|
val compare : t -> t -> int
|
|
|
|
val fields : t -> Field.t option
|
|
|
|
end
|
|
|
|
end
|
|
|
|
module Node : sig
|
|
(** Either an OCaml or a foreign node; or an indication that this
|
|
is a branch of the graph corresponding to uninstrumented
|
|
code. *)
|
|
type t = node
|
|
|
|
val compare : t -> t -> int
|
|
|
|
type classification = private
|
|
| OCaml of OCaml.Node.t
|
|
| Foreign of Foreign.Node.t
|
|
|
|
val classify : t -> classification
|
|
|
|
val of_ocaml_node : OCaml.Node.t -> t
|
|
val of_foreign_node : Foreign.Node.t -> t
|
|
|
|
module Set : Set.S with type elt = t
|
|
module Map : Map.S with type key = t
|
|
end
|
|
|
|
(** Obtains the root of the graph for traversal. [None] is returned if
|
|
the graph is empty. *)
|
|
val root : t -> Node.t option
|
|
end
|
|
|
|
module Heap_snapshot : sig
|
|
type t
|
|
type heap_snapshot = t
|
|
|
|
module Entries : sig
|
|
(** An immutable array of the total number of blocks (= boxed
|
|
values) and the total number of words occupied by such blocks
|
|
(including their headers) for each profiling annotation in
|
|
the heap. *)
|
|
type t
|
|
|
|
val length : t -> int
|
|
val annotation : t -> int -> Annotation.t
|
|
val num_blocks : t -> int -> int
|
|
val num_words_including_headers : t -> int -> int
|
|
|
|
end
|
|
|
|
(** The timestamp of a snapshot. The units are as for [Sys.time]
|
|
(unless custom timestamps are being provided, cf. the [Spacetime] module
|
|
in the standard library). *)
|
|
val timestamp : t -> float
|
|
|
|
val gc_stats : t -> Gc_stats.t
|
|
val entries : t -> Entries.t
|
|
val words_scanned : t -> int
|
|
val words_scanned_with_profinfo : t -> int
|
|
|
|
module Total_allocation : sig
|
|
type t
|
|
|
|
val annotation : t -> Annotation.t
|
|
val num_words_including_headers : t -> int
|
|
val next : t -> t option
|
|
end
|
|
|
|
(** Total allocations across *all threads*. *)
|
|
(* CR-someday mshinwell: change the relevant variables to be thread-local *)
|
|
val total_allocations : t -> Total_allocation.t option
|
|
|
|
module Event : sig
|
|
type t
|
|
|
|
val event_name : t -> string
|
|
val timestamp : t -> float
|
|
end
|
|
|
|
module Series : sig
|
|
type t
|
|
|
|
(** At present, the [Trace.t] associated with a [Series.t] cannot be
|
|
garbage collected or freed. This should not be a problem, since
|
|
the intention is that a post-processor reads the trace and outputs
|
|
another format. *)
|
|
val read : path:string -> t
|
|
|
|
val time_of_writer_close : t -> float
|
|
val num_threads : t -> int
|
|
|
|
type trace_kind = Normal | Finaliser
|
|
val trace : t -> kind:trace_kind -> thread_index:int -> Trace.t option
|
|
|
|
val frame_table : t -> Frame_table.t
|
|
val shape_table : t -> Shape_table.t
|
|
val num_snapshots : t -> int
|
|
val snapshot : t -> index:int -> heap_snapshot
|
|
val events : t -> Event.t list
|
|
|
|
(** Returns [true] iff call count information was recorded in the
|
|
series. *)
|
|
val has_call_counts : t -> bool
|
|
end
|
|
end
|