From deb9afe121e2a68618fbc63d2437ca4530122c48 Mon Sep 17 00:00:00 2001 From: Jules Villard Date: Mon, 22 Jul 2019 09:01:31 -0700 Subject: [PATCH] [backend] a module for recording simple counters-based stats Summary: Use it to trace summary stats. It will be used more/better in future diffs that aggregates stats across parallel workers. Reviewed By: ezgicicek Differential Revision: D16358868 fbshipit-source-id: 764614153 --- infer/src/backend/BackendStats.ml | 93 ++++++++++++++++++++++++++++++ infer/src/backend/BackendStats.mli | 32 ++++++++++ infer/src/backend/Summary.ml | 12 +++- infer/src/backend/Tasks.ml | 4 ++ 4 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 infer/src/backend/BackendStats.ml create mode 100644 infer/src/backend/BackendStats.mli diff --git a/infer/src/backend/BackendStats.ml b/infer/src/backend/BackendStats.ml new file mode 100644 index 000000000..d12ce9484 --- /dev/null +++ b/infer/src/backend/BackendStats.ml @@ -0,0 +1,93 @@ +(* + * 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 + +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 summary_has_model_queries: int } + +let global_stats = + { summary_file_try_load= 0 + ; summary_read_from_disk= 0 + ; summary_cache_hits= 0 + ; summary_cache_misses= 0 + ; summary_has_model_queries= 0 } + + +let get () = global_stats + +let incr_summary_file_try_load () = + global_stats.summary_file_try_load <- global_stats.summary_file_try_load + 1 + + +let incr_summary_read_from_disk () = + global_stats.summary_read_from_disk <- global_stats.summary_read_from_disk + 1 + + +let incr_summary_cache_hits () = + global_stats.summary_cache_hits <- global_stats.summary_cache_hits + 1 + + +let incr_summary_cache_misses () = + global_stats.summary_cache_misses <- global_stats.summary_cache_misses + 1 + + +let incr_summary_has_model_queries () = + global_stats.summary_has_model_queries <- global_stats.summary_has_model_queries + 1 + + +let copy from ~into = + (* so we don't forget to add new fields to [copy] *) + let[@warning "+9"] { summary_file_try_load + ; summary_read_from_disk + ; summary_cache_hits + ; summary_cache_misses + ; summary_has_model_queries } = + from + in + into.summary_file_try_load <- summary_file_try_load ; + into.summary_read_from_disk <- summary_read_from_disk ; + into.summary_cache_hits <- summary_cache_hits ; + into.summary_cache_misses <- summary_cache_misses ; + into.summary_has_model_queries <- summary_has_model_queries + + +let initial = + { summary_file_try_load= 0 + ; summary_read_from_disk= 0 + ; summary_cache_hits= 0 + ; summary_cache_misses= 0 + ; summary_has_model_queries= 0 } + + +let reset () = copy initial ~into:global_stats + +let pp f stats = + (* make sure we print all the fields *) + let[@warning "+9"] { summary_file_try_load + ; summary_read_from_disk + ; summary_cache_hits + ; summary_cache_misses + ; summary_has_model_queries } = + stats + in + 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 + F.fprintf f + "@[Backend stats:@\n\ + @[ file_try_load= %d@;read_from_disk= %d@;cache_hits= %d (%t)@;cache_misses= \ + %d@;has_model_queries= %d@;@]@]@." + summary_file_try_load summary_read_from_disk summary_cache_hits + (pp_hit_percent summary_cache_hits summary_cache_misses) + summary_cache_misses summary_has_model_queries diff --git a/infer/src/backend/BackendStats.mli b/infer/src/backend/BackendStats.mli new file mode 100644 index 000000000..f6e3b5143 --- /dev/null +++ b/infer/src/backend/BackendStats.mli @@ -0,0 +1,32 @@ +(* + * 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 + +(** collect statistics about backend/analysis operations *) + +type t + +val incr_summary_file_try_load : unit -> unit +(** a query to the filesystem attempting to load a summary file *) + +val incr_summary_read_from_disk : unit -> unit +(** a summary file is deserialized from disk *) + +val incr_summary_cache_hits : unit -> unit + +val incr_summary_cache_misses : unit -> unit + +val incr_summary_has_model_queries : unit -> unit +(** someone asked if a proc name has a biabduction model *) + +val reset : unit -> unit +(** reset all stats *) + +val get : unit -> t +(** get the stats so far *) + +val pp : Format.formatter -> t -> unit diff --git a/infer/src/backend/Summary.ml b/infer/src/backend/Summary.ml index fb209163c..bed8b68a9 100644 --- a/infer/src/backend/Summary.ml +++ b/infer/src/backend/Summary.ml @@ -168,6 +168,7 @@ module OnDisk = struct let has_model pname = + BackendStats.incr_summary_has_model_queries () ; Sys.file_exists (DB.filename_to_string (specs_models_filename pname)) = `Yes @@ -176,7 +177,12 @@ module OnDisk = struct (** Load procedure summary from the given file *) - let load_from_file specs_file = Serialization.read_from_file summary_serializer specs_file + let load_from_file specs_file = + BackendStats.incr_summary_file_try_load () ; + let opt = Serialization.read_from_file summary_serializer specs_file in + if Option.is_some opt then BackendStats.incr_summary_read_from_disk () ; + opt + (** Load procedure summary for the given procedure name and update spec table *) let load_summary_to_spec_table = @@ -209,8 +215,10 @@ module OnDisk = struct let get proc_name = match Typ.Procname.Hash.find cache proc_name with | summary -> + BackendStats.incr_summary_cache_hits () ; Some summary | exception Caml.Not_found -> + BackendStats.incr_summary_cache_misses () ; load_summary_to_spec_table proc_name @@ -271,8 +279,10 @@ module OnDisk = struct let reset_all ~filter () = let reset proc_name = let filename = specs_filename_of_procname proc_name in + BackendStats.incr_summary_file_try_load () ; Serialization.read_from_file summary_serializer filename |> Option.iter ~f:(fun summary -> + BackendStats.incr_summary_read_from_disk () ; let blank_summary = reset summary.proc_desc in Serialization.write_to_file summary_serializer filename ~data:blank_summary ) in diff --git a/infer/src/backend/Tasks.ml b/infer/src/backend/Tasks.ml index d7b6b0954..7315240c6 100644 --- a/infer/src/backend/Tasks.ml +++ b/infer/src/backend/Tasks.ml @@ -14,6 +14,7 @@ type 'a task_generator = 'a ProcessPool.task_generator let fork_protect ~f x = (* this is needed whenever a new process is started *) + BackendStats.reset () ; Epilogues.reset () ; EventLogger.prepare () ; L.reset_formatters () ; @@ -21,6 +22,9 @@ let fork_protect ~f x = (* get different streams of random numbers in each fork, in particular to lessen contention in `Filename.mk_temp` *) Random.self_init () ; + Epilogues.register + ~f:(fun () -> L.debug Analysis Quiet "%a@." BackendStats.pp (BackendStats.get ())) + ~description:"dumping summaries stats" ; f x