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