Skip to content

Commit e1be597

Browse files
authored
Merge pull request #6285 from martin-cs/feature/ai-logging
Feature/ai logging
2 parents f0a4e75 + 91e4706 commit e1be597

14 files changed

+295
-19
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include <assert.h>
2+
3+
int global;
4+
5+
int f00(int x)
6+
{
7+
return global + x;
8+
}
9+
10+
int main(void)
11+
{
12+
int local;
13+
unsigned int nondet;
14+
15+
local = 1;
16+
global = 1;
17+
18+
assert(local == global);
19+
20+
if(nondet)
21+
{
22+
local = 2;
23+
}
24+
if(nondet)
25+
{
26+
global = 2;
27+
}
28+
29+
assert(local == global);
30+
31+
do
32+
{
33+
local = 3;
34+
global = 3;
35+
} while(nondet-- > 0);
36+
37+
assert(local == global);
38+
39+
local = 4;
40+
global = 4;
41+
42+
local = f00(1);
43+
global = f00(1);
44+
45+
assert(local == global);
46+
47+
return 0;
48+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
CORE
2+
main.c
3+
--verify --recursive-interprocedural --vsd --loop-unwind-and-branching 10 --one-domain-per-history --verbosity 10
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main\.assertion\.1] line \d+ assertion local == global: SUCCESS$
7+
^\[main\.assertion\.2] line \d+ assertion local == global: UNKNOWN$
8+
^\[main\.assertion\.3] line \d+ assertion local == global: SUCCESS$
9+
^\[main\.assertion\.4] line \d+ assertion local == global: UNKNOWN$
10+
^ai_baset::visit \d+ in main$
11+
^ai_baset::visit_edge from \d+ to \d+\.\.\. gives a new history\.\.\. applying transformer\.\.\. merging\.\.\. result queued\.$
12+
^ai_baset::visit_function_call at \d+$
13+
^ai_baset::visit_end_function main$
14+
^ai_recursive_interproceduralt::visit_edge_function_call from \d+ to \d+$
15+
^p = local_control_flow_history : location \d+
16+
^global \(\) -> 0 @ \[\d+\]$
17+
--
18+
^warning: ignoring
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
CORE
2+
main.c
3+
--verify --recursive-interprocedural --vsd --loop-unwind-and-branching 10 --one-domain-per-history --verbosity 8
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main\.assertion\.1] line \d+ assertion local == global: SUCCESS$
7+
^\[main\.assertion\.2] line \d+ assertion local == global: UNKNOWN$
8+
^\[main\.assertion\.3] line \d+ assertion local == global: SUCCESS$
9+
^\[main\.assertion\.4] line \d+ assertion local == global: UNKNOWN$
10+
--
11+
^warning: ignoring
12+
^p = local_control_flow_history : location \d+
13+
^global \(\) -> 0 @ \[\d+\]$
14+
^ai_baset::visit \d+ in main$
15+
^ai_baset::visit_edge from \d+ to \d+\.\.\. gives a new history\.\.\. applying transformer\.\.\. merging\.\.\. result queued\.$
16+
^ai_baset::visit_function_call at \d+$
17+
^ai_baset::visit_end_function main$
18+
^ai_recursive_interproceduralt::visit_edge_function_call from \d+ to \d+$
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
CORE
2+
main.c
3+
--verify --recursive-interprocedural --vsd --loop-unwind-and-branching 10 --one-domain-per-history --verbosity 9
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main\.assertion\.1] line \d+ assertion local == global: SUCCESS$
7+
^\[main\.assertion\.2] line \d+ assertion local == global: UNKNOWN$
8+
^\[main\.assertion\.3] line \d+ assertion local == global: SUCCESS$
9+
^\[main\.assertion\.4] line \d+ assertion local == global: UNKNOWN$
10+
^ai_baset::visit \d+ in main$
11+
^ai_baset::visit_edge from \d+ to \d+\.\.\. gives a new history\.\.\. applying transformer\.\.\. merging\.\.\. result queued\.$
12+
^ai_baset::visit_function_call at \d+$
13+
^ai_baset::visit_end_function main$
14+
^ai_recursive_interproceduralt::visit_edge_function_call from \d+ to \d+$
15+
--
16+
^warning: ignoring
17+
^p = local_control_flow_history : location \d+
18+
^global \(\) -> 0 @ \[\d+\]$
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
CORE
2+
main.c
3+
--verify --three-way-merge --vsd --loop-unwind-and-branching 10 --one-domain-per-history --verbosity 10
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main\.assertion\.1] line \d+ assertion local == global: SUCCESS$
7+
^\[main\.assertion\.2] line \d+ assertion local == global: UNKNOWN$
8+
^\[main\.assertion\.3] line \d+ assertion local == global: SUCCESS$
9+
^\[main\.assertion\.4] line \d+ assertion local == global: SUCCESS$
10+
^ai_baset::visit \d+ in main$
11+
^ai_baset::visit_edge from \d+ to \d+\.\.\. gives a new history\.\.\. applying transformer\.\.\. merging\.\.\. result queued\.$
12+
^ai_baset::visit_function_call at \d+$
13+
^ai_baset::visit_end_function main$
14+
^ai_three_way_merget::visit_edge_function_call from \d+ to \d+$
15+
^ai_three_way_merget::visit_edge_function_call edge from \d+ to \d+\.\.\. gives a new history\.\.\. applying transformer\.\.\. three way merge\.\.\. merging\.\.\. result queued\.$
16+
^p = local_control_flow_history : location \d+
17+
^global \(\) -> 0 @ \[\d+\]$
18+
--
19+
^warning: ignoring

