Skip to content

Use BDDs for encoding symex guards #3730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

romainbrenguier
Copy link
Contributor

@romainbrenguier romainbrenguier commented Jan 9, 2019

The main commit is "Use BDDs for encoding guards in symex". Commits that are before are in preparation for this one (in particular getting rid of usage of functions the new version will not implement). Commits that follow are clean-up in the code that use the guard (in particular getting rid of simplifications that are now unnecessary).

I still wan't to run this on more benchmarks before it is merged. For what I've seen so far, this is about 10% faster than the current symex, but this is not uniform across benchmarks (it doesn't help for "simple" instances, i.e. which take less than 2s).

  • Each commit message has a non-empty body, explaining why the change was made.
  • Methods or procedures I have added are documented, following the guidelines provided in CODING_STANDARD.md.
  • [na] The feature or user visible behaviour I have added or modified has been documented in the User Guide in doc/cprover-manual/
  • Regression or unit tests are included, or existing tests cover the modified code (in this case I have detailed which ones those are in the commit message).
  • My commit message includes data points confirming performance improvements (if claimed).
  • My PR is restricted to a single feature or bugfix.
  • [na] White-space or formatting changes outside the feature-related changed lines are in commits of their own.

@tautschnig
Copy link
Collaborator

Before reviewing this in any way: I believe I had mentioned #310. Does this PR relate to it in any way?

@romainbrenguier
Copy link
Contributor Author

@tautschnig

Before reviewing this in any way: I believe I had mentioned #310. Does this PR relate to it in any way?

Yes, the idea is similar, but this is taking it one step further: instead of keeping guards as exprt and using BDDs to simplify them at some points in the code, we always keep the guards as BDDs and only convert to exprt when as_expr is called.

Copy link
Collaborator

@tautschnig tautschnig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given this is marked "In progress" I'm sure this is the plan, but just to be explicit: please turn this into a series of PRs, there are a lot of seemingly unrelated changes.

@@ -1342,8 +1342,7 @@ void goto_checkt::check_rec(const exprt &expr, guardt &guard, bool address)
guard.add(op);
}

guard.swap(old_guard);

guard = std::move(old_guard);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost randomly poking at commits: what's the improvement here? (I actually have a yet-to-be-PR'ed commit lying around making the opposite change, i.e., replacing uses of std::move by swap.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new implementation of guardt doesn't have a swap (though exprt has). And since old_guard is not used afterward, I don't see a reason for using swap?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For irept-based implementations = std::move(...) is at best as efficient as swap, and possibly less efficient if USE_MOVE is not enabled. (But I do concede that we should just get rid of USE_MOVE as an optional feature as we require C++11 anyway.) So in that setting the change doesn't seem to provide any added value.

With the new implementation of guardt not being an irept, the situation of course is different. But that needs to be spelled out in the commit message...

@tautschnig
Copy link
Collaborator

Yes, the idea is similar, but this is taking it one step further: instead of keeping guards as exprt and using BDDs to simplify them at some points in the code, we always keep the guards as BDDs and only convert to exprt when as_expr is called.

Ok, but do note that in terms of history this is a step backwards: guardt used to be unrelated to exprt, and making it an exprt enabled access to more sharing when previously we had a lot of redundant copies.


guard.add(not_exprt(if_expr.cond()));
copy.add(not_exprt(if_expr.cond()));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be guard.add

@tautschnig
Copy link
Collaborator

There is a lot of great cleanup in this PR that should be merged as soon as possible, but via individual PRs (really one per commit). Then this PR can be reduced to the necessary minimum and also the effect of BDDs (and not that of the cleanup) can be measured.

@romainbrenguier romainbrenguier force-pushed the experiment/bdd-guards4 branch 3 times, most recently from 0b6eca3 to a8ba19d Compare January 10, 2019 10:55
@romainbrenguier romainbrenguier force-pushed the experiment/bdd-guards4 branch 8 times, most recently from 9ca95cd to 88ff3a4 Compare January 11, 2019 14:04
@romainbrenguier romainbrenguier force-pushed the experiment/bdd-guards4 branch 3 times, most recently from 398bd01 to 468c01d Compare March 5, 2019 06:34
Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️
This PR failed Diffblue compatibility checks (cbmc commit: 468c01d).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/103158445
Status will be re-evaluated on next push.
Common spurious failures:

  • the cbmc commit has disappeared in the mean time (e.g. in a force-push)

  • the author is not in the list of contributors (e.g. first-time contributors).

  • the compatibility was already broken by an earlier merge.

