more initial checking of stats
[gem5.git] / kern / kernel_stats.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 #include <map>
30 #include <stack>
31 #include <string>
32
33 #include "base/statistics.hh"
34 #include "base/trace.hh"
35 #include "cpu/exec_context.hh"
36 #include "kern/kernel_stats.hh"
37 #include "sim/stats.hh"
38 #include "sim/sw_context.hh"
39 #include "targetarch/isa_traits.hh"
40 #include "targetarch/osfpal.hh"
41 #include "targetarch/syscalls.hh"
42
43 using namespace std;
44 using namespace Stats;
45
46 class KSData
47 {
48 private:
49 string _name;
50 ExecContext *xc;
51 BaseCPU *cpu;
52
53 public:
54 KSData(ExecContext *_xc, BaseCPU *_cpu)
55 : xc(_xc), cpu(_cpu), iplLast(0), iplLastTick(0), lastUser(false),
56 lastModeTick(0)
57 {}
58
59 const string &name() { return _name; }
60 void regStats(const string &name);
61
62 public:
63 Scalar<> _arm;
64 Scalar<> _quiesce;
65 Scalar<> _ivlb;
66 Scalar<> _ivle;
67 Scalar<> _hwrei;
68
69 Vector<> _iplCount;
70 Vector<> _iplGood;
71 Vector<> _iplTicks;
72 Formula _iplUsed;
73
74 Vector<> _callpal;
75 Vector<> _syscall;
76 Vector<> _faults;
77
78 Vector<> _mode;
79 Vector<> _modeGood;
80 Formula _modeFraction;
81 Vector<> _modeTicks;
82
83 Scalar<> _swap_context;
84
85 private:
86 int iplLast;
87 Tick iplLastTick;
88
89 bool lastUser;
90 Tick lastModeTick;
91
92 public:
93 void swpipl(int ipl);
94 void mode(bool user);
95 void callpal(int code);
96 };
97
98 KernelStats::KernelStats(ExecContext *xc, BaseCPU *cpu)
99 { data = new KSData(xc, cpu); }
100
101 KernelStats::~KernelStats()
102 { delete data; }
103
104 void
105 KernelStats::regStats(const string &name)
106 { data->regStats(name); }
107
108 void
109 KSData::regStats(const string &name)
110 {
111 _name = name;
112
113 _arm
114 .name(name + ".inst.arm")
115 .desc("number of arm instructions executed")
116 ;
117
118 _quiesce
119 .name(name + ".inst.quiesce")
120 .desc("number of quiesce instructions executed")
121 ;
122
123 _ivlb
124 .name(name + ".inst.ivlb")
125 .desc("number of ivlb instructions executed")
126 ;
127
128 _ivle
129 .name(name + ".inst.ivle")
130 .desc("number of ivle instructions executed")
131 ;
132
133 _hwrei
134 .name(name + ".inst.hwrei")
135 .desc("number of hwrei instructions executed")
136 ;
137
138 _iplCount
139 .init(32)
140 .name(name + ".ipl_count")
141 .desc("number of times we switched to this ipl")
142 .flags(total | pdf | nozero | nonan)
143 ;
144
145 _iplGood
146 .init(32)
147 .name(name + ".ipl_good")
148 .desc("number of times we switched to this ipl from a different ipl")
149 .flags(total | pdf | nozero | nonan)
150 ;
151
152 _iplTicks
153 .init(32)
154 .name(name + ".ipl_ticks")
155 .desc("number of cycles we spent at this ipl")
156 .flags(total | pdf | nozero | nonan)
157 ;
158
159 _iplUsed
160 .name(name + ".ipl_used")
161 .desc("fraction of swpipl calls that actually changed the ipl")
162 .flags(total | nozero | nonan)
163 ;
164
165 _iplUsed = _iplGood / _iplCount;
166
167 _callpal
168 .init(256)
169 .name(name + ".callpal")
170 .desc("number of callpals executed")
171 .flags(total | pdf | nozero | nonan)
172 ;
173
174 for (int i = 0; i < PAL::NumCodes; ++i) {
175 const char *str = PAL::name(i);
176 if (str)
177 _callpal.subname(i, str);
178 }
179
180 _syscall
181 .init(SystemCalls<Tru64>::Number)
182 .name(name + ".syscall")
183 .desc("number of syscalls executed")
184 .flags(total | pdf | nozero | nonan)
185 ;
186
187 for (int i = 0; i < SystemCalls<Tru64>::Number; ++i) {
188 const char *str = SystemCalls<Tru64>::name(i);
189 if (str) {
190 _syscall.subname(i, str);
191 }
192 }
193
194 _faults
195 .init(Num_Faults)
196 .name(name + ".faults")
197 .desc("number of faults")
198 .flags(total | pdf | nozero | nonan)
199 ;
200
201 for (int i = 1; i < Num_Faults; ++i) {
202 const char *str = FaultName(i);
203 if (str)
204 _faults.subname(i, str);
205 }
206
207 _mode
208 .init(2)
209 .name(name + ".mode_switch")
210 .subname(0, "kernel")
211 .subname(1, "user")
212 .desc("number of protection mode switches")
213 ;
214
215 _modeGood
216 .init(2)
217 ;
218
219 _modeFraction
220 .name(name + ".mode_switch_good")
221 .subname(0, "kernel")
222 .subname(1, "user")
223 .desc("fraction of useful protection mode switches")
224 .flags(total)
225 ;
226 _modeFraction = _modeGood / _mode;
227
228 _modeTicks
229 .init(2)
230 .name(name + ".mode_ticks")
231 .subname(0, "kernel")
232 .subname(1, "user")
233 .desc("number of ticks spent at the given mode")
234 .flags(pdf)
235 ;
236
237 _swap_context
238 .name(name + ".swap_context")
239 .desc("number of times the context was actually changed")
240 ;
241 }
242
243 void
244 KernelStats::arm()
245 { data->_arm++; }
246
247 void
248 KernelStats::quiesce()
249 { data->_quiesce++; }
250
251 void
252 KernelStats::ivlb()
253 { data->_ivlb++; }
254
255 void
256 KernelStats::ivle()
257 { data->_ivle++; }
258
259 void
260 KernelStats::hwrei()
261 { data->_hwrei++; }
262
263 void
264 KernelStats::fault(Fault fault)
265 { data->_faults[fault]++; }
266
267 void
268 KernelStats::swpipl(int ipl)
269 { data->swpipl(ipl); }
270
271 void
272 KernelStats::mode(bool user)
273 { data->mode(user); }
274
275 void
276 KernelStats::context(Addr old_pcbb, Addr new_pcbb)
277 { data->_swap_context++; }
278
279 void
280 KernelStats::callpal(int code)
281 { data->callpal(code); }
282
283
284 void
285 KSData::swpipl(int ipl)
286 {
287 assert(ipl >= 0 && ipl <= 0x1f && "invalid IPL\n");
288
289 _iplCount[ipl]++;
290
291 if (ipl == iplLast)
292 return;
293
294 _iplGood[ipl]++;
295 _iplTicks[iplLast] += curTick - iplLastTick;
296 iplLastTick = curTick;
297 iplLast = ipl;
298 }
299
300 void
301 KSData::mode(bool user)
302 {
303 _mode[user]++;
304 if (user == lastUser)
305 return;
306
307 _modeGood[user]++;
308 _modeTicks[lastUser] += curTick - lastModeTick;
309
310 lastModeTick = curTick;
311 lastUser = user;
312
313 if (xc->system->bin) {
314 if (!xc->swCtx || xc->swCtx->callStack.empty()) {
315 if (user)
316 xc->system->User->activate();
317 else
318 xc->system->Kernel->activate();
319 }
320 }
321 }
322
323 void
324 KSData::callpal(int code)
325 {
326 if (!PAL::name(code))
327 return;
328
329 _callpal[code]++;
330
331 switch (code) {
332 case PAL::callsys:
333 {
334 int number = xc->regs.intRegFile[0];
335 if (SystemCalls<Tru64>::validSyscallNumber(number)) {
336 int cvtnum = SystemCalls<Tru64>::convert(number);
337 _syscall[cvtnum]++;
338 }
339 }
340 break;
341 }
342
343 if (code == PAL::swpctx) {
344 SWContext *out = xc->swCtx;
345 System *sys = xc->system;
346 if (!sys->bin)
347 return;
348 DPRINTF(TCPIP, "swpctx event\n");
349 if (out) {
350 DPRINTF(TCPIP, "swapping context out with this stack!\n");
351 xc->system->dumpState(xc);
352 Addr oldPCB = xc->regs.ipr[TheISA::IPR_PALtemp23];
353
354 if (out->callStack.empty()) {
355 DPRINTF(TCPIP, "but removing it, cuz empty!\n");
356 SWContext *find = sys->findContext(oldPCB);
357 if (find) {
358 assert(sys->findContext(oldPCB) == out);
359 sys->remContext(oldPCB);
360 }
361 delete out;
362 } else {
363 DPRINTF(TCPIP, "switching out context with pcb %#x, top fn %s\n",
364 oldPCB, out->callStack.top()->name);
365 if (!sys->findContext(oldPCB)) {
366 if (!sys->addContext(oldPCB, out))
367 panic("could not add context");
368 }
369 }
370 }
371
372 Addr newPCB = xc->regs.intRegFile[16];
373 SWContext *in = sys->findContext(newPCB);
374 xc->swCtx = in;
375
376 if (in) {
377 assert(!in->callStack.empty() &&
378 "should not be switching in empty context");
379 DPRINTF(TCPIP, "swapping context in with this callstack!\n");
380 xc->system->dumpState(xc);
381 sys->remContext(newPCB);
382 fnCall *top = in->callStack.top();
383 DPRINTF(TCPIP, "switching in to pcb %#x, %s\n", newPCB, top->name);
384 assert(top->myBin && "should not switch to context with no Bin");
385 top->myBin->activate();
386 } else {
387 sys->Kernel->activate();
388 }
389 DPRINTF(TCPIP, "end swpctx\n");
390 }
391 }