From 9028b91ec7da4d8aaf4b8bc5cbebb66585b59a5a Mon Sep 17 00:00:00 2001 From: Dino Distefano Date: Wed, 21 Nov 2018 12:54:52 -0800 Subject: [PATCH] Load data from performance profiler Reviewed By: martinoluca Differential Revision: D9593836 fbshipit-source-id: 923bfc1f3 --- infer/man/man1/infer-analyze.txt | 3 + infer/man/man1/infer-full.txt | 7 ++ infer/man/man1/infer.txt | 4 + infer/src/atd/perf_profiler.atd | 17 +++-- infer/src/backend/InferPrint.ml | 6 ++ infer/src/backend/LoadPerfData.ml | 84 +++++++++++++++++++++ infer/src/backend/LoadPerfData.mli | 10 +++ infer/src/base/Config.ml | 8 ++ infer/src/base/Config.mli | 2 + infer/src/bufferoverrun/itv.ml | 1 - infer/src/unit/PerfProfilerATDParserTest.ml | 25 +++++- 11 files changed, 158 insertions(+), 9 deletions(-) create mode 100644 infer/src/backend/LoadPerfData.ml create mode 100644 infer/src/backend/LoadPerfData.mli diff --git a/infer/man/man1/infer-analyze.txt b/infer/man/man1/infer-analyze.txt index 403dd1f4f..91292a465 100644 --- a/infer/man/man1/infer-analyze.txt +++ b/infer/man/man1/infer-analyze.txt @@ -202,6 +202,9 @@ OPTIONS Activates: Enable --ownership and disable all other checkers (Conversely: --no-ownership-only) + --perf-profiler-data-file file + Specify the file containing perf profiler data to read + --print-active-checkers Activates: Print the active checkers before starting the analysis (Conversely: --no-print-active-checkers) diff --git a/infer/man/man1/infer-full.txt b/infer/man/man1/infer-full.txt index 3915b21e3..6c3b55cc7 100644 --- a/infer/man/man1/infer-full.txt +++ b/infer/man/man1/infer-full.txt @@ -578,6 +578,10 @@ OPTIONS Activates: Enable --ownership and disable all other checkers (Conversely: --no-ownership-only) See also infer-analyze(1). + --perf-profiler-data-file file + Specify the file containing perf profiler data to read + See also infer-analyze(1). + --pmd-xml Activates: Output issues in (PMD) XML format (Conversely: --no-pmd-xml) See also infer-run(1). @@ -1290,6 +1294,9 @@ INTERNAL OPTIONS data. When false, error traces are shorter and show only direct flow via souces/sinks (Conversely: --no-passthroughs) + --perf-profiler-data-file-reset + Cancel the effect of --perf-profiler-data-file. + --precondition-stats Activates: Print stats about preconditions to standard output (Conversely: --no-precondition-stats) diff --git a/infer/man/man1/infer.txt b/infer/man/man1/infer.txt index da81e55fb..b3f29f846 100644 --- a/infer/man/man1/infer.txt +++ b/infer/man/man1/infer.txt @@ -578,6 +578,10 @@ OPTIONS Activates: Enable --ownership and disable all other checkers (Conversely: --no-ownership-only) See also infer-analyze(1). + --perf-profiler-data-file file + Specify the file containing perf profiler data to read + See also infer-analyze(1). + --pmd-xml Activates: Output issues in (PMD) XML format (Conversely: --no-pmd-xml) See also infer-run(1). diff --git a/infer/src/atd/perf_profiler.atd b/infer/src/atd/perf_profiler.atd index 45264d759..7b9663ddb 100644 --- a/infer/src/atd/perf_profiler.atd +++ b/infer/src/atd/perf_profiler.atd @@ -6,11 +6,18 @@ *) type perf_profiler_item = { - function_name : string; - avg_inclusive_cpu_time_ms : float; - avg_exclusive_cpu_time_ms : float; - p90_inclusive_cpu_time_ms : float; - p90_exclusive_cpu_time_ms : float; + function_name: string; + count_trace_id: int; + sum_inclusive_cpu_time: float; + avg_inclusive_cpu_time_ms: float; + sum_exclusive_cpu_time: float; + avg_exclusive_cpu_time_ms: float; + p90_inclusive_cpu_time_ms: float; + p90_exclusive_cpu_time_ms: float; + p50_inclusive_cpu_time_ms: float; + p50_exclusive_cpu_time_ms: float; + p25_inclusive_cpu_time_ms: float; + p25_exclusive_cpu_time_ms: float; } type perf_profiler = perf_profiler_item list diff --git a/infer/src/backend/InferPrint.ml b/infer/src/backend/InferPrint.ml index d794e1ab1..19064bb38 100644 --- a/infer/src/backend/InferPrint.ml +++ b/infer/src/backend/InferPrint.ml @@ -1062,6 +1062,12 @@ let register_perf_stats_report () = let main ~report_json = + ( if Config.loop_hoisting then + match Config.perf_profiler_data_file with + | Some fname -> + LoadPerfData.read_file_perf_data fname + | _ -> + () ) ; let issue_formats = init_issues_format_list report_json in let formats_by_report_kind = let costs_report_format_kind = diff --git a/infer/src/backend/LoadPerfData.ml b/infer/src/backend/LoadPerfData.ml new file mode 100644 index 000000000..0ab32a053 --- /dev/null +++ b/infer/src/backend/LoadPerfData.ml @@ -0,0 +1,84 @@ +(* + * Copyright (c) 2018-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! IStd +module L = Logging + +module PerfProfilerDataMap = Caml.Map.Make (struct + type t = Typ.Procname.t + + let compare = Typ.Procname.compare +end) + +let global_perf_profiler_data : Perf_profiler_t.perf_profiler_item PerfProfilerDataMap.t ref = + ref PerfProfilerDataMap.empty + + +let split_class_method_name = + let class_sep = String.Search_pattern.create "::" in + fun qualified_method_name -> + match String.Search_pattern.index class_sep ~in_:qualified_method_name with + | Some class_sep_pos -> + let class_name = + String.sub qualified_method_name ~pos:0 ~len:class_sep_pos + |> String.tr ~target:'/' ~replacement:'.' + in + let method_name = + let prefix_len = class_sep_pos + 2 in + String.sub qualified_method_name ~pos:prefix_len + ~len:(String.length qualified_method_name - prefix_len) + in + Some (class_name, method_name) + | _ -> + None + + +let pp_perf_profiler_item itm = + let open Perf_profiler_t in + L.(debug Analysis Medium) + "@\n\n\ + \ [Perf Profiler Log] Function: '%s' @\n\ + \ count trace id = %i @\n\ + \ sum inclusive cpu time = %f@\n\ + \ avg inclusive time = %f @\n\ + \ sum exclusive cpu time = %f @\n\ + \ avg exclusive_time = %f @\n\ + \ inclusive p90 = %f @\n\ + \ exclusive p90 = %f @\n\ + \ inclusive p50 = %f @\n\ + \ exclusive p50 = %f @\n\ + \ inclusive p25 = %f @\n\ + \ exclusive p25 = %f @\n" + itm.function_name itm.count_trace_id itm.sum_inclusive_cpu_time itm.avg_inclusive_cpu_time_ms + itm.sum_exclusive_cpu_time itm.avg_exclusive_cpu_time_ms itm.p90_inclusive_cpu_time_ms + itm.p90_exclusive_cpu_time_ms itm.p50_inclusive_cpu_time_ms itm.p50_exclusive_cpu_time_ms + itm.p25_inclusive_cpu_time_ms itm.p25_exclusive_cpu_time_ms + + +let read_file_perf_data fname = + let perf_profiler_data_str = + match Utils.read_file fname with + | Ok l -> + List.map ~f:Perf_profiler_j.perf_profiler_of_string l + | Error error -> + L.user_error "Failed to read file '%s': %s@." fname error ; + [] + in + let do_item itm = + pp_perf_profiler_item itm ; + match split_class_method_name itm.Perf_profiler_t.function_name with + | Some (classname, methodname) -> + let signature = JavaProfilerSamples.JNI.void_method_with_no_arguments in + L.(debug Analysis Medium) + "@\n classname = %s methodname = %s @\n" classname methodname ; + let procname = JavaProfilerSamples.create_procname ~classname ~methodname ~signature in + L.(debug Analysis Medium) " procname= %a @\n" Typ.Procname.pp procname ; + global_perf_profiler_data := + PerfProfilerDataMap.add procname itm !global_perf_profiler_data + | _ -> + () + in + List.iter ~f:(fun items -> List.iter ~f:do_item items) perf_profiler_data_str diff --git a/infer/src/backend/LoadPerfData.mli b/infer/src/backend/LoadPerfData.mli new file mode 100644 index 000000000..607d2e426 --- /dev/null +++ b/infer/src/backend/LoadPerfData.mli @@ -0,0 +1,10 @@ +(* + * Copyright (c) 2018-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! IStd + +val read_file_perf_data : string -> unit diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index 3bc7d963d..021b0c17c 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -1493,6 +1493,12 @@ and log_file = ~default:"logs" "Specify the file to use for logging" +and perf_profiler_data_file = + CLOpt.mk_path_opt ~long:"perf-profiler-data-file" + ~in_help:InferCommand.[(Analyze, manual_generic)] + ~meta:"file" "Specify the file containing perf profiler data to read" + + and linter = CLOpt.mk_string_opt ~long:"linter" ~in_help:InferCommand.[(Capture, manual_clang_linters)] @@ -2726,6 +2732,8 @@ and log_events = !log_events and log_file = !log_file +and perf_profiler_data_file = !perf_profiler_data_file + and loop_hoisting = !loop_hoisting and max_nesting = !max_nesting diff --git a/infer/src/base/Config.mli b/infer/src/base/Config.mli index 51cd5a3f2..85c8f0dde 100644 --- a/infer/src/base/Config.mli +++ b/infer/src/base/Config.mli @@ -466,6 +466,8 @@ val log_events : bool val log_file : string +val perf_profiler_data_file : string option + val loop_hoisting : bool val max_nesting : int option diff --git a/infer/src/bufferoverrun/itv.ml b/infer/src/bufferoverrun/itv.ml index fff073b96..0d9d324ae 100644 --- a/infer/src/bufferoverrun/itv.ml +++ b/infer/src/bufferoverrun/itv.ml @@ -385,7 +385,6 @@ module NonNegativePolynomial = struct let top_lifted_increasing ~f p1 p2 = match (p1, p2) with Top, _ | _, Top -> Top | NonTop p1, NonTop p2 -> NonTop (f p1 p2) - let plus = top_lifted_increasing ~f:NonNegativeNonTopPolynomial.plus let mult = top_lifted_increasing ~f:NonNegativeNonTopPolynomial.mult diff --git a/infer/src/unit/PerfProfilerATDParserTest.ml b/infer/src/unit/PerfProfilerATDParserTest.ml index fb616408d..846ca1c64 100644 --- a/infer/src/unit/PerfProfilerATDParserTest.ml +++ b/infer/src/unit/PerfProfilerATDParserTest.ml @@ -15,12 +15,31 @@ let test_parser = in [ ("test_parser_1", "[]", []) ; ( "test_parser_2" - , {|[{"function_name":"pkg/cls::\u003Cclinit>","avg_inclusive_cpu_time_ms":123.01234567899,"avg_exclusive_cpu_time_ms":9.8765432123456,"p90_inclusive_cpu_time_ms":1.012,"p90_exclusive_cpu_time_ms":3.14159}]|} + , {|[{"function_name":"pkg/cls::\u003Cclinit>", + "count_trace_id": 2, + "sum_inclusive_cpu_time": 34.4324324, + "avg_inclusive_cpu_time_ms":123.01234567899, + "sum_exclusive_cpu_time": 17.4543543, + "avg_exclusive_cpu_time_ms":9.8765432123456, + "p90_inclusive_cpu_time_ms":1.0, + "p90_exclusive_cpu_time_ms":1.15, + "p50_inclusive_cpu_time_ms": 1.1, + "p50_exclusive_cpu_time_ms": 1.2, + "p25_inclusive_cpu_time_ms": 1.3, + "p25_exclusive_cpu_time_ms": 1.4 + }]|} , [ { Perf_profiler_t.function_name= "pkg/cls::" + ; count_trace_id= 2 + ; sum_inclusive_cpu_time= 34.4324324 ; avg_inclusive_cpu_time_ms= 123.01234567899 + ; sum_exclusive_cpu_time= 17.4543543 ; avg_exclusive_cpu_time_ms= 9.8765432123456 - ; p90_inclusive_cpu_time_ms= 1.012 - ; p90_exclusive_cpu_time_ms= 3.14159 } ] ) ] + ; p90_inclusive_cpu_time_ms= 1.0 + ; p90_exclusive_cpu_time_ms= 1.15 + ; p50_inclusive_cpu_time_ms= 1.1 + ; p50_exclusive_cpu_time_ms= 1.2 + ; p25_inclusive_cpu_time_ms= 1.3 + ; p25_exclusive_cpu_time_ms= 1.4 } ] ) ] |> List.map ~f:(fun (name, test_input, expected_output) -> name >:: create_test test_input expected_output )