Move activity tracking code into its own class. Now the CPU no longer has to keep track of the activity tracking internals; it just calls advance() on the class and uses it to tell if it should deschedule itself.

SConscript:
    Split off activity/idling code into its own class to do the processing separately.
cpu/o3/alpha_cpu_builder.cc:
cpu/o3/alpha_params.hh:
    Activity stuff.  This is mostly for debugging and may be removed later on (or changed to enable/disable activity idling).
cpu/o3/cpu.cc:
    Move activity idling stuff mostly into its own class, so it no longer clutters this file.
cpu/o3/cpu.hh:
    Move activity idling stuff into its own class.
python/m5/objects/AlphaFullCPU.py:
    Add parameter for initial activity value.

--HG--
extra : convert_revision : f32f7cc03895dc07ab57ddba78c5402a1a8b0f1a
This commit is contained in:
Kevin Lim 2006-05-19 15:37:52 -04:00
parent c7e7d07ec3
commit c4a87f874a
8 changed files with 273 additions and 175 deletions

View file

@ -80,6 +80,7 @@ base_sources = Split('''
base/stats/visit.cc
base/stats/text.cc
cpu/activity.cc
cpu/base.cc
cpu/base_dyn_inst.cc
cpu/cpu_exec_context.cc

122
cpu/activity.cc Normal file
View file

@ -0,0 +1,122 @@
#include "base/timebuf.hh"
#include "cpu/activity.hh"
ActivityRecorder::ActivityRecorder(int num_stages, int longest_latency,
int activity)
: activityBuffer(longest_latency, 0), longestLatency(longest_latency),
activityCount(activity), numStages(num_stages)
{
stageActive = new bool[numStages];
memset(stageActive, 0, numStages);
}
void
ActivityRecorder::activity()
{
if (activityBuffer[0]) {
return;
}
activityBuffer[0] = true;
++activityCount;
DPRINTF(Activity, "Activity: %i\n", activityCount);
}
void
ActivityRecorder::advance()
{
if (activityBuffer[-longestLatency]) {
--activityCount;
assert(activityCount >= 0);
DPRINTF(Activity, "Activity: %i\n", activityCount);
if (activityCount == 0) {
DPRINTF(Activity, "No activity left!\n");
}
}
activityBuffer.advance();
}
void
ActivityRecorder::activateStage(const int idx)
{
if (!stageActive[idx]) {
++activityCount;
stageActive[idx] = true;
DPRINTF(Activity, "Activity: %i\n", activityCount);
} else {
DPRINTF(Activity, "Stage %i already active.\n", idx);
}
// assert(activityCount < longestLatency + numStages + 1);
}
void
ActivityRecorder::deactivateStage(const int idx)
{
if (stageActive[idx]) {
--activityCount;
stageActive[idx] = false;
DPRINTF(Activity, "Activity: %i\n", activityCount);
} else {
DPRINTF(Activity, "Stage %i already inactive.\n", idx);
}
assert(activityCount >= 0);
}
void
ActivityRecorder::reset()
{
activityCount = 0;
memset(stageActive, 0, numStages);
for (int i = 0; i < longestLatency + 1; ++i)
activityBuffer.advance();
}
void
ActivityRecorder::dump()
{
for (int i = 0; i <= longestLatency; ++i) {
cprintf("[Idx:%i %i] ", i, activityBuffer[-i]);
}
cprintf("\n");
for (int i = 0; i < numStages; ++i) {
cprintf("[Stage:%i %i]\n", i, stageActive[i]);
}
cprintf("\n");
cprintf("Activity count: %i\n", activityCount);
}
void
ActivityRecorder::validate()
{
int count = 0;
for (int i = 0; i <= longestLatency; ++i) {
if (activityBuffer[-i]) {
count++;
}
}
for (int i = 0; i < numStages; ++i) {
if (stageActive[i]) {
count++;
}
}
assert(count == activityCount);
}

67
cpu/activity.hh Normal file
View file

@ -0,0 +1,67 @@
#ifndef __CPU_ACTIVITY_HH__
#define __CPU_ACTIVITY_HH__
#include "base/timebuf.hh"
#include "base/trace.hh"
class ActivityRecorder {
public:
ActivityRecorder(int num_stages, int longest_latency, int count);
/** Records that there is activity this cycle. */
void activity();
/** Advances the activity buffer, decrementing the activityCount if active
* communication just left the time buffer, and descheduling the CPU if
* there is no activity.
*/
void advance();
/** Marks a stage as active. */
void activateStage(const int idx);
/** Deactivates a stage. */
void deactivateStage(const int idx);
int getActivityCount() { return activityCount; }
void setActivityCount(int count)
{ activityCount = count; }
bool active() { return activityCount; }
void reset();
void dump();
void validate();
private:
/** Time buffer that tracks if any cycles has active communication
* in them. It should be as long as the longest communication
* latency in the system. Each time any time buffer is written,
* the activity buffer should also be written to. The
* activityBuffer is advanced along with all the other time
* buffers, so it should have a 1 somewhere in it only if there
* is active communication in a time buffer.
*/
TimeBuffer<bool> activityBuffer;
int longestLatency;
/** Tracks how many stages and cycles of time buffer have
* activity. Stages increment this count when they switch to
* active, and decrement it when they switch to
* inactive. Whenever a cycle that previously had no information
* is written in the time buffer, this is incremented. When a
* cycle that had information exits the time buffer due to age,
* this count is decremented. When the count is 0, there is no
* activity in the CPU, and it can be descheduled.
*/
int activityCount;
int numStages;
/** Records which stages are active/inactive. */
bool *stageActive;
};
#endif // __CPU_ACTIVITY_HH__

View file

@ -48,6 +48,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
Param<int> clock;
Param<int> numThreads;
Param<int> activity;
#if FULL_SYSTEM
SimObjectParam<System *> system;
@ -156,6 +157,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
INIT_PARAM(clock, "clock speed"),
INIT_PARAM(numThreads, "number of HW thread contexts"),
INIT_PARAM_DFLT(activity, "Initial activity count", 0),
#if FULL_SYSTEM
INIT_PARAM(system, "System object"),
@ -301,6 +303,7 @@ CREATE_SIM_OBJECT(DerivAlphaFullCPU)
params->name = getInstanceName();
params->numberOfThreads = actual_num_threads;
params->activity = activity;
#if FULL_SYSTEM
params->system = system;

View file

@ -64,6 +64,8 @@ class AlphaSimpleParams : public BaseFullCPU::Params
BaseCPU *checker;
unsigned activity;
//
// Caches
//

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* Copyright (c) 2004-2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -33,8 +33,8 @@
#else
#include "sim/process.hh"
#endif
#include "sim/root.hh"
#include "cpu/activity.hh"
#include "cpu/checker/cpu.hh"
#include "cpu/cpu_exec_context.hh"
#include "cpu/exec_context.hh"
@ -42,6 +42,7 @@
#include "cpu/o3/alpha_impl.hh"
#include "cpu/o3/cpu.hh"
#include "sim/root.hh"
#include "sim/stat_control.hh"
using namespace std;
@ -104,16 +105,15 @@ FullO3CPU<Impl>::FullO3CPU(Params *params)
TheISA::NumMiscRegs * number_of_threads,
TheISA::ZeroReg),
// What to pass to these time buffers?
// For now just have these time buffers be pretty big.
// @todo: Make these time buffer sizes parameters.
// @todo: Make these time buffer sizes parameters or derived
// from latencies
timeBuffer(5, 5),
fetchQueue(5, 5),
decodeQueue(5, 5),
renameQueue(5, 5),
iewQueue(5, 5),
activityBuffer(5, 0),
activityCount(0),
activityRec(NumStages, 10, params->activity),
globalSeqNum(1),
@ -150,9 +150,9 @@ FullO3CPU<Impl>::FullO3CPU(Params *params)
tids.resize(number_of_threads);
#endif
// The stages also need their CPU pointer setup. However this must be
// done at the upper level CPU because they have pointers to the upper
// level CPU, and not this FullO3CPU.
// The stages also need their CPU pointer setup. However this
// must be done at the upper level CPU because they have pointers
// to the upper level CPU, and not this FullO3CPU.
// Set up Pointers to the activeThreads list for each stage
fetch.setActiveThreads(&activeThreads);
@ -207,11 +207,11 @@ FullO3CPU<Impl>::FullO3CPU(Params *params)
commitRenameMap[tid].init(TheISA::NumIntRegs,
params->numPhysIntRegs,
lreg_idx, //Index for Logical. Regs
lreg_idx, //Index for Logical. Regs
TheISA::NumFloatRegs,
params->numPhysFloatRegs,
freg_idx, //Index for Float Regs
freg_idx, //Index for Float Regs
TheISA::NumMiscRegs,
@ -223,11 +223,11 @@ FullO3CPU<Impl>::FullO3CPU(Params *params)
renameMap[tid].init(TheISA::NumIntRegs,
params->numPhysIntRegs,
lreg_idx, //Index for Logical. Regs
lreg_idx, //Index for Logical. Regs
TheISA::NumFloatRegs,
params->numPhysFloatRegs,
freg_idx, //Index for Float Regs
freg_idx, //Index for Float Regs
TheISA::NumMiscRegs,
@ -258,10 +258,6 @@ FullO3CPU<Impl>::FullO3CPU(Params *params)
lastRunningCycle = curTick;
for (int i = 0; i < NumStages; ++i) {
stageActive[i] = false;
}
contextSwitch = false;
}
@ -336,7 +332,7 @@ FullO3CPU<Impl>::tick()
++numCycles;
activity = false;
// activity = false;
//Tick each of the stages
fetch.tick();
@ -361,14 +357,22 @@ FullO3CPU<Impl>::tick()
renameQueue.advance();
iewQueue.advance();
advanceActivityBuffer();
activityRec.advance();
if (removeInstsThisCycle) {
cleanUpRemovedInsts();
}
if (_status != SwitchedOut && activityCount && !tickEvent.scheduled()) {
tickEvent.schedule(curTick + cycles(1));
if (!tickEvent.scheduled()) {
if (_status == SwitchedOut) {
// increment stat
lastRunningCycle = curTick;
} else if (!activityRec.active()) {
lastRunningCycle = curTick;
timesIdled++;
} else {
tickEvent.schedule(curTick + cycles(1));
}
}
#if !FULL_SYSTEM
@ -592,7 +596,7 @@ FullO3CPU<Impl>::activateContext(int tid, int delay)
// Be sure to signal that there's some activity so the CPU doesn't
// deschedule itself.
activityThisCycle();
activityRec.activity();
fetch.wakeFromQuiesce();
_status = Running;
@ -669,13 +673,18 @@ FullO3CPU<Impl>::switchOut(Sampler *_sampler)
rename.switchOut();
iew.switchOut();
commit.switchOut();
// Wake the CPU and record activity so everything can drain out if
// the CPU is currently idle.
wakeCPU();
activityRec.activity();
}
template <class Impl>
void
FullO3CPU<Impl>::signalSwitched()
{
if (++switchCount == 5) {
if (++switchCount == NumStages) {
fetch.doSwitchOut();
rename.doSwitchOut();
commit.doSwitchOut();
@ -699,18 +708,16 @@ template <class Impl>
void
FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
{
// Flush out any old data from the activity buffers.
for (int i = 0; i < 6; ++i) {
// Flush out any old data from the time buffers.
for (int i = 0; i < 10; ++i) {
timeBuffer.advance();
fetchQueue.advance();
decodeQueue.advance();
renameQueue.advance();
iewQueue.advance();
activityBuffer.advance();
}
activityCount = 0;
bzero(&stageActive, sizeof(stageActive));
activityRec.reset();
BaseCPU::takeOverFrom(oldCPU);
@ -722,23 +729,23 @@ FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
assert(!tickEvent.scheduled());
// @todo: Figure out how to properly select the tid to put onto the active threads list.
// @todo: Figure out how to properly select the tid to put onto
// the active threads list.
int tid = 0;
list<unsigned>::iterator isActive = find(
activeThreads.begin(), activeThreads.end(), tid);
if (isActive == activeThreads.end()) {
//May Need to Re-code this if the delay variable is the
//delay needed for thread to activate
//May Need to Re-code this if the delay variable is the delay
//needed for thread to activate
DPRINTF(FullCPU, "Adding Thread %i to active threads list\n",
tid);
activeThreads.push_back(tid);
}
// Set all status's to active, schedule the
// CPU's tick event.
// Set all statuses to active, schedule the CPU's tick event.
// @todo: Fix up statuses so this is handled properly
for (int i = 0; i < execContexts.size(); ++i) {
ExecContext *xc = execContexts[i];
@ -850,10 +857,6 @@ template <class Impl>
void
FullO3CPU<Impl>::setArchIntReg(int reg_idx, uint64_t val, unsigned tid)
{
if (reg_idx == TheISA::ZeroReg) {
warn("Setting r31 through ArchIntReg in CPU, cycle %i\n", curTick);
}
PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx);
regFile.setIntReg(phys_reg, val);
@ -1049,8 +1052,8 @@ FullO3CPU<Impl>::squashInstIt(const ListIt &instIt, const unsigned &tid)
// Mark it as squashed.
(*instIt)->setSquashed();
//@todo: Formulate a consistent method for deleting
//instructions from the instruction list
// @todo: Formulate a consistent method for deleting
// instructions from the instruction list
// Remove the instruction from the list.
removeList.push(instIt);
}
@ -1074,14 +1077,14 @@ FullO3CPU<Impl>::cleanUpRemovedInsts()
removeInstsThisCycle = false;
}
/*
template <class Impl>
void
FullO3CPU<Impl>::removeAllInsts()
{
instList.clear();
}
*/
template <class Impl>
void
FullO3CPU<Impl>::dumpInsts()
@ -1102,98 +1105,30 @@ FullO3CPU<Impl>::dumpInsts()
++num;
}
}
/*
template <class Impl>
void
FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst)
{
iew.wakeDependents(inst);
}
*/
template <class Impl>
void
FullO3CPU<Impl>::wakeCPU()
{
if (activityCount || tickEvent.scheduled()) {
if (activityRec.active() || tickEvent.scheduled()) {
DPRINTF(Activity, "CPU already running.\n");
return;
}
idleCycles += curTick - lastRunningCycle;
DPRINTF(Activity, "Waking up CPU\n");
idleCycles += (curTick - 1) - lastRunningCycle;
tickEvent.schedule(curTick);
}
template <class Impl>
void
FullO3CPU<Impl>::activityThisCycle()
{
if (activityBuffer[0]) {
return;
}
activityBuffer[0] = true;
activity = true;
++activityCount;
DPRINTF(Activity, "Activity: %i\n", activityCount);
}
template <class Impl>
void
FullO3CPU<Impl>::advanceActivityBuffer()
{
if (activityBuffer[-5]) {
--activityCount;
assert(activityCount >= 0);
DPRINTF(Activity, "Activity: %i\n", activityCount);
if (activityCount == 0) {
DPRINTF(FullCPU, "No activity left, going to idle!\n");
lastRunningCycle = curTick;
timesIdled++;
}
}
activityBuffer.advance();
}
template <class Impl>
void
FullO3CPU<Impl>::activateStage(const StageIdx idx)
{
if (!stageActive[idx]) {
++activityCount;
stageActive[idx] = true;
DPRINTF(Activity, "Activity: %i\n", activityCount);
} else {
DPRINTF(Activity, "Stage %i already active.\n", idx);
}
// @todo: Number is hardcoded for now. Replace with parameter.
assert(activityCount < 15);
}
template <class Impl>
void
FullO3CPU<Impl>::deactivateStage(const StageIdx idx)
{
if (stageActive[idx]) {
--activityCount;
stageActive[idx] = false;
DPRINTF(Activity, "Activity: %i\n", activityCount);
} else {
DPRINTF(Activity, "Stage %i already inactive.\n", idx);
}
assert(activityCount >= 0);
}
template <class Impl>
int
FullO3CPU<Impl>::getFreeTid()

View file

@ -26,8 +26,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __CPU_O3_FULL_CPU_HH__
#define __CPU_O3_FULL_CPU_HH__
#ifndef __CPU_O3_CPU_HH__
#define __CPU_O3_CPU_HH__
#include <iostream>
#include <list>
@ -38,6 +38,7 @@
#include "base/statistics.hh"
#include "base/timebuf.hh"
#include "config/full_system.hh"
#include "cpu/activity.hh"
#include "cpu/base.hh"
#include "cpu/cpu_exec_context.hh"
#include "cpu/o3/comm.hh"
@ -70,7 +71,7 @@ template <class Impl>
class FullO3CPU : public BaseFullCPU
{
public:
//Put typedefs from the Impl here.
// Typedefs from the Impl here.
typedef typename Impl::CPUPol CPUPolicy;
typedef typename Impl::Params Params;
typedef typename Impl::DynInstPtr DynInstPtr;
@ -191,20 +192,18 @@ class FullO3CPU : public BaseFullCPU
* Note: this is a virtual function. CPU-Specific
* functionality defined in derived classes
*/
virtual void syscall(int tid) {}
virtual void syscall(int tid) { panic("Unimplemented!"); }
/** Check if there are any system calls pending. */
void checkSyscalls();
/** Switches out this CPU.
* @todo: Implement this.
*/
void switchOut(Sampler *sampler);
void signalSwitched();
/** Takes over from another CPU.
* @todo: Implement this.
*/
void takeOverFrom(BaseCPU *oldCPU);
@ -299,12 +298,8 @@ class FullO3CPU : public BaseFullCPU
/** Add Instructions to the CPU Remove List*/
void addToRemoveList(DynInstPtr &inst);
/** Remove an instruction from the front of the list. It is expected
* that there are no instructions in front of it (that is, none are older
* than the instruction being removed). Used when retiring instructions.
* @todo: Remove the argument to this function, and just have it remove
* last instruction once it's verified that commit has the same ordering
* as the instruction list.
/** Remove an instruction from the front end of the list. There's
* no restriction on location of the instruction.
*/
void removeFrontInst(DynInstPtr &inst);
@ -319,15 +314,15 @@ class FullO3CPU : public BaseFullCPU
void cleanUpRemovedInsts();
/** Remove all instructions from the list. */
void removeAllInsts();
// void removeAllInsts();
void dumpInsts();
/** Basically a wrapper function so that instructions executed at
* commit can tell the instruction queue that they have completed.
* Eventually this hack should be removed.
* commit can tell the instruction queue that they have
* completed. Eventually this hack should be removed.
*/
void wakeDependents(DynInstPtr &inst);
// void wakeDependents(DynInstPtr &inst);
public:
/** List of all the instructions in flight. */
@ -338,12 +333,12 @@ class FullO3CPU : public BaseFullCPU
*/
std::queue<ListIt> removeList;
//#ifdef DEBUG
#ifdef DEBUG
std::set<InstSeqNum> snList;
//#endif
#endif
/** Records if instructions need to be removed this cycle due to being
* retired or squashed.
/** Records if instructions need to be removed this cycle due to
* being retired or squashed.
*/
bool removeInstsThisCycle;
@ -425,46 +420,19 @@ class FullO3CPU : public BaseFullCPU
/** The IEW stage's instruction queue. */
TimeBuffer<IEWStruct> iewQueue;
private:
/** Time buffer that tracks if any cycles has active communication in them.
* It should be as long as the longest communication latency in the system.
* Each time any time buffer is written, the activity buffer should also
* be written to. The activityBuffer is advanced along with all the other
* time buffers, so it should always have a 1 somewhere in it only if there
* is active communication in a time buffer.
*/
TimeBuffer<bool> activityBuffer;
/** Tracks how many stages and cycles of time buffer have activity. Stages
* increment this count when they switch to active, and decrement it when
* they switch to inactive. Whenever a cycle that previously had no
* information is written in the time buffer, this is incremented. When
* a cycle that had information exits the time buffer due to age, this
* count is decremented. When the count is 0, there is no activity in the
* CPU, and it can be descheduled.
*/
int activityCount;
/** Records if there has been activity this cycle. */
bool activity;
/** Records which stages are active/inactive. */
bool stageActive[NumStages];
public:
ActivityRecorder activityRec;
void activityThisCycle() { activityRec.activity(); }
void activateStage(const StageIdx idx)
{ activityRec.activateStage(idx); }
void deactivateStage(const StageIdx idx)
{ activityRec.deactivateStage(idx); }
/** Wakes the CPU, rescheduling the CPU if it's not already active. */
void wakeCPU();
/** Records that there is activity this cycle. */
void activityThisCycle();
/** Advances the activity buffer, decrementing the activityCount if active
* communication just left the time buffer, and descheduling the CPU if
* there is no activity.
*/
void advanceActivityBuffer();
/** Marks a stage as active. */
void activateStage(const StageIdx idx);
/** Deactivates a stage. */
void deactivateStage(const StageIdx idx);
/** Gets a free thread id. Use if thread ids change across system. */
int getFreeTid();
@ -550,4 +518,4 @@ class FullO3CPU : public BaseFullCPU
Stats::Formula totalIpc;
};
#endif
#endif // __CPU_O3_CPU_HH__

View file

@ -3,7 +3,7 @@ from BaseCPU import BaseCPU
class DerivAlphaFullCPU(BaseCPU):
type = 'DerivAlphaFullCPU'
activity = Param.Unsigned("Initial count")
numThreads = Param.Unsigned("number of HW thread contexts")
if not build_env['FULL_SYSTEM']: