memtest.cc revision 1899
15173Sgblack@eecs.umich.edu/* 25173Sgblack@eecs.umich.edu * Copyright (c) 2002-2005 The Regents of The University of Michigan 35173Sgblack@eecs.umich.edu * All rights reserved. 45173Sgblack@eecs.umich.edu * 55173Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 65173Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 75173Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 85173Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 95173Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 105173Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 115173Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 125173Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 135173Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 145173Sgblack@eecs.umich.edu * this software without specific prior written permission. 155173Sgblack@eecs.umich.edu * 165173Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 175173Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 185173Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 195173Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 205173Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 215173Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 225173Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 235173Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 245173Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255173Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 265173Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275173Sgblack@eecs.umich.edu */ 285173Sgblack@eecs.umich.edu 295173Sgblack@eecs.umich.edu// FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded 305173Sgblack@eecs.umich.edu 315173Sgblack@eecs.umich.edu#include <iomanip> 325173Sgblack@eecs.umich.edu#include <set> 335173Sgblack@eecs.umich.edu#include <sstream> 345173Sgblack@eecs.umich.edu#include <string> 355173Sgblack@eecs.umich.edu#include <vector> 365173Sgblack@eecs.umich.edu 375173Sgblack@eecs.umich.edu#include "base/misc.hh" 385173Sgblack@eecs.umich.edu#include "base/statistics.hh" 395173Sgblack@eecs.umich.edu#include "cpu/exec_context.hh" 405173Sgblack@eecs.umich.edu#include "cpu/memtest/memtest.hh" 415173Sgblack@eecs.umich.edu#include "mem/cache/base_cache.hh" 425173Sgblack@eecs.umich.edu#include "sim/builder.hh" 435173Sgblack@eecs.umich.edu#include "sim/sim_events.hh" 445173Sgblack@eecs.umich.edu#include "sim/stats.hh" 455173Sgblack@eecs.umich.edu 465173Sgblack@eecs.umich.eduusing namespace std; 475173Sgblack@eecs.umich.edu 485173Sgblack@eecs.umich.eduint TESTER_ALLOCATOR=0; 495173Sgblack@eecs.umich.edu 505173Sgblack@eecs.umich.eduMemTest::MemTest(const string &name, 515173Sgblack@eecs.umich.edu MemInterface *_cache_interface, 525173Sgblack@eecs.umich.edu FunctionalMemory *main_mem, 535173Sgblack@eecs.umich.edu FunctionalMemory *check_mem, 545173Sgblack@eecs.umich.edu unsigned _memorySize, 555173Sgblack@eecs.umich.edu unsigned _percentReads, 565173Sgblack@eecs.umich.edu unsigned _percentCopies, 575173Sgblack@eecs.umich.edu unsigned _percentUncacheable, 585173Sgblack@eecs.umich.edu unsigned _progressInterval, 595173Sgblack@eecs.umich.edu unsigned _percentSourceUnaligned, 605173Sgblack@eecs.umich.edu unsigned _percentDestUnaligned, 61 Addr _traceAddr, 62 Counter _max_loads) 63 : SimObject(name), 64 tickEvent(this), 65 cacheInterface(_cache_interface), 66 mainMem(main_mem), 67 checkMem(check_mem), 68 size(_memorySize), 69 percentReads(_percentReads), 70 percentCopies(_percentCopies), 71 percentUncacheable(_percentUncacheable), 72 progressInterval(_progressInterval), 73 nextProgressMessage(_progressInterval), 74 percentSourceUnaligned(_percentSourceUnaligned), 75 percentDestUnaligned(percentDestUnaligned), 76 maxLoads(_max_loads) 77{ 78 vector<string> cmd; 79 cmd.push_back("/bin/ls"); 80 vector<string> null_vec; 81 xc = new ExecContext(NULL, 0, mainMem, 0); 82 83 blockSize = cacheInterface->getBlockSize(); 84 blockAddrMask = blockSize - 1; 85 traceBlockAddr = blockAddr(_traceAddr); 86 87 //setup data storage with interesting values 88 uint8_t *data1 = new uint8_t[size]; 89 uint8_t *data2 = new uint8_t[size]; 90 uint8_t *data3 = new uint8_t[size]; 91 memset(data1, 1, size); 92 memset(data2, 2, size); 93 memset(data3, 3, size); 94 curTick = 0; 95 96 baseAddr1 = 0x100000; 97 baseAddr2 = 0x400000; 98 uncacheAddr = 0x800000; 99 100 // set up intial memory contents here 101 mainMem->prot_write(baseAddr1, data1, size); 102 checkMem->prot_write(baseAddr1, data1, size); 103 mainMem->prot_write(baseAddr2, data2, size); 104 checkMem->prot_write(baseAddr2, data2, size); 105 mainMem->prot_write(uncacheAddr, data3, size); 106 checkMem->prot_write(uncacheAddr, data3, size); 107 108 delete [] data1; 109 delete [] data2; 110 delete [] data3; 111 112 // set up counters 113 noResponseCycles = 0; 114 numReads = 0; 115 tickEvent.schedule(0); 116 117 id = TESTER_ALLOCATOR++; 118} 119 120static void 121printData(ostream &os, uint8_t *data, int nbytes) 122{ 123 os << hex << setfill('0'); 124 // assume little-endian: print bytes from highest address to lowest 125 for (uint8_t *dp = data + nbytes - 1; dp >= data; --dp) { 126 os << setw(2) << (unsigned)*dp; 127 } 128 os << dec; 129} 130 131void 132MemTest::completeRequest(MemReqPtr &req, uint8_t *data) 133{ 134 //Remove the address from the list of outstanding 135 std::set<unsigned>::iterator removeAddr = outstandingAddrs.find(req->paddr); 136 assert(removeAddr != outstandingAddrs.end()); 137 outstandingAddrs.erase(removeAddr); 138 139 switch (req->cmd) { 140 case Read: 141 if (memcmp(req->data, data, req->size) != 0) { 142 cerr << name() << ": on read of 0x" << hex << req->paddr 143 << " (0x" << hex << blockAddr(req->paddr) << ")" 144 << "@ cycle " << dec << curTick 145 << ", cache returns 0x"; 146 printData(cerr, req->data, req->size); 147 cerr << ", expected 0x"; 148 printData(cerr, data, req->size); 149 cerr << endl; 150 fatal(""); 151 } 152 153 numReads++; 154 numReadsStat++; 155 156 if (numReads == nextProgressMessage) { 157 ccprintf(cerr, "%s: completed %d read accesses @%d\n", 158 name(), numReads, curTick); 159 nextProgressMessage += progressInterval; 160 } 161 162 if (numReads >= maxLoads) 163 SimExit(curTick, "Maximum number of loads reached!"); 164 break; 165 166 case Write: 167 numWritesStat++; 168 break; 169 170 case Copy: 171 //Also remove dest from outstanding list 172 removeAddr = outstandingAddrs.find(req->dest); 173 assert(removeAddr != outstandingAddrs.end()); 174 outstandingAddrs.erase(removeAddr); 175 numCopiesStat++; 176 break; 177 178 default: 179 panic("invalid command"); 180 } 181 182 if (blockAddr(req->paddr) == traceBlockAddr) { 183 cerr << name() << ": completed " 184 << (req->cmd.isWrite() ? "write" : "read") 185 << " access of " 186 << dec << req->size << " bytes at address 0x" 187 << hex << req->paddr 188 << " (0x" << hex << blockAddr(req->paddr) << ")" 189 << ", value = 0x"; 190 printData(cerr, req->data, req->size); 191 cerr << " @ cycle " << dec << curTick; 192 193 cerr << endl; 194 } 195 196 noResponseCycles = 0; 197 delete [] data; 198} 199 200 201void 202MemTest::regStats() 203{ 204 using namespace Stats; 205 206 207 numReadsStat 208 .name(name() + ".num_reads") 209 .desc("number of read accesses completed") 210 ; 211 212 numWritesStat 213 .name(name() + ".num_writes") 214 .desc("number of write accesses completed") 215 ; 216 217 numCopiesStat 218 .name(name() + ".num_copies") 219 .desc("number of copy accesses completed") 220 ; 221} 222 223void 224MemTest::tick() 225{ 226 if (!tickEvent.scheduled()) 227 tickEvent.schedule(curTick + cycles(1)); 228 229 if (++noResponseCycles >= 500000) { 230 cerr << name() << ": deadlocked at cycle " << curTick << endl; 231 fatal(""); 232 } 233 234 if (cacheInterface->isBlocked()) { 235 return; 236 } 237 238 //make new request 239 unsigned cmd = random() % 100; 240 unsigned offset = random() % size; 241 unsigned base = random() % 2; 242 uint64_t data = random(); 243 unsigned access_size = random() % 4; 244 unsigned cacheable = random() % 100; 245 246 //If we aren't doing copies, use id as offset, and do a false sharing 247 //mem tester 248 if (percentCopies == 0) { 249 //We can eliminate the lower bits of the offset, and then use the id 250 //to offset within the blks 251 offset &= ~63; //Not the low order bits 252 offset += id; 253 access_size = 0; 254 } 255 256 MemReqPtr req = new MemReq(); 257 258 if (cacheable < percentUncacheable) { 259 req->flags |= UNCACHEABLE; 260 req->paddr = uncacheAddr + offset; 261 } else { 262 req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset; 263 } 264 // bool probe = (random() % 2 == 1) && !req->isUncacheable(); 265 bool probe = false; 266 267 req->size = 1 << access_size; 268 req->data = new uint8_t[req->size]; 269 req->paddr &= ~(req->size - 1); 270 req->time = curTick; 271 req->xc = xc; 272 273 if (cmd < percentReads) { 274 // read 275 276 //For now we only allow one outstanding request per addreess per tester 277 //This means we assume CPU does write forwarding to reads that alias something 278 //in the cpu store buffer. 279 if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return; 280 else outstandingAddrs.insert(req->paddr); 281 282 req->cmd = Read; 283 uint8_t *result = new uint8_t[8]; 284 checkMem->access(Read, req->paddr, result, req->size); 285 if (blockAddr(req->paddr) == traceBlockAddr) { 286 cerr << name() 287 << ": initiating read " 288 << ((probe) ? "probe of " : "access of ") 289 << dec << req->size << " bytes from addr 0x" 290 << hex << req->paddr 291 << " (0x" << hex << blockAddr(req->paddr) << ")" 292 << " at cycle " 293 << dec << curTick << endl; 294 } 295 if (probe) { 296 cacheInterface->probeAndUpdate(req); 297 completeRequest(req, result); 298 } else { 299 req->completionEvent = new MemCompleteEvent(req, result, this); 300 cacheInterface->access(req); 301 } 302 } else if (cmd < (100 - percentCopies)){ 303 // write 304 305 //For now we only allow one outstanding request per addreess per tester 306 //This means we assume CPU does write forwarding to reads that alias something 307 //in the cpu store buffer. 308 if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return; 309 else outstandingAddrs.insert(req->paddr); 310 311 req->cmd = Write; 312 memcpy(req->data, &data, req->size); 313 checkMem->access(Write, req->paddr, req->data, req->size); 314 if (blockAddr(req->paddr) == traceBlockAddr) { 315 cerr << name() << ": initiating write " 316 << ((probe)?"probe of ":"access of ") 317 << dec << req->size << " bytes (value = 0x"; 318 printData(cerr, req->data, req->size); 319 cerr << ") to addr 0x" 320 << hex << req->paddr 321 << " (0x" << hex << blockAddr(req->paddr) << ")" 322 << " at cycle " 323 << dec << curTick << endl; 324 } 325 if (probe) { 326 cacheInterface->probeAndUpdate(req); 327 completeRequest(req, NULL); 328 } else { 329 req->completionEvent = new MemCompleteEvent(req, NULL, this); 330 cacheInterface->access(req); 331 } 332 } else { 333 // copy 334 unsigned source_align = random() % 100; 335 unsigned dest_align = random() % 100; 336 unsigned offset2 = random() % size; 337 338 Addr source = ((base) ? baseAddr1 : baseAddr2) + offset; 339 Addr dest = ((base) ? baseAddr2 : baseAddr1) + offset2; 340 if (outstandingAddrs.find(source) != outstandingAddrs.end()) return; 341 else outstandingAddrs.insert(source); 342 if (outstandingAddrs.find(dest) != outstandingAddrs.end()) return; 343 else outstandingAddrs.insert(dest); 344 345 if (source_align >= percentSourceUnaligned) { 346 source = blockAddr(source); 347 } 348 if (dest_align >= percentDestUnaligned) { 349 dest = blockAddr(dest); 350 } 351 req->cmd = Copy; 352 req->flags &= ~UNCACHEABLE; 353 req->paddr = source; 354 req->dest = dest; 355 delete [] req->data; 356 req->data = new uint8_t[blockSize]; 357 req->size = blockSize; 358 if (source == traceBlockAddr || dest == traceBlockAddr) { 359 cerr << name() 360 << ": initiating copy of " 361 << dec << req->size << " bytes from addr 0x" 362 << hex << source 363 << " (0x" << hex << blockAddr(source) << ")" 364 << " to addr 0x" 365 << hex << dest 366 << " (0x" << hex << blockAddr(dest) << ")" 367 << " at cycle " 368 << dec << curTick << endl; 369 } 370 cacheInterface->access(req); 371 uint8_t result[blockSize]; 372 checkMem->access(Read, source, &result, blockSize); 373 checkMem->access(Write, dest, &result, blockSize); 374 } 375} 376 377 378void 379MemCompleteEvent::process() 380{ 381 tester->completeRequest(req, data); 382 delete this; 383} 384 385 386const char * 387MemCompleteEvent::description() 388{ 389 return "memory access completion"; 390} 391 392 393BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest) 394 395 SimObjectParam<BaseCache *> cache; 396 SimObjectParam<FunctionalMemory *> main_mem; 397 SimObjectParam<FunctionalMemory *> check_mem; 398 Param<unsigned> memory_size; 399 Param<unsigned> percent_reads; 400 Param<unsigned> percent_copies; 401 Param<unsigned> percent_uncacheable; 402 Param<unsigned> progress_interval; 403 Param<unsigned> percent_source_unaligned; 404 Param<unsigned> percent_dest_unaligned; 405 Param<Addr> trace_addr; 406 Param<Counter> max_loads; 407 408END_DECLARE_SIM_OBJECT_PARAMS(MemTest) 409 410 411BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest) 412 413 INIT_PARAM(cache, "L1 cache"), 414 INIT_PARAM(main_mem, "hierarchical memory"), 415 INIT_PARAM(check_mem, "check memory"), 416 INIT_PARAM(memory_size, "memory size"), 417 INIT_PARAM(percent_reads, "target read percentage"), 418 INIT_PARAM(percent_copies, "target copy percentage"), 419 INIT_PARAM(percent_uncacheable, "target uncacheable percentage"), 420 INIT_PARAM(progress_interval, "progress report interval (in accesses)"), 421 INIT_PARAM(percent_source_unaligned, 422 "percent of copy source address that are unaligned"), 423 INIT_PARAM(percent_dest_unaligned, 424 "percent of copy dest address that are unaligned"), 425 INIT_PARAM(trace_addr, "address to trace"), 426 INIT_PARAM(max_loads, "terminate when we have reached this load count") 427 428END_INIT_SIM_OBJECT_PARAMS(MemTest) 429 430 431CREATE_SIM_OBJECT(MemTest) 432{ 433 return new MemTest(getInstanceName(), cache->getInterface(), main_mem, 434 check_mem, memory_size, percent_reads, percent_copies, 435 percent_uncacheable, progress_interval, 436 percent_source_unaligned, percent_dest_unaligned, 437 trace_addr, max_loads); 438} 439 440REGISTER_SIM_OBJECT("MemTest", MemTest) 441