forked from facebook/pyre-check
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprofiling.ml
94 lines (77 loc) · 3.03 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
(* 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 Event = struct
type event_type =
| Duration of int
| Counter of string option
[@@deriving yojson]
type t = {
name: string;
pid: int;
event_type: event_type;
timestamp: int;
tags: (string * string) list;
}
[@@deriving yojson]
let now_in_milliseconds () =
Time_stamp_counter.now ()
|> Time_stamp_counter.to_time ~calibrator:Timer.calibrator
|> Time.to_span_since_epoch
|> Time.Span.to_ms
|> Int.of_float
let create ?(timestamp = now_in_milliseconds ()) ?(tags = []) ~event_type name =
let name = String.filter ~f:Char.is_print name in
let pid = Unix.getpid () |> Pid.to_int in
{ name; 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 =
Configuration.Analysis.get_global ()
>>= (fun { Configuration.Analysis.profiling_output; _ } -> profiling_output)
|> Option.iter ~f:(log_to_path ~event_creator)
let log_memory_event event_creator =
Configuration.Analysis.get_global ()
>>= (fun { Configuration.Analysis.memory_profiling_output; _ } -> memory_profiling_output)
|> Option.iter ~f:(log_to_path ~event_creator)
let track_duration_event ?(tags = []) ~f name =
let timer = Timer.start () in
let result = f () in
let duration = Timer.stop_in_us timer in
let create_event () = Event.create name ~tags ~event_type:(Duration duration) in
log_performance_event create_event;
result
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 track_duration_and_shared_memory ?tags ~f name =
track_shared_memory_usage () ~name:(Format.sprintf "Before %s" name);
let result = track_duration_event name ?tags ~f in
track_shared_memory_usage () ~name:(Format.sprintf "After %s" name);
result