Automatically infer the @PerformanceCritical annotations from the overriden methods

Summary: public
This allows to run the checker and get feedback about potential expensive call stacks without having to annotate first all the methods that are overriding PerofrmanceCritical-annotated methods

Reviewed By: cristianoc

Differential Revision: D2693556

fb-gh-sync-id: cb60278
master
jrm 9 years ago committed by facebook-github-bot-5
parent dcdebbd811
commit d712635feb

@ -8,6 +8,19 @@
*) *)
module F = Format
type t = type t =
| Direct of Procname.t | Direct of Procname.t
| Indirect of Procname.t * t list | Indirect of Procname.t * t list
let pp fmt tree =
let rec loop stack = function
| Direct pname ->
F.fprintf fmt "%s -> %s" stack (Procname.to_string pname)
| Indirect (pname, l) ->
let stack' = stack ^ " -> " ^ (Procname.to_string pname) in
IList.iter (loop stack') l in
loop "@" tree

@ -11,3 +11,6 @@
type t = type t =
| Direct of Procname.t | Direct of Procname.t
| Indirect of Procname.t * t list | Indirect of Procname.t * t list
(** print the list of call stacks in the tree *)
val pp : Format.formatter -> t -> unit

@ -10,6 +10,9 @@
module L = Logging module L = Logging
let infer_performance_critical_methods = true
let calls_expensive_method = let calls_expensive_method =
"CHECKERS_CALLS_EXPENSIVE_METHOD" "CHECKERS_CALLS_EXPENSIVE_METHOD"
@ -45,6 +48,17 @@ let method_is_performance_critical pname =
check_method Annotations.ia_is_performance_critical pname check_method Annotations.ia_is_performance_critical pname
let method_overrides_performance_critical tenv pname =
let overrides () =
let found = ref false in
PatternMatch.proc_iter_overridden_methods
(fun pn -> found := method_is_performance_critical pn)
tenv pname;
!found in
method_is_performance_critical pname
|| overrides ()
let method_is_expensive pname = let method_is_expensive pname =
check_method Annotations.ia_is_expensive pname check_method Annotations.ia_is_expensive pname
@ -152,12 +166,17 @@ let check_one_procedure tenv pname pdesc =
let checked_pnames = ref Procname.Set.empty in let checked_pnames = ref Procname.Set.empty in
Cfg.Procdesc.fold_calls Cfg.Procdesc.fold_calls
(collect_expensive_call pdesc checked_pnames) [] pdesc in (collect_expensive_call pdesc checked_pnames) [] pdesc in
update_summary expensive_call_trees pname;
match expensive_call_trees with match expensive_call_trees with
| [] -> () | [] -> ()
| call_trees when infer_performance_critical_methods ->
if method_overrides_performance_critical tenv pname then
report_expensive_calls pname pdesc loc call_trees
| call_trees when performance_critical -> | call_trees when performance_critical ->
report_expensive_calls pname pdesc loc call_trees report_expensive_calls pname pdesc loc call_trees
| call_trees -> | _ -> ()
update_summary call_trees pname
let callback_performance_checker _ get_proc_desc _ tenv pname proc_desc = let callback_performance_checker _ get_proc_desc _ tenv pname proc_desc =

@ -12,15 +12,29 @@ package codetoanalyze.java.checkers;
import com.facebook.infer.annotation.Expensive; import com.facebook.infer.annotation.Expensive;
import com.facebook.infer.annotation.PerformanceCritical; import com.facebook.infer.annotation.PerformanceCritical;
class Other {
@Expensive
void expensive() {
}
void callsExpensive1() {
expensive();
}
}
public class ExpensiveCallExample { public class ExpensiveCallExample {
Object mObject; Other mOther;
void nonExpensiveMethod() {} void nonExpensiveMethod() {}
@Expensive @Expensive
void expensiveMethod() { void expensiveMethod() {
mObject = new Object(); mOther = new Other();
} }
void methodWrapper() { void methodWrapper() {
@ -47,4 +61,13 @@ public class ExpensiveCallExample {
object.m5(); object.m5();
} }
void callsExpensive2() {
mOther.callsExpensive1();
}
@PerformanceCritical
void longerCallStackToExpensive() {
callsExpensive2();
}
} }

@ -33,7 +33,7 @@ public class ExpensiveCallTest {
@BeforeClass @BeforeClass
public static void loadResults() throws InterruptedException, IOException { public static void loadResults() throws InterruptedException, IOException {
inferResults = inferResults =
InferResults.loadCheckersResults(ImmutableCastTest.class, SOURCE_FILE); InferResults.loadCheckersResults(ExpensiveCallTest.class, SOURCE_FILE);
} }
@Test @Test
@ -43,6 +43,7 @@ public class ExpensiveCallTest {
"directlyCallingExpensiveMethod", "directlyCallingExpensiveMethod",
"indirectlyCallingExpensiveMethod", "indirectlyCallingExpensiveMethod",
"callingExpensiveMethodFromInterface", "callingExpensiveMethodFromInterface",
"longerCallStackToExpensive",
}; };
assertThat( assertThat(
"Results should contain " + CALLS_EXPENSIVE_METHOD, "Results should contain " + CALLS_EXPENSIVE_METHOD,

Loading…
Cancel
Save