GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/main/command_executor.cpp Lines: 76 102 74.5 %
Date: 2021-09-15 Branches: 178 412 43.2 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Kshitij Bansal, Andrew Reynolds, Morgan Deters
4
 *
5
 * This file is part of the cvc5 project.
6
 *
7
 * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8
 * in the top-level source directory and their institutional affiliations.
9
 * All rights reserved.  See the file COPYING in the top-level source
10
 * directory for licensing information.
11
 * ****************************************************************************
12
 *
13
 * An additional layer between commands and invoking them.
14
 */
15
16
#include "main/command_executor.h"
17
18
#ifndef __WIN32__
19
#  include <sys/resource.h>
20
#endif /* ! __WIN32__ */
21
22
#include <iomanip>
23
#include <iostream>
24
#include <memory>
25
#include <string>
26
#include <vector>
27
28
#include "main/main.h"
29
#include "smt/command.h"
30
#include "smt/smt_engine.h"
31
32
namespace cvc5 {
33
namespace main {
34
35
// Function to cancel any (externally-imposed) limit on CPU time.
36
// This is used for competitions while a solution (proof or model)
37
// is being dumped (so that we don't give "sat" or "unsat" then get
38
// interrupted partway through outputting a proof!).
39
void setNoLimitCPU() {
40
  // Windows doesn't have these things, just ignore
41
#ifndef __WIN32__
42
  struct rlimit rlc;
43
  int st = getrlimit(RLIMIT_CPU, &rlc);
44
  if(st == 0) {
45
    rlc.rlim_cur = rlc.rlim_max;
46
    setrlimit(RLIMIT_CPU, &rlc);
47
  }
48
#endif /* ! __WIN32__ */
49
}
50
51
8800
CommandExecutor::CommandExecutor(std::unique_ptr<api::Solver>& solver)
52
    : d_solver(solver),
53
8800
      d_symman(new SymbolManager(d_solver.get())),
54
17600
      d_result()
55
{
56
8800
}
57
17600
CommandExecutor::~CommandExecutor()
58
{
59
17600
}
60
61
6173
void CommandExecutor::storeOptionsAsOriginal()
62
{
63
6173
  d_solver->d_originalOptions->copyValues(d_solver->d_smtEngine->getOptions());
64
6173
}
65
66
6153
void CommandExecutor::printStatistics(std::ostream& out) const
67
{
68
6153
  if (d_solver->getOptionInfo("stats").boolValue())
69
  {
70
    const auto& stats = d_solver->getStatistics();
71
    auto it = stats.begin(d_solver->getOptionInfo("stats-expert").boolValue(),
72
                          d_solver->getOptionInfo("stats-all").boolValue());
73
    for (; it != stats.end(); ++it)
74
    {
75
      out << it->first << " = " << it->second << std::endl;
76
    }
77
  }
78
6153
}
79
80
void CommandExecutor::printStatisticsSafe(int fd) const
81
{
82
  if (d_solver->getOptionInfo("stats").boolValue())
83
  {
84
    d_solver->printStatisticsSafe(fd);
85
  }
86
}
87
88
303559
bool CommandExecutor::doCommand(Command* cmd)
89
{
90
303559
  CommandSequence *seq = dynamic_cast<CommandSequence*>(cmd);
91
303559
  if(seq != nullptr) {
92
    // assume no error
93
4971
    bool status = true;
94
95
12749
    for (CommandSequence::iterator subcmd = seq->begin();
96
12749
         status && subcmd != seq->end();
97
         ++subcmd)
98
    {
99
7778
      status = doCommand(*subcmd);
100
    }
101
102
4971
    return status;
103
  } else {
104
298588
    if (d_solver->getOptionInfo("verbosity").intValue() > 2)
105
    {
106
11
      d_solver->getDriverOptions().out() << "Invoking: " << *cmd << std::endl;
107
    }
108
109
298588
    return doCommandSingleton(cmd);
110
  }
111
}
112
113
void CommandExecutor::reset()
114
{
115
  printStatistics(d_solver->getDriverOptions().err());
116
  Command::resetSolver(d_solver.get());
117
}
118
119
298616
bool CommandExecutor::doCommandSingleton(Command* cmd)
120
{
121
597232
  bool status = solverInvoke(
122
895848
      d_solver.get(), d_symman.get(), cmd, d_solver->getDriverOptions().out());
123
124
597232
  api::Result res;
125
298616
  const CheckSatCommand* cs = dynamic_cast<const CheckSatCommand*>(cmd);
126
298616
  if(cs != nullptr) {
127
9234
    d_result = res = cs->getResult();
128
  }
129
  const CheckSatAssumingCommand* csa =
130
298616
      dynamic_cast<const CheckSatAssumingCommand*>(cmd);
131
298616
  if (csa != nullptr)
132
  {
133
994
    d_result = res = csa->getResult();
134
  }
135
298616
  const QueryCommand* q = dynamic_cast<const QueryCommand*>(cmd);
136
298616
  if(q != nullptr) {
137
609
    d_result = res = q->getResult();
138
  }
139
140
298616
  bool isResultUnsat = res.isUnsat() || res.isEntailed();
141
298616
  bool isResultSat = res.isSat() || res.isNotEntailed();
142
143
  // dump the model/proof/unsat core if option is set
144
298616
  if (status) {
145
597156
    std::vector<std::unique_ptr<Command> > getterCommands;
146
895734
    if (d_solver->getOptionInfo("dump-models").boolValue()
147
895744
        && (isResultSat
148
34
            || (res.isSatUnknown()
149
                && res.getUnknownExplanation() == api::Result::INCOMPLETE)))
150
    {
151
10
      getterCommands.emplace_back(new GetModelCommand());
152
    }
153
298578
    if (d_solver->getOptionInfo("dump-proofs").boolValue() && isResultUnsat)
154
    {
155
      getterCommands.emplace_back(new GetProofCommand());
156
    }
157
158
895734
    if ((d_solver->getOptionInfo("dump-instantiations").boolValue()
159
597009
         || d_solver->getOptionInfo("dump-instantiations-debug").boolValue())
160
895881
        && GetInstantiationsCommand::isEnabled(d_solver.get(), res))
161
    {
162
15
      getterCommands.emplace_back(new GetInstantiationsCommand());
163
    }
164
165
895734
    if ((d_solver->getOptionInfo("dump-unsat-cores").boolValue()
166
597147
         || d_solver->getOptionInfo("dump-unsat-cores-full").boolValue())
167
895758
        && isResultUnsat)
168
    {
169
3
      getterCommands.emplace_back(new GetUnsatCoreCommand());
170
    }
171
172
895734
    if (d_solver->getOptionInfo("dump-difficulty").boolValue()
173
895734
        && (isResultUnsat || isResultSat || res.isSatUnknown()))
174
    {
175
      getterCommands.emplace_back(new GetDifficultyCommand());
176
    }
177
178
298578
    if (!getterCommands.empty()) {
179
      // set no time limit during dumping if applicable
180
28
      if (d_solver->getOptionInfo("force-no-limit-cpu-while-dump").boolValue())
181
      {
182
        setNoLimitCPU();
183
      }
184
56
      for (const auto& getterCommand : getterCommands) {
185
28
        status = doCommandSingleton(getterCommand.get());
186
28
        if (!status)
187
        {
188
          break;
189
        }
190
      }
191
    }
192
  }
193
597232
  return status;
194
}
195
196
298616
bool solverInvoke(api::Solver* solver,
197
                  SymbolManager* sm,
198
                  Command* cmd,
199
                  std::ostream& out)
200
{
201
  // print output for -o raw-benchmark
202
298616
  if (solver->isOutputOn("raw-benchmark"))
203
  {
204
11
    std::ostream& ss = solver->getOutput("raw-benchmark");
205
11
    cmd->toStream(ss);
206
  }
207
208
298616
  if (solver->getOptionInfo("parse-only").boolValue())
209
  {
210
    return true;
211
  }
212
213
298616
  cmd->invoke(solver, sm, out);
214
  // ignore the error if the command-verbosity is 0 for this command
215
  std::string commandName =
216
597232
      std::string("command-verbosity:") + cmd->getCommandName();
217
298616
  if (solver->getOption(commandName) == "0")
218
  {
219
    return true;
220
  }
221
298616
  return !cmd->fail();
222
}
223
224
6153
void CommandExecutor::flushOutputStreams() {
225
6153
  printStatistics(d_solver->getDriverOptions().err());
226
227
  // make sure out and err streams are flushed too
228
6153
  d_solver->getDriverOptions().out() << std::flush;
229
6153
  d_solver->getDriverOptions().err() << std::flush;
230
6153
}
231
232
}  // namespace main
233
29556
}  // namespace cvc5