Skip to content

Log SMT formula to file for new incremental backend. #7126

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
merged 2 commits into from
Sep 29, 2022

Conversation

esteffin
Copy link
Contributor

Add the possibility to log the SMT formula generated by the new SMT2 incremental backend to a file.

To use the feature add --outfile <filename> to command-line arguments.

  • 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.
  • 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.
  • White-space or formatting changes outside the feature-related changed lines are in commits of their own.

@esteffin esteffin force-pushed the esteffin/log-smt-formula-to-file branch from 0bf0711 to a506981 Compare September 13, 2022 11:00
@codecov
Copy link

codecov bot commented Sep 13, 2022

Codecov Report

Base: 77.88% // Head: 77.89% // Increases project coverage by +0.00% 🎉

Coverage data is based on head (1dc2e03) compared to base (c764c1d).
Patch coverage: 91.66% of modified lines in pull request are covered.

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #7126   +/-   ##
========================================
  Coverage    77.88%   77.89%           
========================================
  Files         1576     1576           
  Lines       181856   181886   +30     
========================================
+ Hits        141645   141675   +30     
  Misses       40211    40211           
Impacted Files Coverage Δ
src/util/expr.h 97.02% <ø> (ø)
src/goto-checker/solver_factory.cpp 78.17% <86.95%> (+0.93%) ⬆️
...rc/solvers/smt2_incremental/smt_solver_process.cpp 79.16% <100.00%> (+9.72%) ⬆️
src/solvers/smt2_incremental/smt_solver_process.h 100.00% <100.00%> (ø)

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

@esteffin esteffin force-pushed the esteffin/log-smt-formula-to-file branch from a506981 to 43439bc Compare September 16, 2022 13:13
@esteffin esteffin marked this pull request as ready for review September 16, 2022 13:13
@esteffin esteffin force-pushed the esteffin/log-smt-formula-to-file branch from 43439bc to b2b7199 Compare September 16, 2022 17:06
@tautschnig tautschnig self-assigned this Sep 17, 2022
@@ -0,0 +1,71 @@
#!/usr/bin/env python3
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we really need that script? Couldn't it also be done by using --outfile /dev/stdout?

Copy link
Contributor Author

@esteffin esteffin Sep 20, 2022

Choose a reason for hiding this comment

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

Yes, unfortunately we need it as:

  1. We test on windows where /dev/stdout may not work
  2. By adding --outfile /dev/stdout we will know that the SMT formula is printed on the screen, not that it is added to the out file, so we cannot distinguish file from normal output.
  3. The way the test output is checked is not in a certain order while the python script enforce a certain ordering, so if we want to have 2 (check-sat) calls the old system will be satisfied with one (check-sat) in the output, the new one instead will require 2 in the specified order

Copy link
Collaborator

Choose a reason for hiding this comment

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

  1. I believe you can use - instead of /dev/stdout, which will then work across platforms.
  2. Granted, but I'm not sure this one aspect is a sufficient reason to warrant yet another piece of code that needs to be maintained.
  3. You can use activate-multi-line-match to handle this case.

I don't intend to block on that, but every line of code that is written has a (future) cost. So I ask for careful consideration whether this really is needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately in the new SMT backend we do not support the old --outfile - behaviour as, because of the interactive behaviour, the output will be interleaved with other messages (defying the sense of --outfile).
It is still possible to get the SMT formula on the stdout by using --verbosity 10 and then filtering the lines sent to the solver.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Hmm, good point. So I guess you have to keep the Python script, and I'm just hoping it won't break...

Copy link
Contributor

Choose a reason for hiding this comment

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

  1. I believe you can use - instead of /dev/stdout, which will then work across platforms.

The - option is special cased in the solver factory. So tests which rely on this aren't fully testing the code path for writing to file.

I think this python script has value beyond the new incremental smt backend, because it could also be used to test the dimacs output for example.

@tautschnig tautschnig removed their assignment Sep 17, 2022
// Using std::endl to flush the stream as it is a debugging functionality,
// and we can guarantee a consistent output in case of hanging after
// (check-sat)
*out_stream << command_string << std::endl;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you perhaps just want to use std::flush instead? Most of the comment would remain useful to keep, though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As we want a new line and a flush I prefer std::endl instead of adding a new line + adding an explicit std::flush.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ok, but then you might want the comment to say "Using std::endl instead of \n"

@@ -35,9 +37,12 @@ class smt_piped_solver_processt : public smt_base_solver_processt
/// The command and arguments for invoking the smt2 solver.
/// \param message_handler:
/// The messaging system to be used for logging purposes.
/// \param out_stream:
/// Pointer to the stream to print the SMT formula. `nullptr` if no output.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Indent

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

smt_piped_solver_processt(
std::string command_line,
message_handlert &message_handler);
message_handlert &message_handler,
std::unique_ptr<std::ostream> out_stream);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is passing the std::unique_ptr by value rather than as a reference the right thing to do?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes as we want to extend the lifetime of the passed stream to the one of the smt_solver_proces object that is longer than the one of the solver_factory where the pointer is created.

