mirror of https://github.com/YosysHQ/yosys.git
Added timout functionality to SAT solver
This commit is contained in:
parent
21e38bed98
commit
8fbb5b6240
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
|
||||||
#include "minisat/core/Solver.h"
|
#include "minisat/core/Solver.h"
|
||||||
|
@ -50,8 +51,22 @@ void ezMiniSAT::clear()
|
||||||
ezSAT::clear();
|
ezSAT::clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ezMiniSAT *ezMiniSAT::alarmHandlerThis = NULL;
|
||||||
|
clock_t ezMiniSAT::alarmHandlerTimeout = 0;
|
||||||
|
|
||||||
|
void ezMiniSAT::alarmHandler(int)
|
||||||
|
{
|
||||||
|
if (clock() > alarmHandlerTimeout) {
|
||||||
|
alarmHandlerThis->minisatSolver->interrupt();
|
||||||
|
alarmHandlerTimeout = 0;
|
||||||
|
} else
|
||||||
|
alarm(1);
|
||||||
|
}
|
||||||
|
|
||||||
bool ezMiniSAT::solver(const std::vector<int> &modelExpressions, std::vector<bool> &modelValues, const std::vector<int> &assumptions)
|
bool ezMiniSAT::solver(const std::vector<int> &modelExpressions, std::vector<bool> &modelValues, const std::vector<int> &assumptions)
|
||||||
{
|
{
|
||||||
|
solverTimoutStatus = false;
|
||||||
|
|
||||||
if (0) {
|
if (0) {
|
||||||
contradiction:
|
contradiction:
|
||||||
delete minisatSolver;
|
delete minisatSolver;
|
||||||
|
@ -104,7 +119,28 @@ contradiction:
|
||||||
else
|
else
|
||||||
assumps.push(Minisat::mkLit(minisatVars.at(-idx-1), true));
|
assumps.push(Minisat::mkLit(minisatVars.at(-idx-1), true));
|
||||||
|
|
||||||
if (!minisatSolver->solve(assumps))
|
sighandler_t old_alarm_sighandler;
|
||||||
|
int old_alarm_timeout;
|
||||||
|
|
||||||
|
if (solverTimeout > 0) {
|
||||||
|
alarmHandlerThis = this;
|
||||||
|
alarmHandlerTimeout = clock() + solverTimeout*CLOCKS_PER_SEC;
|
||||||
|
old_alarm_timeout = alarm(0);
|
||||||
|
old_alarm_sighandler = signal(SIGALRM, alarmHandler);
|
||||||
|
alarm(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool foundSolution = minisatSolver->solve(assumps);
|
||||||
|
|
||||||
|
if (solverTimeout > 0) {
|
||||||
|
if (alarmHandlerTimeout == 0)
|
||||||
|
solverTimoutStatus = true;
|
||||||
|
alarm(0);
|
||||||
|
signal(SIGALRM, old_alarm_sighandler);
|
||||||
|
alarm(old_alarm_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundSolution)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
modelValues.clear();
|
modelValues.clear();
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define EZMINISAT_H
|
#define EZMINISAT_H
|
||||||
|
|
||||||
#include "ezsat.h"
|
#include "ezsat.h"
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
// minisat is using limit macros and format macros in their headers that
|
// minisat is using limit macros and format macros in their headers that
|
||||||
// can be the source of some troubles when used from c++11. thefore we
|
// can be the source of some troubles when used from c++11. thefore we
|
||||||
|
@ -36,6 +37,10 @@ private:
|
||||||
std::vector<int> minisatVars;
|
std::vector<int> minisatVars;
|
||||||
bool foundContradiction;
|
bool foundContradiction;
|
||||||
|
|
||||||
|
static ezMiniSAT *alarmHandlerThis;
|
||||||
|
static clock_t alarmHandlerTimeout;
|
||||||
|
static void alarmHandler(int);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ezMiniSAT();
|
ezMiniSAT();
|
||||||
virtual ~ezMiniSAT();
|
virtual ~ezMiniSAT();
|
||||||
|
|
|
@ -38,6 +38,9 @@ ezSAT::ezSAT()
|
||||||
cnfConsumed = false;
|
cnfConsumed = false;
|
||||||
cnfVariableCount = 0;
|
cnfVariableCount = 0;
|
||||||
cnfClausesCount = 0;
|
cnfClausesCount = 0;
|
||||||
|
|
||||||
|
solverTimeout = 0;
|
||||||
|
solverTimoutStatus = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ezSAT::~ezSAT()
|
ezSAT::~ezSAT()
|
||||||
|
|
|
@ -69,6 +69,9 @@ private:
|
||||||
int bind_cnf_or(const std::vector<int> &args);
|
int bind_cnf_or(const std::vector<int> &args);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
int solverTimeout;
|
||||||
|
bool solverTimoutStatus;
|
||||||
|
|
||||||
ezSAT();
|
ezSAT();
|
||||||
virtual ~ezSAT();
|
virtual ~ezSAT();
|
||||||
|
|
||||||
|
@ -130,6 +133,14 @@ public:
|
||||||
return solver(modelExpressions, modelValues, assumptions);
|
return solver(modelExpressions, modelValues, assumptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setSolverTimeout(int newTimeoutSeconds) {
|
||||||
|
solverTimeout = newTimeoutSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getSolverTimoutStatus() {
|
||||||
|
return solverTimoutStatus;
|
||||||
|
}
|
||||||
|
|
||||||
// manage CNF (usually only accessed by SAT solvers)
|
// manage CNF (usually only accessed by SAT solvers)
|
||||||
|
|
||||||
virtual void clear();
|
virtual void clear();
|
||||||
|
|
|
@ -52,12 +52,15 @@ struct SatHelper
|
||||||
std::vector<std::string> shows;
|
std::vector<std::string> shows;
|
||||||
SigPool show_signal_pool;
|
SigPool show_signal_pool;
|
||||||
SigSet<RTLIL::Cell*> show_drivers;
|
SigSet<RTLIL::Cell*> show_drivers;
|
||||||
int max_timestep;
|
int max_timestep, timeout;
|
||||||
|
bool gotTimeout;
|
||||||
|
|
||||||
SatHelper(RTLIL::Design *design, RTLIL::Module *module) :
|
SatHelper(RTLIL::Design *design, RTLIL::Module *module) :
|
||||||
design(design), module(module), sigmap(module), ct(design), satgen(&ez, design, &sigmap)
|
design(design), module(module), sigmap(module), ct(design), satgen(&ez, design, &sigmap)
|
||||||
{
|
{
|
||||||
max_timestep = -1;
|
max_timestep = -1;
|
||||||
|
timeout = 0;
|
||||||
|
gotTimeout = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup(int timestep = -1)
|
void setup(int timestep = -1)
|
||||||
|
@ -190,12 +193,22 @@ struct SatHelper
|
||||||
|
|
||||||
bool solve(const std::vector<int> &assumptions)
|
bool solve(const std::vector<int> &assumptions)
|
||||||
{
|
{
|
||||||
return ez.solve(modelExpressions, modelValues, assumptions);
|
log_assert(gotTimeout == false);
|
||||||
|
ez.setSolverTimeout(timeout);
|
||||||
|
bool success = ez.solve(modelExpressions, modelValues, assumptions);
|
||||||
|
if (ez.getSolverTimoutStatus())
|
||||||
|
gotTimeout = true;
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool solve(int a = 0, int b = 0, int c = 0, int d = 0, int e = 0, int f = 0)
|
bool solve(int a = 0, int b = 0, int c = 0, int d = 0, int e = 0, int f = 0)
|
||||||
{
|
{
|
||||||
return ez.solve(modelExpressions, modelValues, a, b, c, d, e, f);
|
log_assert(gotTimeout == false);
|
||||||
|
ez.setSolverTimeout(timeout);
|
||||||
|
bool success = ez.solve(modelExpressions, modelValues, a, b, c, d, e, f);
|
||||||
|
if (ez.getSolverTimoutStatus())
|
||||||
|
gotTimeout = true;
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ModelBlockInfo {
|
struct ModelBlockInfo {
|
||||||
|
@ -380,6 +393,17 @@ static void print_proof_failed()
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_timeout()
|
||||||
|
{
|
||||||
|
log("\n");
|
||||||
|
log(" _____ _ _ _____ ____ _ _____\n");
|
||||||
|
log(" /__ __\\/ \\/ \\__/|/ __// _ \\/ \\ /\\/__ __\\\n");
|
||||||
|
log(" / \\ | || |\\/||| \\ | / \\|| | || / \\\n");
|
||||||
|
log(" | | | || | ||| /_ | \\_/|| \\_/| | |\n");
|
||||||
|
log(" \\_/ \\_/\\_/ \\|\\____\\\\____/\\____/ \\_/\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
|
||||||
static void print_qed()
|
static void print_qed()
|
||||||
{
|
{
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -442,9 +466,15 @@ struct SatPass : public Pass {
|
||||||
log(" -maxsteps <N>\n");
|
log(" -maxsteps <N>\n");
|
||||||
log(" Set a maximum length for the induction.\n");
|
log(" Set a maximum length for the induction.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -timeout <N>\n");
|
||||||
|
log(" Maximum number of seconds a single SAT instance may take.\n");
|
||||||
|
log("\n");
|
||||||
log(" -verify\n");
|
log(" -verify\n");
|
||||||
log(" Return an error and stop the synthesis script if the proof fails.\n");
|
log(" Return an error and stop the synthesis script if the proof fails.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -verify-no-timeout\n");
|
||||||
|
log(" Like -verify but do not return an error for timeouts.\n");
|
||||||
|
log("\n");
|
||||||
}
|
}
|
||||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||||
{
|
{
|
||||||
|
@ -452,8 +482,8 @@ struct SatPass : public Pass {
|
||||||
std::map<int, std::vector<std::pair<std::string, std::string>>> sets_at;
|
std::map<int, std::vector<std::pair<std::string, std::string>>> sets_at;
|
||||||
std::map<int, std::vector<std::string>> unsets_at;
|
std::map<int, std::vector<std::string>> unsets_at;
|
||||||
std::vector<std::string> shows;
|
std::vector<std::string> shows;
|
||||||
int loopcount = 0, seq_len = 0, maxsteps = 0;
|
int loopcount = 0, seq_len = 0, maxsteps = 0, timeout = 0;
|
||||||
bool verify = false;
|
bool verify = false, fail_on_timeout = false;
|
||||||
|
|
||||||
log_header("Executing SAT pass (solving SAT problems in the circuit).\n");
|
log_header("Executing SAT pass (solving SAT problems in the circuit).\n");
|
||||||
|
|
||||||
|
@ -464,9 +494,18 @@ struct SatPass : public Pass {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-verify") {
|
if (args[argidx] == "-verify") {
|
||||||
|
fail_on_timeout = true;
|
||||||
verify = true;
|
verify = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-verify-no-timeout") {
|
||||||
|
verify = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[argidx] == "-timeout" && argidx+1 < args.size()) {
|
||||||
|
timeout = atoi(args[++argidx].c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (args[argidx] == "-max" && argidx+1 < args.size()) {
|
if (args[argidx] == "-max" && argidx+1 < args.size()) {
|
||||||
loopcount = atoi(args[++argidx].c_str());
|
loopcount = atoi(args[++argidx].c_str());
|
||||||
continue;
|
continue;
|
||||||
|
@ -539,6 +578,7 @@ struct SatPass : public Pass {
|
||||||
basecase.sets_at = sets_at;
|
basecase.sets_at = sets_at;
|
||||||
basecase.unsets_at = unsets_at;
|
basecase.unsets_at = unsets_at;
|
||||||
basecase.shows = shows;
|
basecase.shows = shows;
|
||||||
|
basecase.timeout = timeout;
|
||||||
|
|
||||||
for (int timestep = 1; timestep <= seq_len; timestep++)
|
for (int timestep = 1; timestep <= seq_len; timestep++)
|
||||||
basecase.setup(timestep);
|
basecase.setup(timestep);
|
||||||
|
@ -546,6 +586,7 @@ struct SatPass : public Pass {
|
||||||
inductstep.sets = sets;
|
inductstep.sets = sets;
|
||||||
inductstep.prove = prove;
|
inductstep.prove = prove;
|
||||||
inductstep.shows = shows;
|
inductstep.shows = shows;
|
||||||
|
inductstep.timeout = timeout;
|
||||||
|
|
||||||
inductstep.setup(1);
|
inductstep.setup(1);
|
||||||
inductstep.ez.assume(inductstep.setup_proof(1));
|
inductstep.ez.assume(inductstep.setup_proof(1));
|
||||||
|
@ -573,6 +614,9 @@ struct SatPass : public Pass {
|
||||||
goto tip_failed;
|
goto tip_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (basecase.gotTimeout)
|
||||||
|
goto timeout;
|
||||||
|
|
||||||
log("Base case for induction length %d proven.\n", inductlen);
|
log("Base case for induction length %d proven.\n", inductlen);
|
||||||
basecase.ez.assume(property);
|
basecase.ez.assume(property);
|
||||||
|
|
||||||
|
@ -589,6 +633,8 @@ struct SatPass : public Pass {
|
||||||
inductstep.ez.numCnfVariables(), inductstep.ez.numCnfClauses());
|
inductstep.ez.numCnfVariables(), inductstep.ez.numCnfClauses());
|
||||||
|
|
||||||
if (!inductstep.solve(inductstep.ez.NOT(property))) {
|
if (!inductstep.solve(inductstep.ez.NOT(property))) {
|
||||||
|
if (inductstep.gotTimeout)
|
||||||
|
goto timeout;
|
||||||
log("Induction step proven: SUCCESS!\n");
|
log("Induction step proven: SUCCESS!\n");
|
||||||
print_qed();
|
print_qed();
|
||||||
goto tip_success;
|
goto tip_success;
|
||||||
|
@ -622,6 +668,7 @@ struct SatPass : public Pass {
|
||||||
sathelper.sets_at = sets_at;
|
sathelper.sets_at = sets_at;
|
||||||
sathelper.unsets_at = unsets_at;
|
sathelper.unsets_at = unsets_at;
|
||||||
sathelper.shows = shows;
|
sathelper.shows = shows;
|
||||||
|
sathelper.timeout = timeout;
|
||||||
|
|
||||||
if (seq_len == 0) {
|
if (seq_len == 0) {
|
||||||
sathelper.setup();
|
sathelper.setup();
|
||||||
|
@ -668,6 +715,8 @@ struct SatPass : public Pass {
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (sathelper.gotTimeout)
|
||||||
|
goto timeout;
|
||||||
if (did_rerun)
|
if (did_rerun)
|
||||||
log("SAT solving finished - no more models found.\n");
|
log("SAT solving finished - no more models found.\n");
|
||||||
else if (prove.size() == 0)
|
else if (prove.size() == 0)
|
||||||
|
@ -678,6 +727,14 @@ struct SatPass : public Pass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (0) {
|
||||||
|
timeout:
|
||||||
|
log("Interrupted SAT solver: TIMEOUT!\n");
|
||||||
|
print_timeout();
|
||||||
|
if (fail_on_timeout)
|
||||||
|
log_error("Called with -verify and proof did time out!\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} SatPass;
|
} SatPass;
|
||||||
|
|
||||||
|
|
|
@ -51,8 +51,8 @@ done
|
||||||
{
|
{
|
||||||
echo "read_ilang ${job}_top_nomap.il"
|
echo "read_ilang ${job}_top_nomap.il"
|
||||||
echo "read_ilang ${job}_top_techmap.il"
|
echo "read_ilang ${job}_top_techmap.il"
|
||||||
echo "sat -verify -show a,b,y_rtl,y_xst -prove y_rtl y_xst ${job}_top_nomap"
|
echo "sat -timeout 60 -verify-no-timeout -show a,b,y_rtl,y_xst -prove y_rtl y_xst ${job}_top_nomap"
|
||||||
echo "sat -verify -show a,b,y_rtl,y_xst -prove y_rtl y_xst ${job}_top_techmap"
|
echo "sat -timeout 60 -verify-no-timeout -show a,b,y_rtl,y_xst -prove y_rtl y_xst ${job}_top_techmap"
|
||||||
if [[ $job != expression_* ]]; then
|
if [[ $job != expression_* ]]; then
|
||||||
echo "eval -brute_force_equiv_checker ${job}_rtl_nomap ${job}_xst_nomap"
|
echo "eval -brute_force_equiv_checker ${job}_rtl_nomap ${job}_xst_nomap"
|
||||||
echo "eval -brute_force_equiv_checker ${job}_rtl_techmap ${job}_xst_techmap"
|
echo "eval -brute_force_equiv_checker ${job}_rtl_techmap ${job}_xst_techmap"
|
||||||
|
|
Loading…
Reference in New Issue