GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/main/command_executor.cpp Lines: 71 96 74.0 %
Date: 2021-09-07 Branches: 163 364 44.8 %

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
8780
CommandExecutor::CommandExecutor(std::unique_ptr<api::Solver>& solver)
52
    : d_solver(solver),
53
8780
      d_symman(new SymbolManager(d_solver.get())),
54
17560
      d_result()
55
{
56
8780
}
57
17560
CommandExecutor::~CommandExecutor()
58
{
59
17560
}
60
61
6160
void CommandExecutor::storeOptionsAsOriginal()
62
{
63
6160
  d_solver->d_originalOptions->copyValues(d_solver->d_smtEngine->getOptions());
64
6160
}
65
66
6140
void CommandExecutor::printStatistics(std::ostream& out) const
67
{
68
6140
  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
6140
}
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
303387
bool CommandExecutor::doCommand(Command* cmd)
89
{
90
303387
  if (d_solver->getOptionInfo("parse-only").boolValue())
91
  {
92
    return true;
93
  }
94
95
303387
  CommandSequence *seq = dynamic_cast<CommandSequence*>(cmd);
96
303387
  if(seq != nullptr) {
97
    // assume no error
98
4971
    bool status = true;
99
100
12749
    for (CommandSequence::iterator subcmd = seq->begin();
101
12749
         status && subcmd != seq->end();
102
         ++subcmd)
103
    {
104
7778
      status = doCommand(*subcmd);
105
    }
106
107
4971
    return status;
108
  } else {
109
298416
    if (d_solver->getOptionInfo("verbosity").intValue() > 2)
110
    {
111
11
      d_solver->getDriverOptions().out() << "Invoking: " << *cmd << std::endl;
112
    }
113
114
298416
    return doCommandSingleton(cmd);
115
  }
116
}
117
118
void CommandExecutor::reset()
119
{
120
  printStatistics(d_solver->getDriverOptions().err());
121
  Command::resetSolver(d_solver.get());
122
}
123
124
298444
bool CommandExecutor::doCommandSingleton(Command* cmd)
125
{
126
596888
  bool status = solverInvoke(
127
895332
      d_solver.get(), d_symman.get(), cmd, d_solver->getDriverOptions().out());
128
129
596888
  api::Result res;
130
298444
  const CheckSatCommand* cs = dynamic_cast<const CheckSatCommand*>(cmd);
131
298444
  if(cs != nullptr) {
132
9225
    d_result = res = cs->getResult();
133
  }
134
  const CheckSatAssumingCommand* csa =
135
298444
      dynamic_cast<const CheckSatAssumingCommand*>(cmd);
136
298444
  if (csa != nullptr)
137
  {
138
992
    d_result = res = csa->getResult();
139
  }
140
298444
  const QueryCommand* q = dynamic_cast<const QueryCommand*>(cmd);
141
298444
  if(q != nullptr) {
142
609
    d_result = res = q->getResult();
143
  }
144
145
298444
  bool isResultUnsat = res.isUnsat() || res.isEntailed();
146
298444
  bool isResultSat = res.isSat() || res.isNotEntailed();
147
148
  // dump the model/proof/unsat core if option is set
149
298444
  if (status) {
150
596812
    std::vector<std::unique_ptr<Command> > getterCommands;
151
895218
    if (d_solver->getOptionInfo("dump-models").boolValue()
152
895228
        && (isResultSat
153
34
            || (res.isSatUnknown()
154
                && res.getUnknownExplanation() == api::Result::INCOMPLETE)))
155
    {
156
10
      getterCommands.emplace_back(new GetModelCommand());
157
    }
158
298406
    if (d_solver->getOptionInfo("dump-proofs").boolValue() && isResultUnsat)
159
    {
160
      getterCommands.emplace_back(new GetProofCommand());
161
    }
162
163
895218
    if ((d_solver->getOptionInfo("dump-instantiations").boolValue()
164
596665
         || d_solver->getOptionInfo("dump-instantiations-debug").boolValue())
165
895365
        && GetInstantiationsCommand::isEnabled(d_solver.get(), res))
166
    {
167
15
      getterCommands.emplace_back(new GetInstantiationsCommand());
168
    }
169
170
895218
    if ((d_solver->getOptionInfo("dump-unsat-cores").boolValue()
171
596803
         || d_solver->getOptionInfo("dump-unsat-cores-full").boolValue())
172
895242
        && isResultUnsat)
173
    {
174
3
      getterCommands.emplace_back(new GetUnsatCoreCommand());
175
    }
176
177
298406
    if (!getterCommands.empty()) {
178
      // set no time limit during dumping if applicable
179
28
      if (d_solver->getOptionInfo("force-no-limit-cpu-while-dump").boolValue())
180
      {
181
        setNoLimitCPU();
182
      }
183
56
      for (const auto& getterCommand : getterCommands) {
184
28
        status = doCommandSingleton(getterCommand.get());
185
28
        if (!status)
186
        {
187
          break;
188
        }
189
      }
190
    }
191
  }
192
596888
  return status;
193
}
194
195
298444
bool solverInvoke(api::Solver* solver,
196
                  SymbolManager* sm,
197
                  Command* cmd,
198
                  std::ostream& out)
199
{
200
298444
  cmd->invoke(solver, sm, out);
201
  // ignore the error if the command-verbosity is 0 for this command
202
  std::string commandName =
203
596888
      std::string("command-verbosity:") + cmd->getCommandName();
204
298444
  if (solver->getOption(commandName) == "0")
205
  {
206
    return true;
207
  }
208
298444
  return !cmd->fail();
209
}
210
211
6140
void CommandExecutor::flushOutputStreams() {
212
6140
  printStatistics(d_solver->getDriverOptions().err());
213
214
  // make sure out and err streams are flushed too
215
6140
  d_solver->getDriverOptions().out() << std::flush;
216
6140
  d_solver->getDriverOptions().err() << std::flush;
217
6140
}
218
219
}  // namespace main
220
29481
}  // namespace cvc5