Major improvements in the graph output code. Mostly adding more
[gem5.git] / cpu / memtest / memtest.cc
index 9deebb28204a6e9d021f970c2c6cc0f052cf2f69..27f790fac6939fff8ed7f98ee8d24a15bc1e8660 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003 The Regents of The University of Michigan
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 
 // FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded
 
-#include <string>
-#include <sstream>
 #include <iomanip>
+#include <set>
+#include <sstream>
+#include <string>
 #include <vector>
 
-#include "cpu/memtest/memtest.hh"
 #include "base/misc.hh"
-#include "sim/sim_events.hh"
-#include "mem/functional_mem/main_memory.hh"
-#include "mem/cache/base_cache.hh"
-
 #include "base/statistics.hh"
-#include "sim/sim_stats.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/memtest/memtest.hh"
+#include "mem/cache/base_cache.hh"
+#include "sim/builder.hh"
+#include "sim/sim_events.hh"
+#include "sim/stats.hh"
 
 using namespace std;
 
+int TESTER_ALLOCATOR=0;
+
 MemTest::MemTest(const string &name,
                  MemInterface *_cache_interface,
                  FunctionalMemory *main_mem,
                  FunctionalMemory *check_mem,
                  unsigned _memorySize,
                  unsigned _percentReads,
+                 unsigned _percentCopies,
                  unsigned _percentUncacheable,
-                 unsigned _maxReads,
                  unsigned _progressInterval,
-                 Addr _traceAddr)
-    : BaseCPU(name, 1),
+                 unsigned _percentSourceUnaligned,
+                 unsigned _percentDestUnaligned,
+                 Addr _traceAddr,
+                 Counter _max_loads)
+    : SimObject(name),
       tickEvent(this),
       cacheInterface(_cache_interface),
       mainMem(main_mem),
       checkMem(check_mem),
       size(_memorySize),
       percentReads(_percentReads),
+      percentCopies(_percentCopies),
       percentUncacheable(_percentUncacheable),
-      maxReads(_maxReads),
       progressInterval(_progressInterval),
-      nextProgressMessage(_progressInterval)
+      nextProgressMessage(_progressInterval),
+      percentSourceUnaligned(_percentSourceUnaligned),
+      percentDestUnaligned(percentDestUnaligned),
+      maxLoads(_max_loads)
 {
     vector<string> cmd;
     cmd.push_back("/bin/ls");
     vector<string> null_vec;
-    xc = new ExecContext(this ,0,mainMem,0);
+    xc = new ExecContext(NULL, 0, mainMem, 0);
 
     blockSize = cacheInterface->getBlockSize();
     blockAddrMask = blockSize - 1;
@@ -103,8 +112,9 @@ MemTest::MemTest(const string &name,
     // set up counters
     noResponseCycles = 0;
     numReads = 0;
-    numWrites = 0;
     tickEvent.schedule(0);
+
+    id = TESTER_ALLOCATOR++;
 }
 
 static void
@@ -119,13 +129,19 @@ printData(ostream &os, uint8_t *data, int nbytes)
 }
 
 void
