From 8dd7700482b8ad7fa5e96469b23f0c917f5e3599 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 28 Jul 2007 20:30:43 -0700 Subject: Turn the instruction tracing code into pluggable sim objects. These need to be refined a little still and given parameters. --HG-- extra : convert_revision : 9a8f5a7bd9dacbebbbd2c235cd890c49a81040d7 --- src/cpu/legiontrace.cc | 600 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 600 insertions(+) create mode 100644 src/cpu/legiontrace.cc (limited to 'src/cpu/legiontrace.cc') diff --git a/src/cpu/legiontrace.cc b/src/cpu/legiontrace.cc new file mode 100644 index 000000000..58181cb88 --- /dev/null +++ b/src/cpu/legiontrace.cc @@ -0,0 +1,600 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + * Lisa Hsu + * Nathan Binkert + * Steve Raasch + */ + +#include "arch/isa_specific.hh" +#if THE_ISA != SPARC_ISA + #error Legion tracing only works with SPARC simulations! +#endif + +#include "config/full_system.hh" +#if !FULL_SYSTEM + #error Legion tracing only works in full system! +#endif + +#include +#include +#include + +#include "arch/sparc/predecoder.hh" +#include "arch/sparc/regfile.hh" +#include "arch/sparc/utility.hh" +#include "base/socket.hh" +#include "cpu/base.hh" +#include "cpu/legiontrace.hh" +#include "cpu/static_inst.hh" +#include "cpu/thread_context.hh" +#include "params/LegionTrace.hh" +#include "sim/system.hh" + +#if FULL_SYSTEM +#include "arch/tlb.hh" +#endif + +//XXX This is temporary +#include "cpu/m5legion_interface.h" + +using namespace std; +using namespace TheISA; + +#if FULL_SYSTEM +static int diffcount = 0; +static bool wasMicro = false; +#endif + +namespace Trace { +SharedData *shared_data = NULL; + +void +setupSharedData() +{ + int shmfd = shmget('M' << 24 | getuid(), sizeof(SharedData), 0777); + if (shmfd < 0) + fatal("Couldn't get shared memory fd. Is Legion running?"); + + shared_data = (SharedData*)shmat(shmfd, NULL, SHM_RND); + if (shared_data == (SharedData*)-1) + fatal("Couldn't allocate shared memory"); + + if (shared_data->flags != OWN_M5) + fatal("Shared memory has invalid owner"); + + if (shared_data->version != VERSION) + fatal("Shared Data is wrong version! M5: %d Legion: %d", VERSION, + shared_data->version); + + // step legion forward one cycle so we can get register values + shared_data->flags = OWN_LEGION; +} + +//////////////////////////////////////////////////////////////////////// +// +// Utility methods for pretty printing a report about a difference +// + +inline char * genCenteredLabel(int length, char * buffer, char * label) +{ + int labelLength = strlen(label); + assert(labelLength <= length); + int leftPad = (length - labelLength) / 2; + int rightPad = length - leftPad - labelLength; + char format[64]; + sprintf(format, "%%%ds%%s%%%ds", leftPad, rightPad); + sprintf(buffer, format, "", label, ""); + return buffer; +} + +inline void printRegPair(ostream & os, char const * title, uint64_t a, uint64_t b) +{ + ccprintf(os, " %16s | %#018x %s %#-018x \n", + title, a, (a == b) ? "|" : "X", b); +} + +inline void printColumnLabels(ostream & os) +{ + static char * regLabel = genCenteredLabel(16, new char[17], "Register"); + static char * m5Label = genCenteredLabel(18, new char[18], "M5"); + static char * legionLabel = genCenteredLabel(18, new char[18], "Legion"); + ccprintf(os, " %s | %s | %s \n", regLabel, m5Label, legionLabel); + ccprintf(os, "--------------------+-----------------------+-----------------------\n"); +} + +inline void printSectionHeader(ostream & os, char * name) +{ + char sectionString[70]; + genCenteredLabel(69, sectionString, name); + ccprintf(os, "====================================================================\n"); + ccprintf(os, "%69s\n", sectionString); + ccprintf(os, "====================================================================\n"); +} + +inline void printLevelHeader(ostream & os, int level) +{ + char sectionString[70]; + char levelName[70]; + sprintf(levelName, "Trap stack level %d", level); + genCenteredLabel(69, sectionString, levelName); + ccprintf(os, "====================================================================\n"); + ccprintf(os, "%69s\n", sectionString); + ccprintf(os, "====================================================================\n"); +} + +void +Trace::LegionTraceRecord::dump() +{ + ostream &outs = Trace::output(); + + static TheISA::Predecoder predecoder(NULL); + // Compare + bool compared = false; + bool diffPC = false; + bool diffCC = false; + bool diffInst = false; + bool diffIntRegs = false; + bool diffFpRegs = false; + bool diffTpc = false; + bool diffTnpc = false; + bool diffTstate = false; + bool diffTt = false; + bool diffTba = false; + bool diffHpstate = false; + bool diffHtstate = false; + bool diffHtba = false; + bool diffPstate = false; + bool diffY = false; + bool diffFsr = false; + bool diffCcr = false; + bool diffTl = false; + bool diffGl = false; + bool diffAsi = false; + bool diffPil = false; + bool diffCwp = false; + bool diffCansave = false; + bool diffCanrestore = false; + bool diffOtherwin = false; + bool diffCleanwin = false; + bool diffTlb = false; + Addr m5Pc, lgnPc; + + if (!shared_data) + setupSharedData(); + + // We took a trap on a micro-op... + if (wasMicro && !staticInst->isMicroop()) + { + // let's skip comparing this tick + while (!compared) + if (shared_data->flags == OWN_M5) { + shared_data->flags = OWN_LEGION; + compared = true; + } + compared = false; + wasMicro = false; + } + + if (staticInst->isLastMicroop()) + wasMicro = false; + else if (staticInst->isMicroop()) + wasMicro = true; + + + if(!staticInst->isMicroop() || staticInst->isLastMicroop()) { + while (!compared) { + if (shared_data->flags == OWN_M5) { + m5Pc = PC & SparcISA::PAddrImplMask; + if (bits(shared_data->pstate,3,3)) { + m5Pc &= mask(32); + } + lgnPc = shared_data->pc & SparcISA::PAddrImplMask; + if (lgnPc != m5Pc) + diffPC = true; + + if (shared_data->cycle_count != + thread->getCpuPtr()->instCount()) + diffCC = true; + + if (shared_data->instruction != + (SparcISA::MachInst)staticInst->machInst) { + diffInst = true; + } + // assume we have %g0 working correctly + for (int i = 1; i < TheISA::NumIntArchRegs; i++) { + if (thread->readIntReg(i) != shared_data->intregs[i]) { + diffIntRegs = true; + } + } + for (int i = 0; i < TheISA::NumFloatRegs/2; i++) { + if (thread->readFloatRegBits(i*2, + FloatRegFile::DoubleWidth) != + shared_data->fpregs[i]) { + diffFpRegs = true; + } + } + uint64_t oldTl = + thread->readMiscRegNoEffect(MISCREG_TL); + if (oldTl != shared_data->tl) + diffTl = true; + for (int i = 1; i <= MaxTL; i++) { + thread->setMiscRegNoEffect(MISCREG_TL, i); + if (thread->readMiscRegNoEffect(MISCREG_TPC) != + shared_data->tpc[i-1]) + diffTpc = true; + if (thread->readMiscRegNoEffect(MISCREG_TNPC) != + shared_data->tnpc[i-1]) + diffTnpc = true; + if (thread->readMiscRegNoEffect(MISCREG_TSTATE) != + shared_data->tstate[i-1]) + diffTstate = true; + if (thread->readMiscRegNoEffect(MISCREG_TT) != + shared_data->tt[i-1]) + diffTt = true; + if (thread->readMiscRegNoEffect(MISCREG_HTSTATE) != + shared_data->htstate[i-1]) + diffHtstate = true; + } + thread->setMiscRegNoEffect(MISCREG_TL, oldTl); + + if(shared_data->tba != thread->readMiscRegNoEffect(MISCREG_TBA)) + diffTba = true; + //When the hpstate register is read by an instruction, + //legion has bit 11 set. When it's in storage, it doesn't. + //Since we don't directly support seperate interpretations + //of the registers like that, the bit is always set to 1 and + //we just don't compare it. It's not supposed to matter + //anyway. + if((shared_data->hpstate | (1 << 11)) != + thread->readMiscRegNoEffect(MISCREG_HPSTATE)) + diffHpstate = true; + if(shared_data->htba != + thread->readMiscRegNoEffect(MISCREG_HTBA)) + diffHtba = true; + if(shared_data->pstate != + thread->readMiscRegNoEffect(MISCREG_PSTATE)) + diffPstate = true; + //if(shared_data->y != + // thread->readMiscRegNoEffect(MISCREG_Y)) + if(shared_data->y != + thread->readIntReg(NumIntArchRegs + 1)) + diffY = true; + if(shared_data->fsr != + thread->readMiscRegNoEffect(MISCREG_FSR)) { + diffFsr = true; + if (mbits(shared_data->fsr, 63,10) == + mbits(thread->readMiscRegNoEffect(MISCREG_FSR), + 63,10)) { + thread->setMiscRegNoEffect(MISCREG_FSR, + shared_data->fsr); + diffFsr = false; + } + } + //if(shared_data->ccr != + // thread->readMiscRegNoEffect(MISCREG_CCR)) + if(shared_data->ccr != + thread->readIntReg(NumIntArchRegs + 2)) + diffCcr = true; + if(shared_data->gl != + thread->readMiscRegNoEffect(MISCREG_GL)) + diffGl = true; + if(shared_data->asi != + thread->readMiscRegNoEffect(MISCREG_ASI)) + diffAsi = true; + if(shared_data->pil != + thread->readMiscRegNoEffect(MISCREG_PIL)) + diffPil = true; + if(shared_data->cwp != + thread->readMiscRegNoEffect(MISCREG_CWP)) + diffCwp = true; + //if(shared_data->cansave != + // thread->readMiscRegNoEffect(MISCREG_CANSAVE)) + if(shared_data->cansave != + thread->readIntReg(NumIntArchRegs + 3)) + diffCansave = true; + //if(shared_data->canrestore != + // thread->readMiscRegNoEffect(MISCREG_CANRESTORE)) + if(shared_data->canrestore != + thread->readIntReg(NumIntArchRegs + 4)) + diffCanrestore = true; + //if(shared_data->otherwin != + // thread->readMiscRegNoEffect(MISCREG_OTHERWIN)) + if(shared_data->otherwin != + thread->readIntReg(NumIntArchRegs + 6)) + diffOtherwin = true; + //if(shared_data->cleanwin != + // thread->readMiscRegNoEffect(MISCREG_CLEANWIN)) + if(shared_data->cleanwin != + thread->readIntReg(NumIntArchRegs + 5)) + diffCleanwin = true; + + for (int i = 0; i < 64; i++) { + if (shared_data->itb[i] != + thread->getITBPtr()->TteRead(i)) + diffTlb = true; + if (shared_data->dtb[i] != + thread->getDTBPtr()->TteRead(i)) + diffTlb = true; + } + + if (diffPC || diffCC || diffInst || + diffIntRegs || diffFpRegs || + diffTpc || diffTnpc || diffTstate || diffTt || + diffHpstate || diffHtstate || diffHtba || + diffPstate || diffY || diffCcr || diffTl || diffFsr || + diffGl || diffAsi || diffPil || diffCwp || + diffCansave || diffCanrestore || + diffOtherwin || diffCleanwin || diffTlb) { + + outs << "Differences found between M5 and Legion:"; + if (diffPC) + outs << " [PC]"; + if (diffCC) + outs << " [CC]"; + if (diffInst) + outs << " [Instruction]"; + if (diffIntRegs) + outs << " [IntRegs]"; + if (diffFpRegs) + outs << " [FpRegs]"; + if (diffTpc) + outs << " [Tpc]"; + if (diffTnpc) + outs << " [Tnpc]"; + if (diffTstate) + outs << " [Tstate]"; + if (diffTt) + outs << " [Tt]"; + if (diffHpstate) + outs << " [Hpstate]"; + if (diffHtstate) + outs << " [Htstate]"; + if (diffHtba) + outs << " [Htba]"; + if (diffPstate) + outs << " [Pstate]"; + if (diffY) + outs << " [Y]"; + if (diffFsr) + outs << " [FSR]"; + if (diffCcr) + outs << " [Ccr]"; + if (diffTl) + outs << " [Tl]"; + if (diffGl) + outs << " [Gl]"; + if (diffAsi) + outs << " [Asi]"; + if (diffPil) + outs << " [Pil]"; + if (diffCwp) + outs << " [Cwp]"; + if (diffCansave) + outs << " [Cansave]"; + if (diffCanrestore) + outs << " [Canrestore]"; + if (diffOtherwin) + outs << " [Otherwin]"; + if (diffCleanwin) + outs << " [Cleanwin]"; + if (diffTlb) + outs << " [Tlb]"; + outs << endl << endl; + + outs << right << setfill(' ') << setw(15) + << "M5 PC: " << "0x"<< setw(16) << setfill('0') + << hex << m5Pc << endl; + outs << setfill(' ') << setw(15) + << "Legion PC: " << "0x" + << setw(16) << setfill('0') << hex + << lgnPc << endl << endl; + + outs << right << setfill(' ') << setw(15) + << "M5 CC: " << "0x" + << setw(16) << setfill('0') << hex + << thread->getCpuPtr()->instCount() << endl; + outs << setfill(' ') << setw(15) + << "Legion CC: " << "0x" + << setw(16) << setfill('0') << hex + << shared_data->cycle_count << endl << endl; + + outs << setfill(' ') << setw(15) + << "M5 Inst: " << "0x" + << setw(8) << setfill('0') << hex + << staticInst->machInst + << staticInst->disassemble(m5Pc, debugSymbolTable) + << endl; + + predecoder.setTC(thread); + predecoder.moreBytes(m5Pc, m5Pc, + shared_data->instruction); + + assert(predecoder.extMachInstReady()); + + StaticInstPtr legionInst = + StaticInst::decode(predecoder.getExtMachInst(), lgnPc); + outs << setfill(' ') << setw(15) + << " Legion Inst: " + << "0x" << setw(8) << setfill('0') << hex + << shared_data->instruction + << legionInst->disassemble(lgnPc, debugSymbolTable) + << endl << endl; + + printSectionHeader(outs, "General State"); + printColumnLabels(outs); + printRegPair(outs, "HPstate", + thread->readMiscRegNoEffect(MISCREG_HPSTATE), + shared_data->hpstate | (1 << 11)); + printRegPair(outs, "Htba", + thread->readMiscRegNoEffect(MISCREG_HTBA), + shared_data->htba); + printRegPair(outs, "Pstate", + thread->readMiscRegNoEffect(MISCREG_PSTATE), + shared_data->pstate); + printRegPair(outs, "Y", + //thread->readMiscRegNoEffect(MISCREG_Y), + thread->readIntReg(NumIntArchRegs + 1), + shared_data->y); + printRegPair(outs, "FSR", + thread->readMiscRegNoEffect(MISCREG_FSR), + shared_data->fsr); + printRegPair(outs, "Ccr", + //thread->readMiscRegNoEffect(MISCREG_CCR), + thread->readIntReg(NumIntArchRegs + 2), + shared_data->ccr); + printRegPair(outs, "Tl", + thread->readMiscRegNoEffect(MISCREG_TL), + shared_data->tl); + printRegPair(outs, "Gl", + thread->readMiscRegNoEffect(MISCREG_GL), + shared_data->gl); + printRegPair(outs, "Asi", + thread->readMiscRegNoEffect(MISCREG_ASI), + shared_data->asi); + printRegPair(outs, "Pil", + thread->readMiscRegNoEffect(MISCREG_PIL), + shared_data->pil); + printRegPair(outs, "Cwp", + thread->readMiscRegNoEffect(MISCREG_CWP), + shared_data->cwp); + printRegPair(outs, "Cansave", + //thread->readMiscRegNoEffect(MISCREG_CANSAVE), + thread->readIntReg(NumIntArchRegs + 3), + shared_data->cansave); + printRegPair(outs, "Canrestore", + //thread->readMiscRegNoEffect(MISCREG_CANRESTORE), + thread->readIntReg(NumIntArchRegs + 4), + shared_data->canrestore); + printRegPair(outs, "Otherwin", + //thread->readMiscRegNoEffect(MISCREG_OTHERWIN), + thread->readIntReg(NumIntArchRegs + 6), + shared_data->otherwin); + printRegPair(outs, "Cleanwin", + //thread->readMiscRegNoEffect(MISCREG_CLEANWIN), + thread->readIntReg(NumIntArchRegs + 5), + shared_data->cleanwin); + outs << endl; + for (int i = 1; i <= MaxTL; i++) { + printLevelHeader(outs, i); + printColumnLabels(outs); + thread->setMiscRegNoEffect(MISCREG_TL, i); + printRegPair(outs, "Tpc", + thread->readMiscRegNoEffect(MISCREG_TPC), + shared_data->tpc[i-1]); + printRegPair(outs, "Tnpc", + thread->readMiscRegNoEffect(MISCREG_TNPC), + shared_data->tnpc[i-1]); + printRegPair(outs, "Tstate", + thread->readMiscRegNoEffect(MISCREG_TSTATE), + shared_data->tstate[i-1]); + printRegPair(outs, "Tt", + thread->readMiscRegNoEffect(MISCREG_TT), + shared_data->tt[i-1]); + printRegPair(outs, "Htstate", + thread->readMiscRegNoEffect(MISCREG_HTSTATE), + shared_data->htstate[i-1]); + } + thread->setMiscRegNoEffect(MISCREG_TL, oldTl); + outs << endl; + + printSectionHeader(outs, "General Purpose Registers"); + static const char * regtypes[4] = + {"%g", "%o", "%l", "%i"}; + for(int y = 0; y < 4; y++) { + for(int x = 0; x < 8; x++) { + char label[8]; + sprintf(label, "%s%d", regtypes[y], x); + printRegPair(outs, label, + thread->readIntReg(y*8+x), + shared_data->intregs[y*8+x]); + } + } + if (diffFpRegs) { + for (int x = 0; x < 32; x++) { + char label[8]; + sprintf(label, "%%f%d", x); + printRegPair(outs, label, + thread->readFloatRegBits(x*2, + FloatRegFile::DoubleWidth), + shared_data->fpregs[x]); + } + } + if (diffTlb) { + printColumnLabels(outs); + char label[8]; + for (int x = 0; x < 64; x++) { + if (shared_data->itb[x] != + ULL(0xFFFFFFFFFFFFFFFF) || + thread->getITBPtr()->TteRead(x) != + ULL(0xFFFFFFFFFFFFFFFF)) { + sprintf(label, "I-TLB:%02d", x); + printRegPair(outs, label, + thread->getITBPtr()->TteRead(x), + shared_data->itb[x]); + } + } + for (int x = 0; x < 64; x++) { + if (shared_data->dtb[x] != + ULL(0xFFFFFFFFFFFFFFFF) || + thread->getDTBPtr()->TteRead(x) != + ULL(0xFFFFFFFFFFFFFFFF)) { + sprintf(label, "D-TLB:%02d", x); + printRegPair(outs, label, + thread->getDTBPtr()->TteRead(x), + shared_data->dtb[x]); + } + } + thread->getITBPtr()->dumpAll(); + thread->getDTBPtr()->dumpAll(); + } + + diffcount++; + if (diffcount > 3) + fatal("Differences found between Legion and M5\n"); + } else + diffcount = 0; + + compared = true; + shared_data->flags = OWN_LEGION; + } + } // while + } // if not microop +} + +/* namespace Trace */ } + +//////////////////////////////////////////////////////////////////////// +// +// ExeTracer Simulation Object +// +Trace::LegionTrace * +LegionTraceParams::create() +{ + return new Trace::LegionTrace(name); +}; -- cgit v1.2.3