-
Notifications
You must be signed in to change notification settings - Fork 98
/
Copy pathperf_script.ml
104 lines (96 loc) · 3.82 KB
/
perf_script.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
open! Core
open! Async
open Magic_trace_lib
module Time_ns = Time_ns_unix
let run ?(debug = false) ?events_writer ?ocaml_exception_info ~trace_scope file =
(* CR-someday cgaebel: Get the git root by shelling out to `git rev-parse --show-toplevel`.
This works, but is ridiculous. *)
let git_root = "../../.." in
let script = In_channel.read_all (git_root ^ "/test/" ^ file) in
let lines = String.split script ~on:'\n' in
let next_pid = ref 0 in
let next_thread = ref 0 in
let module Trace = struct
type thread = int
let allocate_pid ~name:_ =
incr next_pid;
!next_pid
;;
let allocate_thread ~pid:_ ~name:_ =
incr next_thread;
!next_thread
;;
let write_duration_begin ~args:_ ~thread:_ ~name ~time : unit =
if not String.(name = "branch-misses" || name = "cache-misses")
then printf "-> %8s BEGIN %s\n" (Time_ns.Span.to_string_hum time) name
;;
let write_duration_end ~args:_ ~thread:_ ~name ~time : unit =
if not String.(name = "branch-misses" || name = "cache-misses")
then printf "-> %8s END %s\n" (Time_ns.Span.to_string_hum time) name
;;
let write_duration_complete ~args ~thread ~name ~time ~time_end : unit =
write_duration_begin ~args ~thread ~name ~time;
write_duration_end ~args ~thread ~name ~time:time_end
;;
let write_duration_instant ~args ~thread ~name ~time : unit =
write_duration_begin ~args ~thread ~name ~time;
printf "-> END %s\n" name
;;
let write_counter ~args:_ ~thread:_ ~name:_ ~time:_ : unit = ()
end
in
Magic_trace_lib.Trace_writer.debug := debug;
Exn.protect
~finally:(fun () -> Magic_trace_lib.Trace_writer.debug := false)
~f:(fun () ->
let trace_writer =
Trace_writer.create_expert
~trace_scope
~debug_info:None
~ocaml_exception_info
~earliest_time:Time_ns.Span.zero
~hits:[]
~annotate_inferred_start_times:true
(module Trace)
in
let first_event_time = ref Time_ns.Span.Option.none in
(* Make the start of the trace start at time=0, regardless of when it actually started. *)
let adjust_event_time (event : Event.t) : Event.t =
Event.change_time event ~f:(fun event_time ->
let first_event_time =
match%optional.Time_ns.Span.Option !first_event_time with
| None ->
first_event_time := Time_ns.Span.Option.some event_time;
event_time
| Some first_event_time -> first_event_time
in
Time_ns.Span.( - ) event_time first_event_time)
in
let should_print_perf_line (event : Event.t) =
match event with
| Ok { data = Trace data; _ } ->
(* Most of a trace is just jumps within a single function. Those are basically
uninteresting to magic-trace, so skip them to keep tests a little cleaner. *)
not ([%compare.equal: Symbol.t] data.src.symbol data.dst.symbol)
| Error _ | Ok _ -> true
in
let%map split_lines =
Perf_decode.For_testing.split_line_pipe (Pipe.of_list lines) |> Pipe.to_list
in
List.iter split_lines ~f:(fun lines ->
let event =
Perf_decode.For_testing.to_event lines |> Option.map ~f:adjust_event_time
in
match event with
| Some event ->
if should_print_perf_line event
then (
match lines with
| [ line ] -> printf "%s\n" line
| lines -> print_s [%message (lines : string list)]);
let event = Event.With_write_info.create ~should_write:true event in
Trace_writer.write_event ?events_writer trace_writer event
| None -> ());
printf "INPUT TRACE STREAM ENDED, any lines printed below this were deferred\n";
Trace_writer.end_of_trace trace_writer)
;;