cpu: add more instruction mix statistics
[gem5.git] / src / cpu / simple / base.cc
1 /*
2 * Copyright (c) 2010-2012 ARM Limited
3 * Copyright (c) 2013 Advanced Micro Devices, Inc.
4 * All rights reserved
5 *
6 * The license below extends only to copyright in the software and shall
7 * not be construed as granting a license to any other intellectual
8 * property including but not limited to intellectual property relating
9 * to a hardware implementation of the functionality of the software
10 * licensed hereunder. You may use the software subject to the license
11 * terms below provided that you ensure that this notice is replicated
12 * unmodified and in its entirety in all distributions of the software,
13 * modified or unmodified, in source code or in binary form.
14 *
15 * Copyright (c) 2002-2005 The Regents of The University of Michigan
16 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Authors: Steve Reinhardt
42 */
43
44 #include "arch/kernel_stats.hh"
45 #include "arch/stacktrace.hh"
46 #include "arch/tlb.hh"
47 #include "arch/utility.hh"
48 #include "arch/vtophys.hh"
49 #include "base/loader/symtab.hh"
50 #include "base/cp_annotate.hh"
51 #include "base/cprintf.hh"
52 #include "base/inifile.hh"
53 #include "base/misc.hh"
54 #include "base/pollevent.hh"
55 #include "base/trace.hh"
56 #include "base/types.hh"
57 #include "config/the_isa.hh"
58 #include "cpu/simple/base.hh"
59 #include "cpu/base.hh"
60 #include "cpu/checker/cpu.hh"
61 #include "cpu/checker/thread_context.hh"
62 #include "cpu/exetrace.hh"
63 #include "cpu/pred/bpred_unit.hh"
64 #include "cpu/profile.hh"
65 #include "cpu/simple_thread.hh"
66 #include "cpu/smt.hh"
67 #include "cpu/static_inst.hh"
68 #include "cpu/thread_context.hh"
69 #include "debug/Decode.hh"
70 #include "debug/Fetch.hh"
71 #include "debug/Quiesce.hh"
72 #include "mem/mem_object.hh"
73 #include "mem/packet.hh"
74 #include "mem/request.hh"
75 #include "params/BaseSimpleCPU.hh"
76 #include "sim/byteswap.hh"
77 #include "sim/debug.hh"
78 #include "sim/faults.hh"
79 #include "sim/full_system.hh"
80 #include "sim/sim_events.hh"
81 #include "sim/sim_object.hh"
82 #include "sim/stats.hh"
83 #include "sim/system.hh"
84
85 using namespace std;
86 using namespace TheISA;
87
88 BaseSimpleCPU::BaseSimpleCPU(BaseSimpleCPUParams *p)
89 : BaseCPU(p),
90 branchPred(p->branchPred),
91 traceData(NULL), thread(NULL)
92 {
93 if (FullSystem)
94 thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb,
95 p->isa[0]);
96 else
97 thread = new SimpleThread(this, /* thread_num */ 0, p->system,
98 p->workload[0], p->itb, p->dtb, p->isa[0]);
99
100 thread->setStatus(ThreadContext::Halted);
101
102 tc = thread->getTC();
103
104 if (p->checker) {
105 BaseCPU *temp_checker = p->checker;
106 checker = dynamic_cast<CheckerCPU *>(temp_checker);
107 checker->setSystem(p->system);
108 // Manipulate thread context
109 ThreadContext *cpu_tc = tc;
110 tc = new CheckerThreadContext<ThreadContext>(cpu_tc, this->checker);
111 } else {
112 checker = NULL;
113 }
114
115 numInst = 0;
116 startNumInst = 0;
117 numOp = 0;
118 startNumOp = 0;
119 numLoad = 0;
120 startNumLoad = 0;
121 lastIcacheStall = 0;
122 lastDcacheStall = 0;
123
124 threadContexts.push_back(tc);
125
126
127 fetchOffset = 0;
128 stayAtPC = false;
129 }
130
131 BaseSimpleCPU::~BaseSimpleCPU()
132 {
133 }
134
135 void
136 BaseSimpleCPU::deallocateContext(ThreadID thread_num)
137 {
138 // for now, these are equivalent
139 suspendContext(thread_num);
140 }
141
142
143 void
144 BaseSimpleCPU::haltContext(ThreadID thread_num)
145 {
146 // for now, these are equivalent
147 suspendContext(thread_num);
148 }
149
150
151 void
152 BaseSimpleCPU::regStats()
153 {
154 using namespace Stats;
155
156 BaseCPU::regStats();
157
158 numInsts
159 .name(name() + ".committedInsts")
160 .desc("Number of instructions committed")
161 ;
162
163 numOps
164 .name(name() + ".committedOps")
165 .desc("Number of ops (including micro ops) committed")
166 ;
167
168 numIntAluAccesses
169 .name(name() + ".num_int_alu_accesses")
170 .desc("Number of integer alu accesses")
171 ;
172
173 numFpAluAccesses
174 .name(name() + ".num_fp_alu_accesses")
175 .desc("Number of float alu accesses")
176 ;
177
178 numCallsReturns
179 .name(name() + ".num_func_calls")
180 .desc("number of times a function call or return occured")
181 ;
182
183 numCondCtrlInsts
184 .name(name() + ".num_conditional_control_insts")
185 .desc("number of instructions that are conditional controls")
186 ;
187
188 numIntInsts
189 .name(name() + ".num_int_insts")
190 .desc("number of integer instructions")
191 ;
192
193 numFpInsts
194 .name(name() + ".num_fp_insts")
195 .desc("number of float instructions")
196 ;
197
198 numIntRegReads
199 .name(name() + ".num_int_register_reads")
200 .desc("number of times the integer registers were read")
201 ;
202
203 numIntRegWrites
204 .name(name() + ".num_int_register_writes")
205 .desc("number of times the integer registers were written")
206 ;
207
208 numFpRegReads
209 .name(name() + ".num_fp_register_reads")
210 .desc("number of times the floating registers were read")
211 ;
212
213 numFpRegWrites
214 .name(name() + ".num_fp_register_writes")
215 .desc("number of times the floating registers were written")
216 ;
217
218 numCCRegReads
219 .name(name() + ".num_cc_register_reads")
220 .desc("number of times the CC registers were read")
221 .flags(nozero)
222 ;
223
224 numCCRegWrites
225 .name(name() + ".num_cc_register_writes")
226 .desc("number of times the CC registers were written")
227 .flags(nozero)
228 ;
229
230 numMemRefs
231 .name(name()+".num_mem_refs")
232 .desc("number of memory refs")
233 ;
234
235 numStoreInsts
236 .name(name() + ".num_store_insts")
237 .desc("Number of store instructions")
238 ;
239
240 numLoadInsts
241 .name(name() + ".num_load_insts")
242 .desc("Number of load instructions")
243 ;
244
245 notIdleFraction
246 .name(name() + ".not_idle_fraction")
247 .desc("Percentage of non-idle cycles")
248 ;
249
250 idleFraction
251 .name(name() + ".idle_fraction")
252 .desc("Percentage of idle cycles")
253 ;
254
255 numBusyCycles
256 .name(name() + ".num_busy_cycles")
257 .desc("Number of busy cycles")
258 ;
259
260 numIdleCycles
261 .name(name()+".num_idle_cycles")
262 .desc("Number of idle cycles")
263 ;
264
265 icacheStallCycles
266 .name(name() + ".icache_stall_cycles")
267 .desc("ICache total stall cycles")
268 .prereq(icacheStallCycles)
269 ;
270
271 dcacheStallCycles
272 .name(name() + ".dcache_stall_cycles")
273 .desc("DCache total stall cycles")
274 .prereq(dcacheStallCycles)
275 ;
276
277 icacheRetryCycles
278 .name(name() + ".icache_retry_cycles")
279 .desc("ICache total retry cycles")
280 .prereq(icacheRetryCycles)
281 ;
282
283 dcacheRetryCycles
284 .name(name() + ".dcache_retry_cycles")
285 .desc("DCache total retry cycles")
286 .prereq(dcacheRetryCycles)
287 ;
288
289 statExecutedInstType
290 .init(Enums::Num_OpClass)
291 .name(name() + ".op_class")
292 .desc("Class of executed instruction")
293 .flags(total | pdf | dist)
294 ;
295 for (unsigned i = 0; i < Num_OpClasses; ++i) {
296 statExecutedInstType.subname(i, Enums::OpClassStrings[i]);
297 }
298
299 idleFraction = constant(1.0) - notIdleFraction;
300 numIdleCycles = idleFraction * numCycles;
301 numBusyCycles = (notIdleFraction)*numCycles;
302
303 numBranches
304 .name(name() + ".Branches")
305 .desc("Number of branches fetched")
306 .prereq(numBranches);
307
308 numPredictedBranches
309 .name(name() + ".predictedBranches")
310 .desc("Number of branches predicted as taken")
311 .prereq(numPredictedBranches);
312
313 numBranchMispred
314 .name(name() + ".BranchMispred")
315 .desc("Number of branch mispredictions")
316 .prereq(numBranchMispred);
317 }
318
319 void
320 BaseSimpleCPU::resetStats()
321 {
322 // startNumInst = numInst;
323 notIdleFraction = (_status != Idle);
324 }
325
326 void
327 BaseSimpleCPU::serializeThread(ostream &os, ThreadID tid)
328 {
329 assert(_status == Idle || _status == Running);
330 assert(tid == 0);
331
332 thread->serialize(os);
333 }
334
335 void
336 BaseSimpleCPU::unserializeThread(Checkpoint *cp, const string &section,
337 ThreadID tid)
338 {
339 if (tid != 0)
340 fatal("Trying to load more than one thread into a SimpleCPU\n");
341 thread->unserialize(cp, section);
342 }
343
344 void
345 change_thread_state(ThreadID tid, int activate, int priority)
346 {
347 }
348
349 Addr
350 BaseSimpleCPU::dbg_vtophys(Addr addr)
351 {
352 return vtophys(tc, addr);
353 }
354
355 void
356 BaseSimpleCPU::wakeup()
357 {
358 if (thread->status() != ThreadContext::Suspended)
359 return;
360
361 DPRINTF(Quiesce,"Suspended Processor awoke\n");
362 thread->activate();
363 }
364
365 void
366 BaseSimpleCPU::checkForInterrupts()
367 {
368 if (checkInterrupts(tc)) {
369 Fault interrupt = interrupts->getInterrupt(tc);
370
371 if (interrupt != NoFault) {
372 fetchOffset = 0;
373 interrupts->updateIntrInfo(tc);
374 interrupt->invoke(tc);
375 thread->decoder.reset();
376 }
377 }
378 }
379
380
381 void
382 BaseSimpleCPU::setupFetchRequest(Request *req)
383 {
384 Addr instAddr = thread->instAddr();
385
386 // set up memory request for instruction fetch
387 DPRINTF(Fetch, "Fetch: PC:%08p\n", instAddr);
388
389 Addr fetchPC = (instAddr & PCMask) + fetchOffset;
390 req->setVirt(0, fetchPC, sizeof(MachInst), Request::INST_FETCH, instMasterId(),
391 instAddr);
392 }
393
394
395 void
396 BaseSimpleCPU::preExecute()
397 {
398 // maintain $r0 semantics
399 thread->setIntReg(ZeroReg, 0);
400 #if THE_ISA == ALPHA_ISA
401 thread->setFloatReg(ZeroReg, 0.0);
402 #endif // ALPHA_ISA
403
404 // check for instruction-count-based events
405 comInstEventQueue[0]->serviceEvents(numInst);
406 system->instEventQueue.serviceEvents(system->totalNumInsts);
407
408 // decode the instruction
409 inst = gtoh(inst);
410
411 TheISA::PCState pcState = thread->pcState();
412
413 if (isRomMicroPC(pcState.microPC())) {
414 stayAtPC = false;
415 curStaticInst = microcodeRom.fetchMicroop(pcState.microPC(),
416 curMacroStaticInst);
417 } else if (!curMacroStaticInst) {
418 //We're not in the middle of a macro instruction
419 StaticInstPtr instPtr = NULL;
420
421 TheISA::Decoder *decoder = &(thread->decoder);
422
423 //Predecode, ie bundle up an ExtMachInst
424 //If more fetch data is needed, pass it in.
425 Addr fetchPC = (pcState.instAddr() & PCMask) + fetchOffset;
426 //if(decoder->needMoreBytes())
427 decoder->moreBytes(pcState, fetchPC, inst);
428 //else
429 // decoder->process();
430
431 //Decode an instruction if one is ready. Otherwise, we'll have to
432 //fetch beyond the MachInst at the current pc.
433 instPtr = decoder->decode(pcState);
434 if (instPtr) {
435 stayAtPC = false;
436 thread->pcState(pcState);
437 } else {
438 stayAtPC = true;
439 fetchOffset += sizeof(MachInst);
440 }
441
442 //If we decoded an instruction and it's microcoded, start pulling
443 //out micro ops
444 if (instPtr && instPtr->isMacroop()) {
445 curMacroStaticInst = instPtr;
446 curStaticInst = curMacroStaticInst->fetchMicroop(pcState.microPC());
447 } else {
448 curStaticInst = instPtr;
449 }
450 } else {
451 //Read the next micro op from the macro op
452 curStaticInst = curMacroStaticInst->fetchMicroop(pcState.microPC());
453 }
454
455 //If we decoded an instruction this "tick", record information about it.
456 if (curStaticInst) {
457 #if TRACING_ON
458 traceData = tracer->getInstRecord(curTick(), tc,
459 curStaticInst, thread->pcState(), curMacroStaticInst);
460
461 DPRINTF(Decode,"Decode: Decoded %s instruction: %#x\n",
462 curStaticInst->getName(), curStaticInst->machInst);
463 #endif // TRACING_ON
464 }
465
466 if (branchPred && curStaticInst && curStaticInst->isControl()) {
467 // Use a fake sequence number since we only have one
468 // instruction in flight at the same time.
469 const InstSeqNum cur_sn(0);
470 const ThreadID tid(0);
471 pred_pc = thread->pcState();
472 const bool predict_taken(
473 branchPred->predict(curStaticInst, cur_sn, pred_pc, tid));
474
475 if (predict_taken)
476 ++numPredictedBranches;
477 }
478 }
479
480 void
481 BaseSimpleCPU::postExecute()
482 {
483 assert(curStaticInst);
484
485 TheISA::PCState pc = tc->pcState();
486 Addr instAddr = pc.instAddr();
487 if (FullSystem && thread->profile) {
488 bool usermode = TheISA::inUserMode(tc);
489 thread->profilePC = usermode ? 1 : instAddr;
490 ProfileNode *node = thread->profile->consume(tc, curStaticInst);
491 if (node)
492 thread->profileNode = node;
493 }
494
495 if (curStaticInst->isMemRef()) {
496 numMemRefs++;
497 }
498
499 if (curStaticInst->isLoad()) {
500 ++numLoad;
501 comLoadEventQueue[0]->serviceEvents(numLoad);
502 }
503
504 if (CPA::available()) {
505 CPA::cpa()->swAutoBegin(tc, pc.nextInstAddr());
506 }
507
508 if (curStaticInst->isControl()) {
509 ++numBranches;
510 }
511
512 /* Power model statistics */
513 //integer alu accesses
514 if (curStaticInst->isInteger()){
515 numIntAluAccesses++;
516 numIntInsts++;
517 }
518
519 //float alu accesses
520 if (curStaticInst->isFloating()){
521 numFpAluAccesses++;
522 numFpInsts++;
523 }
524
525 //number of function calls/returns to get window accesses
526 if (curStaticInst->isCall() || curStaticInst->isReturn()){
527 numCallsReturns++;
528 }
529
530 //the number of branch predictions that will be made
531 if (curStaticInst->isCondCtrl()){
532 numCondCtrlInsts++;
533 }
534
535 //result bus acceses
536 if (curStaticInst->isLoad()){
537 numLoadInsts++;
538 }
539
540 if (curStaticInst->isStore()){
541 numStoreInsts++;
542 }
543 /* End power model statistics */
544
545 statExecutedInstType[curStaticInst->opClass()]++;
546
547 if (FullSystem)
548 traceFunctions(instAddr);
549
550 if (traceData) {
551 traceData->dump();
552 delete traceData;
553 traceData = NULL;
554 }
555 }
556
557 void
558 BaseSimpleCPU::advancePC(Fault fault)
559 {
560 const bool branching(thread->pcState().branching());
561
562 //Since we're moving to a new pc, zero out the offset
563 fetchOffset = 0;
564 if (fault != NoFault) {
565 curMacroStaticInst = StaticInst::nullStaticInstPtr;
566 fault->invoke(tc, curStaticInst);
567 thread->decoder.reset();
568 } else {
569 if (curStaticInst) {
570 if (curStaticInst->isLastMicroop())
571 curMacroStaticInst = StaticInst::nullStaticInstPtr;
572 TheISA::PCState pcState = thread->pcState();
573 TheISA::advancePC(pcState, curStaticInst);
574 thread->pcState(pcState);
575 }
576 }
577
578 if (branchPred && curStaticInst && curStaticInst->isControl()) {
579 // Use a fake sequence number since we only have one
580 // instruction in flight at the same time.
581 const InstSeqNum cur_sn(0);
582 const ThreadID tid(0);
583
584 if (pred_pc == thread->pcState()) {
585 // Correctly predicted branch
586 branchPred->update(cur_sn, tid);
587 } else {
588 // Mis-predicted branch
589 branchPred->squash(cur_sn, pcState(),
590 branching, tid);
591 ++numBranchMispred;
592 }
593 }
594 }
595
596 void
597 BaseSimpleCPU::startup()
598 {
599 BaseCPU::startup();
600 thread->startup();
601 }