Summary: This change introduces a new binary, called `InferStatsAggregator`, that once invoked, aggregates together all the stats generated by the single invocations of frontend/backend/reporting, that can be used for performance measurements. Reviewed By: jvillard Differential Revision: D3317000 fbshipit-source-id: 61ec615master
parent
83a14a3541
commit
f89e66dc60
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* vim: set ft=rust:
|
||||||
|
* vim: set ft=reason:
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
type t = {
|
||||||
|
sum: float,
|
||||||
|
avg: float,
|
||||||
|
min: float,
|
||||||
|
p10: float,
|
||||||
|
median: float,
|
||||||
|
p75: float,
|
||||||
|
max: float,
|
||||||
|
count: int
|
||||||
|
};
|
||||||
|
|
||||||
|
let to_json s =>
|
||||||
|
`Assoc [
|
||||||
|
("sum", `Float s.sum),
|
||||||
|
("avg", `Float s.avg),
|
||||||
|
("min", `Float s.min),
|
||||||
|
("p10", `Float s.p10),
|
||||||
|
("median", `Float s.median),
|
||||||
|
("p75", `Float s.p75),
|
||||||
|
("max", `Float s.max),
|
||||||
|
("count", `Int s.count)
|
||||||
|
];
|
||||||
|
|
||||||
|
let from_json json => {
|
||||||
|
let open! Yojson.Basic.Util;
|
||||||
|
{
|
||||||
|
sum: json |> member "sum" |> to_float,
|
||||||
|
avg: json |> member "avg" |> to_float,
|
||||||
|
min: json |> member "min" |> to_float,
|
||||||
|
p10: json |> member "p10" |> to_float,
|
||||||
|
median: json |> member "median" |> to_float,
|
||||||
|
p75: json |> member "p75" |> to_float,
|
||||||
|
max: json |> member "max" |> to_float,
|
||||||
|
count: json |> member "count" |> to_int
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let compute_statistics values => {
|
||||||
|
let num_elements = IList.length values;
|
||||||
|
let sum = IList.fold_left (fun acc v => acc +. v) 0.0 values;
|
||||||
|
let average = sum /. float_of_int num_elements;
|
||||||
|
let values_arr = Array.of_list values;
|
||||||
|
Array.sort
|
||||||
|
(
|
||||||
|
fun a b =>
|
||||||
|
if (a == b) {
|
||||||
|
0
|
||||||
|
} else if (a -. b < 0.0) {
|
||||||
|
(-1)
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
)
|
||||||
|
values_arr;
|
||||||
|
let percentile pct => {
|
||||||
|
assert (pct >= 0.0 && pct <= 1.0);
|
||||||
|
assert (num_elements > 0);
|
||||||
|
let max_index = num_elements - 1;
|
||||||
|
let pct_index = float_of_int max_index *. pct;
|
||||||
|
let low_index = int_of_float (Pervasives.floor pct_index);
|
||||||
|
let high_index = int_of_float (Pervasives.ceil pct_index);
|
||||||
|
let low = values_arr.(low_index);
|
||||||
|
let high = values_arr.(high_index);
|
||||||
|
(low +. high) /. 2.0
|
||||||
|
};
|
||||||
|
{
|
||||||
|
sum,
|
||||||
|
avg: average,
|
||||||
|
min: percentile 0.0,
|
||||||
|
p10: percentile 0.10,
|
||||||
|
median: percentile 0.50,
|
||||||
|
p75: percentile 0.75,
|
||||||
|
max: percentile 1.0,
|
||||||
|
count: num_elements
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* vim: set ft=rust:
|
||||||
|
* vim: set ft=reason:
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
type t;
|
||||||
|
|
||||||
|
let to_json: t => Yojson.Basic.json;
|
||||||
|
|
||||||
|
let from_json: Yojson.Basic.json => t;
|
||||||
|
|
||||||
|
let compute_statistics: list float => t;
|
@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* vim: set ft=rust:
|
||||||
|
* vim: set ft=reason:
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
open! Utils;
|
||||||
|
|
||||||
|
let filename = "aggregated_stats.json";
|
||||||
|
|
||||||
|
let dir_exists dir =>
|
||||||
|
try (Sys.is_directory dir) {
|
||||||
|
| Sys_error _ => false
|
||||||
|
};
|
||||||
|
|
||||||
|
let find_json_files_in_dir dir => {
|
||||||
|
let is_valid_json_file path => {
|
||||||
|
let s = Unix.lstat path;
|
||||||
|
let json_regex = Str.regexp_case_fold ".*\\.json$";
|
||||||
|
not (Str.string_match (Str.regexp (".*" ^ Str.quote filename ^ "$")) path 0) &&
|
||||||
|
Str.string_match json_regex path 0 && s.st_kind == Unix.S_REG
|
||||||
|
};
|
||||||
|
dir_exists dir ?
|
||||||
|
{
|
||||||
|
let content = Array.to_list (Sys.readdir dir);
|
||||||
|
let content_with_path = IList.map (fun p => Filename.concat dir p) content;
|
||||||
|
IList.filter is_valid_json_file content_with_path
|
||||||
|
} :
|
||||||
|
[]
|
||||||
|
};
|
||||||
|
|
||||||
|
let find_stats_files_in_dir dir => {
|
||||||
|
let frontend_stats_files = find_json_files_in_dir (
|
||||||
|
Filename.concat dir Config.frontend_stats_dir_name
|
||||||
|
);
|
||||||
|
let backend_stats_files = find_json_files_in_dir (
|
||||||
|
Filename.concat dir Config.backend_stats_dir_name
|
||||||
|
);
|
||||||
|
let reporting_stats_files = find_json_files_in_dir (
|
||||||
|
Filename.concat dir Config.reporting_stats_dir_name
|
||||||
|
);
|
||||||
|
(frontend_stats_files, backend_stats_files, reporting_stats_files)
|
||||||
|
};
|
||||||
|
|
||||||
|
let load_data_from_infer_deps file => {
|
||||||
|
let extract_path line =>
|
||||||
|
switch (Str.split_delim (Str.regexp (Str.quote "\t")) line) {
|
||||||
|
| [target, _, path, ..._] =>
|
||||||
|
if (dir_exists path) {
|
||||||
|
(target, path)
|
||||||
|
} else {
|
||||||
|
raise (Failure ("path '" ^ path ^ "' is not a valid directory"))
|
||||||
|
}
|
||||||
|
| _ => raise (Failure "malformed input")
|
||||||
|
};
|
||||||
|
let lines = Option.get (Utils.read_file file);
|
||||||
|
try (Ok (IList.map extract_path lines)) {
|
||||||
|
| Failure msg => Error msg
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let find_all_stats_files () => {
|
||||||
|
let accumulate_paths acc paths => {
|
||||||
|
let (f, b, r) = acc;
|
||||||
|
let (f', b', r') = paths;
|
||||||
|
(f @ f', b @ b', r @ r')
|
||||||
|
};
|
||||||
|
let concatenate_paths p1 p2 =>
|
||||||
|
if (Filename.is_relative p2) {
|
||||||
|
Filename.concat p1 p2
|
||||||
|
} else {
|
||||||
|
p2
|
||||||
|
};
|
||||||
|
let infer_out = Config.results_dir;
|
||||||
|
let result =
|
||||||
|
switch Config.buck_out {
|
||||||
|
| Some p =>
|
||||||
|
if (dir_exists p) {
|
||||||
|
let data = load_data_from_infer_deps (
|
||||||
|
Filename.concat infer_out Config.buck_infer_deps_file_name
|
||||||
|
);
|
||||||
|
switch data {
|
||||||
|
| Ok r =>
|
||||||
|
let paths = IList.map (fun (_, path) => path) r;
|
||||||
|
Ok (Filename.concat p Filename.parent_dir_name, paths)
|
||||||
|
| Error _ as e => e
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Error ("buck-out path '" ^ p ^ "' not found")
|
||||||
|
}
|
||||||
|
| None => Ok (infer_out, [infer_out])
|
||||||
|
};
|
||||||
|
switch result {
|
||||||
|
| Ok (base_path, paths_to_explore) =>
|
||||||
|
Ok (
|
||||||
|
IList.fold_left
|
||||||
|
(
|
||||||
|
fun acc path =>
|
||||||
|
accumulate_paths acc (find_stats_files_in_dir (concatenate_paths base_path path))
|
||||||
|
)
|
||||||
|
([], [], [])
|
||||||
|
paths_to_explore
|
||||||
|
)
|
||||||
|
| Error _ as e => e
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let open_json_file file => Yojson.Basic.from_file file;
|
||||||
|
|
||||||
|
let write_to_json_file destfile json => {
|
||||||
|
let stats_oc = open_out destfile;
|
||||||
|
Yojson.Basic.pretty_to_channel stats_oc json;
|
||||||
|
close_out stats_oc
|
||||||
|
};
|
||||||
|
|
||||||
|
let aggregate_stats_to_file paths destfile => {
|
||||||
|
let load_stats paths => IList.map (fun path => PerfStats.from_json (open_json_file path)) paths;
|
||||||
|
let all_perf_stats = load_stats paths;
|
||||||
|
switch all_perf_stats {
|
||||||
|
| [] => Printf.eprintf "No stats to aggregate into %s\n" destfile
|
||||||
|
| _ =>
|
||||||
|
let aggr_stats = PerfStats.aggregate all_perf_stats;
|
||||||
|
write_to_json_file destfile aggr_stats
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let () = {
|
||||||
|
let infer_out = Config.results_dir;
|
||||||
|
let result = find_all_stats_files ();
|
||||||
|
switch result {
|
||||||
|
| Ok (f, b, r) =>
|
||||||
|
let aggregated_frontend_stats_dir = Filename.concat infer_out Config.frontend_stats_dir_name;
|
||||||
|
let aggregated_backend_stats_dir = Filename.concat infer_out Config.backend_stats_dir_name;
|
||||||
|
let aggregated_reporting_stats_dir = Filename.concat infer_out Config.reporting_stats_dir_name;
|
||||||
|
DB.create_dir aggregated_frontend_stats_dir;
|
||||||
|
DB.create_dir aggregated_backend_stats_dir;
|
||||||
|
DB.create_dir aggregated_reporting_stats_dir;
|
||||||
|
aggregate_stats_to_file f (Filename.concat aggregated_frontend_stats_dir filename);
|
||||||
|
aggregate_stats_to_file b (Filename.concat aggregated_backend_stats_dir filename);
|
||||||
|
aggregate_stats_to_file r (Filename.concat aggregated_reporting_stats_dir filename)
|
||||||
|
| Error msg => failwith msg
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* vim: set ft=rust:
|
||||||
|
* vim: set ft=reason:
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
open! Utils;
|
Loading…
Reference in new issue