GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/main/command_executor.cpp Lines: 76 102 74.5 %
Date: 2021-08-17 Branches: 108 216 50.0 %

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 "options/base_options.h"
30
#include "options/main_options.h"
31
#include "smt/command.h"
32
33
namespace cvc5 {
34
namespace main {
35
36
// Function to cancel any (externally-imposed) limit on CPU time.
37
// This is used for competitions while a solution (proof or model)
38
// is being dumped (so that we don't give "sat" or "unsat" then get
39
// interrupted partway through outputting a proof!).
40
void setNoLimitCPU() {
41
  // Windows doesn't have these things, just ignore
42
#ifndef __WIN32__
43
  struct rlimit rlc;
44
  int st = getrlimit(RLIMIT_CPU, &rlc);
45
  if(st == 0) {
46
    rlc.rlim_cur = rlc.rlim_max;
47
    setrlimit(RLIMIT_CPU, &rlc);
48
  }
49
#endif /* ! __WIN32__ */
50
}
51
52
6130
CommandExecutor::CommandExecutor(const Options& options)
53
6130
    : d_solver(new api::Solver(&options)),
54
6130
      d_symman(new SymbolManager(d_solver.get())),
55
18390
      d_result()
56
{
57
6130
}
58
18390
CommandExecutor::~CommandExecutor()
59
{
60
  // ensure that symbol manager is destroyed before solver
61
6130
  d_symman.reset(nullptr);
62
6130
  d_solver.reset(nullptr);
63
12260
}
64
65
6110
void CommandExecutor::printStatistics(std::ostream& out) const
66
{
67
6110
  const auto& baseopts = d_solver->getOptions().base;
68
6110
  if (baseopts.statistics)
69
  {
70
    const auto& stats = d_solver->getStatistics();
71
    auto it = stats.begin(baseopts.statisticsExpert, baseopts.statisticsAll);
72
    for (; it != stats.end(); ++it)
73
    {
74
      out << it->first << " = " << it->second << std::endl;
75
    }
76
  }
77
6110
}
78
79
void CommandExecutor::printStatisticsSafe(int fd) const
80
{
81
  if (d_solver->getOptions().base.statistics)
82
  {
83
    d_solver->printStatisticsSafe(fd);
84
  }
85
}
86
87
303840
bool CommandExecutor::doCommand(Command* cmd)
88
{
89
303840
  if (d_solver->getOptions().base.parseOnly)
90
  {
91
    return true;
92
  }
93
94
303840
  CommandSequence *seq = dynamic_cast<CommandSequence*>(cmd);
95
303840
  if(seq != nullptr) {
96
    // assume no error
97
4970
    bool status = true;
98
99
12747
    for (CommandSequence::iterator subcmd = seq->begin();
100
12747
         status && subcmd != seq->end();
101
         ++subcmd)
102
    {
103
7777
      status = doCommand(*subcmd);
104
    }
105
106
4970
    return status;
107
  } else {
108
298870
    if (d_solver->getOptions().base.verbosity > 2)
109
    {
110
11
      *d_solver->getOptions().base.out << "Invoking: " << *cmd << std::endl;
111
    }
112
113
298870
    return doCommandSingleton(cmd);
114
  }
115
}
116
117
void CommandExecutor::reset()
118
{
119
  printStatistics(*d_solver->getOptions().base.err);
120
121
  Command::resetSolver(d_solver.get());
122
}
123
124
298898
bool CommandExecutor::doCommandSingleton(Command* cmd)
125
{
126
298898
  bool status = true;
127
298898
  if (d_solver->getOptions().base.verbosity >= -1)
128
  {
129
298898
    status = solverInvoke(
130
298898
        d_solver.get(), d_symman.get(), cmd, d_solver->getOptions().base.out);
131
  }
132
  else
133
  {
134
    status = solverInvoke(d_solver.get(), d_symman.get(), cmd, nullptr);
135
  }
136
137
597796
  api::Result res;
138
298898
  const CheckSatCommand* cs = dynamic_cast<const CheckSatCommand*>(cmd);
139
298898
  if(cs != nullptr) {
140
9199
    d_result = res = cs->getResult();
141
  }
142
  const CheckSatAssumingCommand* csa =
143
298898
      dynamic_cast<const CheckSatAssumingCommand*>(cmd);
144
298898
  if (csa != nullptr)
145
  {
146
991
    d_result = res = csa->getResult();
147
  }
148
298898
  const QueryCommand* q = dynamic_cast<const QueryCommand*>(cmd);
149
298898
  if(q != nullptr) {
150
608
    d_result = res = q->getResult();
151
  }
152
153
298898
  bool isResultUnsat = res.isUnsat() || res.isEntailed();
154
155
  // dump the model/proof/unsat core if option is set
156
298898
  if (status) {
157
597720
    std::vector<std::unique_ptr<Command> > getterCommands;
158
597720
    if (d_solver->getOptions().driver.dumpModels
159
298870
        && (res.isSat()
160
34
            || (res.isSatUnknown()
161
                && res.getUnknownExplanation() == api::Result::INCOMPLETE)))
162
    {
163
10
      getterCommands.emplace_back(new GetModelCommand());
164
    }
165
298860
    if (d_solver->getOptions().driver.dumpProofs && isResultUnsat)
166
    {
167
      getterCommands.emplace_back(new GetProofCommand());
168
    }
169
170
597720
    if ((d_solver->getOptions().driver.dumpInstantiations
171
298707
         || d_solver->getOptions().driver.dumpInstantiationsDebug)
172
299013
        && GetInstantiationsCommand::isEnabled(d_solver.get(), res))
173
    {
174
15
      getterCommands.emplace_back(new GetInstantiationsCommand());
175
    }
176
177
597720
    if ((d_solver->getOptions().driver.dumpUnsatCores
178
298851
         || d_solver->getOptions().driver.dumpUnsatCoresFull)
179
298884
        && isResultUnsat)
180
    {
181
3
      getterCommands.emplace_back(new GetUnsatCoreCommand());
182
    }
183
184
298860
    if (!getterCommands.empty()) {
185
      // set no time limit during dumping if applicable
186
28
      if (d_solver->getOptions().driver.forceNoLimitCpuWhileDump)
187
      {
188
        setNoLimitCPU();
189
      }
190
56
      for (const auto& getterCommand : getterCommands) {
191
28
        status = doCommandSingleton(getterCommand.get());
192
28
        if (!status)
193
        {
194
          break;
195
        }
196
      }
197
    }
198
  }
199
597796
  return status;
200
}
201
202
298898
bool solverInvoke(api::Solver* solver,
203
                  SymbolManager* sm,
204
                  Command* cmd,
205
                  std::ostream* out)
206
{
207
298898
  if (out == NULL)
208
  {
209
    cmd->invoke(solver, sm);
210
  }
211
  else
212
  {
213
298898
    cmd->invoke(solver, sm, *out);
214
  }
215
  // ignore the error if the command-verbosity is 0 for this command
216
  std::string commandName =
217
597796
      std::string("command-verbosity:") + cmd->getCommandName();
218
298898
  if (solver->getOption(commandName) == "0")
219
  {
220
    return true;
221
  }
222
298898
  return !cmd->fail();
223
}
224
225
6110
void CommandExecutor::flushOutputStreams() {
226
6110
  printStatistics(*d_solver->getOptions().base.err);
227
228
  // make sure out and err streams are flushed too
229
230
6110
  if (d_solver->getOptions().base.out != nullptr)
231
  {
232
6110
    *d_solver->getOptions().base.out << std::flush;
233
  }
234
6110
  if (d_solver->getOptions().base.err != nullptr)
235
  {
236
6110
    *d_solver->getOptions().base.err << std::flush;
237
  }
238
6110
}
239
240
}  // namespace main
241
29316
}  // namespace cvc5