|
21 | 21 |
|
22 | 22 | #define DEBUG_TYPE "Z3CrosscheckOracle" |
23 | 23 |
|
| 24 | +// Queries attempted at most `Z3CrosscheckMaxAttemptsPerQuery` number of times. |
| 25 | +// Multiple `check()` calls might be called on the same query if previous |
| 26 | +// attempts of the same query resulted in UNSAT for any reason. Each query is |
| 27 | +// only counted once for these statistics, the retries are not accounted for. |
24 | 28 | STATISTIC(NumZ3QueriesDone, "Number of Z3 queries done"); |
25 | 29 | STATISTIC(NumTimesZ3TimedOut, "Number of times Z3 query timed out"); |
26 | 30 | STATISTIC(NumTimesZ3ExhaustedRLimit, |
@@ -77,16 +81,32 @@ void Z3CrosscheckVisitor::finalizeVisitor(BugReporterContext &BRC, |
77 | 81 | RefutationSolver->addConstraint(SMTConstraints); |
78 | 82 | } |
79 | 83 |
|
80 | | - // And check for satisfiability |
81 | | - llvm::TimeRecord Start = llvm::TimeRecord::getCurrentTime(/*Start=*/true); |
82 | | - std::optional<bool> IsSAT = RefutationSolver->check(); |
83 | | - llvm::TimeRecord Diff = llvm::TimeRecord::getCurrentTime(/*Start=*/false); |
84 | | - Diff -= Start; |
85 | | - Result = Z3Result{ |
86 | | - IsSAT, |
87 | | - static_cast<unsigned>(Diff.getWallTime() * 1000), |
88 | | - RefutationSolver->getStatistics()->getUnsigned("rlimit count"), |
| 84 | + auto GetUsedRLimit = [](const llvm::SMTSolverRef &Solver) { |
| 85 | + return Solver->getStatistics()->getUnsigned("rlimit count"); |
| 86 | + }; |
| 87 | + |
| 88 | + auto AttemptOnce = [&](const llvm::SMTSolverRef &Solver) -> Z3Result { |
| 89 | + constexpr auto getCurrentTime = llvm::TimeRecord::getCurrentTime; |
| 90 | + unsigned InitialRLimit = GetUsedRLimit(Solver); |
| 91 | + double Start = getCurrentTime(/*Start=*/true).getWallTime(); |
| 92 | + std::optional<bool> IsSAT = Solver->check(); |
| 93 | + double End = getCurrentTime(/*Start=*/false).getWallTime(); |
| 94 | + return { |
| 95 | + IsSAT, |
| 96 | + static_cast<unsigned>((End - Start) * 1000), |
| 97 | + GetUsedRLimit(Solver) - InitialRLimit, |
| 98 | + }; |
89 | 99 | }; |
| 100 | + |
| 101 | + // And check for satisfiability |
| 102 | + unsigned MinQueryTimeAcrossAttempts = std::numeric_limits<unsigned>::max(); |
| 103 | + for (unsigned I = 0; I < Opts.Z3CrosscheckMaxAttemptsPerQuery; ++I) { |
| 104 | + Result = AttemptOnce(RefutationSolver); |
| 105 | + Result.Z3QueryTimeMilliseconds = |
| 106 | + std::min(MinQueryTimeAcrossAttempts, Result.Z3QueryTimeMilliseconds); |
| 107 | + if (Result.IsSAT.has_value()) |
| 108 | + return; |
| 109 | + } |
90 | 110 | } |
91 | 111 |
|
92 | 112 | void Z3CrosscheckVisitor::addConstraints( |
|
0 commit comments