summaryrefslogtreecommitdiff
path: root/cpu
diff options
context:
space:
mode:
authorNathan Binkert <binkertn@umich.edu>2005-10-18 19:07:42 -0400
committerNathan Binkert <binkertn@umich.edu>2005-10-18 19:07:42 -0400
commita81c03737addc8e9a9b00cde0354e6c0ab4561af (patch)
treee7415ec9c2a97cf676d5599a1cec2c1fd775ace2 /cpu
parent357ee7a845eac0bd903ed31e31eec993d54a698c (diff)
downloadgem5-a81c03737addc8e9a9b00cde0354e6c0ab4561af.tar.xz
Add new function profiling stuff, wrap the pc_sample stuff into it.
SConscript: Get rid of the pc_sample stuff and move to the new profiling stuff base/traceflags.py: DPRINTF Stack stuff cpu/base.cc: cpu/base.hh: cpu/exec_context.cc: cpu/exec_context.hh: cpu/simple/cpu.cc: Add profiling stuff kern/kernel_stats.hh: Use a smart pointer sim/system.cc: sim/system.hh: Create a new symbol table that has all of the symbols for a particular system util/stats/categories.py: change around the categories, add categories for function profiling stuff util/stats/profile.py: No profile parsing and display code to deal with function profiling stuff, graph, dot, and text outputs. --HG-- extra : convert_revision : b3de0cdc8bd468e42647966e2640ae009bda9eb8
Diffstat (limited to 'cpu')
-rw-r--r--cpu/base.cc42
-rw-r--r--cpu/base.hh17
-rw-r--r--cpu/exec_context.cc38
-rw-r--r--cpu/exec_context.hh9
-rw-r--r--cpu/profile.cc147
-rw-r--r--cpu/profile.hh74
-rw-r--r--cpu/simple/cpu.cc23
7 files changed, 335 insertions, 15 deletions
diff --git a/cpu/base.cc b/cpu/base.cc
index 8d97bc330..a6e71c808 100644
--- a/cpu/base.cc
+++ b/cpu/base.cc
@@ -142,8 +142,19 @@ BaseCPU::BaseCPU(Params *p)
e->schedule(p->functionTraceStart);
}
}
+#if FULL_SYSTEM
+ profileEvent = NULL;
+ if (params->profile)
+ profileEvent = new ProfileEvent(this, params->profile);
+#endif
}
+BaseCPU::Params::Params()
+{
+#if FULL_SYSTEM
+ profile = false;
+#endif
+}
void
BaseCPU::enableFunctionTrace()
@@ -163,6 +174,16 @@ BaseCPU::init()
}
void
+BaseCPU::startup()
+{
+#if FULL_SYSTEM
+ if (!params->deferRegistration && profileEvent)
+ profileEvent->schedule(curTick);
+#endif
+}
+
+
+void
BaseCPU::regStats()
{
using namespace Stats;
@@ -231,11 +252,32 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU)
for (int i = 0; i < NumInterruptLevels; ++i)
interrupts[i] = oldCPU->interrupts[i];
intstatus = oldCPU->intstatus;
+
+ for (int i = 0; i < execContexts.size(); ++i)
+ execContexts[i]->profile->clear();
+
+ if (profileEvent)
+ profileEvent->schedule(curTick);
#endif
}
#if FULL_SYSTEM
+BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval)
+ : Event(&mainEventQueue), cpu(_cpu), interval(_interval)
+{ }
+
+void
+BaseCPU::ProfileEvent::process()
+{
+ for (int i = 0, size = cpu->execContexts.size(); i < size; ++i) {
+ ExecContext *xc = cpu->execContexts[i];
+ xc->profile->sample(xc->profileNode, xc->profilePC);
+ }
+
+ schedule(curTick + interval);
+}
+
void
BaseCPU::post_interrupt(int int_num, int index)
{
diff --git a/cpu/base.hh b/cpu/base.hh
index b9617a730..914d06982 100644
--- a/cpu/base.hh
+++ b/cpu/base.hh
@@ -33,6 +33,7 @@
#include "base/statistics.hh"
#include "config/full_system.hh"
+#include "cpu/profile.hh"
#include "cpu/sampler/sampler.hh"
#include "sim/eventq.hh"
#include "sim/sim_object.hh"
@@ -76,6 +77,18 @@ class BaseCPU : public SimObject
bool check_interrupts() const { return intstatus != 0; }
uint64_t intr_status() const { return intstatus; }
+
+ class ProfileEvent : public Event
+ {
+ private:
+ BaseCPU *cpu;
+ int interval;
+
+ public:
+ ProfileEvent(BaseCPU *cpu, int interval);
+ void process();
+ };
+ ProfileEvent *profileEvent;
#endif
protected:
@@ -113,7 +126,10 @@ class BaseCPU : public SimObject
#if FULL_SYSTEM
System *system;
int cpu_id;
+ Tick profile;
#endif
+
+ Params();
};
const Params *params;
@@ -122,6 +138,7 @@ class BaseCPU : public SimObject
virtual ~BaseCPU();
virtual void init();
+ virtual void startup();
virtual void regStats();
void registerExecContexts();
diff --git a/cpu/exec_context.cc b/cpu/exec_context.cc
index 91578bdf1..3fe951387 100644
--- a/cpu/exec_context.cc
+++ b/cpu/exec_context.cc
@@ -32,10 +32,15 @@
#include "cpu/exec_context.hh"
#if FULL_SYSTEM
+#include "base/callback.hh"
#include "base/cprintf.hh"
+#include "base/output.hh"
+#include "cpu/profile.hh"
#include "kern/kernel_stats.hh"
#include "sim/serialize.hh"
+#include "sim/sim_exit.hh"
#include "sim/system.hh"
+#include "targetarch/stacktrace.hh"
#else
#include "sim/process.hh"
#endif
@@ -51,10 +56,24 @@ ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num, System *_sys,
cpu_id(-1), mem(_mem), itb(_itb), dtb(_dtb), system(_sys),
memctrl(_sys->memctrl), physmem(_sys->physmem),
kernelBinning(system->kernelBinning), bin(kernelBinning->bin),
- fnbin(kernelBinning->fnbin), func_exe_inst(0), storeCondFailures(0)
+ fnbin(kernelBinning->fnbin), profile(NULL),
+ func_exe_inst(0), storeCondFailures(0)
{
kernelStats = new Kernel::Statistics(this);
memset(&regs, 0, sizeof(RegFile));
+
+ if (cpu->params->profile) {
+ profile = new FunctionProfile(system->allSymtab);
+ Callback *cb =
+ new MakeCallback<ExecContext, &ExecContext::dumpFuncProfile>(this);
+ registerExitCallback(cb);
+ }
+
+ // let's fill with a dummy node for now so we don't get a segfault
+ // on the first cycle when there's no node available.
+ static ProfileNode dummyNode;
+ profileNode = &dummyNode;
+ profilePC = 3;
}
#else
ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num,
@@ -83,6 +102,14 @@ ExecContext::~ExecContext()
#endif
}
+#if FULL_SYSTEM
+void
+ExecContext::dumpFuncProfile()
+{
+ std::ostream *os = simout.create(csprintf("profile.%s.dat", cpu->name()));
+ profile->dump(this, *os);
+}
+#endif
void
ExecContext::takeOverFrom(ExecContext *oldContext)
@@ -106,15 +133,6 @@ ExecContext::takeOverFrom(ExecContext *oldContext)
oldContext->_status = ExecContext::Unallocated;
}
-#if FULL_SYSTEM
-void
-ExecContext::execute(const StaticInstBase *inst)
-{
- assert(kernelStats);
- system->kernelBinning->execute(this, inst);
-}
-#endif
-
void
ExecContext::serialize(ostream &os)
{
diff --git a/cpu/exec_context.hh b/cpu/exec_context.hh
index 6a17951f9..6f38a6960 100644
--- a/cpu/exec_context.hh
+++ b/cpu/exec_context.hh
@@ -46,8 +46,9 @@ class BaseCPU;
#include "sim/system.hh"
#include "targetarch/alpha_memory.hh"
+class FunctionProfile;
+class ProfileNode;
class MemoryController;
-class StaticInstBase;
namespace Kernel { class Binning; class Statistics; }
#else // !FULL_SYSTEM
@@ -138,7 +139,11 @@ class ExecContext
Kernel::Statistics *kernelStats;
bool bin;
bool fnbin;
- void execute(const StaticInstBase *inst);
+
+ FunctionProfile *profile;
+ ProfileNode *profileNode;
+ Addr profilePC;
+ void dumpFuncProfile();
#else
Process *process;
diff --git a/cpu/profile.cc b/cpu/profile.cc
new file mode 100644
index 000000000..b17a3c74e
--- /dev/null
+++ b/cpu/profile.cc
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+
+#include "base/bitfield.hh"
+#include "base/trace.hh"
+#include "cpu/base.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/profile.hh"
+
+using namespace std;
+
+ProfileNode::ProfileNode()
+ : count(0)
+{ }
+
+void
+ProfileNode::dump(const string &symbol, uint64_t id, const SymbolTable *symtab,
+ ostream &os) const
+{
+ ccprintf(os, "%#x %s %d ", id, symbol, count);
+ ChildList::const_iterator i, end = children.end();
+ for (i = children.begin(); i != end; ++i) {
+ const ProfileNode &node = i->second;
+ ccprintf(os, "%#x ", (intptr_t)&node);
+ }
+
+ ccprintf(os, "\n");
+
+ for (i = children.begin(); i != end; ++i) {
+ Addr addr = i->first;
+ string symbol;
+ if (addr == 1)
+ symbol = "user";
+ else if (addr == 2)
+ symbol = "console";
+ else if (addr == 3)
+ symbol = "unknown";
+ else if (!symtab->findSymbol(addr, symbol))
+ panic("could not find symbol for address %#x\n", addr);
+
+ const ProfileNode &node = i->second;
+ node.dump(symbol, (intptr_t)&node, symtab, os);
+ }
+}
+
+void
+ProfileNode::clear()
+{
+ count = 0;
+ ChildList::iterator i, end = children.end();
+ for (i = children.begin(); i != end; ++i) {
+ ProfileNode &node = i->second;
+ node.clear();
+ }
+
+}
+
+FunctionProfile::FunctionProfile(const SymbolTable *_symtab)
+ : symtab(_symtab)
+{
+}
+
+FunctionProfile::~FunctionProfile()
+{
+}
+
+ProfileNode *
+FunctionProfile::consume(const StackTrace *trace)
+{
+ const vector<Addr> &stack = trace->getstack();
+ ProfileNode *current = &top;
+ for (int i = 0, size = stack.size(); i < size; ++i)
+ current = &current->children[stack[size - i - 1]];
+
+ return current;
+}
+
+void
+FunctionProfile::clear()
+{
+ top.clear();
+ pc_count.clear();
+}
+
+void
+FunctionProfile::dump(ExecContext *xc, ostream &os) const
+{
+ ccprintf(os, ">>>PC data\n");
+ map<Addr, Counter>::const_iterator i, end = pc_count.end();
+ for (i = pc_count.begin(); i != end; ++i) {
+ Addr pc = i->first;
+ Counter count = i->second;
+
+ std::string symbol;
+ if (pc == 1)
+ ccprintf(os, "user %d\n", count);
+ else if (symtab->findSymbol(pc, symbol) && !symbol.empty())
+ ccprintf(os, "%s %d\n", symbol, count);
+ else
+ ccprintf(os, "%#x %d\n", pc, count);
+ }
+
+ ccprintf(os, ">>>function data\n");
+ top.dump("top", 0, symtab, os);
+}
+
+void
+FunctionProfile::sample(ProfileNode *node, Addr pc)
+{
+ node->count++;
+
+ Addr symaddr;
+ if (symtab->findNearestAddr(pc, symaddr)) {
+ pc_count[symaddr]++;
+ } else {
+ // record PC even if we don't have a symbol to avoid
+ // silently biasing the histogram
+ pc_count[pc]++;
+ }
+}
diff --git a/cpu/profile.hh b/cpu/profile.hh
new file mode 100644
index 000000000..9da170eb4
--- /dev/null
+++ b/cpu/profile.hh
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_PROFILE_HH__
+#define __CPU_PROFILE_HH__
+
+#include <map>
+
+#include "cpu/static_inst.hh"
+#include "sim/host.hh"
+#include "targetarch/stacktrace.hh"
+
+class ProfileNode
+{
+ private:
+ friend class FunctionProfile;
+
+ typedef std::map<Addr, ProfileNode> ChildList;
+ ChildList children;
+
+ public:
+ int count;
+
+ public:
+ ProfileNode();
+
+ void dump(const std::string &symbol, uint64_t id,
+ const SymbolTable *symtab, std::ostream &os) const;
+ void clear();
+};
+
+class FunctionProfile
+{
+ private:
+ const SymbolTable *symtab;
+ ProfileNode top;
+ std::map<Addr, Counter> pc_count;
+
+ public:
+ FunctionProfile(const SymbolTable *symtab);
+ ~FunctionProfile();
+
+ ProfileNode *consume(const StackTrace *trace);
+ void clear();
+ void dump(ExecContext *xc, std::ostream &out) const;
+ void sample(ProfileNode *node, Addr pc);
+};
+
+#endif // __CPU_PROFILE_HH__
diff --git a/cpu/simple/cpu.cc b/cpu/simple/cpu.cc
index 1bd5547e7..8f7534e16 100644
--- a/cpu/simple/cpu.cc
+++ b/cpu/simple/cpu.cc
@@ -50,6 +50,7 @@
#include "cpu/simple/cpu.hh"
#include "cpu/smt.hh"
#include "cpu/static_inst.hh"
+#include "kern/kernel_stats.hh"
#include "mem/base_mem.hh"
#include "mem/mem_interface.hh"
#include "sim/builder.hh"
@@ -65,6 +66,7 @@
#include "mem/functional/physical.hh"
#include "sim/system.hh"
#include "targetarch/alpha_memory.hh"
+#include "targetarch/stacktrace.hh"
#include "targetarch/vtophys.hh"
#else // !FULL_SYSTEM
#include "mem/functional/functional.hh"
@@ -753,8 +755,21 @@ SimpleCPU::tick()
fault = curStaticInst->execute(this, traceData);
#if FULL_SYSTEM
- if (xc->fnbin)
- xc->execute(curStaticInst.get());
+ if (xc->fnbin) {
+ assert(xc->kernelStats);
+ system->kernelBinning->execute(xc, inst);
+ }
+
+ if (xc->profile) {
+ bool usermode = (xc->regs.ipr[AlphaISA::IPR_DTB_CM] & 0x18) != 0;
+ xc->profilePC = usermode ? 1 : xc->regs.pc;
+ StackTrace *trace = StackTrace::create(xc, inst);
+ if (trace) {
+ xc->profileNode = xc->profile->consume(trace);
+ trace->dprintf();
+ delete trace;
+ }
+ }
#endif
if (curStaticInst->isMemRef()) {
@@ -806,7 +821,6 @@ SimpleCPU::tick()
tickEvent.schedule(curTick + cycles(1));
}
-
////////////////////////////////////////////////////////////////////////
//
// SimpleCPU Simulation Object
@@ -824,6 +838,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
SimObjectParam<FunctionalMemory *> mem;
SimObjectParam<System *> system;
Param<int> cpu_id;
+ Param<Tick> profile;
#else
SimObjectParam<Process *> workload;
#endif // FULL_SYSTEM
@@ -856,6 +871,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
INIT_PARAM(mem, "memory"),
INIT_PARAM(system, "system object"),
INIT_PARAM(cpu_id, "processor ID"),
+ INIT_PARAM(profile, ""),
#else
INIT_PARAM(workload, "processes to run"),
#endif // FULL_SYSTEM
@@ -894,6 +910,7 @@ CREATE_SIM_OBJECT(SimpleCPU)
params->mem = mem;
params->system = system;
params->cpu_id = cpu_id;
+ params->profile = profile;
#else
params->process = workload;
#endif