memtest.cc revision 145
1/* 2 * Copyright (c) 2003 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29// FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded 30 31#include <string> 32#include <sstream> 33#include <iomanip> 34#include <vector> 35 36#include "cpu/memtest/memtest.hh" 37#include "base/misc.hh" 38#include "sim/sim_events.hh" 39#include "mem/functional_mem/main_memory.hh" 40#include "mem/cache/base_cache.hh" 41 42#include "base/statistics.hh" 43#include "sim/sim_stats.hh" 44 45using namespace std; 46 47MemTest::MemTest(const string &name, 48 MemInterface *_cache_interface, 49 FunctionalMemory *main_mem, 50 FunctionalMemory *check_mem, 51 unsigned _memorySize, 52 unsigned _percentReads, 53 unsigned _percentUncacheable, 54 unsigned _progressInterval, 55 Addr _traceAddr, 56 Counter max_loads_any_thread, 57 Counter max_loads_all_threads) 58 : BaseCPU(name, 1, 0, 0, max_loads_any_thread, max_loads_all_threads), 59 tickEvent(this), 60 cacheInterface(_cache_interface), 61 mainMem(main_mem), 62 checkMem(check_mem), 63 size(_memorySize), 64 percentReads(_percentReads), 65 percentUncacheable(_percentUncacheable), 66 progressInterval(_progressInterval), 67 nextProgressMessage(_progressInterval) 68{ 69 vector<string> cmd; 70 cmd.push_back("/bin/ls"); 71 vector<string> null_vec; 72 xc = new ExecContext(this ,0,mainMem,0); 73 74 blockSize = cacheInterface->getBlockSize(); 75 blockAddrMask = blockSize - 1; 76 traceBlockAddr = blockAddr(_traceAddr); 77 78 //setup data storage with interesting values 79 uint8_t *data1 = new uint8_t[size]; 80 uint8_t *data2 = new uint8_t[size]; 81 uint8_t *data3 = new uint8_t[size]; 82 memset(data1, 1, size); 83 memset(data2, 2, size); 84 memset(data3, 3, size); 85 curTick = 0; 86 87 baseAddr1 = 0x100000; 88 baseAddr2 = 0x400000; 89 uncacheAddr = 0x800000; 90 91 // set up intial memory contents here 92 mainMem->prot_write(baseAddr1, data1, size); 93 checkMem->prot_write(baseAddr1, data1, size); 94 mainMem->prot_write(baseAddr2, data2, size); 95 checkMem->prot_write(baseAddr2, data2, size); 96 mainMem->prot_write(uncacheAddr, data3, size); 97 checkMem->prot_write(uncacheAddr, data3, size); 98 99 delete [] data1; 100 delete [] data2; 101 delete [] data3; 102 103 // set up counters 104 noResponseCycles = 0; 105 numReads = 0; 106 numWrites = 0; 107 tickEvent.schedule(0); 108} 109 110static void 111printData(ostream &os, uint8_t *data, int nbytes) 112{ 113 os << hex << setfill('0'); 114 // assume little-endian: print bytes from highest address to lowest 115 for (uint8_t *dp = data + nbytes - 1; dp >= data; --dp) { 116 os << setw(2) << (unsigned)*dp; 117 } 118 os << dec; 119} 120 121void 122MemTest::completeRequest(MemReqPtr req, uint8_t *data) 123{ 124 switch (req->cmd) { 125 case Read: 126 if (memcmp(req->data, data, req->size) != 0) { 127 cerr << name() << ": on read of 0x" << hex << req->paddr 128 << " @ cycle " << dec << curTick 129 << ", cache returns 0x"; 130 printData(cerr, req->data, req->size); 131 cerr << ", expected 0x"; 132 printData(cerr, data, req->size); 133 cerr << endl; 134 fatal(""); 135 } 136 137 numReads++; 138 139 if (numReads.value() == nextProgressMessage) { 140 cerr << name() << ": completed " << numReads.value() 141 << " read accesses @ " << curTick << endl; 142 nextProgressMessage += progressInterval; 143 } 144 145 comLoadEventQueue[0]->serviceEvents(numReads.value()); 146 break; 147 148 case Write: 149 numWrites++; 150 break; 151 152 153 default: 154 panic("invalid command"); 155 } 156 157 if (blockAddr(req->paddr) == traceBlockAddr) { 158 cerr << name() << ": completed " 159 << (req->cmd.isWrite() ? "write" : "read") << " access of " 160 << req->size << " bytes at address 0x" 161 << hex << req->paddr << ", value = 0x"; 162 printData(cerr, req->data, req->size); 163 cerr << " @ cycle " << dec << curTick; 164 165 cerr << endl; 166 } 167 168 noResponseCycles = 0; 169 delete [] data; 170} 171 172 173void 174MemTest::regStats() 175{ 176 using namespace Statistics; 177 178 numReads 179 .name(name() + ".num_reads") 180 .desc("number of read accesses completed") 181 ; 182 183 numWrites 184 .name(name() + ".num_writes") 185 .desc("number of write accesses completed") 186 ; 187 188 numCopies 189 .name(name() + ".num_copies") 190 .desc("number of copy accesses completed") 191 ; 192} 193 194void 195MemTest::tick() 196{ 197 if (!tickEvent.scheduled()) 198 tickEvent.schedule(curTick + 1); 199 200 if (++noResponseCycles >= 5000) { 201 cerr << name() << ": deadlocked at cycle " << curTick << endl; 202 fatal(""); 203 } 204 205 if (cacheInterface->isBlocked()) { 206 return; 207 } 208 209 //make new request 210 unsigned cmd = rand() % 100; 211 unsigned offset1 = random() % size; 212 unsigned base = random() % 2; 213 uint64_t data = random(); 214 unsigned access_size = random() % 4; 215 unsigned cacheable = rand() % 100; 216 unsigned probe = rand() % 2; 217 218 MemReqPtr req = new MemReq(); 219 220 if (cacheable < percentUncacheable) { 221 req->flags |= UNCACHEABLE; 222 req->paddr = uncacheAddr + offset1; 223 } else { 224 req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset1; 225 } 226 227 req->size = 1 << access_size; 228 req->data = new uint8_t[req->size]; 229 req->paddr &= ~(req->size - 1); 230 req->time = curTick; 231 req->xc = xc; 232 233 if (cmd < percentReads) { 234 // read 235 req->cmd = Read; 236 uint8_t *result = new uint8_t[8]; 237 checkMem->access(Read, req->paddr, result, req->size); 238 if (blockAddr(req->paddr) == traceBlockAddr) { 239 cerr << name() << ": initiating read " 240 << ((probe)?"probe of ":"access of ") 241 << req->size << " bytes from addr 0x" 242 << hex << req->paddr << " at cycle " 243 << dec << curTick << endl; 244 } 245 if (probe) { 246 cacheInterface->probeAndUpdate(req); 247 completeRequest(req, result); 248 } else { 249 req->completionEvent = new MemCompleteEvent(req, result, this); 250 cacheInterface->access(req); 251 } 252 } else { 253 // write 254 req->cmd = Write; 255 memcpy(req->data, &data, req->size); 256 checkMem->access(Write, req->paddr, req->data, req->size); 257 if (blockAddr(req->paddr) == traceBlockAddr) { 258 cerr << name() << ": initiating write " 259 << ((probe)?"probe of ":"access of ") 260 << req->size << " bytes (value = 0x"; 261 printData(cerr, req->data, req->size); 262 cerr << ") to addr 0x" 263 << hex << req->paddr << " at cycle " 264 << dec << curTick << endl; 265 } 266 if (probe) { 267 cacheInterface->probeAndUpdate(req); 268 completeRequest(req, NULL); 269 } else { 270 req->completionEvent = new MemCompleteEvent(req, NULL, this); 271 cacheInterface->access(req); 272 } 273 } 274} 275 276 277void 278MemCompleteEvent::process() 279{ 280 tester->completeRequest(req, data); 281 delete this; 282} 283 284 285const char * 286MemCompleteEvent::description() 287{ 288 return "memory access completion"; 289} 290 291 292BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest) 293 294 SimObjectParam<BaseCache *> cache; 295 SimObjectParam<FunctionalMemory *> main_mem; 296 SimObjectParam<FunctionalMemory *> check_mem; 297 Param<unsigned> memory_size; 298 Param<unsigned> percent_reads; 299 Param<unsigned> percent_uncacheable; 300 Param<unsigned> progress_interval; 301 Param<Addr> trace_addr; 302 Param<Counter> max_loads_any_thread; 303 Param<Counter> max_loads_all_threads; 304 305END_DECLARE_SIM_OBJECT_PARAMS(MemTest) 306 307 308BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest) 309 310 INIT_PARAM(cache, "L1 cache"), 311 INIT_PARAM(main_mem, "hierarchical memory"), 312 INIT_PARAM(check_mem, "check memory"), 313 INIT_PARAM_DFLT(memory_size, "memory size", 65536), 314 INIT_PARAM_DFLT(percent_reads, "target read percentage", 65), 315 INIT_PARAM_DFLT(percent_uncacheable, "target uncacheable percentage", 10), 316 INIT_PARAM_DFLT(progress_interval, 317 "progress report interval (in accesses)", 1000000), 318 INIT_PARAM_DFLT(trace_addr, "address to trace", 0), 319 INIT_PARAM_DFLT(max_loads_any_thread, 320 "terminate when any thread reaches this load count", 321 0), 322 INIT_PARAM_DFLT(max_loads_all_threads, 323 "terminate when all threads have reached this load count", 324 0) 325 326END_INIT_SIM_OBJECT_PARAMS(MemTest) 327 328 329CREATE_SIM_OBJECT(MemTest) 330{ 331 return new MemTest(getInstanceName(), cache->getInterface(), main_mem, 332 check_mem, memory_size, percent_reads, 333 percent_uncacheable, progress_interval, 334 trace_addr, max_loads_any_thread, 335 max_loads_all_threads); 336} 337 338REGISTER_SIM_OBJECT("MemTest", MemTest) 339