Comment on lines 228 to 233
if(
cmdline.isset("stop-on-fail") || cmdline.isset("dimacs") ||
(cmdline.isset("outfile") && !cmdline.isset("incremental-smt2-solver")))
{
options.set_option("stop-on-fail", true);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm either failing to parse the commit message or don't understand why the incremental SMT2 solver now interacts with "outfile" in this way. Is it the case that "outfile" has a very different semantics with the incremental SMT2 solver?! Does not seem like a good idea.

Copy link
Contributor

Choose a reason for hiding this comment

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

If we stop on fail, then we stop processing after the first round of solving. If we want to dump the SMT2 formula to file for all rounds of solving for ease of debugging (human reading) of the written file then we need to not stop on failure. Otherwise only the first round of solving is written to file, because we stopped on failure.

My somewhat related question would be why do we automatically stop on failure when --outfile is used with any of the decision procedures?

Copy link
Collaborator

Choose a reason for hiding this comment

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

To your "somewhat related question:" no actual solving takes place with other back-ends with --outfile, and also: what would be the semantics of having only a single output file but multiple formulae having to be written?

So if the incremental SMT2 back-end has substantially different behaviour (solving actually takes place, multiple formulae are written) then we really shouldn't be using the same command-line option name. This confusing user-experience is a blocker.

Copy link
Member

@peterschrammel peterschrammel Sep 21, 2022

Choose a reason for hiding this comment

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

Otherwise only the first round of solving is written to file, because we stopped on failure.

But if you specified --stop-on-fail then this is exactly what you asked for. So, I don't see the point of having special behaviour here, @thomasspriggs. If you want all rounds to be written to the file then remove the --stop-on-fail flag.

Copy link
Contributor

Choose a reason for hiding this comment

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

But this is for when we aren't explicitly specifying --stop-on-fail. The argument parsing is currently adding "stop-on-fail" implicitly when --outfile is specified. Do we need to add an explicit --continue-on-fail to override the implicit option?

Copy link
Member

@peterschrammel peterschrammel Sep 21, 2022

Choose a reason for hiding this comment

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

I see. Then I'd call the current behaviour somewhat confusing... not sure how to fix that without having different behaviour for incremental vs non-incremental, or having multiple options. (Definitely not a --continue-on-fail option)

@esteffin esteffin force-pushed the esteffin/log-smt-formula-to-file branch from b2b7199 to ca83774 Compare September 21, 2022 15:48
Copy link
Contributor

@thomasspriggs thomasspriggs left a comment

Choose a reason for hiding this comment

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

Partial review only.

{
throw invalid_command_line_argument_exceptiont(
"failed to open file: " + outfile, "--outfile");
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⛏️ This section of code appears to have been duplicated from the get_smt2, can you separate it into a function. I guess the function should take the (potentially empty) outfile string and either throw or return an std::unique_ptr<std::ofstream>.

Comment on lines 228 to 233
if(
cmdline.isset("stop-on-fail") || cmdline.isset("dimacs") ||
(cmdline.isset("outfile") && !cmdline.isset("incremental-smt2-solver")))
{
options.set_option("stop-on-fail", true);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

If we stop on fail, then we stop processing after the first round of solving. If we want to dump the SMT2 formula to file for all rounds of solving for ease of debugging (human reading) of the written file then we need to not stop on failure. Otherwise only the first round of solving is written to file, because we stopped on failure.

My somewhat related question would be why do we automatically stop on failure when --outfile is used with any of the decision procedures?

// Using std::endl to flush the stream as it is a debugging functionality,
// and we can guarantee a consistent output in case of hanging after
// (check-sat)
*out_stream << command_string << std::endl;
Copy link
Contributor

Choose a reason for hiding this comment

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

Does it make sense to print a message that this action has been performed? E.g.

std::cout << "Outputting SMTLib to $file"

Probably somewhere else (constructor maybe?) so that the user can see what's going on (now I can use that, but there's no indication that this worked at all, which I found a bit surprising).

@esteffin esteffin force-pushed the esteffin/log-smt-formula-to-file branch from ca83774 to 95a411c Compare September 22, 2022 17:20
@esteffin esteffin closed this Sep 26, 2022
@esteffin esteffin force-pushed the esteffin/log-smt-formula-to-file branch from 95a411c to 06b377d Compare September 26, 2022 23:58
@thomasspriggs thomasspriggs reopened this Sep 27, 2022
@thomasspriggs
Copy link
Contributor

Re-opened as it was closed in error.

@esteffin esteffin force-pushed the esteffin/log-smt-formula-to-file branch from ecfd902 to 7fd76e6 Compare September 27, 2022 10:24
@esteffin
Copy link
Contributor Author

Due to review comments, some extra work has been done so that now the --outfile works as with other backends (including --outfile - that will log on stdout.
Also when --outfile is added no SMT solver will be run.

There will be a subsequent PR that will add a new argument --dump-smt-formula that will log the SMT formula to a file while the SMT solver is also run (no stop-on-fail behaviour).

@esteffin esteffin force-pushed the esteffin/log-smt-formula-to-file branch 5 times, most recently from 5f22a32 to 821b9ad Compare September 27, 2022 16:09
Copy link
Contributor

@thomasspriggs thomasspriggs left a comment

Choose a reason for hiding this comment

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

👍

@esteffin esteffin force-pushed the esteffin/log-smt-formula-to-file branch from 821b9ad to 1dc2e03 Compare September 27, 2022 19:09
@esteffin
Copy link
Contributor Author

@tautschnig I think the new reworked commits should address your comments and concerns, especially as now the old --outfile behaviour has been restored.
Can you please double check this and if all good approve this PR?

@kroening kroening merged commit 66f913e into diffblue:develop Sep 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants