[inferbo,cost] Add cost models for java.util.Collections

Reviewed By: mbouaziz

Differential Revision: D15080211

fbshipit-source-id: 91c9b6dba
master
Ezgi Çiçek 6 years ago committed by Facebook Github Bot
parent 0414024314
commit c85563d606

@ -58,6 +58,8 @@ let implements_iterator = implements "java.util.Iterator"
let implements_collection = implements "java.util.Collection" let implements_collection = implements "java.util.Collection"
let implements_collections = implements "java.util.Collections"
let implements_list = implements "java.util.List" let implements_list = implements "java.util.List"
let implements_pseudo_collection t s = let implements_pseudo_collection t s =

@ -36,6 +36,9 @@ val implements_iterator : Tenv.t -> string -> bool
val implements_collection : Tenv.t -> string -> bool val implements_collection : Tenv.t -> string -> bool
(** Check whether class implements a Java's Collection *) (** Check whether class implements a Java's Collection *)
val implements_collections : Tenv.t -> string -> bool
(** Check whether class implements a Java's Collections *)
val implements_pseudo_collection : Tenv.t -> string -> bool val implements_pseudo_collection : Tenv.t -> string -> bool
(** Check whether class implements a pseudo Collection with support (** Check whether class implements a pseudo Collection with support
for get() and size() methods *) for get() and size() methods *)

@ -664,6 +664,15 @@ module Collection = struct
let add coll_id = {exec= change_size_by ~size_f:Itv.incr coll_id; check= no_check} let add coll_id = {exec= change_size_by ~size_f:Itv.incr coll_id; check= no_check}
let singleton_collection el_var =
let exec env ~ret:((id, _) as ret) mem =
let {exec= new_exec; check= _} = new_collection el_var in
let mem = new_exec env ~ret mem in
change_size_by ~size_f:Itv.incr id ~ret env mem
in
{exec; check= no_check}
(** increase the size by [0, 1] because put replaces the value (** increase the size by [0, 1] because put replaces the value
rather than add a new one when the key is found in the map *) rather than add a new one when the key is found in the map *)
let put coll_id = let put coll_id =
@ -877,6 +886,16 @@ module Call = struct
; -"std" &:: "basic_string" &::.*--> no_model ; -"std" &:: "basic_string" &::.*--> no_model
; +PatternMatch.implements_collection ; +PatternMatch.implements_collection
&:: "<init>" <>$ capt_var_exn $+ capt_exp $--> Collection.init &:: "<init>" <>$ capt_var_exn $+ capt_exp $--> Collection.init
(* model sets as lists *)
; +PatternMatch.implements_collections
&:: "singleton" <>$ capt_exp $--> Collection.singleton_collection
; +PatternMatch.implements_collections
&:: "emptySet" <>$ capt_exp $--> Collection.new_collection
(* model maps as lists *)
; +PatternMatch.implements_collections
&:: "singletonMap" <>$ capt_exp $--> Collection.singleton_collection
; +PatternMatch.implements_collections
&:: "singletonList" <>$ capt_exp $--> Collection.singleton_collection
; +PatternMatch.implements_collection ; +PatternMatch.implements_collection
&:: "get" <>$ capt_var_exn $+ capt_exp $--> Collection.get_or_set_at_index &:: "get" <>$ capt_var_exn $+ capt_exp $--> Collection.get_or_set_at_index
; +PatternMatch.implements_collection ; +PatternMatch.implements_collection

@ -34,9 +34,14 @@ module Collections = struct
n_log_n length n_log_n length
let linear coll_exp {location} ~ret:_ inferbo_mem = let of_length_bound ~degree_kind coll_exp ~of_function {location} ~ret:_ inferbo_mem =
eval_collection_length coll_exp location ~of_function:"List.contains" inferbo_mem eval_collection_length coll_exp location inferbo_mem ~of_function
|> BasicCost.of_non_negative_bound |> BasicCost.of_non_negative_bound ~degree_kind
let linear = of_length_bound ~degree_kind:Polynomials.DegreeKind.Linear
let logarithmic = of_length_bound ~degree_kind:Polynomials.DegreeKind.Log
end end
let provider_get {pname; location} ~ret:(_, ret_typ) _ : BasicCost.t = let provider_get {pname; location} ~ret:(_, ret_typ) _ : BasicCost.t =
@ -83,8 +88,24 @@ module Call = struct
let dispatch : (Tenv.t, model) ProcnameDispatcher.Call.dispatcher = let dispatch : (Tenv.t, model) ProcnameDispatcher.Call.dispatcher =
let open ProcnameDispatcher.Call in let open ProcnameDispatcher.Call in
make_dispatcher make_dispatcher
[ -"java.util.Collections" &:: "sort" $ capt_exp $--> Collections.sort [ +PatternMatch.implements_collections &:: "sort" $ capt_exp $--> Collections.sort
; +PatternMatch.implements_list &:: "contains" <>$ capt_exp $+...$--> Collections.linear ; +PatternMatch.implements_list &:: "contains" <>$ capt_exp
$+...$--> Collections.linear ~of_function:"List.contains"
; +PatternMatch.implements_collections
&:: "binarySearch" <>$ capt_exp
$+...$--> Collections.logarithmic ~of_function:"Collections.binarySearch"
; +PatternMatch.implements_collections
&:: "copy" <>$ capt_exp
$+...$--> Collections.linear ~of_function:"Collections.copy"
; +PatternMatch.implements_collections
&:: "fill" <>$ capt_exp
$+...$--> Collections.linear ~of_function:"Collections.fill"
; +PatternMatch.implements_collections
&:: "reverse" <>$ capt_exp
$+...$--> Collections.linear ~of_function:"Collections.reverse"
; +PatternMatch.implements_collections
&:: "shuffle" <>$ capt_exp
$+...$--> Collections.linear ~of_function:"Collections.shuffle"
; +PatternMatch.implements_lang "String" ; +PatternMatch.implements_lang "String"
&:: "substring" <>$ capt_exp $+ capt_exp $--> String.substring &:: "substring" <>$ capt_exp $+ capt_exp $--> String.substring
; +PatternMatch.implements_lang "String" ; +PatternMatch.implements_lang "String"

@ -251,4 +251,5 @@ public class ArrayListTest {
// l.length // l.length
for (int i = 0; i < slist.size(); i++) {} for (int i = 0; i < slist.size(); i++) {}
} }
} }

