forked from facebook/pyre-check
-
Notifications
You must be signed in to change notification settings - Fork 0
/
profiling.ml
138 lines (108 loc) · 4.28 KB
/
profiling.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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
(* Copyright (c) 2019-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. *)
open Core
open Pyre
module Worker = Hack_parallel.Std.Worker
module GlobalState = struct
type t = {
mutable profiling_output: string option;
mutable memory_profiling_output: string option;
}
let global_state = { profiling_output = None; memory_profiling_output = None }
let initialize ?profiling_output ?memory_profiling_output () =
Option.iter profiling_output ~f:(fun output -> global_state.profiling_output <- output);
Option.iter memory_profiling_output ~f:(fun output ->
global_state.memory_profiling_output <- output);
()
let get () = global_state
let restore old_state =
global_state.profiling_output <- old_state.profiling_output;
global_state.memory_profiling_output <- old_state.memory_profiling_output
end
module Event = struct
type event_type =
| Duration of int
| Counter of string option
[@@deriving yojson]
type t = {
name: string;
worker_id: int;
pid: int;
event_type: event_type;
timestamp: int;
tags: (string * string) list;
}
[@@deriving yojson]
let now_in_microseconds () =
Time_stamp_counter.now ()
|> Time_stamp_counter.to_time ~calibrator:Timer.calibrator
|> Time.to_span_since_epoch
|> Time.Span.to_us
|> Int.of_float
let create ?(timestamp = now_in_microseconds ()) ?(tags = []) ~event_type name =
let name = String.filter ~f:Char.is_print name in
let pid = Unix.getpid () |> Pid.to_int in
let worker_id = Worker.current_worker_id () in
{ name; worker_id; pid; event_type; timestamp; tags }
end
let log_to_path path ~event_creator =
let path = Path.create_absolute ~follow_symbolic_links:false path in
let line = event_creator () |> Event.to_yojson |> Yojson.Safe.to_string in
File.append ~lines:[line] path
(* Taking a constructor instead of an event here so that events can be created lazily *)
let log_performance_event event_creator =
Option.iter GlobalState.global_state.profiling_output ~f:(log_to_path ~event_creator)
let log_memory_event event_creator =
Option.iter GlobalState.global_state.memory_profiling_output ~f:(log_to_path ~event_creator)
type 'a result_with_tags = {
result: 'a;
tags: unit -> (string * string) list;
}
let track_duration_event_with_dynamic_tags ~f name =
let timer = Timer.start () in
let { result; tags } = f () in
let duration = Timer.stop_in_us timer in
let create_event () =
let tags = tags () in
Event.create name ~tags ~event_type:(Duration duration)
in
log_performance_event create_event;
result
let track_duration_event ?(tags = []) ~f name =
let f () = { result = f (); tags = (fun () -> tags) } in
track_duration_event_with_dynamic_tags ~f name
let track_shared_memory_usage ?name () =
let create_event () =
let used_heap_size = SharedMem.heap_size () in
let wasted_heap_size = SharedMem.wasted_heap_size () in
let { SharedMem.nonempty_slots = nonempty_hash_slots; used_slots = used_hash_slots; _ } =
SharedMem.hash_stats ()
in
let { SharedMem.used_slots = used_dependency_slots; _ } = SharedMem.dep_stats () in
let create_tag name counter = name, string_of_int counter in
Event.create
"Shared Memory Usage"
~event_type:(Event.Counter name)
~tags:
[
create_tag "used_heap_size" used_heap_size;
create_tag "wasted_heap_size" wasted_heap_size;
create_tag "nonempty_hash_slots" nonempty_hash_slots;
create_tag "used_hash_slots" used_hash_slots;
create_tag "used_dependency_slots" used_dependency_slots;
]
in
log_memory_event create_event
let with_before_and_after_shared_memory_tracking f ~name =
track_shared_memory_usage () ~name:(Format.sprintf "Before %s" name);
let result = f () in
track_shared_memory_usage () ~name:(Format.sprintf "After %s" name);
result
let track_duration_and_shared_memory ?tags ~f name =
with_before_and_after_shared_memory_tracking (fun () -> track_duration_event name ?tags ~f) ~name
let track_duration_and_shared_memory_with_dynamic_tags ~f name =
with_before_and_after_shared_memory_tracking
(fun () -> track_duration_event_with_dynamic_tags name ~f)
~name