-MemTest::completeRequest(MemReqPtr req, uint8_t *data)
+MemTest::completeRequest(MemReqPtr &req, uint8_t *data)
 {
+    //Remove the address from the list of outstanding
+    std::set<unsigned>::iterator removeAddr = outstandingAddrs.find(req->paddr);
+    assert(removeAddr != outstandingAddrs.end());
+    outstandingAddrs.erase(removeAddr);
+
     switch (req->cmd) {
       case Read:
         if (memcmp(req->data, data, req->size) != 0) {
             cerr << name() << ": on read of 0x" << hex << req->paddr
-                 << " @ cycle " << dec << curTick
+                 << " (0x" << hex << blockAddr(req->paddr) << ")"
+                 << "@ cycle " << dec << curTick
                  << ", cache returns 0x";
             printData(cerr, req->data, req->size);
             cerr << ", expected 0x";
@@ -135,26 +151,29 @@ MemTest::completeRequest(MemReqPtr req, uint8_t *data)
         }
 
         numReads++;
+        numReadsStat++;
 
-        if (numReads.val() == nextProgressMessage) {
-            cerr << name() << ": completed " << numReads.val()
-                 << " read accesses @ " << curTick << endl;
+        if (numReads == nextProgressMessage) {
+            ccprintf(cerr, "%s: completed %d read accesses @%d\n",
+                     name(), numReads, curTick);
             nextProgressMessage += progressInterval;
         }
 
-        if (numReads.val() == maxReads) {
-            stringstream stream;
-            stream << name() << " reached max read count (" << maxReads
-                   << ")" << endl;
-
-            new SimExitEvent(stream.str());
-        }
+        if (numReads >= maxLoads)
+            SimExit(curTick, "Maximum number of loads reached!");
         break;
 
       case Write:
-        numWrites++;
+        numWritesStat++;
         break;
 
+      case Copy:
+        //Also remove dest from outstanding list
+        removeAddr = outstandingAddrs.find(req->dest);
+        assert(removeAddr != outstandingAddrs.end());
+        outstandingAddrs.erase(removeAddr);
+        numCopiesStat++;
+        break;
 
       default:
         panic("invalid command");
@@ -162,10 +181,15 @@ MemTest::completeRequest(MemReqPtr req, uint8_t *data)
 
     if (blockAddr(req->paddr) == traceBlockAddr) {
         cerr << name() << ": completed "
-             << (req->cmd.isWrite() ? "write" : "read") << " access of "
-             << req->size << " bytes at address 0x"
-             << hex << req->paddr << ", value = 0x";
+             << (req->cmd.isWrite() ? "write" : "read")
+             << " access of "
+             << dec << req->size << " bytes at address 0x"
+             << hex << req->paddr
+             << " (0x" << hex << blockAddr(req->paddr) << ")"
+             << ", value = 0x";
         printData(cerr, req->data, req->size);
+        cerr << " @ cycle " << dec << curTick;
+
         cerr << endl;
     }
 
@@ -177,19 +201,20 @@ MemTest::completeRequest(MemReqPtr req, uint8_t *data)
 void
 MemTest::regStats()
 {
-    using namespace Statistics;
+    using namespace Stats;
+
 
-    numReads
+    numReadsStat
         .name(name() + ".num_reads")
         .desc("number of read accesses completed")
         ;
 
-    numWrites
+    numWritesStat
         .name(name() + ".num_writes")
         .desc("number of write accesses completed")
         ;
 
-    numCopies
+    numCopiesStat
         .name(name() + ".num_copies")
         .desc("number of copy accesses completed")
         ;
@@ -199,9 +224,9 @@ void
 MemTest::tick()
 {
     if (!tickEvent.scheduled())
-        tickEvent.schedule(curTick + 1);
+        tickEvent.schedule(curTick + cycles(1));
 
-    if (++noResponseCycles >= 5000) {
+    if (++noResponseCycles >= 500000) {
         cerr << name() << ": deadlocked at cycle " << curTick << endl;
         fatal("");
     }
@@ -211,21 +236,33 @@ MemTest::tick()
     }
 
     //make new request
-    unsigned cmd = rand() % 100;
-    unsigned offset1 = random() % size;
+    unsigned cmd = random() % 100;
+    unsigned offset = random() % size;
     unsigned base = random() % 2;
     uint64_t data = random();
     unsigned access_size = random() % 4;
-    unsigned cacheable = rand() % 100;
+    unsigned cacheable = random() % 100;
+
+    //If we aren't doing copies, use id as offset, and do a false sharing
+    //mem tester
+    if (percentCopies == 0) {
+        //We can eliminate the lower bits of the offset, and then use the id
+        //to offset within the blks
+        offset &= ~63; //Not the low order bits
+        offset += id;
+        access_size = 0;
+    }
 
     MemReqPtr req = new MemReq();
 
     if (cacheable < percentUncacheable) {
         req->flags |= UNCACHEABLE;
-        req->paddr = uncacheAddr + offset1;
+        req->paddr = uncacheAddr + offset;
     } else {
-        req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset1;
+        req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset;
     }
+    // bool probe = (random() % 2 == 1) && !req->isUncacheable();
+    bool probe = false;
 
     req->size = 1 << access_size;
     req->data = new uint8_t[req->size];
@@ -235,33 +272,105 @@ MemTest::tick()
 
     if (cmd < percentReads) {
         // read
+
+        //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(req->paddr) != outstandingAddrs.end()) return;
+        else outstandingAddrs.insert(req->paddr);
+
         req->cmd = Read;
         uint8_t *result = new uint8_t[8];
         checkMem->access(Read, req->paddr, result, req->size);
         if (blockAddr(req->paddr) == traceBlockAddr) {
-            cerr << name() << ": initiating read of "
-                 << req->size << " bytes from addr 0x"
-                 << hex << req->paddr << " at cycle "
+            cerr << name()
+                 << ": initiating read "
+                 << ((probe) ? "probe of " : "access of ")
+                 << dec << req->size << " bytes from addr 0x"
+                 << hex << req->paddr
+                 << " (0x" << hex << blockAddr(req->paddr) << ")"
+                 << " at cycle "
                  << dec << curTick << endl;
         }
-
-        req->completionEvent = new MemCompleteEvent(req, result, this);
-        cacheInterface->access(req);
-    } else {
+        if (probe) {
+            cacheInterface->probeAndUpdate(req);
+            completeRequest(req, result);
+        } else {
+            req->completionEvent = new MemCompleteEvent(req, result, this);
+            cacheInterface->access(req);
+        }
+    } else if (cmd < (100 - percentCopies)){
         // 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(req->paddr) != outstandingAddrs.end()) return;
+        else outstandingAddrs.insert(req->paddr);
+
         req->cmd = Write;
         memcpy(req->data, &data, req->size);
         checkMem->access(Write, req->paddr, req->data, req->size);
         if (blockAddr(req->paddr) == traceBlockAddr) {
-            cerr << name() << ": initiating write of "
-                 << req->size << " bytes (value = 0x";
+            cerr << name() << ": initiating write "
+                 << ((probe)?"probe of ":"access of ")
+                 << dec << req->size << " bytes (value = 0x";
             printData(cerr, req->data, req->size);
             cerr << ") to addr 0x"
-                 << hex << req->paddr << " at cycle "
+                 << hex << req->paddr
+                 << " (0x" << hex << blockAddr(req->paddr) << ")"
+                 << " at cycle "
+                 << dec << curTick << endl;
+        }
+        if (probe) {
+            cacheInterface->probeAndUpdate(req);
+            completeRequest(req, NULL);
+        } else {
+            req->completionEvent = new MemCompleteEvent(req, NULL, this);
+            cacheInterface->access(req);
+        }
+    } else {
+        // copy
+        unsigned source_align = random() % 100;
+        unsigned dest_align = random() % 100;
+        unsigned offset2 = random() % size;
+
+        Addr source = ((base) ? baseAddr1 : baseAddr2) + offset;
+        Addr dest = ((base) ? baseAddr2 : baseAddr1) + offset2;
+        if (outstandingAddrs.find(source) != outstandingAddrs.end()) return;
+        else outstandingAddrs.insert(source);
+        if (outstandingAddrs.find(dest) != outstandingAddrs.end()) return;
+        else outstandingAddrs.insert(dest);
+
+        if (source_align >= percentSourceUnaligned) {
+            source = blockAddr(source);
+        }
+        if (dest_align >= percentDestUnaligned) {
+            dest = blockAddr(dest);
+        }
+        req->cmd = Copy;
+        req->flags &= ~UNCACHEABLE;
+        req->paddr = source;
+        req->dest = dest;
+        delete [] req->data;
+        req->data = new uint8_t[blockSize];
+        req->size = blockSize;
+        if (source == traceBlockAddr || dest == traceBlockAddr) {
+            cerr << name()
+                 << ": initiating copy of "
+                 << dec << req->size << " bytes from addr 0x"
+                 << hex << source
+                 << " (0x" << hex << blockAddr(source) << ")"
+                 << " to addr 0x"
+                 << hex << dest
+                 << " (0x" << hex << blockAddr(dest) << ")"
+                 << " at cycle "
                  << dec << curTick << endl;
         }
-        req->completionEvent = new MemCompleteEvent(req, NULL, this);
         cacheInterface->access(req);
+        uint8_t result[blockSize];
+        checkMem->access(Read, source, &result, blockSize);
+        checkMem->access(Write, dest, &result, blockSize);
     }
 }
 
@@ -288,10 +397,13 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest)
     SimObjectParam<FunctionalMemory *> check_mem;
     Param<unsigned> memory_size;
     Param<unsigned> percent_reads;
+    Param<unsigned> percent_copies;
     Param<unsigned> percent_uncacheable;
-    Param<unsigned> max_reads;
     Param<unsigned> progress_interval;
+    Param<unsigned> percent_source_unaligned;
+    Param<unsigned> percent_dest_unaligned;
     Param<Addr> trace_addr;
+    Param<Counter> max_loads;
 
 END_DECLARE_SIM_OBJECT_PARAMS(MemTest)
 
@@ -301,13 +413,17 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest)
     INIT_PARAM(cache, "L1 cache"),
     INIT_PARAM(main_mem, "hierarchical memory"),
     INIT_PARAM(check_mem, "check memory"),
-    INIT_PARAM_DFLT(memory_size, "memory size", 65536),
-    INIT_PARAM_DFLT(percent_reads, "target read percentage", 65),
-    INIT_PARAM_DFLT(percent_uncacheable, "target uncacheable percentage", 10),
-    INIT_PARAM_DFLT(max_reads, "number of reads to simulate", 0),
-    INIT_PARAM_DFLT(progress_interval,
-                    "progress report interval (in accesses)", 1000000),
-    INIT_PARAM_DFLT(trace_addr, "address to trace", 0)
+    INIT_PARAM(memory_size, "memory size"),
+    INIT_PARAM(percent_reads, "target read percentage"),
+    INIT_PARAM(percent_copies, "target copy percentage"),
+    INIT_PARAM(percent_uncacheable, "target uncacheable percentage"),
+    INIT_PARAM(progress_interval, "progress report interval (in accesses)"),
+    INIT_PARAM(percent_source_unaligned,
+               "percent of copy source address that are unaligned"),
+    INIT_PARAM(percent_dest_unaligned,
+               "percent of copy dest address that are unaligned"),
+    INIT_PARAM(trace_addr, "address to trace"),
+    INIT_PARAM(max_loads, "terminate when we have reached this load count")
 
 END_INIT_SIM_OBJECT_PARAMS(MemTest)
 
@@ -315,10 +431,10 @@ END_INIT_SIM_OBJECT_PARAMS(MemTest)
 CREATE_SIM_OBJECT(MemTest)
 {
     return new MemTest(getInstanceName(), cache->getInterface(), main_mem,
-                       check_mem,
-                       memory_size, percent_reads,
-                       percent_uncacheable, max_reads, progress_interval,
-                       trace_addr);
+                       check_mem, memory_size, percent_reads, percent_copies,
+                       percent_uncacheable, progress_interval,
+                       percent_source_unaligned, percent_dest_unaligned,
+                       trace_addr, max_loads);
 }
 
 REGISTER_SIM_OBJECT("MemTest", MemTest)