From 465b7c4a920e3bdaf35b45c2285687af8ac6e3b7 Mon Sep 17 00:00:00 2001 From: hsc Date: Tue, 10 Apr 2012 19:35:40 +0000 Subject: [PATCH] checksum-oostubs: fault-space pruning, job enqueueing git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1043 8c4709b5-6ec9-48aa-a5cd-a96041d1645a --- core/experiments/checksum-oostubs/campaign.cc | 302 ++++++++++++------ 1 file changed, 206 insertions(+), 96 deletions(-) diff --git a/core/experiments/checksum-oostubs/campaign.cc b/core/experiments/checksum-oostubs/campaign.cc index ae1ea43e..f26bc52c 100644 --- a/core/experiments/checksum-oostubs/campaign.cc +++ b/core/experiments/checksum-oostubs/campaign.cc @@ -1,70 +1,33 @@ #include +#include +#include #include "campaign.hpp" #include "experimentInfo.hpp" #include "controller/CampaignManager.hpp" #include "util/Logger.hpp" +#include "util/MemoryMap.hpp" + +#include "ecc_region.hpp" + +#include "plugins/tracing/TracingPlugin.hpp" +char const * const trace_filename = "trace.pb"; 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}, +// equivalence class type: addr, [i1, i2] +// addr: byte to inject a bit-flip into +// [i1, i2]: interval of instruction numbers, counted from experiment +// begin +struct equivalence_class { + sal::address_t data_address; + int instr1, instr2; + sal::address_t instr2_absolute; // FIXME we could record them all here }; - - bool ChecksumOOStuBSCampaign::run() { Logger log("ChecksumOOStuBS Campaign"); @@ -82,63 +45,210 @@ bool ChecksumOOStuBSCampaign::run() log << "startup" << endl; - unsigned count = 0; + // load trace + log << "loading trace ..." << endl; + ifstream tracef(trace_filename); + if (tracef.fail()) { + log << "couldn't open " << trace_filename << endl; + return false; + } + Trace trace; + trace.ParseFromIstream(&tracef); + tracef.close(); + log << "... done." << endl; - 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; + // a map of addresses of ECC protected objects + MemoryMap mm; + for (unsigned i = 0; i < sizeof(memoryMap)/sizeof(*memoryMap); ++i) { + mm.add(memoryMap[i][0], memoryMap[i][1]); + } + + // set of equivalence classes that need one (rather: eight, one for + // each bit in that byte) experiment to determine them all + std::vector ecs_need_experiment; + // set of equivalence classes that need no experiment, because we know + // they'd be identical to the golden run + std::vector ecs_no_effect; + + equivalence_class current_ec; + + // map for efficient access when results come in + std::map experiment_ecs; + // experiment count + int count = 0; + + // for every injection address ... + for (MemoryMap::iterator it = mm.begin(); it != mm.end(); ++it) { + std::cerr << "."; + sal::address_t data_address = *it; + current_ec.instr1 = 0; + int instr = 0; + sal::address_t instr_absolute = 0; // FIXME this one probably should also be recorded ... + Trace_Event const *ev; + + // for every section in the trace between subsequent memory + // accesses to that address ... + // XXX reorganizing the trace for efficient seeks could speed this up + for (int eventnr = 0; eventnr < trace.event_size(); ++eventnr) { + ev = &trace.event(eventnr); + + // instruction events just get counted + if (!ev->has_memaddr()) { + // new instruction + instr++; + instr_absolute = ev->ip(); + continue; + + // skip accesses to other data + } else if (ev->memaddr() != data_address) { + continue; + + // skip zero-sized intervals: these can + // occur when an instruction accesses a + // memory location more than once + // (e.g., INC, CMPXCHG) + } else if (current_ec.instr1 > instr) { + continue; + } + + // we now have an interval-terminating R/W + // event to the memaddr we're currently looking + // at: + + // complete the equivalence interval + current_ec.instr2 = instr; + current_ec.instr2_absolute = instr_absolute; + current_ec.data_address = data_address; + + if (ev->accesstype() == ev->READ) { + // a sequence ending with READ: we need + // to do one experiment to cover it + // completely + ecs_need_experiment.push_back(current_ec); + + // instantly enqueue jobs: that way the job clients can already + // start working in parallel + for (int bitnr = 0; bitnr < 8; ++bitnr) { + ChecksumOOStuBSExperimentData *d = new ChecksumOOStuBSExperimentData; + // we pick the rightmost instruction in that interval + d->msg.set_instr_offset(current_ec.instr2); + d->msg.set_instr_address(current_ec.instr2_absolute); + d->msg.set_mem_addr(current_ec.data_address); + d->msg.set_bit_offset(bitnr); + + experiment_ecs[d] = &ecs_need_experiment.back(); + + fi::campaignmanager.addParam(d); + ++count; + } + } else if (ev->accesstype() == ev->WRITE) { + // a sequence ending with WRITE: an + // injection anywhere here would have + // no effect. + ecs_no_effect.push_back(current_ec); + } else { + log << "WAT" << endl; + } + + // next interval must start at next + // instruction; the aforementioned + // skipping mechanism wouldn't work + // otherwise + current_ec.instr1 = instr + 1; + } + + // close the last interval: + // Why -1? In most cases it does not make sense to inject before the + // very last instruction, as we won't execute it anymore. This *only* + // makes sense if we also inject into parts of the result vector. This + // is not the case in this experiment, and with -1 we'll get a + // result comparable to the non-pruned campaign. + // XXX still true for checksum-oostubs? + current_ec.instr2 = instr - 1; + current_ec.instr2_absolute = 0; // won't be used + current_ec.data_address = data_address; + // zero-sized? skip. + if (current_ec.instr1 > current_ec.instr2) { + continue; + } + // as the experiment ends, this byte is a "don't care": + ecs_no_effect.push_back(current_ec); + } + + fi::campaignmanager.noMoreParameters(); + log << "done enqueueing parameter sets (" << count << ")." << endl; + + log << "equivalence classes generated:" + << " need_experiment = " << ecs_need_experiment.size() + << " no_effect = " << ecs_no_effect.size() << endl; + + // statistics + unsigned long num_dumb_experiments = 0; + for (std::vector::const_iterator it = ecs_need_experiment.begin(); + it != ecs_need_experiment.end(); ++it) { + num_dumb_experiments += (*it).instr2 - (*it).instr1 + 1; + } + for (std::vector::const_iterator it = ecs_no_effect.begin(); + it != ecs_no_effect.end(); ++it) { + num_dumb_experiments += (*it).instr2 - (*it).instr1 + 1; + } + log << "pruning: reduced " << num_dumb_experiments * 8 << + " experiments to " << ecs_need_experiment.size() * 8 << endl; + +/* + // CSV header + results << "injection_ip\tinstr_offset\tinjection_bit\tresulttype\tresultdata\terror_corrected\tdetails" << endl; + + // store no-effect "experiment" results + // (for comparison reasons; we'll store that more compactly later) + for (std::vector::const_iterator it = ecs_no_effect.begin(); + it != ecs_no_effect.end(); ++it) { + for (int bitnr = 0; bitnr < 8; ++bitnr) { + for (int instr = (*it).instr1; instr <= (*it).instr2; ++instr) { + results + << (*it).instr2_absolute << "\t" // incorrect in all but one case! + << instr << "\t" + << ((*it).byte_offset * 8 + bitnr) << "\t" + << "1" << "\t" + << "45" << "\t" + << "0" << "\t" + << "" << "\n"; } } } - #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(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"; - */ + equivalence_class *ec = experiment_ecs[res]; + + // sanity check + if (ec->instr2 != res->msg.instr_offset()) { + results << "WTF" << endl; + log << "WTF" << endl; + delete res; + continue; + } + + // explode equivalence class to single "experiments" + // (for comparison reasons; we'll store that more compactly later) + for (int instr = ec->instr1; instr <= ec->instr2; ++instr) { + results + << res->msg.injection_ip() << "\t" // incorrect in all but one case! + << instr << "\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; }