This test is deactivated for the build with BDDs because it takes more
than 10 minutes for the test to complete.
This is due to the size of the BDD representing the guards growing more than
they do when reprented as exprt.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit pick: s/reprented/represented/

than 10 minutes for the test to complete.
This is due to the size of the BDD representing the guards growing more than
they do when reprented as exprt.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit pick 2: No need for blank line

@romainbrenguier romainbrenguier force-pushed the experiment/bdd-guards4 branch from 468c01d to ddf0491 Compare March 5, 2019 09:28
Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️
This PR failed Diffblue compatibility checks (cbmc commit: ddf0491).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/103176652
Status will be re-evaluated on next push.
Common spurious failures:

  • the cbmc commit has disappeared in the mean time (e.g. in a force-push)

  • the author is not in the list of contributors (e.g. first-time contributors).

  • the compatibility was already broken by an earlier merge.

No functional changes.
This was done automatically using clang-format.
This is in preparation to moving this two files, so that clang-format
doesn't reformat the file at the same time they are moved, and so that
the move commit is clean.
We want to add an implementation of guard that uses BDDs, which are part
of the solvers module. We cannot add a dependency of the util module on
solvers.
The guard used there was actually only used as a conjunction, so it can
be replaced by a list of expressions, of which we take the conjunction
when needed.
This in preparation to using BDDs to encode guards,
every part of the code creating guards need to reference a guard_manager.
A reference to a namespace was stored without being ever used.
Instead the result of from_exprt and the input of as_expr should be
BDDs.
This makes it possible to reuse the same manager for several exprt
conversion and to combine the results obtain from the from_expr
conversion with BDD operations.
The type of identifier can vary depending on the BDD implementation
used. Using long there was kind of a hack and not correct on
architecture where pointers wouldn't fit in a long.
Caching the intermediary results can lead to big performance
improvements since the number of calls without cache could be
potentially exponential in the size of the BDD.
This is not used yet in CBMC.
The aim is to specify at compile time whether we want to use this new
implementation or the old one.

Using BDDs ensures the guards are always in some "simple" form.
This is to clearly seperate the two implementations.
The choice between the two will be made in guard.h
To avoid confusion with the other guard implementation.

This forces us to use includes instead of forward declaration for guardt
because forward declaration doesn't work well with typedef.
Depending on the BDD_GUARDS flag, we will use the expr implementation or
the BDD implementation.
This adds instruction to COMPILING.md so that people interested in
performances can find about it, and try it.
Expressions obtained from BDDs are already simple. Trying to simplify
them is redundant and can slow down the execution.
We add this field so that symex code can take the decision to simplify
or not an expression based on this information.
We add the BDD_GUARDS flags in the travis step which is compiling with
CUDD to test that the bdd_guard implementation.
One of the JBMC tests will take a long time when BDD are used.
We deactivate it for now in the case BDD_GUARDS is defined.
This is acceptable since using BDDs for guards is still experimental.
Ideally we should find what takes too long in the execution and optimize
it, but it may be that we hit a particular class of guards for which the
BDDs have to be big.
This avoids having an argument that is both input and output and makes
using this function nicer.
No functional change
@romainbrenguier romainbrenguier force-pushed the experiment/bdd-guards4 branch from ddf0491 to 22ed54b Compare March 7, 2019 11:03
Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️
This PR failed Diffblue compatibility checks (cbmc commit: 22ed54b).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/103523152
Status will be re-evaluated on next push.
Common spurious failures:

  • the cbmc commit has disappeared in the mean time (e.g. in a force-push)

  • the author is not in the list of contributors (e.g. first-time contributors).

  • the compatibility was already broken by an earlier merge.

@romainbrenguier romainbrenguier merged commit 0b58dc5 into diffblue:develop Mar 7, 2019
@romainbrenguier romainbrenguier deleted the experiment/bdd-guards4 branch March 7, 2019 13:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants