memtest.cc revision 1259
1/* 2 * Copyright (c) 2002-2004 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 "base/misc.hh" 37#include "base/statistics.hh" 38#include "cpu/memtest/memtest.hh" 39#include "mem/cache/base_cache.hh" 40#include "mem/functional_mem/main_memory.hh" 41#include "sim/builder.hh" 42#include "sim/sim_events.hh" 43#include "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 _percentCopies, 54 unsigned _percentUncacheable, 55 unsigned _progressInterval, 56 unsigned _percentSourceUnaligned, 57 unsigned _percentDestUnaligned, 58 Addr _traceAddr, 59 Counter max_loads_any_thread, 60 Counter max_loads_all_threads) 61 : BaseCPU(name, 1, true, 0, 0, max_loads_any_thread, 62 max_loads_all_threads), 63 tickEvent(this), 64 cacheInterface(_cache_interface), 65 mainMem(main_mem), 66 checkMem(check_mem), 67 size(_memorySize), 68 percentReads(_percentReads), 69 percentCopies(_percentCopies), 70 percentUncacheable(_percentUncacheable), 71 progressInterval(_progressInterval), 72 nextProgressMessage(_progressInterval), 73 percentSourceUnaligned(_percentSourceUnaligned), 74 percentDestUnaligned(percentDestUnaligned) 75{ 76 vector<string> cmd; 77 cmd.push_back("/bin/ls"); 78 vector<string> null_vec; 79 xc = new ExecContext(this ,0,mainMem,0); 80 81 blockSize = cacheInterface->getBlockSize(); 82 blockAddrMask = blockSize - 1; 83 traceBlockAddr = blockAddr(_traceAddr); 84 85 //setup data storage with interesting values 86 uint8_t *data1 = new uint8_t[size]; 87 uint8_t *data2 = new uint8_t[size]; 88 uint8_t *data3 = new uint8_t[size]; 89 memset(data1, 1, size); 90 memset(data2, 2, size); 91 memset(data3, 3, size); 92 curTick = 0; 93 94 baseAddr1 = 0x100000; 95 baseAddr2 = 0x400000; 96 uncacheAddr = 0x800000; 97 98 // set up intial memory contents here 99 mainMem->prot_write(baseAddr1, data1, size); 100 checkMem->prot_write(baseAddr1, data1, size); 101 mainMem->prot_write(baseAddr2, data2, size); 102 checkMem->prot_write(baseAddr2, data2, size); 103 mainMem->prot_write(uncacheAddr, data3, size); 104 checkMem->prot_write(uncacheAddr, data3, size); 105 106 delete [] data1; 107 delete [] data2; 108 delete [] data3; 109 110 // set up counters 111 noResponseCycles = 0; 112 numReads = 0; 113 tickEvent.schedule(0); 114} 115 116static void 117printData(ostream &os, uint8_t *data, int nbytes) 118{ 119 os << hex << setfill('0'); 120 // assume little-endian: print bytes from highest address to lowest 121 for (uint8_t *dp = data + nbytes - 1; dp >= data; --dp) { 122 os << setw(2) << (unsigned)*dp; 123 } 124 os << dec; 125} 126 127void 128MemTest::completeRequest(MemReqPtr &req, uint8_t *data) 129{ 130 switch (req->cmd) { 131 case Read: 132 if (memcmp(req->data, data, req->size) != 0) { 133 cerr << name() << ": on read of 0x" << hex << req->paddr 134 << " (0x" << hex << blockAddr(req->paddr) << ")" 135 << "@ cycle " << dec << curTick 136 << ", cache returns 0x"; 137 printData(cerr, req->data, req->size); 138 cerr << ", expected 0x"; 139 printData(cerr, data, req->size); 140 cerr << endl; 141 fatal(""); 142 } 143 144 numReads++; 145 numReadsStat++; 146 147 if (numReads == nextProgressMessage) { 148 ccprintf(cerr, "%s: completed %d read accesses @%d\n", 149 name(), numReads, curTick); 150 nextProgressMessage += progressInterval; 151 } 152 153 comLoadEventQueue[0]->serviceEvents(numReads); 154 break; 155 156 case Write: 157 numWritesStat++; 158 break; 159 160 case Copy: 161 numCopiesStat++; 162 break; 163 164 default: 165 panic("invalid command"); 166 } 167 168 if (blockAddr(req->paddr) == traceBlockAddr) { 169 cerr << name() << ": completed " 170 << (req->cmd.isWrite() ? "write" : "read") 171 << " access of " 172 << dec << req->size << " bytes at address 0x" 173 << hex << req->paddr 174 << " (0x" << hex << blockAddr(req->paddr) << ")" 175 << ", value = 0x"; 176 printData(cerr, req->data, req->size); 177 cerr << " @ cycle " << dec << curTick; 178 179 cerr << endl; 180 } 181 182 noResponseCycles = 0; 183 delete [] data; 184} 185 186 187void 188MemTest::regStats() 189{ 190 using namespace Stats; 191 192 193 numReadsStat 194 .name(name() + ".num_reads") 195 .desc("number of read accesses completed") 196 ; 197 198 numWritesStat 199 .name(name() + ".num_writes") 200 .desc("number of write accesses completed") 201 ; 202 203 numCopiesStat 204 .name(name() + ".num_copies") 205 .desc("number of copy accesses completed") 206 ; 207} 208 209void 210MemTest::tick() 211{ 212 if (!tickEvent.scheduled()) 213 tickEvent.schedule(curTick + 1); 214 215 if (++noResponseCycles >= 5000) { 216 cerr << name() << ": deadlocked at cycle " << curTick << endl; 217 fatal(""); 218 } 219 220 if (cacheInterface->isBlocked()) { 221 return; 222 } 223 224 //make new request 225 unsigned cmd = rand() % 100; 226 unsigned offset1 = random() % size; 227 unsigned offset2 = random() % size; 228 unsigned base = random() % 2; 229 uint64_t data = random(); 230 unsigned access_size = random() % 4; 231 unsigned cacheable = rand() % 100; 232 unsigned source_align = rand() % 100; 233 unsigned dest_align = rand() % 100; 234 235 MemReqPtr req = new MemReq(); 236 237 if (cacheable < percentUncacheable) { 238 req->flags |= UNCACHEABLE; 239 req->paddr = uncacheAddr + offset1; 240 } else { 241 req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset1; 242 } 243 bool probe = (rand() % 2 == 1) && !req->isUncacheable(); 244 probe = false; 245 246 req->size = 1 << access_size; 247 req->data = new uint8_t[req->size]; 248 req->paddr &= ~(req->size - 1); 249 req->time = curTick; 250 req->xc = xc; 251 252 if (cmd < percentReads) { 253 // read 254 req->cmd = Read; 255 uint8_t *result = new uint8_t[8]; 256 checkMem->access(Read, req->paddr, result, req->size); 257 if (blockAddr(req->paddr) == traceBlockAddr) { 258 cerr << name() 259 << ": initiating read " 260 << ((probe)?"probe of ":"access of ") 261 << dec << req->size << " bytes from addr 0x" 262 << hex << req->paddr 263 << " (0x" << hex << blockAddr(req->paddr) << ")" 264 << " at cycle " 265 << dec << curTick << endl; 266 } 267 if (probe) { 268 cacheInterface->probeAndUpdate(req); 269 completeRequest(req, result); 270 } else { 271 req->completionEvent = new MemCompleteEvent(req, result, this); 272 cacheInterface->access(req); 273 } 274 } else if (cmd < (100 - percentCopies)){ 275 // write 276 req->cmd = Write; 277 memcpy(req->data, &data, req->size); 278 checkMem->access(Write, req->paddr, req->data, req->size); 279 if (blockAddr(req->paddr) == traceBlockAddr) { 280 cerr << name() << ": initiating write " 281 << ((probe)?"probe of ":"access of ") 282 << dec << req->size << " bytes (value = 0x"; 283 printData(cerr, req->data, req->size); 284 cerr << ") to addr 0x" 285 << hex << req->paddr 286 << " (0x" << hex << blockAddr(req->paddr) << ")" 287 << " at cycle " 288 << dec << curTick << endl; 289 } 290 if (probe) { 291 cacheInterface->probeAndUpdate(req); 292 completeRequest(req, NULL); 293 } else { 294 req->completionEvent = new MemCompleteEvent(req, NULL, this); 295 cacheInterface->access(req); 296 } 297 } else { 298 // copy 299 Addr source = ((base) ? baseAddr1 : baseAddr2) + offset1; 300 Addr dest = ((base) ? baseAddr2 : baseAddr1) + offset2; 301 if (source_align >= percentSourceUnaligned) { 302 source = blockAddr(source); 303 } 304 if (dest_align >= percentDestUnaligned) { 305 dest = blockAddr(dest); 306 } 307 req->cmd = Copy; 308 req->flags &= ~UNCACHEABLE; 309 req->paddr = source; 310 req->dest = dest; 311 delete [] req->data; 312 req->data = new uint8_t[blockSize]; 313 req->size = blockSize; 314 if (source == traceBlockAddr || dest == traceBlockAddr) { 315 cerr << name() 316 << ": initiating copy of " 317 << dec << req->size << " bytes from addr 0x" 318 << hex << source 319 << " (0x" << hex << blockAddr(source) << ")" 320 << " to addr 0x" 321 << hex << dest 322 << " (0x" << hex << blockAddr(dest) << ")" 323 << " at cycle " 324 << dec << curTick << endl; 325 } 326 cacheInterface->access(req); 327 uint8_t result[blockSize]; 328 checkMem->access(Read, source, &result, blockSize); 329 checkMem->access(Write, dest, &result, blockSize); 330 } 331} 332 333 334void 335MemCompleteEvent::process() 336{ 337 tester->completeRequest(req, data); 338 delete this; 339} 340 341 342const char * 343MemCompleteEvent::description() 344{ 345 return "memory access completion"; 346} 347 348 349BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest) 350 351 SimObjectParam<BaseCache *> cache; 352 SimObjectParam<FunctionalMemory *> main_mem; 353 SimObjectParam<FunctionalMemory *> check_mem; 354 Param<unsigned> memory_size; 355 Param<unsigned> percent_reads; 356 Param<unsigned> percent_copies; 357 Param<unsigned> percent_uncacheable; 358 Param<unsigned> progress_interval; 359 Param<unsigned> percent_source_unaligned; 360 Param<unsigned> percent_dest_unaligned; 361 Param<Addr> trace_addr; 362 Param<Counter> max_loads_any_thread; 363 Param<Counter> max_loads_all_threads; 364 365END_DECLARE_SIM_OBJECT_PARAMS(MemTest) 366 367 368BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest) 369 370 INIT_PARAM(cache, "L1 cache"), 371 INIT_PARAM(main_mem, "hierarchical memory"), 372 INIT_PARAM(check_mem, "check memory"), 373 INIT_PARAM_DFLT(memory_size, "memory size", 65536), 374 INIT_PARAM_DFLT(percent_reads, "target read percentage", 65), 375 INIT_PARAM_DFLT(percent_copies, "target copy percentage", 0), 376 INIT_PARAM_DFLT(percent_uncacheable, "target uncacheable percentage", 10), 377 INIT_PARAM_DFLT(progress_interval, 378 "progress report interval (in accesses)", 1000000), 379 INIT_PARAM_DFLT(percent_source_unaligned, "percent of copy source address " 380 "that are unaligned", 50), 381 INIT_PARAM_DFLT(percent_dest_unaligned, "percent of copy dest address " 382 "that are unaligned", 50), 383 INIT_PARAM_DFLT(trace_addr, "address to trace", 0), 384 INIT_PARAM_DFLT(max_loads_any_thread, 385 "terminate when any thread reaches this load count", 386 0), 387 INIT_PARAM_DFLT(max_loads_all_threads, 388 "terminate when all threads have reached this load count", 389 0) 390 391END_INIT_SIM_OBJECT_PARAMS(MemTest) 392 393 394CREATE_SIM_OBJECT(MemTest) 395{ 396 return new MemTest(getInstanceName(), cache->getInterface(), main_mem, 397 check_mem, memory_size, percent_reads, percent_copies, 398 percent_uncacheable, progress_interval, 399 percent_source_unaligned, percent_dest_unaligned, 400 trace_addr, max_loads_any_thread, 401 max_loads_all_threads); 402} 403 404REGISTER_SIM_OBJECT("MemTest", MemTest) 405