another directory rename: failstar -> fail
"failstar" sounds like a name for a cruise liner from the 80s. As "*" isn't a desirable part of directory names, just name the whole thing "fail/", the core parts being stored in "fail/core/". Additionally fixing two build system dependency issues: - missing jobserver -> protomessages dependency - broken bochs -> fail dependency (add_custom_target DEPENDS only allows plain file dependencies ... cmake for the win) git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@956 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
31
core/experiments/checksum-oostubs/CMakeLists.txt
Normal file
31
core/experiments/checksum-oostubs/CMakeLists.txt
Normal file
@ -0,0 +1,31 @@
|
||||
set(EXPERIMENT_NAME checksum-oostubs)
|
||||
set(EXPERIMENT_TYPE CoolChecksumExperiment) # FIXME naming conflict
|
||||
configure_file(../instantiate-experiment.ah.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/instantiate-${EXPERIMENT_NAME}.ah @ONLY
|
||||
)
|
||||
|
||||
## Setup desired protobuf descriptions HERE ##
|
||||
set(MY_PROTOS
|
||||
checksum-oostubs.proto
|
||||
)
|
||||
|
||||
set(MY_CAMPAIGN_SRCS
|
||||
experiment.hpp
|
||||
experiment.cc
|
||||
campaign.hpp
|
||||
campaign.cc
|
||||
)
|
||||
|
||||
#### PROTOBUFS ####
|
||||
find_package(Protobuf REQUIRED)
|
||||
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
|
||||
|
||||
## Build library
|
||||
add_library(${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SRCS})
|
||||
|
||||
## This is the example's campaign server distributing experiment parameters
|
||||
add_executable(${EXPERIMENT_NAME}-server main.cc)
|
||||
target_link_libraries(${EXPERIMENT_NAME}-server ${EXPERIMENT_NAME} fail ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY})
|
||||
1
core/experiments/checksum-oostubs/MemoryMap.hpp
Symbolic link
1
core/experiments/checksum-oostubs/MemoryMap.hpp
Symbolic link
@ -0,0 +1 @@
|
||||
../../util/MemoryMap.hpp
|
||||
140
core/experiments/checksum-oostubs/campaign.cc
Normal file
140
core/experiments/checksum-oostubs/campaign.cc
Normal file
@ -0,0 +1,140 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "campaign.hpp"
|
||||
#include "experimentInfo.hpp"
|
||||
#include "controller/CampaignManager.hpp"
|
||||
#include "util/Logger.hpp"
|
||||
|
||||
using namespace fi;
|
||||
using std::endl;
|
||||
|
||||
char const * const results_csv = "chksumoostubs.csv";
|
||||
|
||||
//TODO: generate new values for the updated experiment
|
||||
const unsigned memoryMap[49][2] = {
|
||||
{0x109134, 4},
|
||||
{0x10913c, 4},
|
||||
{0x109184, 4},
|
||||
{0x1091cc, 1},
|
||||
{0x109238, 256},
|
||||
{0x109344, 4},
|
||||
{0x109350, 4},
|
||||
{0x109354, 4},
|
||||
{0x109368, 1},
|
||||
{0x109374, 4},
|
||||
{0x109388, 1},
|
||||
{0x109398, 4},
|
||||
{0x1093a0, 4},
|
||||
{0x1093b4, 4},
|
||||
{0x1093b8, 4},
|
||||
{0x1093c0, 4},
|
||||
{0x1093d0, 4},
|
||||
{0x1093dc, 4},
|
||||
{0x1093e0, 4},
|
||||
{0x1093e8, 1},
|
||||
{0x1093f0, 4},
|
||||
{0x1093f4, 4},
|
||||
{0x10a460, 4},
|
||||
{0x10a468, 4},
|
||||
{0x10a470, 4},
|
||||
{0x10a478, 4},
|
||||
{0x10a480, 4},
|
||||
{0x10a488, 4},
|
||||
{0x10a494, 4},
|
||||
{0x10a498, 4},
|
||||
{0x10a4a8, 4},
|
||||
{0x10a4ad, 1},
|
||||
{0x10a4b4, 4},
|
||||
{0x10a4b8, 4},
|
||||
{0x10a4c8, 4},
|
||||
{0x10a4cd, 1},
|
||||
{0x10a4d4, 4},
|
||||
{0x10a4d8, 4},
|
||||
{0x10a4e8, 4},
|
||||
{0x10a4ed, 1},
|
||||
{0x10a4f4, 4},
|
||||
{0x10a4f8, 4},
|
||||
{0x10a500, 4},
|
||||
{0x10d350, 4},
|
||||
{0x10d358, 4},
|
||||
{0x10d37c, 4},
|
||||
{0x10d384, 4},
|
||||
{0x10d3a8, 4},
|
||||
{0x10d3b0, 4},
|
||||
};
|
||||
|
||||
|
||||
|
||||
bool CoolChecksumCampaign::run()
|
||||
{
|
||||
Logger log("CoolChecksumCampaign");
|
||||
|
||||
ifstream test(results_csv);
|
||||
if (test.is_open()) {
|
||||
log << results_csv << " already exists" << endl;
|
||||
return false;
|
||||
}
|
||||
ofstream results(results_csv);
|
||||
if (!results.is_open()) {
|
||||
log << "failed to open " << results_csv << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
log << "startup" << endl;
|
||||
|
||||
unsigned count = 0;
|
||||
|
||||
for(int member = 0; member < 49; ++member){ //TODO: 49 -> constant
|
||||
for (int bit_offset = 0; bit_offset < (memoryMap[member][1])*8; ++bit_offset) {
|
||||
for (int instr_offset = 0; instr_offset < OOSTUBS_NUMINSTR; ++instr_offset) {
|
||||
CoolChecksumExperimentData *d = new CoolChecksumExperimentData;
|
||||
d->msg.set_instr_offset(instr_offset);
|
||||
d->msg.set_mem_addr(memoryMap[member][0]);
|
||||
d->msg.set_bit_offset(bit_offset);
|
||||
|
||||
fi::campaignmanager.addParam(d);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
for (int bit_offset = 0; bit_offset < COOL_ECC_OBJUNDERTEST_SIZE*8; ++bit_offset) {
|
||||
for (int instr_offset = 0; instr_offset < OOSTUBS_NUMINSTR; ++instr_offset) {
|
||||
CoolChecksumExperimentData *d = new CoolChecksumExperimentData;
|
||||
d->msg.set_instr_offset(instr_offset);
|
||||
d->msg.set_mem_addr(0x0);
|
||||
d->msg.set_bit_offset(bit_offset);
|
||||
|
||||
fi::campaignmanager.addParam(d);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
fi::campaignmanager.noMoreParameters();
|
||||
log << "done enqueueing parameter sets (" << count << ")." << endl;
|
||||
|
||||
// collect results
|
||||
CoolChecksumExperimentData *res;
|
||||
int rescount = 0;
|
||||
results << "injection_ip\tinstr_offset\tinjection_bit\tresulttype\tresultdata\terror_corrected\tdetails" << endl;
|
||||
while ((res = static_cast<CoolChecksumExperimentData *>(fi::campaignmanager.getDone()))) {
|
||||
rescount++;
|
||||
|
||||
results
|
||||
<< res->msg.injection_ip() << "\t"
|
||||
<< res->msg.instr_offset() << "\t"
|
||||
<< res->msg.mem_addr() << "\t"
|
||||
<< res->msg.bit_offset() << "\t"
|
||||
<< res->msg.resulttype() << "\t"
|
||||
<< res->msg.resultdata() << "\t"
|
||||
<< res->msg.error_corrected() << "\t"
|
||||
<< res->msg.details() << "\n";
|
||||
delete res;
|
||||
}
|
||||
log << "done. sent " << count << " received " << rescount << endl;
|
||||
results.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
20
core/experiments/checksum-oostubs/campaign.hpp
Normal file
20
core/experiments/checksum-oostubs/campaign.hpp
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef __COOLCAMPAIGN_HPP__
|
||||
#define __COOLCAMPAIGN_HPP__
|
||||
|
||||
#include "controller/Campaign.hpp"
|
||||
#include "controller/ExperimentData.hpp"
|
||||
#include "checksum-oostubs.pb.h"
|
||||
|
||||
class CoolChecksumExperimentData : public fi::ExperimentData {
|
||||
public:
|
||||
OOStuBSProtoMsg msg;
|
||||
CoolChecksumExperimentData() : fi::ExperimentData(&msg) {}
|
||||
};
|
||||
|
||||
|
||||
class CoolChecksumCampaign : public fi::Campaign {
|
||||
public:
|
||||
virtual bool run();
|
||||
};
|
||||
|
||||
#endif
|
||||
29
core/experiments/checksum-oostubs/checksum-oostubs.proto
Normal file
29
core/experiments/checksum-oostubs/checksum-oostubs.proto
Normal file
@ -0,0 +1,29 @@
|
||||
message OOStuBSProtoMsg {
|
||||
// parameters
|
||||
required int32 instr_offset = 1;
|
||||
required int32 mem_addr = 2;
|
||||
required int32 bit_offset = 3;
|
||||
|
||||
// results
|
||||
// make these optional to reduce overhead for server->client communication
|
||||
enum ResultType {
|
||||
CALCDONE = 1;
|
||||
TIMEOUT = 2;
|
||||
TRAP = 3;
|
||||
UNKNOWN = 4;
|
||||
}
|
||||
// instruction pointer where injection was done
|
||||
optional uint32 injection_ip = 4;
|
||||
// result type, see above
|
||||
optional ResultType resulttype = 5;
|
||||
// result data, depending on resulttype:
|
||||
// CALCDONE: resultdata = calculated value
|
||||
// TIMEOUT: resultdata = latest EIP
|
||||
// TRAP: resultdata = latest EIP
|
||||
// UNKNOWN: resultdata = latest EIP
|
||||
optional uint32 resultdata = 6;
|
||||
// did ECC correct the fault?
|
||||
optional int32 error_corrected = 7;
|
||||
// optional textual description of what happened
|
||||
optional string details = 8;
|
||||
}
|
||||
180
core/experiments/checksum-oostubs/experiment.cc
Normal file
180
core/experiments/checksum-oostubs/experiment.cc
Normal file
@ -0,0 +1,180 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "util/Logger.hpp"
|
||||
|
||||
#include "experiment.hpp"
|
||||
#include "experimentInfo.hpp"
|
||||
#include "campaign.hpp"
|
||||
|
||||
#include "SAL/SALConfig.hpp"
|
||||
#include "SAL/SALInst.hpp"
|
||||
#include "SAL/Memory.hpp"
|
||||
#include "SAL/bochs/BochsRegister.hpp"
|
||||
#include "controller/Event.hpp"
|
||||
|
||||
#include "checksum-oostubs.pb.h"
|
||||
|
||||
using std::endl;
|
||||
|
||||
bool CoolChecksumExperiment::run()
|
||||
{
|
||||
#if BX_SUPPORT_X86_64
|
||||
int targetreg = sal::RID_RDX;
|
||||
#else
|
||||
int targetreg = sal::RID_EDX;
|
||||
#endif
|
||||
Logger log("Checksum-OOStuBS", false);
|
||||
fi::BPEvent bp;
|
||||
|
||||
log << "startup" << endl;
|
||||
|
||||
#if 1
|
||||
fi::GuestEvent g;
|
||||
while (true) {
|
||||
sal::simulator.addEventAndWait(&g);
|
||||
std::cout << g.getData() << std::flush;
|
||||
}
|
||||
#elif 0
|
||||
// STEP 1: run until interesting function starts, and save state
|
||||
bp.setWatchInstructionPointer(OOSTUBS_FUNC_ENTRY);
|
||||
sal::simulator.addEventAndWait(&bp);
|
||||
log << "test function entry reached, saving state" << endl;
|
||||
log << "EIP = " << std::hex << bp.getTriggerInstructionPointer() << " or " << sal::simulator.getRegisterManager().getInstructionPointer() << endl;
|
||||
log << "error_corrected = " << std::dec << ((int)sal::simulator.getMemoryManager().getByte(OOSTUBS_ERROR_CORRECTED)) << endl;
|
||||
sal::simulator.save("checksum-oostubs.state");
|
||||
#elif 1
|
||||
// STEP 2: determine # instructions from start to end
|
||||
log << "restoring state" << endl;
|
||||
sal::simulator.restore("checksum-oostubs.state");
|
||||
log << "EIP = " << std::hex << sal::simulator.getRegisterManager().getInstructionPointer() << endl;
|
||||
|
||||
// make sure the timer interrupt doesn't disturb us
|
||||
//sal::simulator.deactivateTimer(0); // leave it on, explicitly
|
||||
|
||||
unsigned count;
|
||||
bp.setWatchInstructionPointer(fi::ANY_ADDR);
|
||||
for (count = 0; bp.getTriggerInstructionPointer() != OOSTUBS_FUNC_DONE; ++count) {
|
||||
//for (count = 0; count < OOSTUBS_NUMINSTR; ++count) { //TODO?
|
||||
sal::simulator.addEventAndWait(&bp);
|
||||
//log << "EIP = " << std::hex << sal::simulator.getRegisterManager().getInstructionPointer() << endl;
|
||||
}
|
||||
log << "experiment finished after " << count << " instructions" << endl;
|
||||
|
||||
unsigned char results[OOSTUBS_RESULTS_BYTES];
|
||||
for(int i=0; i<OOSTUBS_RESULTS_BYTES; ++i){
|
||||
results[i] = (unsigned)sal::simulator.getMemoryManager().getByte(OOSTUBS_RESULTS_ADDR + i);
|
||||
}
|
||||
for(int i=0; i<OOSTUBS_RESULTS_BYTES/4; ++i){
|
||||
log << "results[" << i << "]: " << std::hex << *(((unsigned*)results)+i) << endl;
|
||||
}
|
||||
|
||||
#elif 1
|
||||
// FIXME consider moving experiment repetition into Fail* or even the
|
||||
// SAL -- whether and how this is possible with the chosen backend is
|
||||
// backend specific
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
|
||||
// STEP 3: The actual experiment.
|
||||
log << "restoring state" << endl;
|
||||
sal::simulator.restore("coolecc.state");
|
||||
|
||||
log << "asking job server for experiment parameters" << endl;
|
||||
CoolChecksumExperimentData param;
|
||||
if (!m_jc.getParam(param)) {
|
||||
log << "Dying." << endl;
|
||||
// communicate that we were told to die
|
||||
sal::simulator.terminate(1);
|
||||
}
|
||||
int id = param.getWorkloadID();
|
||||
int instr_offset = param.msg.instr_offset();
|
||||
int bit_offset = param.msg.bit_offset();
|
||||
log << "job " << id << " instr " << instr_offset << " bit " << bit_offset << endl;
|
||||
|
||||
// FIXME could be improved (especially for backends supporting
|
||||
// breakpoints natively) by utilizing a previously recorded instruction
|
||||
// trace
|
||||
bp.setWatchInstructionPointer(fi::ANY_ADDR);
|
||||
for (int count = 0; count < instr_offset; ++count) {
|
||||
sal::simulator.addEventAndWait(&bp);
|
||||
}
|
||||
|
||||
// inject
|
||||
sal::guest_address_t inject_addr = COOL_ECC_OBJUNDERTEST + bit_offset / 8;
|
||||
sal::MemoryManager& mm = sal::simulator.getMemoryManager();
|
||||
sal::byte_t data = mm.getByte(inject_addr);
|
||||
sal::byte_t newdata = data ^ (1 << (bit_offset % 8));
|
||||
mm.setByte(inject_addr, newdata);
|
||||
// note at what IP we did it
|
||||
int32_t injection_ip = sal::simulator.getRegisterManager().getInstructionPointer();
|
||||
param.msg.set_injection_ip(injection_ip);
|
||||
log << "inject @ ip " << injection_ip
|
||||
<< " offset " << std::dec << (bit_offset / 8)
|
||||
<< " (bit " << (bit_offset % 8) << ") 0x"
|
||||
<< std::hex << ((int)data) << " -> 0x" << ((int)newdata) << endl;
|
||||
|
||||
// aftermath
|
||||
fi::BPEvent ev_done(COOL_ECC_CALCDONE);
|
||||
sal::simulator.addEvent(&ev_done);
|
||||
fi::BPEvent ev_timeout(fi::ANY_ADDR);
|
||||
ev_timeout.setCounter(COOL_ECC_NUMINSTR + 3000);
|
||||
sal::simulator.addEvent(&ev_timeout);
|
||||
fi::TrapEvent ev_trap(fi::ANY_TRAP);
|
||||
sal::simulator.addEvent(&ev_trap);
|
||||
|
||||
fi::BaseEvent* ev = sal::simulator.waitAny();
|
||||
if (ev == &ev_done) {
|
||||
int32_t data = sal::simulator.getRegisterManager().getSetOfType(sal::RT_GP).getRegister(targetreg)->getData();
|
||||
log << std::dec << "Result EDX = " << data << endl;
|
||||
param.msg.set_resulttype(CoolChecksumProtoMsg_ResultType_CALCDONE);
|
||||
param.msg.set_resultdata(data);
|
||||
} else if (ev == &ev_timeout) {
|
||||
log << std::dec << "Result TIMEOUT" << endl;
|
||||
param.msg.set_resulttype(CoolChecksumProtoMsg_ResultType_TIMEOUT);
|
||||
param.msg.set_resultdata(sal::simulator.getRegisterManager().getInstructionPointer());
|
||||
} else if (ev == &ev_trap) {
|
||||
log << std::dec << "Result TRAP #" << ev_trap.getTriggerNumber() << endl;
|
||||
param.msg.set_resulttype(CoolChecksumProtoMsg_ResultType_TRAP);
|
||||
param.msg.set_resultdata(sal::simulator.getRegisterManager().getInstructionPointer());
|
||||
} else {
|
||||
log << std::dec << "Result WTF?" << endl;
|
||||
param.msg.set_resulttype(CoolChecksumProtoMsg_ResultType_UNKNOWN);
|
||||
param.msg.set_resultdata(sal::simulator.getRegisterManager().getInstructionPointer());
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "eventid " << ev << " EIP " << sal::simulator.getRegisterManager().getInstructionPointer();
|
||||
param.msg.set_details(ss.str());
|
||||
}
|
||||
int32_t error_corrected = sal::simulator.getMemoryManager().getByte(COOL_ECC_ERROR_CORRECTED);
|
||||
param.msg.set_error_corrected(error_corrected);
|
||||
m_jc.sendResult(param);
|
||||
|
||||
}
|
||||
#endif
|
||||
// FIXME We currently need to explicitly terminate. See below.
|
||||
sal::simulator.terminate();
|
||||
|
||||
// FIXME Simply returning currently fails, because afterwards
|
||||
// a) the ExperimentFlow base class cleans up this experiment's
|
||||
// remaining events,
|
||||
// b) the CoroutineManager deletes this coroutine and frees the
|
||||
// associated stack (and in particular the memory the event that
|
||||
// most recently activated us lies in),
|
||||
// c) BochsController tries to dynamic_cast<fi::BPRangeEvent*>(pBase)
|
||||
// this very event (bochs/Controller.cc:112).
|
||||
// This could be partially fixed by adding a "continue;" to the first
|
||||
// if() in this loop in BochsController, but it would still fail if
|
||||
// there were more events waiting to be fired. The general problem is
|
||||
// that we're removing events while we're in BochsController's (or
|
||||
// whose ever) event handling loop.
|
||||
//
|
||||
// Outline for a proper fix: Split all event handling loops into two
|
||||
// parts,
|
||||
// 1. collect all events to be fired in some kind of list data
|
||||
// structure,
|
||||
// 2. fire all collected events in a centralized SimulatorController
|
||||
// function.
|
||||
// The data structure and the centralized function should be chosen in
|
||||
// a way that this construct *can* deal with events being removed while
|
||||
// iterating over them.
|
||||
return true;
|
||||
}
|
||||
14
core/experiments/checksum-oostubs/experiment.hpp
Normal file
14
core/experiments/checksum-oostubs/experiment.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef __COOLEXPERIMENT_HPP__
|
||||
#define __COOLEXPERIMENT_HPP__
|
||||
|
||||
#include "controller/ExperimentFlow.hpp"
|
||||
#include "jobserver/JobClient.hpp"
|
||||
|
||||
class CoolChecksumExperiment : public fi::ExperimentFlow {
|
||||
fi::JobClient m_jc;
|
||||
public:
|
||||
CoolChecksumExperiment() : m_jc("ios.cs.tu-dortmund.de") {}
|
||||
bool run();
|
||||
};
|
||||
|
||||
#endif
|
||||
48
core/experiments/checksum-oostubs/experimentInfo.hpp
Normal file
48
core/experiments/checksum-oostubs/experimentInfo.hpp
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef __EXPERIMENT_INFO_HPP__
|
||||
#define __EXPERIMENT_INFO_HPP__
|
||||
|
||||
// FIXME autogenerate this
|
||||
|
||||
#if 1 // with ECC
|
||||
|
||||
// the task function's entry address:
|
||||
// nm -C ecc.elf|fgrep main
|
||||
#define OOSTUBS_FUNC_ENTRY 0x00103f2c
|
||||
// empty function that is called explicitly when the experiment finished
|
||||
// nm -C ecc.elf|fgrep "finished()"
|
||||
#define OOSTUBS_FUNC_DONE 0x001093f0
|
||||
// number of instructions the target executes under non-error conditions from ENTRY to DONE:
|
||||
// (result of experiment's step #2)
|
||||
#define OOSTUBS_NUMINSTR 0x4a3401
|
||||
// number of instructions that are executed additionally for error corrections
|
||||
// (this is a rough guess ... TODO)
|
||||
#define OOSTUBS_RECOVERYINSTR 0x2000
|
||||
// the ECC protected object's address:
|
||||
// nm -C ecc.elf|fgrep objectUnderTest
|
||||
#define COOL_ECC_OBJUNDERTEST 0x002127a4 //FIXME
|
||||
// the ECC protected object's payload size:
|
||||
// (we know that from the object's definition and usual memory layout)
|
||||
#define COOL_ECC_OBJUNDERTEST_SIZE 10 //FIXME
|
||||
// the variable that's increased if ECC corrects an error:
|
||||
// nm -C ecc.elf|fgrep errors_corrected
|
||||
#define OOSTUBS_ERROR_CORRECTED 0x0010e3a4
|
||||
//
|
||||
// nm -C ecc.elf|fgrep results
|
||||
#define OOSTUBS_RESULTS_ADDR 0x0010d794
|
||||
#define OOSTUBS_RESULTS_BYTES 12
|
||||
#define OOSTUBS_RESULT0 0xab3566a9
|
||||
#define OOSTUBS_RESULT1 0x44889112
|
||||
#define OOSTUBS_RESULT2 0x10420844
|
||||
|
||||
#else // without ECC
|
||||
|
||||
#define COOL_ECC_FUNC_ENTRY 0x00200a90
|
||||
#define COOL_ECC_CALCDONE 0x00200ab7
|
||||
#define COOL_ECC_NUMINSTR 97
|
||||
#define COOL_ECC_OBJUNDERTEST 0x0021263c
|
||||
#define COOL_ECC_OBJUNDERTEST_SIZE 10
|
||||
#define COOL_ECC_ERROR_CORRECTED 0x002127b0 // dummy
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
15
core/experiments/checksum-oostubs/main.cc
Normal file
15
core/experiments/checksum-oostubs/main.cc
Normal file
@ -0,0 +1,15 @@
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "controller/CampaignManager.hpp"
|
||||
#include "experiments/checksum-oostubs/campaign.hpp"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CoolChecksumCampaign c;
|
||||
if (fi::campaignmanager.runCampaign(&c)) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user