[cost] Add version to BasicCost.t

Summary: It adds version to BasicCost.t.

Reviewed By: ezgicicek

Differential Revision: D17069691

fbshipit-source-id: e232432bd
master
Sungkeun Cho 5 years ago committed by Facebook Github Bot
parent ddaf51713e
commit 4351ba9bd1

@ -63,7 +63,9 @@ type hum_info = {
type cost_info = { type cost_info = {
polynomial_version : int;
polynomial : string; polynomial : string;
?degree : int option;
hum : hum_info; hum : hum_info;
} }

@ -54,7 +54,7 @@ let dedup (issues : Jsonbug_t.jsonbug list) =
module CostsSummary = struct module CostsSummary = struct
module DegreeMap = Caml.Map.Make (Polynomials.Degree) module DegreeMap = Caml.Map.Make (Int)
type 'a count = {top: 'a; zero: 'a; degrees: 'a DegreeMap.t} type 'a count = {top: 'a; zero: 'a; degrees: 'a DegreeMap.t}
@ -63,6 +63,7 @@ module CostsSummary = struct
type previous_current = {previous: int; current: int} type previous_current = {previous: int; current: int}
let count costs = let count costs =
let incr = function None -> Some 1 | Some x -> Some (x + 1) in
let count_aux t (e : CostDomain.BasicCost.t) = let count_aux t (e : CostDomain.BasicCost.t) =
match CostDomain.BasicCost.degree e with match CostDomain.BasicCost.degree e with
| None -> | None ->
@ -72,16 +73,27 @@ module CostsSummary = struct
assert (Polynomials.Degree.is_zero d) ; assert (Polynomials.Degree.is_zero d) ;
{t with zero= t.zero + 1} {t with zero= t.zero + 1}
| Some d -> | Some d ->
let degrees = let degrees = DegreeMap.update (Polynomials.Degree.encode_to_int d) incr t.degrees in
DegreeMap.update d (function None -> Some 1 | Some x -> Some (x + 1)) t.degrees {t with degrees}
in in
let count_aux_degree t (degree : int option) =
match degree with
| None ->
{t with top= t.top + 1}
| Some d when Int.equal d 0 ->
{t with zero= t.zero + 1}
| Some d ->
let degrees = DegreeMap.update d incr t.degrees in
{t with degrees} {t with degrees}
in in
List.fold ~init List.fold ~init
~f:(fun acc (v : Jsonbug_t.cost_item) -> ~f:(fun acc (v : Jsonbug_t.cost_item) ->
CostIssues.CostKindMap.fold CostIssues.CostKindMap.fold
(fun _ CostIssues.{extract_cost_f} acc -> (fun _ CostIssues.{extract_cost_f} acc ->
count_aux acc (CostDomain.BasicCost.decode (extract_cost_f v).Jsonbug_t.polynomial) ) let {Jsonbug_t.polynomial_version; polynomial; degree} = extract_cost_f v in
if Int.equal polynomial_version CostDomain.BasicCost.version then
count_aux acc (CostDomain.BasicCost.decode polynomial)
else count_aux_degree acc degree )
CostIssues.enabled_cost_map acc ) CostIssues.enabled_cost_map acc )
costs costs
@ -113,10 +125,8 @@ module CostsSummary = struct
let json_degrees = let json_degrees =
DegreeMap.bindings paired_counts.degrees DegreeMap.bindings paired_counts.degrees
|> List.map ~f:(fun (key, {current; previous}) -> |> List.map ~f:(fun (key, {current; previous}) ->
`Assoc `Assoc [("degree", `Int key); ("current", `Int current); ("previous", `Int previous)]
[ ("degree", `Int (Polynomials.Degree.encode_to_int key)) )
; ("current", `Int current)
; ("previous", `Int previous) ] )
in in
let create_assoc current previous = let create_assoc current previous =
`Assoc [("current", `Int current); ("previous", `Int previous)] `Assoc [("current", `Int current); ("previous", `Int previous)]
@ -139,8 +149,66 @@ let to_map key_func report =
~init:String.Map.empty report ~init:String.Map.empty report
let issue_of_cost kind CostIssues.{complexity_increase_issue; zero_issue; infinite_issue} cost_info module CostItem = struct
~delta ~prev_cost ~curr_cost = type t =
{ cost_item: Jsonbug_t.cost_item
; polynomial: Polynomials.NonNegativePolynomial.t option
; degree_with_term: Polynomials.NonNegativePolynomial.degree_with_term option
; degree: int option }
let lift ~f_poly ~f_deg {polynomial; degree} =
match polynomial with None -> f_deg degree | Some p -> f_poly p
let is_top = lift ~f_poly:CostDomain.BasicCost.is_top ~f_deg:Option.is_none
(* NOTE: incorrect when using [f_deg] *)
let is_zero = lift ~f_poly:CostDomain.BasicCost.is_zero ~f_deg:(fun _ -> false)
(* NOTE: incorrect when using [f_deg] *)
let is_one = lift ~f_poly:CostDomain.BasicCost.is_one ~f_deg:(fun _ -> false)
let compare_by_degree {polynomial= p1; degree= d1} {polynomial= p2; degree= d2} =
match (p1, p2) with
| Some p1, Some p2 ->
CostDomain.BasicCost.compare_by_degree p1 p2
| _, _ -> (
match (d1, d2) with
| None, None ->
0
| None, Some _ ->
1
| Some _, None ->
-1
| Some d1, Some d2 ->
d1 - d2 )
let pp_degree ~only_bigO fmt {degree_with_term; degree} =
match (degree_with_term, degree) with
| None, None ->
Format.pp_print_string fmt "Top"
| None, Some d ->
Format.pp_print_int fmt d
| Some degree_with_term, _ ->
CostDomain.BasicCost.pp_degree ~only_bigO fmt degree_with_term
let pp_cost_msg fmt ({polynomial} as curr_item) =
let pp_cost fmt =
match polynomial with
| None ->
Format.fprintf fmt "NA"
| Some p ->
CostDomain.BasicCost.pp_hum fmt p
in
Format.fprintf fmt "Cost is %t (degree is %a)" pp_cost (pp_degree ~only_bigO:false) curr_item
end
let issue_of_cost kind CostIssues.{complexity_increase_issue; zero_issue; infinite_issue} ~delta
~prev_item
~curr_item:( {CostItem.cost_item= cost_info; degree_with_term= curr_degree_with_term} as
curr_item ) =
let file = cost_info.Jsonbug_t.loc.file in let file = cost_info.Jsonbug_t.loc.file in
let method_name = cost_info.Jsonbug_t.procedure_name in let method_name = cost_info.Jsonbug_t.procedure_name in
let class_name = let class_name =
@ -153,18 +221,12 @@ let issue_of_cost kind CostIssues.{complexity_increase_issue; zero_issue; infini
let procname = ExternalPerfData.make_void_signature_procname class_name method_name in let procname = ExternalPerfData.make_void_signature_procname class_name method_name in
let source_file = SourceFile.create ~warn_on_error:false file in let source_file = SourceFile.create ~warn_on_error:false file in
let issue_type = let issue_type =
if CostDomain.BasicCost.is_top curr_cost then infinite_issue if CostItem.is_top curr_item then infinite_issue
else if CostDomain.BasicCost.is_zero curr_cost then zero_issue else if CostItem.is_zero curr_item then zero_issue
else else
let is_on_cold_start = ExternalPerfData.in_profiler_data_map procname in let is_on_cold_start = ExternalPerfData.in_profiler_data_map procname in
complexity_increase_issue ~is_on_cold_start complexity_increase_issue ~is_on_cold_start
in in
let curr_degree_with_term = CostDomain.BasicCost.get_degree_with_term curr_cost in
let curr_cost_msg fmt () =
Format.fprintf fmt "Cost is %a (degree is %a)" CostDomain.BasicCost.pp_hum curr_cost
(CostDomain.BasicCost.pp_degree ~only_bigO:false)
curr_degree_with_term
in
if (not Config.filtering) || issue_type.IssueType.enabled then if (not Config.filtering) || issue_type.IssueType.enabled then
let qualifier = let qualifier =
let pp_delta fmt delta = let pp_delta fmt delta =
@ -175,7 +237,7 @@ let issue_of_cost kind CostIssues.{complexity_increase_issue; zero_issue; infini
Format.fprintf fmt "increased" Format.fprintf fmt "increased"
in in
let pp_extra_msg fmt () = let pp_extra_msg fmt () =
if Config.developer_mode then curr_cost_msg fmt () if Config.developer_mode then CostItem.pp_cost_msg fmt curr_item
else else
Format.fprintf fmt Format.fprintf fmt
"Please make sure this is an expected change. You can inspect the trace to understand \ "Please make sure this is an expected change. You can inspect the trace to understand \
@ -187,7 +249,6 @@ let issue_of_cost kind CostIssues.{complexity_increase_issue; zero_issue; infini
regressions in this phase." regressions in this phase."
else "" else ""
in in
let prev_degree_with_term = CostDomain.BasicCost.get_degree_with_term prev_cost in
let msg = let msg =
(* Java Only *) (* Java Only *)
if String.equal method_name Typ.Procname.Java.constructor_method_name then "constructor" if String.equal method_name Typ.Procname.Java.constructor_method_name then "constructor"
@ -200,26 +261,28 @@ let issue_of_cost kind CostIssues.{complexity_increase_issue; zero_issue; infini
msg msg
(MarkupFormatter.wrap_bold pp_delta) (MarkupFormatter.wrap_bold pp_delta)
delta delta
(MarkupFormatter.wrap_monospaced (CostDomain.BasicCost.pp_degree ~only_bigO:true)) (MarkupFormatter.wrap_monospaced (CostItem.pp_degree ~only_bigO:true))
prev_degree_with_term prev_item
(MarkupFormatter.wrap_monospaced (CostDomain.BasicCost.pp_degree ~only_bigO:true)) (MarkupFormatter.wrap_monospaced (CostItem.pp_degree ~only_bigO:true))
curr_degree_with_term cold_start_msg pp_extra_msg () curr_item cold_start_msg pp_extra_msg ()
in in
let line = cost_info.Jsonbug_t.loc.lnum in let line = cost_info.Jsonbug_t.loc.lnum in
let column = cost_info.Jsonbug_t.loc.cnum in let column = cost_info.Jsonbug_t.loc.cnum in
let trace = let trace =
let polynomial_traces = let polynomial_traces =
match curr_degree_with_term with match curr_degree_with_term with
| Below (_, degree_term) -> | None ->
[]
| Some (Below (_, degree_term)) ->
Polynomials.NonNegativeNonTopPolynomial.get_symbols degree_term Polynomials.NonNegativeNonTopPolynomial.get_symbols degree_term
|> List.map ~f:Bounds.NonNegativeBound.make_err_trace |> List.map ~f:Bounds.NonNegativeBound.make_err_trace
| Above traces -> | Some (Above traces) ->
[("", Polynomials.TopTraces.make_err_trace traces)] [("", Polynomials.TopTraces.make_err_trace traces)]
in in
let curr_cost_trace = let curr_cost_trace =
[ Errlog.make_trace_element 0 [ Errlog.make_trace_element 0
{Location.line; col= column; file= source_file} {Location.line; col= column; file= source_file}
(Format.asprintf "Updated %a" curr_cost_msg ()) (Format.asprintf "Updated %a" CostItem.pp_cost_msg curr_item)
[] ] [] ]
in in
("", curr_cost_trace) :: polynomial_traces |> Errlog.concat_traces ("", curr_cost_trace) :: polynomial_traces |> Errlog.concat_traces
@ -260,34 +323,28 @@ let of_costs ~(current_costs : Jsonbug_t.costs_report) ~(previous_costs : Jsonbu
match data with match data with
| `Both (current, previous) -> | `Both (current, previous) ->
let max_degree_polynomial l = let max_degree_polynomial l =
let max = let max = List.max_elt l ~compare:CostItem.compare_by_degree in
List.max_elt l ~compare:(fun (_, c1) (_, c2) ->
CostDomain.BasicCost.compare_by_degree c1 c2 )
in
Option.value_exn max Option.value_exn max
in in
let curr_cost_info, curr_cost = max_degree_polynomial current in let curr_item = max_degree_polynomial current in
let _, prev_cost = max_degree_polynomial previous in let prev_item = max_degree_polynomial previous in
if if Config.filtering && (CostItem.is_one curr_item || CostItem.is_one prev_item) then
Config.filtering
&& (CostDomain.BasicCost.is_one curr_cost || CostDomain.BasicCost.is_one prev_cost)
then
(* transitions to/from zero costs are obvious, no need to flag them *) (* transitions to/from zero costs are obvious, no need to flag them *)
(left, both, right) (left, both, right)
else else
let cmp = CostDomain.BasicCost.compare_by_degree curr_cost prev_cost in let cmp = CostItem.compare_by_degree curr_item prev_item in
let concat_opt l v = match v with Some v' -> v' :: l | None -> l in let concat_opt l v = match v with Some v' -> v' :: l | None -> l in
if cmp > 0 then if cmp > 0 then
(* introduced *) (* introduced *)
let left' = let left' =
issue_of_cost kind issue_spec curr_cost_info ~delta:`Increased ~prev_cost ~curr_cost issue_of_cost kind issue_spec ~delta:`Increased ~prev_item ~curr_item
|> concat_opt left |> concat_opt left
in in
(left', both, right) (left', both, right)
else if cmp < 0 then else if cmp < 0 then
(* fixed *) (* fixed *)
let right' = let right' =
issue_of_cost kind issue_spec curr_cost_info ~delta:`Decreased ~prev_cost ~curr_cost issue_of_cost kind issue_spec ~delta:`Decreased ~prev_item ~curr_item
|> concat_opt right |> concat_opt right
in in
(left, both, right') (left, both, right')
@ -298,11 +355,20 @@ let of_costs ~(current_costs : Jsonbug_t.costs_report) ~(previous_costs : Jsonbu
(* costs available only on one of the two reports are discarded, since no comparison can be made *) (* costs available only on one of the two reports are discarded, since no comparison can be made *)
(left, both, right) (left, both, right)
in in
let key_func (cost_info, _) = cost_info.Jsonbug_t.hash in let key_func {CostItem.cost_item} = cost_item.Jsonbug_t.hash in
let to_map = to_map key_func in let to_map = to_map key_func in
let decoded_costs costs ~extract_cost_f = let decoded_costs costs ~extract_cost_f =
List.map costs ~f:(fun c -> List.map costs ~f:(fun c ->
(c, CostDomain.BasicCost.decode (extract_cost_f c).Jsonbug_t.polynomial) ) let cost_info = extract_cost_f c in
let polynomial, degree_with_term =
if Int.equal cost_info.Jsonbug_t.polynomial_version CostDomain.BasicCost.version then
let polynomial = CostDomain.BasicCost.decode cost_info.Jsonbug_t.polynomial in
let degree_with_term = CostDomain.BasicCost.get_degree_with_term polynomial in
(Some polynomial, Some degree_with_term)
else (None, None)
in
let degree = cost_info.Jsonbug_t.degree in
{CostItem.cost_item= c; polynomial; degree_with_term; degree} )
in in
let get_current_costs = decoded_costs current_costs in let get_current_costs = decoded_costs current_costs in
let get_previous_costs = decoded_costs previous_costs in let get_previous_costs = decoded_costs previous_costs in

@ -337,7 +337,11 @@ module JsonCostsPrinter = MakeJsonListPrinter (struct
degree_with_term } degree_with_term }
in in
let cost_info cost = let cost_info cost =
{Jsonbug_t.polynomial= CostDomain.BasicCost.encode cost; hum= hum cost} { Jsonbug_t.polynomial_version= CostDomain.BasicCost.version
; polynomial= CostDomain.BasicCost.encode cost
; degree=
Option.map (CostDomain.BasicCost.degree cost) ~f:Polynomials.Degree.encode_to_int
; hum= hum cost }
in in
let cost_item = let cost_item =
let file = SourceFile.to_rel_path loc.Location.file in let file = SourceFile.to_rel_path loc.Location.file in

@ -7,7 +7,14 @@
open! IStd open! IStd
module F = Format module F = Format
module BasicCost = Polynomials.NonNegativePolynomial
module BasicCost = struct
include Polynomials.NonNegativePolynomial
(* NOTE: Increment the version number if you changed the [t] type. This is for avoiding
demarshalling failure of cost analysis results in running infer-reportdiff. *)
let version = 1
end
(** (**
Module to simulate a record Module to simulate a record

Loading…
Cancel
Save