@ -23,7 +23,7 @@ end)
(* We use this treshold to give error if the cost is above it.
Currently it's set randomly to 200 . * )
let expensive_threshold = Itv . Bound. of_int 200
let expensive_threshold = Itv . NonNegative Bound. of_int _exn 200
(* CFG modules used in several other modules *)
module InstrCFG = ProcCfg . NormalOneInstrPerNode
@ -49,20 +49,20 @@ module TransferFunctionsNodesBasicCost = struct
type extras = BufferOverrunChecker . invariant_map
let cost_atomic_instruction = Itv . Bound. one
let cost_atomic_instruction = Itv . NonNegative Bound. one
let instantiate_cost ~ tenv ~ caller_pdesc ~ inferbo_caller_mem ~ callee_pname ~ params ~ callee_cost =
match Ondemand . get_proc_desc callee_pname with
| None ->
L . ( die InternalError )
" Can't instantiate symbolic cost %a from call to %a (can't get procdesc) " Itv . Bound . pp
callee_cost Typ . Procname . pp callee_pname
" Can't instantiate symbolic cost %a from call to %a (can't get procdesc) "
Itv . NonNegativeBound . pp callee_cost Typ . Procname . pp callee_pname
| Some callee_pdesc ->
match BufferOverrunChecker . Summary . read_summary caller_pdesc callee_pname with
| None ->
L . ( die InternalError )
" Can't instantiate symbolic cost %a from call to %a (can't get summary) " Itv . Bound . pp
callee_cost Typ . Procname . pp callee_pname
" Can't instantiate symbolic cost %a from call to %a (can't get summary) "
Itv . NonNegativeBound . pp callee_cost Typ . Procname . pp callee_pname
| Some inferbo_summary ->
let inferbo_caller_mem = Option . value_exn inferbo_caller_mem in
let callee_entry_mem = BufferOverrunDomain . Summary . get_input inferbo_summary in
@ -72,13 +72,7 @@ module TransferFunctionsNodesBasicCost = struct
BufferOverrunSemantics . get_subst_map tenv callee_pdesc params inferbo_caller_mem
callee_entry_mem ~ callee_ret_alias
in
match Itv . Bound . subst_ub callee_cost subst_map with
| Bottom ->
L . ( die InternalError )
" Instantiation of cost %a from call to %a returned Bottom " Itv . Bound . pp callee_cost
Typ . Procname . pp callee_pname
| NonBottom callee_cost ->
callee_cost
Itv . NonNegativeBound . subst callee_cost subst_map
let exec_instr_cost inferbo_mem ( astate : CostDomain . NodeInstructionToCostMap . astate )
@ -90,7 +84,7 @@ module TransferFunctionsNodesBasicCost = struct
let callee_cost =
match Summary . read_summary pdesc callee_pname with
| Some { post = callee_cost } ->
if Itv . Bound. is_symbolic callee_cost then
if Itv . NonNegative Bound. is_symbolic callee_cost then
instantiate_cost ~ tenv ~ caller_pdesc : pdesc ~ inferbo_caller_mem : inferbo_mem
~ callee_pname ~ params ~ callee_cost
else callee_cost
@ -134,14 +128,14 @@ module AnalyzerNodesBasicCost =
* )
module BoundMap = struct
type t = Itv . Bound. t Node . IdMap . t
type t = Itv . NonNegative Bound. t Node . IdMap . t
let print_upper_bound_map bound_map =
L . ( debug Analysis Medium ) " @ \n \n ******* Bound Map ITV **** @ \n " ;
Node . IdMap . iter
( fun nid b ->
L . ( debug Analysis Medium ) " @ \n node: %a --> bound = %a @ \n " Node . pp_id nid Itv . Bound . pp b
)
L . ( debug Analysis Medium )
" @ \n node: %a --> bound = %a @ \n " Node . pp_id nid Itv . NonNegativeBound . pp b )
bound_map ;
L . ( debug Analysis Medium ) " @ \n ******* END Bound Map ITV **** @ \n \n "
@ -167,7 +161,7 @@ module BoundMap = struct
let node_id = NodeCFG . id node in
match Procdesc . Node . get_kind node with
| Procdesc . Node . Exit_node _ ->
Node . IdMap . add node_id Itv . Bound. one bound_map
Node . IdMap . add node_id Itv . NonNegative Bound. one bound_map
| _ ->
let entry_state_opt =
let instr_node_id = InstrCFG . of_underlying_node node | > InstrCFG . id in
@ -190,18 +184,18 @@ module BoundMap = struct
" @ \n \
[ COST ANALYSIS INTERNAL WARNING : ] No ' env' found . This location is \
unreachable returning cost 0 \ n " ;
Itv . Bound. zero
Itv . NonNegative Bound. zero
| NonBottom mem ->
BufferOverrunDomain . MemReach . heap_range
~ filter_loc : ( filter_loc formal_pvars all_deps )
mem
in
L . ( debug Analysis Medium )
" @ \n >>>Setting bound for node = %a to %a@ \n \n " Node . pp_id node_id Itv . Bound . pp
bound ;
" @ \n >>>Setting bound for node = %a to %a@ \n \n " Node . pp_id node_id
Itv . NonNegativeBound . pp bound ;
Node . IdMap . add node_id bound bound_map
| _ ->
Node . IdMap . add node_id Itv . Bound. zero bound_map
Node . IdMap . add node_id Itv . NonNegative Bound. zero bound_map
in
let bound_map =
List . fold ( NodeCFG . nodes node_cfg ) ~ f : compute_node_upper_bound ~ init : Node . IdMap . empty
@ -216,7 +210,7 @@ module BoundMap = struct
| None ->
L . ( debug Analysis Medium )
" @ \n \n [WARNING] Bound not found for node %a, returning Top @ \n " Node . pp_id nid ;
Itv . Bound. pinf
Itv . NonNegative Bound. to p
end
(* Structural Constraints are expressions of the kind:
@ -295,7 +289,10 @@ end
* )
module MinTree = struct
type mt_node = Leaf of ( Node . id * Itv . Bound . t ) | Min of mt_node list | Plus of mt_node list
type mt_node =
| Leaf of ( Node . id * Itv . NonNegativeBound . t )
| Min of mt_node list
| Plus of mt_node list
let add_leaf node nid leaf =
let leaf' = Leaf ( nid , leaf ) in
@ -307,7 +304,7 @@ module MinTree = struct
let rec pp fmt node =
match node with
| Leaf ( nid , c ) ->
F . fprintf fmt " %a:%a " Node . pp_id nid Itv . Bound. pp c
F . fprintf fmt " %a:%a " Node . pp_id nid Itv . NonNegative Bound. pp c
| Min l ->
F . fprintf fmt " Min(%a) " ( Pp . comma_seq pp ) l
| Plus l ->
@ -338,9 +335,9 @@ return the addends of the sum x_j1+x_j2+..+x_j_n*)
| Leaf ( _ , c ) ->
c
| Min l ->
evaluate_operator Itv . Bound. min _u l
evaluate_operator Itv . NonNegative Bound. min l
| Plus l ->
evaluate_operator Itv . Bound. plus _u l
evaluate_operator Itv . NonNegative Bound. plus l
and evaluate_operator op l =
@ -450,7 +447,7 @@ module ReportedOnNodes = AbstractDomain.FiniteSetOfPPSet (Node.IdSet)
type extras_TransferFunctionsWCET =
{ basic_cost_map : AnalyzerNodesBasicCost . invariant_map
; min_trees_map : Itv . Bound. t Node . IdMap . t
; min_trees_map : Itv . NonNegative Bound. t Node . IdMap . t
; summary : Specs . summary }
(* Calculate the final Worst Case Execution Time predicted for each node.
@ -459,7 +456,7 @@ type extras_TransferFunctionsWCET =
* )
module TransferFunctionsWCET = struct
module CFG = InstrCFG
module Domain = AbstractDomain . Pair ( Itv . Bound) ( ReportedOnNodes )
module Domain = AbstractDomain . Pair ( Itv . NonNegative Bound) ( ReportedOnNodes )
type extras = extras_TransferFunctionsWCET
@ -473,12 +470,13 @@ module TransferFunctionsWCET = struct
(* We don't report when the cost is Top as it corresponds to subsequent 'don't know's.
Instead , we report Top cost only at the top level per function when ` report_infinity ` is set to true * )
let should_report_cost cost =
Itv . Bound . is_not_infty cost && not ( Itv . Bound . le cost expensive_threshold )
Itv . NonNegativeBound . is_not_infty cost
&& not ( Itv . NonNegativeBound . ( < = ) ~ lhs : cost ~ rhs : expensive_threshold )
let do_report summary loc cost =
let ltr =
let cost_desc = F . asprintf " with estimated cost %a " Itv . Bound. pp cost in
let cost_desc = F . asprintf " with estimated cost %a " Itv . NonNegative Bound. pp cost in
[ Errlog . make_trace_element 0 loc cost_desc [] ]
in
let exn =
@ -486,7 +484,7 @@ module TransferFunctionsWCET = struct
F . asprintf
" The execution time from the beginning of the function up to this program point is \
likely above the acceptable threshold of % a ( estimated cost % a ) "
Itv . Bound. pp expensive_threshold Itv . Bound. pp cost
Itv . NonNegative Bound. pp expensive_threshold Itv . NonNegative Bound. pp cost
in
Exceptions . Checkers ( IssueType . expensive_execution_time_call , Localise . verbatim_desc message )
in
@ -503,20 +501,20 @@ module TransferFunctionsWCET = struct
preds
let map_cost trees m : Itv . Bound. t =
let map_cost trees m : Itv . NonNegative Bound. t =
CostDomain . NodeInstructionToCostMap . fold
( fun ( ( node_id , _ ) as instr_node_id ) c acc ->
let t = Node . IdMap . find node_id trees in
let c_node = Itv . Bound. mult c t in
let c_node' = Itv . Bound. plus _u acc c_node in
let c_node = Itv . NonNegative Bound. mult c t in
let c_node' = Itv . NonNegative Bound. plus acc c_node in
L . ( debug Analysis Medium )
" @ \n [AnalyzerWCET] Adding cost: (%a) --> c =%a t = %a @ \n " InstrCFG . pp_id
instr_node_id Itv . Bound. pp c Itv . Bound. pp t ;
instr_node_id Itv . NonNegative Bound. pp c Itv . NonNegative Bound. pp t ;
L . ( debug Analysis Medium )
" @ \n [AnalyzerWCET] Adding cost: (%a) --> c_node=%a cost = %a @ \n " InstrCFG . pp_id
instr_node_id Itv . Bound. pp c_node Itv . Bound. pp c_node' ;
instr_node_id Itv . NonNegative Bound. pp c_node Itv . NonNegative Bound. pp c_node' ;
c_node' )
m Itv . Bound. zero
m Itv . NonNegative Bound. zero
let exec_instr ( ( _ , reported_so_far ) : Domain . astate ) { ProcData . extras } ( node : CFG . node ) instr
@ -533,8 +531,8 @@ module TransferFunctionsWCET = struct
assert false
in
L . ( debug Analysis Medium )
" @ \n >>>AnalyzerWCET] Instr: %a Cost: %a@ \n " ( Sil . pp_instr Pp . text ) instr Itv . Bound . pp
cost_node ;
" @ \n >>>AnalyzerWCET] Instr: %a Cost: %a@ \n " ( Sil . pp_instr Pp . text ) instr
Itv . NonNegativeBound . pp cost_node ;
let astate' =
let und_node = CFG . underlying_node node in
let preds = Procdesc . Node . get_preds und_node in
@ -559,7 +557,7 @@ end
module AnalyzerWCET = AbstractInterpreter . MakeNoCFG ( InstrCFGScheduler ) ( TransferFunctionsWCET )
let check_and_report_infinity cost proc_desc summary =
if not ( Itv . Bound. is_not_infty cost ) then
if not ( Itv . NonNegative Bound. is_not_infty cost ) then
let loc = Procdesc . get_start_node proc_desc | > Procdesc . Node . get_loc in
let message =
F . asprintf " The execution time of the function %a cannot be computed " Typ . Procname . pp
@ -609,11 +607,12 @@ let checker ({Callbacks.tenv; proc_desc} as callback_args) : Specs.summary =
List . fold
~ f : ( fun acc ( nid , t ) ->
let res = MinTree . evaluate_tree t in
L . ( debug Analysis Medium ) " @ \n Tree %a eval to %a @ \n " Node . pp_id nid Itv . Bound . pp res ;
L . ( debug Analysis Medium )
" @ \n Tree %a eval to %a @ \n " Node . pp_id nid Itv . NonNegativeBound . pp res ;
Node . IdMap . add nid res acc )
~ init : Node . IdMap . empty min_trees
in
let initWCET = ( Itv . Bound. zero , ReportedOnNodes . empty ) in
let initWCET = ( Itv . NonNegative Bound. zero , ReportedOnNodes . empty ) in
match
AnalyzerWCET . compute_post
( ProcData . make proc_desc tenv
@ -621,7 +620,7 @@ let checker ({Callbacks.tenv; proc_desc} as callback_args) : Specs.summary =
~ debug : true ~ initial : initWCET
with
| Some ( exit_cost , _ ) ->
L . internal_error " PROCEDURE COST = %a @ \n " Itv . Bound. pp exit_cost ;
L . internal_error " PROCEDURE COST = %a @ \n " Itv . NonNegative Bound. pp exit_cost ;
check_and_report_infinity exit_cost proc_desc summary ;
Summary . update_summary { post = exit_cost } summary
| None ->