(* * 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. *) (** Performance Statistics gathering and reporting *) open! Utils type perf_stats = { rtime : float; utime : float; stime : float; cutime : float; cstime : float; minor_gb : float; promoted_gb : float; major_gb : float; allocated_gb : float; minor_collections : int; major_collections : int; compactions : int; top_heap_gb : float; stack_kb : float; minor_heap_kb : float; attributes_table : AttributesTable.t; } let to_json ps = let attributes_table = AttributesTable.stats () in `Assoc [ ("rtime", `Float ps.rtime); ("utime", `Float ps.utime); ("stime", `Float ps.stime); ("cutime", `Float ps.cutime); ("cstime", `Float ps.cstime); ("minor_gb", `Float ps.minor_gb); ("promoted_gb", `Float ps.promoted_gb); ("major_gb", `Float ps.major_gb); ("allocated_gb", `Float ps.allocated_gb); ("minor_collections", `Int ps.minor_collections); ("major_collections", `Int ps.major_collections); ("compactions", `Int ps.compactions); ("top_heap_gb", `Float ps.top_heap_gb); ("stack_kb", `Float ps.stack_kb); ("minor_heap_kb", `Float ps.minor_heap_kb); ("attributes_table", AttributesTable.to_json attributes_table); ] let from_json json = let open Yojson.Basic.Util in { rtime = json |> member "rtime" |> to_float; utime = json |> member "utime" |> to_float; stime = json |> member "stime" |> to_float; cutime = json |> member "cutime" |> to_float; cstime = json |> member "cstime" |> to_float; minor_gb = json |> member "minor_gb" |> to_float; promoted_gb = json |> member "promoted_gb" |> to_float; major_gb = json |> member "major_gb" |> to_float; allocated_gb = json |> member "allocated_gb" |> to_float; minor_collections = json |> member "minor_collections" |> to_int; major_collections = json |> member "major_collections" |> to_int; compactions = json |> member "compactions" |> to_int; top_heap_gb = json |> member "top_heap_gb" |> to_float; stack_kb = json |> member "stack_kb" |> to_float; minor_heap_kb = json |> member "minor_heap_kb" |> to_float; attributes_table = json |> member "attributes_table" |> AttributesTable.from_json; } let aggregate s = let mk_stats f = StatisticsToolbox.compute_statistics (IList.map f s) in let aggr_rtime = mk_stats (fun stats -> stats.rtime) in let aggr_utime = mk_stats (fun stats -> stats.utime) in let aggr_stime = mk_stats (fun stats -> stats.stime) in let aggr_cutime = mk_stats (fun stats -> stats.cutime) in let aggr_cstime = mk_stats (fun stats -> stats.cstime) in let aggr_minor_gb = mk_stats (fun stats -> stats.minor_gb) in let aggr_promoted_gb = mk_stats (fun stats -> stats.promoted_gb) in let aggr_major_gb = mk_stats (fun stats -> stats.major_gb) in let aggr_allocated_gb = mk_stats (fun stats -> stats.allocated_gb) in let aggr_minor_collections = mk_stats (fun stats -> float_of_int stats.minor_collections) in let aggr_major_collections = mk_stats (fun stats -> float_of_int stats.major_collections) in let aggr_compactions = mk_stats (fun stats -> float_of_int stats.compactions) in let aggr_top_heap_gb = mk_stats (fun stats -> stats.top_heap_gb) in let aggr_stack_kb = mk_stats (fun stats -> stats.stack_kb) in let aggr_minor_heap_kb = mk_stats (fun stats -> stats.minor_heap_kb) in let aggr_attributes_table = AttributesTable.aggregate (IList.map (fun stats -> stats.attributes_table) s) in `Assoc [ ("rtime", StatisticsToolbox.to_json aggr_rtime); ("utime", StatisticsToolbox.to_json aggr_utime); ("stime", StatisticsToolbox.to_json aggr_stime); ("cutime", StatisticsToolbox.to_json aggr_cutime); ("cstime", StatisticsToolbox.to_json aggr_cstime); ("minor_gb", StatisticsToolbox.to_json aggr_minor_gb); ("promoted_gb", StatisticsToolbox.to_json aggr_promoted_gb); ("major_gb", StatisticsToolbox.to_json aggr_major_gb); ("allocated_gb", StatisticsToolbox.to_json aggr_allocated_gb); ("minor_collections", StatisticsToolbox.to_json aggr_minor_collections); ("major_collections", StatisticsToolbox.to_json aggr_major_collections); ("compactions", StatisticsToolbox.to_json aggr_compactions); ("top_heap_gb", StatisticsToolbox.to_json aggr_top_heap_gb); ("stack_kb", StatisticsToolbox.to_json aggr_stack_kb); ("minor_heap_kb", StatisticsToolbox.to_json aggr_minor_heap_kb); ("attributes_table", aggr_attributes_table); ] let stats () = let words_to_kb n = n *. float_of_int (Sys.word_size / 8) /. 1024. in let words_to_mb n = words_to_kb n /. 1024. in let words_to_gb n = words_to_mb n /. 1024. in let gc_stats = Gc.quick_stat () in let allocated_words = gc_stats.minor_words +. gc_stats.major_words -. gc_stats.promoted_words in let gc_ctrl = Gc.get () in let exit_timeofday = Unix.gettimeofday () in let exit_times = Unix.times () in let at = AttributesTable.stats () in { rtime = exit_timeofday -. initial_timeofday; utime = exit_times.tms_utime -. initial_times.tms_utime; stime = exit_times.tms_stime -. initial_times.tms_stime; cutime = exit_times.tms_cutime -. initial_times.tms_cutime; cstime = exit_times.tms_cstime -. initial_times.tms_cstime; minor_gb = words_to_gb gc_stats.minor_words; promoted_gb = words_to_gb gc_stats.promoted_words; major_gb = words_to_gb gc_stats.major_words; allocated_gb = words_to_gb allocated_words; minor_collections = gc_stats.minor_collections; major_collections = gc_stats.major_collections; compactions = gc_stats.compactions; top_heap_gb = words_to_gb (float_of_int gc_stats.top_heap_words); stack_kb = words_to_kb (float_of_int gc_stats.stack_size); minor_heap_kb = words_to_kb (float_of_int gc_ctrl.minor_heap_size); attributes_table = at } let register_report_at_exit file = Pervasives.at_exit (fun () -> try let json_stats = to_json (stats ()) in try let stats_oc = open_out file in Yojson.Basic.pretty_to_channel stats_oc json_stats ; close_out stats_oc with exc -> Format.eprintf "Info: failed to write stats to %s@\n%s@\n%s@\n%s@." file (Printexc.to_string exc) (Yojson.Basic.pretty_to_string json_stats) (Printexc.get_backtrace ()) with exc -> Format.eprintf "Info: failed to compute stats for %s@\n%s@\n%s@." file (Printexc.to_string exc) (Printexc.get_backtrace ()) )