diff options
author | Dam Sunwoo <dam.sunwoo@arm.com> | 2012-11-02 11:32:01 -0500 |
---|---|---|
committer | Dam Sunwoo <dam.sunwoo@arm.com> | 2012-11-02 11:32:01 -0500 |
commit | 81406018b0688e956452cd3e00c1ab9aeb9af764 (patch) | |
tree | a25309e3a443f1c41a33585c3e7d1a55c2213c49 /src/arch | |
parent | 322daba74c122c4ba8c89b73ca8107be02990e5c (diff) | |
download | gem5-81406018b0688e956452cd3e00c1ab9aeb9af764.tar.xz |
ARM: dump stats and process info on context switches
This patch enables dumping statistics and Linux process information on
context switch boundaries (__switch_to() calls) that are used for
Streamline integration (a graphical statistics viewer from ARM).
Diffstat (limited to 'src/arch')
-rw-r--r-- | src/arch/arm/ArmSystem.py | 1 | ||||
-rw-r--r-- | src/arch/arm/linux/system.cc | 104 | ||||
-rw-r--r-- | src/arch/arm/linux/system.hh | 42 |
3 files changed, 144 insertions, 3 deletions
diff --git a/src/arch/arm/ArmSystem.py b/src/arch/arm/ArmSystem.py index db0febe18..3ca9b8573 100644 --- a/src/arch/arm/ArmSystem.py +++ b/src/arch/arm/ArmSystem.py @@ -71,3 +71,4 @@ class LinuxArmSystem(ArmSystem): "File that contains the Device Tree Blob. Don't use DTB if empty.") early_kernel_symbols = Param.Bool(False, "enable early kernel symbol tables before MMU") + enable_context_switch_stats_dump = Param.Bool(False, "enable stats/task info dumping at context switch boundaries") diff --git a/src/arch/arm/linux/system.cc b/src/arch/arm/linux/system.cc index 1347e472d..b06439406 100644 --- a/src/arch/arm/linux/system.cc +++ b/src/arch/arm/linux/system.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2012 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -44,19 +44,24 @@ #include "arch/arm/linux/system.hh" #include "arch/arm/isa_traits.hh" #include "arch/arm/utility.hh" +#include "arch/generic/linux/threadinfo.hh" #include "base/loader/object_file.hh" #include "base/loader/symtab.hh" +#include "cpu/base.hh" +#include "cpu/pc_event.hh" #include "cpu/thread_context.hh" #include "debug/Loader.hh" #include "kern/linux/events.hh" #include "mem/fs_translating_port_proxy.hh" #include "mem/physical.hh" +#include "sim/stat_control.hh" using namespace ArmISA; using namespace Linux; LinuxArmSystem::LinuxArmSystem(Params *p) - : ArmSystem(p) + : ArmSystem(p), + enableContextSwitchStatsDump(p->enable_context_switch_stats_dump) { #ifndef NDEBUG kernelPanicEvent = addKernelFuncEvent<BreakPCEvent>("panic"); @@ -206,6 +211,9 @@ LinuxArmSystem::~LinuxArmSystem() delete uDelaySkipEvent; if (constUDelaySkipEvent) delete constUDelaySkipEvent; + + if (dumpStatsPCEvent) + delete dumpStatsPCEvent; } LinuxArmSystem * @@ -213,3 +221,95 @@ LinuxArmSystemParams::create() { return new LinuxArmSystem(this); } + +void +LinuxArmSystem::startup() +{ + if (enableContextSwitchStatsDump) { + dumpStatsPCEvent = addKernelFuncEvent<DumpStatsPCEvent>("__switch_to"); + if (!dumpStatsPCEvent) + panic("dumpStatsPCEvent not created!"); + + std::string task_filename = "tasks.txt"; + taskFile = simout.create(name() + "." + task_filename); + + for (int i = 0; i < _numContexts; i++) { + ThreadContext *tc = threadContexts[i]; + uint32_t pid = tc->getCpuPtr()->getPid(); + if (pid != Request::invldPid) { + mapPid(tc, pid); + tc->getCpuPtr()->taskId(taskMap[pid]); + } + } + } +} + +void +LinuxArmSystem::mapPid(ThreadContext *tc, uint32_t pid) +{ + // Create a new unique identifier for this pid + std::map<uint32_t, uint32_t>::iterator itr = taskMap.find(pid); + if (itr == taskMap.end()) { + uint32_t map_size = taskMap.size(); + if (map_size > ContextSwitchTaskId::MaxNormalTaskId + 1) { + warn_once("Error out of identifiers for cache occupancy stats"); + taskMap[pid] = ContextSwitchTaskId::Unknown; + } else { + taskMap[pid] = map_size; + } + } +} + +/** This function is called whenever the the kernel function + * "__switch_to" is called to change running tasks. + * + * r0 = task_struct of the previously running process + * r1 = task_info of the previously running process + * r2 = task_info of the next process to run + */ +void +DumpStatsPCEvent::process(ThreadContext *tc) +{ + Linux::ThreadInfo ti(tc); + Addr task_descriptor = tc->readIntReg(2); + uint32_t pid = ti.curTaskPID(task_descriptor); + uint32_t tgid = ti.curTaskTGID(task_descriptor); + std::string next_task_str = ti.curTaskName(task_descriptor); + + // Streamline treats pid == -1 as the kernel process. + // Also pid == 0 implies idle process (except during Linux boot) + int32_t mm = ti.curTaskMm(task_descriptor); + bool is_kernel = (mm == 0); + if (is_kernel && (pid != 0)) { + pid = -1; + tgid = -1; + next_task_str = "kernel"; + } + + LinuxArmSystem* sys = dynamic_cast<LinuxArmSystem *>(tc->getSystemPtr()); + if (!sys) { + panic("System is not LinuxArmSystem while getting Linux process info!"); + } + std::map<uint32_t, uint32_t>& taskMap = sys->taskMap; + + // Create a new unique identifier for this pid + sys->mapPid(tc, pid); + + // Set cpu task id, output process info, and dump stats + tc->getCpuPtr()->taskId(taskMap[pid]); + tc->getCpuPtr()->setPid(pid); + + std::ostream* taskFile = sys->taskFile; + + // Task file is read by cache occupancy plotting script or + // Streamline conversion script. + ccprintf(*taskFile, + "tick=%lld %d cpu_id=%d next_pid=%d next_tgid=%d next_task=%s\n", + curTick(), taskMap[pid], tc->cpuId(), (int) pid, (int) tgid, + next_task_str); + taskFile->flush(); + + // Dump and reset statistics + Stats::schedStatEvent(true, true, curTick(), 0); +} + diff --git a/src/arch/arm/linux/system.hh b/src/arch/arm/linux/system.hh index caf018cb9..feed8cfaa 100644 --- a/src/arch/arm/linux/system.hh +++ b/src/arch/arm/linux/system.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2012 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -43,15 +43,24 @@ #ifndef __ARCH_ARM_LINUX_SYSTEM_HH__ #define __ARCH_ARM_LINUX_SYSTEM_HH__ +#include <cstdio> +#include <map> #include <string> #include <vector> #include "arch/arm/system.hh" +#include "base/output.hh" #include "kern/linux/events.hh" #include "params/LinuxArmSystem.hh" +#include "sim/core.hh" + +class DumpStatsPCEvent; class LinuxArmSystem : public ArmSystem { + protected: + DumpStatsPCEvent *dumpStatsPCEvent; + public: /** Boilerplate params code */ typedef LinuxArmSystemParams Params; @@ -61,6 +70,20 @@ class LinuxArmSystem : public ArmSystem return dynamic_cast<const Params *>(_params); } + /** When enabled, dump stats/task info on context switches for + * Streamline and per-thread cache occupancy studies, etc. */ + bool enableContextSwitchStatsDump; + + /** This map stores a mapping of OS process IDs to internal Task IDs. The + * mapping is done because the stats system doesn't tend to like vectors + * that are much greater than 1000 items and the entire process space is + * 65K. */ + std::map<uint32_t, uint32_t> taskMap; + + /** This is a file that is placed in the run directory that prints out + * mappings between taskIds and OS process IDs */ + std::ostream* taskFile; + LinuxArmSystem(Params *p); ~LinuxArmSystem(); @@ -68,6 +91,12 @@ class LinuxArmSystem : public ArmSystem bool adderBootUncacheable(Addr a); + void startup(); + + /** This function creates a new task Id for the given pid. + * @param tc thread context that is currentyl executing */ + void mapPid(ThreadContext* tc, uint32_t pid); + private: #ifndef NDEBUG /** Event to halt the simulator if the kernel calls panic() */ @@ -97,5 +126,16 @@ class LinuxArmSystem : public ArmSystem Addr penReleaseAddr; }; +class DumpStatsPCEvent : public PCEvent +{ + public: + DumpStatsPCEvent(PCEventQueue *q, const std::string &desc, Addr addr) + : PCEvent(q, desc, addr) + {} + + virtual void process(ThreadContext* tc); +}; + + #endif // __ARCH_ARM_LINUX_SYSTEM_HH__ |