You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
206 lines
7.8 KiB
206 lines
7.8 KiB
(*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*)
|
|
open! IStd
|
|
module F = Format
|
|
module L = Logging
|
|
|
|
include struct
|
|
(* ignore dead modules added by @@deriving fields *)
|
|
[@@@warning "-60"]
|
|
|
|
type t =
|
|
{ mutable summary_file_try_load: int
|
|
; mutable summary_read_from_disk: int
|
|
; mutable summary_cache_hits: int
|
|
; mutable summary_cache_misses: int
|
|
; mutable ondemand_procs_analyzed: int
|
|
; mutable ondemand_local_cache_hits: int
|
|
; mutable ondemand_local_cache_misses: int
|
|
; mutable proc_locker_lock_time: ExecutionDuration.t
|
|
; mutable proc_locker_unlock_time: ExecutionDuration.t
|
|
; mutable restart_scheduler_useful_time: ExecutionDuration.t
|
|
; mutable restart_scheduler_total_time: ExecutionDuration.t }
|
|
[@@deriving fields]
|
|
end
|
|
|
|
let global_stats =
|
|
{ summary_file_try_load= 0
|
|
; summary_read_from_disk= 0
|
|
; summary_cache_hits= 0
|
|
; summary_cache_misses= 0
|
|
; ondemand_procs_analyzed= 0
|
|
; ondemand_local_cache_hits= 0
|
|
; ondemand_local_cache_misses= 0
|
|
; proc_locker_lock_time= ExecutionDuration.zero
|
|
; proc_locker_unlock_time= ExecutionDuration.zero
|
|
; restart_scheduler_useful_time= ExecutionDuration.zero
|
|
; restart_scheduler_total_time= ExecutionDuration.zero }
|
|
|
|
|
|
let get () = global_stats
|
|
|
|
let update_with field ~f =
|
|
match Field.setter field with
|
|
| None ->
|
|
L.die InternalError "incr on non-mutable field %s" (Field.name field)
|
|
| Some set ->
|
|
set global_stats (f (Field.get field global_stats))
|
|
|
|
|
|
let incr field = update_with field ~f:(( + ) 1)
|
|
|
|
let add field exe_duration = update_with field ~f:(ExecutionDuration.add exe_duration)
|
|
|
|
let incr_summary_file_try_load () = incr Fields.summary_file_try_load
|
|
|
|
let incr_summary_read_from_disk () = incr Fields.summary_read_from_disk
|
|
|
|
let incr_summary_cache_hits () = incr Fields.summary_cache_hits
|
|
|
|
let incr_summary_cache_misses () = incr Fields.summary_cache_misses
|
|
|
|
let incr_ondemand_procs_analyzed () = incr Fields.ondemand_procs_analyzed
|
|
|
|
let incr_ondemand_local_cache_hits () = incr Fields.ondemand_local_cache_hits
|
|
|
|
let incr_ondemand_local_cache_misses () = incr Fields.ondemand_local_cache_misses
|
|
|
|
let add_to_proc_locker_lock_time execution_duration =
|
|
add Fields.proc_locker_lock_time execution_duration
|
|
|
|
|
|
let add_to_proc_locker_unlock_time execution_duration =
|
|
add Fields.proc_locker_unlock_time execution_duration
|
|
|
|
|
|
let add_to_restart_scheduler_useful_time execution_duration =
|
|
add Fields.restart_scheduler_useful_time execution_duration
|
|
|
|
|
|
let add_to_restart_scheduler_total_time execution_duration =
|
|
add Fields.restart_scheduler_total_time execution_duration
|
|
|
|
|
|
let copy from ~into : unit =
|
|
let { summary_file_try_load
|
|
; summary_read_from_disk
|
|
; summary_cache_hits
|
|
; summary_cache_misses
|
|
; ondemand_procs_analyzed
|
|
; ondemand_local_cache_hits
|
|
; ondemand_local_cache_misses
|
|
; proc_locker_lock_time
|
|
; proc_locker_unlock_time
|
|
; restart_scheduler_useful_time
|
|
; restart_scheduler_total_time } =
|
|
from
|
|
in
|
|
Fields.Direct.set_all_mutable_fields into ~summary_file_try_load ~summary_read_from_disk
|
|
~summary_cache_hits ~summary_cache_misses ~ondemand_procs_analyzed ~ondemand_local_cache_hits
|
|
~ondemand_local_cache_misses ~proc_locker_lock_time ~proc_locker_unlock_time
|
|
~restart_scheduler_useful_time ~restart_scheduler_total_time
|
|
|
|
|
|
let merge stats1 stats2 =
|
|
{ summary_file_try_load= stats1.summary_file_try_load + stats2.summary_file_try_load
|
|
; summary_read_from_disk= stats1.summary_read_from_disk + stats2.summary_read_from_disk
|
|
; summary_cache_hits= stats1.summary_cache_hits + stats2.summary_cache_hits
|
|
; summary_cache_misses= stats1.summary_cache_misses + stats2.summary_cache_misses
|
|
; ondemand_procs_analyzed= stats1.ondemand_procs_analyzed + stats2.ondemand_procs_analyzed
|
|
; ondemand_local_cache_hits= stats1.ondemand_local_cache_hits + stats2.ondemand_local_cache_hits
|
|
; ondemand_local_cache_misses=
|
|
stats1.ondemand_local_cache_misses + stats2.ondemand_local_cache_misses
|
|
; proc_locker_lock_time=
|
|
ExecutionDuration.add stats1.proc_locker_lock_time stats2.proc_locker_lock_time
|
|
; proc_locker_unlock_time=
|
|
ExecutionDuration.add stats1.proc_locker_unlock_time stats2.proc_locker_unlock_time
|
|
; restart_scheduler_useful_time=
|
|
ExecutionDuration.add stats1.restart_scheduler_useful_time
|
|
stats2.restart_scheduler_useful_time
|
|
; restart_scheduler_total_time=
|
|
ExecutionDuration.add stats1.restart_scheduler_total_time stats2.restart_scheduler_total_time
|
|
}
|
|
|
|
|
|
let initial =
|
|
{ summary_file_try_load= 0
|
|
; summary_read_from_disk= 0
|
|
; summary_cache_hits= 0
|
|
; summary_cache_misses= 0
|
|
; ondemand_procs_analyzed= 0
|
|
; ondemand_local_cache_hits= 0
|
|
; ondemand_local_cache_misses= 0
|
|
; proc_locker_lock_time= ExecutionDuration.zero
|
|
; proc_locker_unlock_time= ExecutionDuration.zero
|
|
; restart_scheduler_useful_time= ExecutionDuration.zero
|
|
; restart_scheduler_total_time= ExecutionDuration.zero }
|
|
|
|
|
|
let reset () = copy initial ~into:global_stats
|
|
|
|
let pp f stats =
|
|
let pp_hit_percent hit miss f =
|
|
let total = hit + miss in
|
|
if Int.equal total 0 then F.pp_print_string f "N/A%%" else F.fprintf f "%d%%" (hit * 100 / total)
|
|
in
|
|
let pp_int_field stats f field =
|
|
F.fprintf f "%s= %d@;" (Field.name field) (Field.get field stats)
|
|
in
|
|
let pp_execution_duration_field stats f field =
|
|
let field_value = Field.get field stats in
|
|
let field_name = Field.name field in
|
|
F.fprintf f "%a@;" (ExecutionDuration.pp ~prefix:field_name) field_value
|
|
in
|
|
let pp_cache_hits stats cache_misses f cache_hits_field =
|
|
let cache_hits = Field.get cache_hits_field stats in
|
|
F.fprintf f "%s= %d (%t)@;" (Field.name cache_hits_field) cache_hits
|
|
(pp_hit_percent cache_hits cache_misses)
|
|
in
|
|
let pp_stats stats f =
|
|
Fields.iter ~summary_file_try_load:(pp_int_field stats f)
|
|
~summary_read_from_disk:(pp_int_field stats f)
|
|
~summary_cache_hits:(pp_cache_hits stats stats.summary_cache_misses f)
|
|
~summary_cache_misses:(pp_int_field stats f) ~ondemand_procs_analyzed:(pp_int_field stats f)
|
|
~ondemand_local_cache_hits:(pp_cache_hits stats stats.ondemand_local_cache_misses f)
|
|
~ondemand_local_cache_misses:(pp_int_field stats f)
|
|
~proc_locker_lock_time:(pp_execution_duration_field stats f)
|
|
~proc_locker_unlock_time:(pp_execution_duration_field stats f)
|
|
~restart_scheduler_useful_time:(pp_execution_duration_field stats f)
|
|
~restart_scheduler_total_time:(pp_execution_duration_field stats f)
|
|
in
|
|
F.fprintf f "@[Backend stats:@\n@[<v2> %t@]@]@." (pp_stats stats)
|
|
|
|
|
|
let log_to_scuba stats =
|
|
let create_counter field =
|
|
[LogEntry.mk_count ~label:("backend_stats." ^ Field.name field) ~value:(Field.get field stats)]
|
|
in
|
|
let create_time_entry field =
|
|
Field.get field stats
|
|
|> ExecutionDuration.to_scuba_entries ~prefix:("backend_stats." ^ Field.name field)
|
|
in
|
|
let entries =
|
|
Fields.to_list ~summary_file_try_load:create_counter ~summary_read_from_disk:create_counter
|
|
~summary_cache_hits:create_counter ~summary_cache_misses:create_counter
|
|
~ondemand_procs_analyzed:create_counter ~ondemand_local_cache_hits:create_counter
|
|
~ondemand_local_cache_misses:create_counter ~proc_locker_lock_time:create_time_entry
|
|
~proc_locker_unlock_time:create_time_entry ~restart_scheduler_useful_time:create_time_entry
|
|
~restart_scheduler_total_time:create_time_entry
|
|
|> List.concat
|
|
in
|
|
ScubaLogging.log_many entries
|
|
|
|
|
|
let log_aggregate stats_list =
|
|
match stats_list with
|
|
| [] ->
|
|
L.internal_error "Empty list of backend stats to aggregate, weird!@\n"
|
|
| one :: rest ->
|
|
let stats = List.fold rest ~init:one ~f:(fun aggregate one -> merge aggregate one) in
|
|
L.debug Analysis Quiet "%a" pp stats ;
|
|
log_to_scuba stats
|