Files
fail/tools/compute-hops/main.cc
Horst Schirmeier b0e13b17c9 tools: abort at unknown cmdline parameters
This change makes all C++-based tools in tools/ abort when they
encounter an unknown commandline parameter (both option or
non-option).  This has already caused some confusion, as in some cases
unexpected behaviour can be the result.  For example, "prune-trace -t
mytrace.tc -d database" up to now ignored the "-t" parameter, took
"mytrace.tc" as the first non-option parameter (and ignored it); as no
option parameter may follow the non-option parameters, all other
options were ignored as well.

Change-Id: Ia0812a518c4760fa28ed54979c81f43fa7aa096e
2014-09-25 17:14:08 +02:00

319 lines
8.5 KiB
C++

// #include <cstdlib>
#include <fstream>
#include <iostream>
#include <cstring>
#include "../../src/core/util/smarthops/TraceReader.hpp"
#include "BasicAlgorithm.hpp"
#include "SmartAlgorithm.hpp"
#include "SimpleAlgorithm.hpp"
#include "ResultCollector.hpp"
#include "../../src/core/util/gzstream/gzstream.h"
#include "util/CommandLine.hpp"
#include "util/Logger.hpp"
#define STDOUT_CMD_STRING "-"
using namespace fail;
typedef enum {
ALGO_SIMPLE,
ALGO_SMART,
} algorithm_e;
bool g_use_weights;
bool g_use_watchpoints;
bool g_use_checkpoints;
unsigned int g_cp_thresh;
unsigned int g_cost_cp;
unsigned int g_rollback_thresh;
std::ofstream g_cp_ofstream;
Logger LOG("hop-calculator", false);
int main(int argc, char *argv[])
{
// Manually fill the command line option parser
CommandLine &cmd = CommandLine::Inst();
CommandLine::option_handle UNKNOWN = cmd.addOption("", "", Arg::None, "USAGE: compute-hops [options]");
CommandLine::option_handle HELP = cmd.addOption("h", "help", Arg::None, "-h,--help \tPrint usage and exit");
CommandLine::option_handle ALGORITHM =
cmd.addOption("a", "algorithm", Arg::Required,
"-a,--algorithm \tHop algorithm (\"simple\"/\"smart\", default: \"none\")");
CommandLine::option_handle OUTPUT_MODE =
cmd.addOption("m", "output-mode", Arg::Required,
"-m,--output-mode \tOutput mode (\"results\"/\"costs\"/\"statistics\", default: \"results\")");
CommandLine::option_handle TRACE_FILE =
cmd.addOption("i", "input-file", Arg::Required,
"-i,--input-file \tInput trace file path");
CommandLine::option_handle OUTPUT_FILE =
cmd.addOption("o", "output-file", Arg::Required,
"-o,--output-file \tOutput file, default: stdout");
CommandLine::option_handle OUTPUT_FILE_PROTOBUF =
cmd.addOption("b", "protobuf-output", Arg::None,
"-b,--protobuf-output \tOutput file will be created in protobuf (HopChain) format");
CommandLine::option_handle USE_COSTS =
cmd.addOption("c", "use-costs", Arg::None,
"-c,--use-costs \tUse hop costs for calculations of Smart-Hopping algorithm");
CommandLine::option_handle USE_WATCHPOINTS =
cmd.addOption("w", "use-watchpoints", Arg::None,
"-w,--use-watchpoints \tUse watchpoints as additional hop candidates");
CommandLine::option_handle USE_CHECKPOINTS =
cmd.addOption("", "use-checkpoints", Arg::None,
"--use-checkpoints \tUse checkpoints to cap costs in case of long hop chains");
CommandLine::option_handle CP_THRESH =
cmd.addOption("", "cp-costs-threshold", Arg::Required,
"--cp-costs-threshold \tIf costs of a hop-chain reach this threshold, a checkpoint will be created");
CommandLine::option_handle CP_COSTS =
cmd.addOption("", "cp-costs", Arg::Required,
"--cp-costs \tThe costs for reloading a checkpoint into the system");
CommandLine::option_handle CP_ROLLBACK_THRESH =
cmd.addOption("", "cp-rollback-threshold", Arg::Required,
"--cp-rollback-threshold \tMinial number of hops to roll back current solution beyond checkpoint. Must be smaller than ((cp_cost_thresh - cp_costs) / 2)");
CommandLine::option_handle CHECKPOINT_OUTPUT_FILE =
cmd.addOption("", "cp-output", Arg::Required,
"--cp-output \tCheckpoint output file");
for (int i = 1; i < argc; ++i) {
cmd.add_args(argv[i]);
}
if (!cmd.parse()) {
std::cerr << "Error parsing arguments." << std::endl;
return 1;
}
if (cmd[HELP] || cmd[UNKNOWN] || cmd.parser()->nonOptionsCount() > 0) {
for (option::Option* opt = cmd[UNKNOWN]; opt; opt = opt->next()) {
std::cerr << "Unknown option: " << opt->name << "\n";
}
for (int i = 0; i < cmd.parser()->nonOptionsCount(); ++i) {
std::cerr << "Unknown non-option: " << cmd.parser()->nonOption(i) << "\n";
}
cmd.printUsage();
if (cmd[HELP]) {
exit(0);
} else {
exit(1);
}
}
if (cmd[USE_CHECKPOINTS]) {
g_use_checkpoints = true;
} else {
g_use_checkpoints = false;
}
if (cmd[USE_WATCHPOINTS]) {
g_use_watchpoints = true;
} else {
g_use_watchpoints = false;
}
if (cmd[USE_COSTS]) {
g_use_weights = true;
} else {
g_use_weights = false;
}
algorithm_e algorithm;
if (cmd[ALGORITHM].count() > 0) {
std::string alg(cmd[ALGORITHM].first()->arg);
if (alg == "simple") {
algorithm = ALGO_SIMPLE;
} else if (alg == "smart") {
algorithm = ALGO_SMART;
} else {
exit(-1);
}
} else {
// default
algorithm = ALGO_SMART;
}
output_mode_e output_mode;
if (cmd[OUTPUT_MODE].count() > 0) {
std::string outp(cmd[OUTPUT_MODE].first()->arg);
if (outp == "results") {
output_mode = OUTPUT_RESULT;
} else if (outp == "costs") {
output_mode = OUTPUT_COSTS;
} else if (outp == "statistics") {
output_mode = OUTPUT_STATISTICS;
} else {
LOG << "Unkown output mode: " << outp << std::endl;
exit(-1);
}
} else {
// default
output_mode = OUTPUT_RESULT;
}
fail::TraceReader trace;
if (cmd[TRACE_FILE].count() > 0) {
const char *filename = cmd[TRACE_FILE].first()->arg;
if (!trace.openTraceFile(filename, 0)) {
LOG << "Unable to open and parse input trace file " << filename << std::endl;
return 1;
}
} else {
LOG << "Input trace file path not defined" << std::endl;
exit(-1);
}
std::ostream *outFile;
if (cmd[OUTPUT_FILE].count() > 0) {
std::string filename(cmd[OUTPUT_FILE].first()->arg);
if (filename.compare(STDOUT_CMD_STRING) == 0) {
outFile = &std::cout;
} else {
std::ofstream *of = new std::ofstream(filename.c_str());
if (!of->is_open()) {
LOG << "Unable to open output file " << filename << std::endl;
exit(-1);
}
outFile = of;
}
} else {
outFile = &std::cout;
}
if (cmd[OUTPUT_FILE_PROTOBUF] && outFile == &std::cout) {
LOG << "If protobuf output format is selected, output file must be defined" << std::endl;
exit(-1);
}
if (cmd[USE_COSTS] && !(algorithm == ALGO_SMART)) {
LOG << "Using costs for calculations is only possible with Smart-Hopping algorithm" << std::endl;
exit(-1);
}
if (cmd[CP_THRESH]) {
if (cmd[CP_THRESH].count() != 1) {
LOG << "Could not parse cp-costs-threshold" << std::endl;
exit(-1);
}
g_cp_thresh = strtoul(cmd[CP_THRESH].first()->arg, NULL, 0);
}
if (cmd[CP_COSTS]) {
if (cmd[CP_COSTS].count() != 1) {
LOG << "Could not parse cp-costs" << std::endl;
exit(-1);
}
g_cost_cp = strtoul(cmd[CP_COSTS].first()->arg, NULL, 0);
}
if (cmd[CP_ROLLBACK_THRESH]) {
if (cmd[CP_ROLLBACK_THRESH].count()!=1) {
LOG << "Could not parse cp-rollback-threshold" << std::endl;
exit(-1);
}
// if (strcmp(argv[9],"max")==0) {
// g_rollback_thresh = (g_cp_thresh - g_cost_cp - 5)/2;
// }
g_rollback_thresh = strtoul(cmd[CP_ROLLBACK_THRESH].first()->arg, NULL, 0);
}
if (cmd[USE_CHECKPOINTS] && !(cmd[CHECKPOINT_OUTPUT_FILE].count() > 0)) {
LOG << "If checkpointing is enabled, --cp-output must be defined" << std::endl;
exit(-1);
}
if (cmd[CHECKPOINT_OUTPUT_FILE].count() > 0) {
std::string filename(cmd[CHECKPOINT_OUTPUT_FILE].first()->arg);
g_cp_ofstream.open(filename.c_str());
if (!g_cp_ofstream.is_open()) {
LOG << "Unable to open cp_out_file " << filename << std::endl;
exit(-1);
}
}
if (cmd[USE_CHECKPOINTS] && (!cmd[CP_THRESH] ||
!cmd[CP_COSTS]|| !cmd[CP_ROLLBACK_THRESH])) {
LOG << "If using checkpointing is enabled, also cp-costs-threshold, "
"cp-costs and cp-rollback-threshold must be defined" << std::endl;
exit(-1);
}
if (!cmd[USE_CHECKPOINTS] && (cmd[CP_THRESH].count() ||
(cmd[CP_COSTS].count() > 0) || (cmd[CP_ROLLBACK_THRESH].count() > 0))) {
LOG << "If using checkpointing is disabled, cp-costs-threshold, "
"cp-costs and cp-rollback-threshold must not be defined" << std::endl;
exit(-1);
}
if (g_use_checkpoints && !(g_cp_thresh > g_cost_cp)) {
LOG << "cp_cost_thresh needs to be bigger than cp_costs" << std::endl;
exit(1);
}
if (g_use_checkpoints && !(g_rollback_thresh < ((g_cp_thresh - g_cost_cp) / 2))) {
LOG << "cp_rollback_hop_thresh needs to be smaller than "
"((cp_cost_thresh - cp_costs) / 2)" << std::endl;
exit(1);
}
ogzstream zipstream;
ResultCollector rc(*outFile, output_mode);
if (cmd[OUTPUT_FILE_PROTOBUF]) {
zipstream.open(cmd[OUTPUT_FILE].first()->arg);
rc.setProtoOStream(new ProtoOStream(&zipstream));
}
BasicAlgorithm *algo;
switch (algorithm) {
case ALGO_SMART:
algo = new SmartAlgorithm(&rc);
break;
case ALGO_SIMPLE:
algo = new SimpleAlgorithm(&rc);
break;
default:
break;
}
rc.startTimer();
algo->calculateAllHops(trace);
rc.stopTimer();
rc.finish();
// ToDo: close output file if not stdout
if (outFile != &std::cout) {
((std::ofstream*)outFile)->close();
delete (std::ofstream*)outFile;
}
if (g_use_checkpoints) {
g_cp_ofstream.close();
}
return 0;
}