open! Core
module Kind = struct
type t =
| Async
| Call
| Return
| Syscall
| Sysret
| Hardware_interrupt
| Interrupt
| Iret
| Jump
| Tx_abort
[@@deriving sexp, compare, bin_io]
end
module Thread = struct
type t =
{ pid : Pid.t option
; tid : Pid.t option
}
[@@deriving sexp, compare, hash, bin_io]
end
module Location = struct
type t =
{ instruction_pointer : Int64.Hex.t
; symbol : Symbol.t
; symbol_offset : Int.Hex.t
}
[@@deriving sexp, fields, bin_io]
module Ignore_symbol = struct
(* Ignoring symbol strings when serializing to save space. This reduces the size of events file
by ~50% based on small tests. The symbol information is still available implicitly by looking at the top
of the callstack that optionally is exported together with the events. Symbol offset will be missing. *)
type nonrec t = t
let to_sexpable { instruction_pointer; _ } = instruction_pointer
let of_sexpable instruction_pointer =
{ instruction_pointer; symbol = Symbol.Unknown; symbol_offset = 0 }
;;
let to_binable { instruction_pointer; _ } = instruction_pointer
let of_binable instruction_pointer =
{ instruction_pointer; symbol = Symbol.Unknown; symbol_offset = 0 }
;;
let caller_identity =
Bin_prot.Shape.Uuid.of_string "0d14b306-09e1-11ed-9c9e-a4bb6d9e5f20"
;;
end
include Binable.Of_binable_with_uuid (Int64.Hex) (Ignore_symbol)
include Sexpable.Of_sexpable (Int64.Hex) (Ignore_symbol)
(* magic-trace has some things that aren't functions but look like they are in the trace
(like "[untraced]" and "[syscall]") *)
let locationless symbol = { instruction_pointer = 0L; symbol; symbol_offset = 0 }
let unknown = locationless Unknown
let untraced = locationless Untraced
let returned = locationless Returned
let syscall = locationless Syscall
end
module Ok = struct
module Data = struct
type t =
| Trace of
{ trace_state_change : Trace_state_change.t option [@sexp.option]
; kind : Kind.t option [@sexp.option]
; src : Location.t
; dst : Location.t
}
| Power of { freq : int }
| Stacktrace_sample of { callstack : Location.t list }
| Event_sample of
{ location : Location.t
; count : int
; name : Collection_mode.Event.Name.t
}
[@@deriving sexp, bin_io]
end
type t =
{ thread : Thread.t
; time : Time_ns.Span.t
; data : Data.t
; in_transaction : bool [@sexp.bool]
}
[@@deriving sexp, bin_io]
end
module Decode_error = struct
type t =
{ thread : Thread.t
(* The time is only present sometimes. I haven't figured out when, exactly, but my
Skylake test machine has it while my Tiger Lake test machine doesn't. It could
easily be a difference between different versions of perf... *)
; time : Time_ns_unix.Span.Option.t
; instruction_pointer : Int64.Hex.t option
; message : string
}
[@@deriving sexp, bin_io]
end
type t = (Ok.t, Decode_error.t) Result.t [@@deriving sexp, bin_io]
let thread (t : t) =
match t with
| Ok { thread; _ } | Error { thread; _ } -> thread
;;
let time (t : t) =
match t with
| Ok { time; _ } -> Time_ns_unix.Span.Option.some time
| Error { time; _ } -> time
;;
let change_time (t : t) ~f : t =
match t with
| Ok ({ time; _ } as t) -> Ok { t with time = f time }
| Error ({ time; _ } as u) ->
(match%optional.Time_ns_unix.Span.Option time with
| None -> t
| Some time -> Error { u with time = Time_ns_unix.Span.Option.some (f time) })
;;
module With_write_info = struct
type outer = t [@@deriving sexp_of]
type t =
{ event : outer
; should_write : bool
}
[@@deriving sexp_of, fields]
let create ?(should_write = true) event = { event; should_write }
end