@ -0,0 +1,49 @@
/*
* Copyright (c) 2019-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.
*/
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.Set;
class CollectionsTest {
int binary_search_log(List<String> list) {
return Collections.binarySearch(list, "x");
}
void shuffle_linear(List<String> list, Random mRandom) {
Collections.shuffle(list, mRandom);
for (int i = 0; i < list.size(); i++) {}
}
void singletonSet_constant() {
Set<String> set = Collections.singleton("ezgi");
for (String s : set) {}
}
void singletonList_constant(String el) {
List<String> list = Collections.singletonList(el);
for (String s : list) {}
}
void fill_linear(List<String> list, String el) {
Collections.fill(list, el);
}
void reverse_linear(List<String> list) {
Collections.reverse(list);
}
void reverse_constant(String el) {
List<String> list = Collections.singletonList(el);
Collections.reverse(list);
}
void copy_linear(List<String> list_from, List<String> list_to) {
Collections.copy(list_to, list_from);
}
}

@ -51,6 +51,13 @@ codetoanalyze/java/performance/CollectionTest.java, CollectionTest.iterate_over_
codetoanalyze/java/performance/CollectionTest.java, CollectionTest.loop_over_call(int,CollectionTest$MyCollection):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 2 + 15 ⋅ size + 5 ⋅ size × list.length, degree = 2,{list.length},call to void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection),Loop at line 17,{size},Loop at line 41] codetoanalyze/java/performance/CollectionTest.java, CollectionTest.loop_over_call(int,CollectionTest$MyCollection):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 2 + 15 ⋅ size + 5 ⋅ size × list.length, degree = 2,{list.length},call to void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection),Loop at line 17,{size},Loop at line 41]
codetoanalyze/java/performance/CollectionTest.java, CollectionTest.nested_iterator_qubic(int,CollectionTest$MyCollection,CollectionTest$MyCollection):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 4 + 13 ⋅ (list1.length - 1) + 28 ⋅ (list1.length - 1) × (list2.length - 1) + 5 ⋅ (list1.length - 1) × (list2.length - 1) × list1.length + 5 ⋅ (list1.length - 1) × (list2.length - 1) × list1.length + 3 ⋅ (list1.length - 1) × list2.length + 3 ⋅ list1.length, degree = 3,{list1.length},Loop at line 55,{list2.length},Loop at line 56,{list1.length},call to void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection),Loop at line 17,{list1.length},call to void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection),Loop at line 17,{list2.length - 1},Loop at line 56,{list1.length - 1},Loop at line 55] codetoanalyze/java/performance/CollectionTest.java, CollectionTest.nested_iterator_qubic(int,CollectionTest$MyCollection,CollectionTest$MyCollection):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 4 + 13 ⋅ (list1.length - 1) + 28 ⋅ (list1.length - 1) × (list2.length - 1) + 5 ⋅ (list1.length - 1) × (list2.length - 1) × list1.length + 5 ⋅ (list1.length - 1) × (list2.length - 1) × list1.length + 3 ⋅ (list1.length - 1) × list2.length + 3 ⋅ list1.length, degree = 3,{list1.length},Loop at line 55,{list2.length},Loop at line 56,{list1.length},call to void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection),Loop at line 17,{list1.length},call to void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection),Loop at line 17,{list2.length - 1},Loop at line 56,{list1.length - 1},Loop at line 55]
codetoanalyze/java/performance/CollectionTest.java, CollectionTest.sparse_array_linear(android.util.SparseArray):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 2 + 5 ⋅ arr.length + 3 ⋅ (arr.length + 1), degree = 1,{arr.length + 1},Loop at line 64,{arr.length},Loop at line 64] codetoanalyze/java/performance/CollectionTest.java, CollectionTest.sparse_array_linear(android.util.SparseArray):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 2 + 5 ⋅ arr.length + 3 ⋅ (arr.length + 1), degree = 1,{arr.length + 1},Loop at line 64,{arr.length},Loop at line 64]
codetoanalyze/java/performance/CollectionsTest.java, CollectionsTest.binary_search_log(java.util.List):int, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 2 + log(list.length), degree = 0 + 1⋅log,{list.length},Modeled call to Collections.binarySearch]
codetoanalyze/java/performance/CollectionsTest.java, CollectionsTest.copy_linear(java.util.List,java.util.List):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 3 + list_to.length, degree = 1,{list_to.length},Modeled call to Collections.copy]
codetoanalyze/java/performance/CollectionsTest.java, CollectionsTest.fill_linear(java.util.List,java.lang.String):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 3 + list.length, degree = 1,{list.length},Modeled call to Collections.fill]
codetoanalyze/java/performance/CollectionsTest.java, CollectionsTest.reverse_linear(java.util.List):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 2 + list.length, degree = 1,{list.length},Modeled call to Collections.reverse]
codetoanalyze/java/performance/CollectionsTest.java, CollectionsTest.shuffle_linear(java.util.List,java.util.Random):void, 1, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 3 + list.length, degree = 1,{list.length},Modeled call to Collections.shuffle]
codetoanalyze/java/performance/CollectionsTest.java, CollectionsTest.singletonList_constant(java.lang.String):void, 2, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here]
codetoanalyze/java/performance/CollectionsTest.java, CollectionsTest.singletonSet_constant():void, 2, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here]
codetoanalyze/java/performance/Compound_loop.java, codetoanalyze.java.performance.Compound_loop.compound_while(int):int, 3, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [Here] codetoanalyze/java/performance/Compound_loop.java, codetoanalyze.java.performance.Compound_loop.compound_while(int):int, 3, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [Here]
codetoanalyze/java/performance/Compound_loop.java, codetoanalyze.java.performance.Compound_loop.compound_while(int):int, 3, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 4 + 5 ⋅ m + 2 ⋅ (1+max(0, m)), degree = 1,{1+max(0, m)},Loop at line 15,{m},Loop at line 15] codetoanalyze/java/performance/Compound_loop.java, codetoanalyze.java.performance.Compound_loop.compound_while(int):int, 3, EXPENSIVE_EXECUTION_CALL, no_bucket, ERROR, [with estimated cost 4 + 5 ⋅ m + 2 ⋅ (1+max(0, m)), degree = 1,{1+max(0, m)},Loop at line 15,{m},Loop at line 15]
codetoanalyze/java/performance/Compound_loop.java, codetoanalyze.java.performance.Compound_loop.nested_while_and_or(int):int, 3, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [Here] codetoanalyze/java/performance/Compound_loop.java, codetoanalyze.java.performance.Compound_loop.nested_while_and_or(int):int, 3, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [Here]

Loading…
Cancel
Save