memtest.cc

来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· CC 代码 · 共 402 行

CC
402
字号
/* * Copyright (c) 2002, 2003, 2004, 2005 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator. * * Permission is granted to use, copy, create derivative works and * redistribute this software and such derivative works for any * purpose, so long as the copyright notice above, this grant of * permission, and the disclaimer below appear in all copies made; and * so long as the name of The University of Michigan is not used in * any advertising or publicity pertaining to the use or distribution * of this software without specific, written prior authorization. * * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH * DAMAGES. * * Authors: Erik G. Hallnor *          Steven K. Reinhardt */// FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded#include <iomanip>#include <set>#include <string>#include <vector>#include "base/misc.hh"#include "base/statistics.hh"#include "cpu/memtest/memtest.hh"#include "mem/mem_object.hh"#include "mem/port.hh"#include "mem/packet.hh"#include "mem/request.hh"#include "sim/sim_events.hh"#include "sim/stats.hh"using namespace std;int TESTER_ALLOCATOR=0;boolMemTest::CpuPort::recvTiming(PacketPtr pkt){    if (pkt->isResponse()) {        memtest->completeRequest(pkt);    } else {        // must be snoop upcall        assert(pkt->isRequest());        assert(pkt->getDest() == Packet::Broadcast);    }    return true;}TickMemTest::CpuPort::recvAtomic(PacketPtr pkt){    // must be snoop upcall    assert(pkt->isRequest());    assert(pkt->getDest() == Packet::Broadcast);    return curTick;}voidMemTest::CpuPort::recvFunctional(PacketPtr pkt){    //Do nothing if we see one come through//    if (curTick != 0)//Supress warning durring initialization//        warn("Functional Writes not implemented in MemTester\n");    //Need to find any response values that intersect and update    return;}voidMemTest::CpuPort::recvStatusChange(Status status){    if (status == RangeChange) {        if (!snoopRangeSent) {            snoopRangeSent = true;            sendStatusChange(Port::RangeChange);        }        return;    }    panic("MemTest doesn't expect recvStatusChange callback!");}voidMemTest::CpuPort::recvRetry(){    memtest->doRetry();}voidMemTest::sendPkt(PacketPtr pkt) {    if (atomic) {        cachePort.sendAtomic(pkt);        completeRequest(pkt);    }    else if (!cachePort.sendTiming(pkt)) {        accessRetry = true;        retryPkt = pkt;    }}MemTest::MemTest(const Params *p)    : MemObject(p),      tickEvent(this),      cachePort("test", this),      funcPort("functional", this),      retryPkt(NULL),//      mainMem(main_mem),//      checkMem(check_mem),      size(p->memory_size),      percentReads(p->percent_reads),      percentFunctional(p->percent_functional),      percentUncacheable(p->percent_uncacheable),      progressInterval(p->progress_interval),      nextProgressMessage(p->progress_interval),      percentSourceUnaligned(p->percent_source_unaligned),      percentDestUnaligned(p->percent_dest_unaligned),      maxLoads(p->max_loads),      atomic(p->atomic){    vector<string> cmd;    cmd.push_back("/bin/ls");    vector<string> null_vec;    //  thread = new SimpleThread(NULL, 0, NULL, 0, mainMem);    curTick = 0;    cachePort.snoopRangeSent = false;    funcPort.snoopRangeSent = true;    // Needs to be masked off once we know the block size.    traceBlockAddr = p->trace_addr;    baseAddr1 = 0x100000;    baseAddr2 = 0x400000;    uncacheAddr = 0x800000;    // set up counters    noResponseCycles = 0;    numReads = 0;    tickEvent.schedule(0);    id = TESTER_ALLOCATOR++;    accessRetry = false;}Port *MemTest::getPort(const std::string &if_name, int idx){    if (if_name == "functional")        return &funcPort;    else if (if_name == "test")        return &cachePort;    else        panic("No Such Port\n");}voidMemTest::init(){    // By the time init() is called, the ports should be hooked up.    blockSize = cachePort.peerBlockSize();    blockAddrMask = blockSize - 1;    traceBlockAddr = blockAddr(traceBlockAddr);    // initial memory contents for both physical memory and functional    // memory should be 0; no need to initialize them.}voidMemTest::completeRequest(PacketPtr pkt){    Request *req = pkt->req;    DPRINTF(MemTest, "completing %s at address %x (blk %x)\n",            pkt->isWrite() ? "write" : "read",            req->getPaddr(), blockAddr(req->getPaddr()));    MemTestSenderState *state =        dynamic_cast<MemTestSenderState *>(pkt->senderState);    uint8_t *data = state->data;    uint8_t *pkt_data = pkt->getPtr<uint8_t>();    //Remove the address from the list of outstanding    std::set<unsigned>::iterator removeAddr =        outstandingAddrs.find(req->getPaddr());    assert(removeAddr != outstandingAddrs.end());    outstandingAddrs.erase(removeAddr);    assert(pkt->isResponse());    if (pkt->isRead()) {        if (memcmp(pkt_data, data, pkt->getSize()) != 0) {            panic("%s: read of %x (blk %x) @ cycle %d "                  "returns %x, expected %x\n", name(),                  req->getPaddr(), blockAddr(req->getPaddr()), curTick,                  *pkt_data, *data);        }        numReads++;        numReadsStat++;        if (numReads == nextProgressMessage) {            ccprintf(cerr, "%s: completed %d read accesses @%d\n",                     name(), numReads, curTick);            nextProgressMessage += progressInterval;        }        if (maxLoads != 0 && numReads >= maxLoads)            exitSimLoop("maximum number of loads reached");    } else {        assert(pkt->isWrite());        numWritesStat++;    }    noResponseCycles = 0;    delete state;    delete [] data;    delete pkt->req;    delete pkt;}voidMemTest::regStats(){    using namespace Stats;    numReadsStat        .name(name() + ".num_reads")        .desc("number of read accesses completed")        ;    numWritesStat        .name(name() + ".num_writes")        .desc("number of write accesses completed")        ;    numCopiesStat        .name(name() + ".num_copies")        .desc("number of copy accesses completed")        ;}voidMemTest::tick(){    if (!tickEvent.scheduled())        tickEvent.schedule(curTick + ticks(1));    if (++noResponseCycles >= 500000) {        cerr << name() << ": deadlocked at cycle " << curTick << endl;        fatal("");    }    if (accessRetry) {        return;    }    //make new request    unsigned cmd = random() % 100;    unsigned offset = random() % size;    unsigned base = random() % 2;    uint64_t data = random();    unsigned access_size = random() % 4;    unsigned cacheable = random() % 100;    //If we aren't doing copies, use id as offset, and do a false sharing    //mem tester    //We can eliminate the lower bits of the offset, and then use the id    //to offset within the blks    offset = blockAddr(offset);    offset += id;    access_size = 0;    Request *req = new Request();    uint32_t flags = 0;    Addr paddr;    if (cacheable < percentUncacheable) {        flags |= UNCACHEABLE;        paddr = uncacheAddr + offset;    } else {        paddr = ((base) ? baseAddr1 : baseAddr2) + offset;    }    bool probe = (random() % 100 < percentFunctional) && !(flags & UNCACHEABLE);    //bool probe = false;    paddr &= ~((1 << access_size) - 1);    req->setPhys(paddr, 1 << access_size, flags);    req->setThreadContext(id,0);    uint8_t *result = new uint8_t[8];    if (cmd < percentReads) {        // read        // For now we only allow one outstanding request per address        // per tester This means we assume CPU does write forwarding        // to reads that alias something in the cpu store buffer.        if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) {            delete [] result;            delete req;            return;        }        outstandingAddrs.insert(paddr);        // ***** NOTE FOR RON: I'm not sure how to access checkMem. - Kevin        funcPort.readBlob(req->getPaddr(), result, req->getSize());        DPRINTF(MemTest,                "initiating read at address %x (blk %x) expecting %x\n",                req->getPaddr(), blockAddr(req->getPaddr()), *result);        PacketPtr pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast);        pkt->setSrc(0);        pkt->dataDynamicArray(new uint8_t[req->getSize()]);        MemTestSenderState *state = new MemTestSenderState(result);        pkt->senderState = state;        if (probe) {            cachePort.sendFunctional(pkt);            completeRequest(pkt);        } else {            sendPkt(pkt);        }    } else {        // write        // For now we only allow one outstanding request per addreess        // per tester.  This means we assume CPU does write forwarding        // to reads that alias something in the cpu store buffer.        if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) {            delete [] result;            delete req;            return;        }        outstandingAddrs.insert(paddr);        DPRINTF(MemTest, "initiating write at address %x (blk %x) value %x\n",                req->getPaddr(), blockAddr(req->getPaddr()), data & 0xff);        PacketPtr pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast);        pkt->setSrc(0);        uint8_t *pkt_data = new uint8_t[req->getSize()];        pkt->dataDynamicArray(pkt_data);        memcpy(pkt_data, &data, req->getSize());        MemTestSenderState *state = new MemTestSenderState(result);        pkt->senderState = state;        funcPort.writeBlob(req->getPaddr(), pkt_data, req->getSize());        if (probe) {            cachePort.sendFunctional(pkt);            completeRequest(pkt);        } else {            sendPkt(pkt);        }    }}voidMemTest::doRetry(){    if (cachePort.sendTiming(retryPkt)) {        accessRetry = false;        retryPkt = NULL;    }}voidMemTest::printAddr(Addr a){    cachePort.printAddr(a);}MemTest *MemTestParams::create(){    return new MemTest(this);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?