kernel_stats.cc revision 754
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 43using namespace std; 44using namespace Stats; 45 46class 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 98KernelStats::KernelStats(ExecContext *xc, BaseCPU *cpu) 99{ data = new KSData(xc, cpu); } 100 101KernelStats::~KernelStats() 102{ delete data; } 103 104void 105KernelStats::regStats(const string &name) 106{ data->regStats(name); } 107 108void 109KSData::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 243void 244KernelStats::arm() 245{ data->_arm++; } 246 247void 248KernelStats::quiesce() 249{ data->_quiesce++; } 250 251void 252KernelStats::ivlb() 253{ data->_ivlb++; } 254 255void 256KernelStats::ivle() 257{ data->_ivle++; } 258 259void 260KernelStats::hwrei() 261{ data->_hwrei++; } 262 263void 264KernelStats::fault(Fault fault) 265{ data->_faults[fault]++; } 266 267void 268KernelStats::swpipl(int ipl) 269{ data->swpipl(ipl); } 270 271void 272KernelStats::mode(bool user) 273{ data->mode(user); } 274 275void 276KernelStats::context(Addr old_pcbb, Addr new_pcbb) 277{ data->_swap_context++; } 278 279void 280KernelStats::callpal(int code) 281{ data->callpal(code); } 282 283 284void 285KSData::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 300void 301KSData::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 323void 324KSData::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} 392