src/analyses/ai.cpp

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,10 @@ bool ai_baset::visit(
269269
{
270270
bool new_data=false;
271271
locationt l = p->current_location();
272+
messaget log(message_handler);
273+
274+
log.progress() << "ai_baset::visit " << l->location_number << " in "
275+
<< function_id << messaget::eom;
272276

273277
// Function call and end are special cases
274278
if(l->is_function_call())
@@ -325,11 +329,27 @@ bool ai_baset::visit_edge(
325329
const namespacet &ns,
326330
working_sett &working_set)
327331
{
332+
messaget log(message_handler);
333+
log.progress() << "ai_baset::visit_edge from "
334+
<< p->current_location()->location_number << " to "
335+
<< to_l->location_number << "... ";
336+
328337
// Has history taught us not to step here...
329338
auto next =
330339
p->step(to_l, *(storage->abstract_traces_before(to_l)), caller_history);
331340
if(next.first == ai_history_baset::step_statust::BLOCKED)
341+
{
342+
log.progress() << "blocked by history" << messaget::eom;
332343
return false;
344+
}
345+
else if(next.first == ai_history_baset::step_statust::NEW)
346+
{
347+
log.progress() << "gives a new history... ";
348+
}
349+
else
350+
{
351+
log.progress() << "merges with existing history... ";
352+
}
333353
trace_ptrt to_p = next.second;
334354

335355
// Abstract domains are mutable so we must copy before we transform
@@ -339,21 +359,50 @@ bool ai_baset::visit_edge(
339359
statet &new_values = *tmp_state;
340360

341361
// Apply transformer
362+
log.progress() << "applying transformer... ";
342363
new_values.transform(function_id, p, to_function_id, to_p, *this, ns);
343364

344365
// Expanding a domain means that it has to be analysed again
345366
// Likewise if the history insists that it is a new trace
346367
// (assuming it is actually reachable).
368+
log.progress() << "merging... ";
369+
bool return_value = false;
347370
if(
348371
merge(new_values, p, to_p) ||
349372
(next.first == ai_history_baset::step_statust::NEW &&
350373
!new_values.is_bottom()))
351374
{
352375
put_in_working_set(working_set, to_p);
353-
return true;
376+
log.progress() << "result queued." << messaget::eom;
377+
return_value = true;
378+
}
379+
else
380+
{
381+
log.progress() << "domain unchanged." << messaget::eom;
354382
}
355383

356-
return false;
384+
// Branch because printing some histories and domains can be expensive
385+
// esp. if the output is then just discarded and this is a critical path.
386+
if(message_handler.get_verbosity() >= messaget::message_levelt::M_DEBUG)
387+
{
388+
log.debug() << "p = ";
389+
p->output(log.debug());
390+
log.debug() << messaget::eom;
391+
392+
log.debug() << "current = ";
393+
current.output(log.debug(), *this, ns);
394+
log.debug() << messaget::eom;
395+
396+
log.debug() << "to_p = ";
397+
to_p->output(log.debug());
398+
log.debug() << messaget::eom;
399+
400+
log.debug() << "new_values = ";
401+
new_values.output(log.debug(), *this, ns);
402+
log.debug() << messaget::eom;
403+
}
404+
405+
return return_value;
357406
}
358407

359408
bool ai_baset::visit_edge_function_call(
@@ -366,6 +415,11 @@ bool ai_baset::visit_edge_function_call(
366415
const goto_functionst &,
367416
const namespacet &ns)
368417
{
418+
messaget log(message_handler);
419+
log.progress() << "ai_baset::visit_edge_function_call from "
420+
<< p_call->current_location()->location_number << " to "
421+
<< l_return->location_number << messaget::eom;
422+
369423
// The default implementation is not interprocedural
370424
// so the effects of the call are approximated but nothing else
371425
return visit_edge(
@@ -391,6 +445,10 @@ bool ai_baset::visit_function_call(
391445

392446
PRECONDITION(l_call->is_function_call());
393447

448+
messaget log(message_handler);
449+
log.progress() << "ai_baset::visit_function_call at "
450+
<< l_call->location_number << messaget::eom;
451+
394452
locationt l_return = std::next(l_call);
395453

396454
// operator() allows analysis of a single goto_program independently
@@ -405,6 +463,8 @@ bool ai_baset::visit_function_call(
405463
const irep_idt &callee_function_id =
406464
to_symbol_expr(callee_expression).get_identifier();
407465

466+
log.progress() << "Calling " << callee_function_id << messaget::eom;
467+
408468
goto_functionst::function_mapt::const_iterator it =
409469
goto_functions.function_map.find(callee_function_id);
410470

@@ -464,6 +524,10 @@ bool ai_baset::visit_end_function(
464524
locationt l = p->current_location();
465525
PRECONDITION(l->is_end_function());
466526

527+
messaget log(message_handler);
528+
log.progress() << "ai_baset::visit_end_function " << function_id
529+
<< messaget::eom;
530+
467531
// Do nothing
468532
return false;
469533
}
@@ -478,6 +542,11 @@ bool ai_recursive_interproceduralt::visit_edge_function_call(
478542
const goto_functionst &goto_functions,
479543
const namespacet &ns)
480544
{
545+
messaget log(message_handler);
546+
log.progress() << "ai_recursive_interproceduralt::visit_edge_function_call"
547+
<< " from " << p_call->current_location()->location_number
548+
<< " to " << l_return->location_number << messaget::eom;
549+
481550
// This is the edge from call site to function head.
482551
{
483552
locationt l_begin = callee.instructions.begin();
@@ -495,6 +564,9 @@ bool ai_recursive_interproceduralt::visit_edge_function_call(
495564
ns,
496565
catch_working_set);
497566

567+
log.progress() << "Handle " << callee_function_id << " recursively"
568+
<< messaget::eom;
569+
498570
// do we need to do/re-do the fixedpoint of the body?
499571
if(new_data)
500572
fixedpoint(
@@ -507,6 +579,8 @@ bool ai_recursive_interproceduralt::visit_edge_function_call(
507579

508580
// This is the edge from function end to return site.
509581
{
582+
log.progress() << "Handle return edges" << messaget::eom;
583+
510584
// get location at end of the procedure we have called
511585
locationt l_end = --callee.instructions.end();
512586
DATA_INVARIANT(

src/analyses/ai.h

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ Author: Daniel Kroening, [email protected]
5151
#include <util/deprecate.h>
5252
#include <util/json.h>
5353
#include <util/make_unique.h>
54+
#include <util/message.h>
5455
#include <util/xml.h>
5556

5657
#include <goto-programs/goto_model.h>
@@ -127,10 +128,12 @@ class ai_baset
127128
ai_baset(
128129
std::unique_ptr<ai_history_factory_baset> &&hf,
129130
std::unique_ptr<ai_domain_factory_baset> &&df,
130-
std::unique_ptr<ai_storage_baset> &&st)
131+
std::unique_ptr<ai_storage_baset> &&st,
132+
message_handlert &mh)
131133
: history_factory(std::move(hf)),
132134
domain_factory(std::move(df)),
133-
storage(std::move(st))
135+
storage(std::move(st)),
136+
message_handler(mh)
134137
{
135138
}
136139

@@ -515,6 +518,9 @@ class ai_baset
515518
{
516519
return storage->get_state(p, *domain_factory);
517520
}
521+
522+
// Logging
523+
message_handlert &message_handler;
518524
};
519525

520526
// Perform interprocedural analysis by simply recursing in the interpreter
@@ -525,8 +531,9 @@ class ai_recursive_interproceduralt : public ai_baset
525531
ai_recursive_interproceduralt(
526532
std::unique_ptr<ai_history_factory_baset> &&hf,
527533
std::unique_ptr<ai_domain_factory_baset> &&df,
528-
std::unique_ptr<ai_storage_baset> &&st)
529-
: ai_baset(std::move(hf), std::move(df), std::move(st))
534+
std::unique_ptr<ai_storage_baset> &&st,
535+
message_handlert &mh)
536+
: ai_baset(std::move(hf), std::move(df), std::move(st), mh)
530537
{
531538
}
532539

@@ -562,7 +569,8 @@ class ait : public ai_recursive_interproceduralt
562569
util_make_unique<
563570
ai_history_factory_default_constructort<ahistoricalt>>(),
564571
util_make_unique<ai_domain_factory_default_constructort<domainT>>(),
565-
util_make_unique<location_sensitive_storaget>())
572+
util_make_unique<location_sensitive_storaget>(),
573+
no_logging)
566574
{
567575
}
568576

@@ -571,7 +579,8 @@ class ait : public ai_recursive_interproceduralt
571579
util_make_unique<
572580
ai_history_factory_default_constructort<ahistoricalt>>(),
573581
std::move(df),
574-
util_make_unique<location_sensitive_storaget>())
582+
util_make_unique<location_sensitive_storaget>(),
583+
no_logging)
575584
{
576585
}
577586

@@ -613,6 +622,9 @@ class ait : public ai_recursive_interproceduralt
613622
/// This function exists to enforce that `domainT` is derived from
614623
/// \ref ai_domain_baset
615624
void dummy(const domainT &s) { const statet &x=s; (void)x; }
625+
626+
// To keep the old constructor interface we disable logging
627+
null_message_handlert no_logging;
616628
};
617629

618630
/// Base class for concurrency-aware abstract interpretation. See

0 commit comments

Comments
 (0)