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