Revert power patch sets with unexpected interactions
The following patches had unexpected interactions with the current upstream code and have been reverted for now: e07fd01651f3: power: Add support for power models 831c7f2f9e39: power: Low-power idle power state for idle CPUs 4f749e00b667: power: Add power states to ClockedObject Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com> --HG-- extra : amend_source : 0b6fb073c6bbc24be533ec431eb51fbf1b269508
This commit is contained in:
parent
8615b27174
commit
be28d96510
57 changed files with 221 additions and 1849 deletions
|
@ -177,7 +177,7 @@ ExtMaster::handleEvent(SST::Event* event)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto req = new Request(ev->getAddr(), ev->getSize(), flags, 0);
|
auto req = new Request(ev->getAddr(), ev->getSize(), flags, 0);
|
||||||
req->setContext(ev->getGroupId());
|
req->setThreadContext(ev->getGroupId(), 0);
|
||||||
|
|
||||||
auto pkt = new Packet(req, cmdO);
|
auto pkt = new Packet(req, cmdO);
|
||||||
pkt->allocate();
|
pkt->allocate();
|
||||||
|
|
|
@ -1521,7 +1521,8 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
|
||||||
// with unexpected atomic snoop requests.
|
// with unexpected atomic snoop requests.
|
||||||
warn("Translating via MISCREG(%d) in functional mode! Fix Me!\n", misc_reg);
|
warn("Translating via MISCREG(%d) in functional mode! Fix Me!\n", misc_reg);
|
||||||
Request req(0, val, 1, flags, Request::funcMasterId,
|
Request req(0, val, 1, flags, Request::funcMasterId,
|
||||||
tc->pcState().pc(), tc->contextId());
|
tc->pcState().pc(), tc->contextId(),
|
||||||
|
tc->threadId());
|
||||||
fault = tc->getDTBPtr()->translateFunctional(&req, tc, mode, tranType);
|
fault = tc->getDTBPtr()->translateFunctional(&req, tc, mode, tranType);
|
||||||
TTBCR ttbcr = readMiscRegNoEffect(MISCREG_TTBCR);
|
TTBCR ttbcr = readMiscRegNoEffect(MISCREG_TTBCR);
|
||||||
HCR hcr = readMiscRegNoEffect(MISCREG_HCR);
|
HCR hcr = readMiscRegNoEffect(MISCREG_HCR);
|
||||||
|
@ -1767,7 +1768,7 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
|
||||||
warn("Translating via MISCREG(%d) in functional mode! Fix Me!\n", misc_reg);
|
warn("Translating via MISCREG(%d) in functional mode! Fix Me!\n", misc_reg);
|
||||||
req->setVirt(0, val, 1, flags, Request::funcMasterId,
|
req->setVirt(0, val, 1, flags, Request::funcMasterId,
|
||||||
tc->pcState().pc());
|
tc->pcState().pc());
|
||||||
req->setContext(tc->contextId());
|
req->setThreadContext(tc->contextId(), tc->threadId());
|
||||||
fault = tc->getDTBPtr()->translateFunctional(req, tc, mode,
|
fault = tc->getDTBPtr()->translateFunctional(req, tc, mode,
|
||||||
tranType);
|
tranType);
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ try_translate(ThreadContext *tc, Addr addr)
|
||||||
Fault fault;
|
Fault fault;
|
||||||
// Set up a functional memory Request to pass to the TLB
|
// Set up a functional memory Request to pass to the TLB
|
||||||
// to get it to translate the vaddr to a paddr
|
// to get it to translate the vaddr to a paddr
|
||||||
Request req(0, addr, 64, 0x40, -1, 0, 0);
|
Request req(0, addr, 64, 0x40, -1, 0, 0, 0);
|
||||||
ArmISA::TLB *tlb;
|
ArmISA::TLB *tlb;
|
||||||
|
|
||||||
// Check the TLBs for a translation
|
// Check the TLBs for a translation
|
||||||
|
|
|
@ -64,7 +64,6 @@
|
||||||
#include "debug/SyscallVerbose.hh"
|
#include "debug/SyscallVerbose.hh"
|
||||||
#include "mem/page_table.hh"
|
#include "mem/page_table.hh"
|
||||||
#include "params/BaseCPU.hh"
|
#include "params/BaseCPU.hh"
|
||||||
#include "sim/clocked_object.hh"
|
|
||||||
#include "sim/full_system.hh"
|
#include "sim/full_system.hh"
|
||||||
#include "sim/process.hh"
|
#include "sim/process.hh"
|
||||||
#include "sim/sim_events.hh"
|
#include "sim/sim_events.hh"
|
||||||
|
@ -356,11 +355,6 @@ BaseCPU::startup()
|
||||||
if (params()->progress_interval) {
|
if (params()->progress_interval) {
|
||||||
new CPUProgressEvent(this, params()->progress_interval);
|
new CPUProgressEvent(this, params()->progress_interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assumption CPU start to operate instantaneously without any latency
|
|
||||||
if (ClockedObject::pwrState() == Enums::PwrState::UNDEFINED)
|
|
||||||
ClockedObject::pwrState(Enums::PwrState::ON);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProbePoints::PMUUPtr
|
ProbePoints::PMUUPtr
|
||||||
|
@ -478,27 +472,6 @@ BaseCPU::findContext(ThreadContext *tc)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
BaseCPU::activateContext(ThreadID thread_num)
|
|
||||||
{
|
|
||||||
// For any active thread running, update CPU power state to active (ON)
|
|
||||||
ClockedObject::pwrState(Enums::PwrState::ON);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
BaseCPU::suspendContext(ThreadID thread_num)
|
|
||||||
{
|
|
||||||
// Check if all threads are suspended
|
|
||||||
for (auto t : threadContexts) {
|
|
||||||
if (t->status() != ThreadContext::Suspended) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All CPU threads suspended, enter lower power state for the CPU
|
|
||||||
ClockedObject::pwrState(Enums::PwrState::CLK_GATED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BaseCPU::switchOut()
|
BaseCPU::switchOut()
|
||||||
{
|
{
|
||||||
|
|
|
@ -279,11 +279,10 @@ class BaseCPU : public MemObject
|
||||||
Trace::InstTracer * getTracer() { return tracer; }
|
Trace::InstTracer * getTracer() { return tracer; }
|
||||||
|
|
||||||
/// Notify the CPU that the indicated context is now active.
|
/// Notify the CPU that the indicated context is now active.
|
||||||
virtual void activateContext(ThreadID thread_num);
|
virtual void activateContext(ThreadID thread_num) {}
|
||||||
|
|
||||||
/// Notify the CPU that the indicated context is now suspended.
|
/// Notify the CPU that the indicated context is now suspended.
|
||||||
/// Check if possible to enter a lower power state
|
virtual void suspendContext(ThreadID thread_num) {}
|
||||||
virtual void suspendContext(ThreadID thread_num);
|
|
||||||
|
|
||||||
/// Notify the CPU that the indicated context is now halted.
|
/// Notify the CPU that the indicated context is now halted.
|
||||||
virtual void haltContext(ThreadID thread_num) {}
|
virtual void haltContext(ThreadID thread_num) {}
|
||||||
|
@ -297,10 +296,6 @@ class BaseCPU : public MemObject
|
||||||
/// Get the number of thread contexts available
|
/// Get the number of thread contexts available
|
||||||
unsigned numContexts() { return threadContexts.size(); }
|
unsigned numContexts() { return threadContexts.size(); }
|
||||||
|
|
||||||
/// Convert ContextID to threadID
|
|
||||||
ThreadID contextToThread(ContextID cid)
|
|
||||||
{ return static_cast<ThreadID>(cid - threadContexts[0]->contextId()); }
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef BaseCPUParams Params;
|
typedef BaseCPUParams Params;
|
||||||
const Params *params() const
|
const Params *params() const
|
||||||
|
|
|
@ -886,7 +886,7 @@ BaseDynInst<Impl>::initiateMemRead(Addr addr, unsigned size, unsigned flags)
|
||||||
sreqHigh = savedSreqHigh;
|
sreqHigh = savedSreqHigh;
|
||||||
} else {
|
} else {
|
||||||
req = new Request(asid, addr, size, flags, masterId(), this->pc.instAddr(),
|
req = new Request(asid, addr, size, flags, masterId(), this->pc.instAddr(),
|
||||||
thread->contextId());
|
thread->contextId(), threadNumber);
|
||||||
|
|
||||||
req->taskId(cpu->taskId());
|
req->taskId(cpu->taskId());
|
||||||
|
|
||||||
|
@ -942,7 +942,7 @@ BaseDynInst<Impl>::writeMem(uint8_t *data, unsigned size,
|
||||||
sreqHigh = savedSreqHigh;
|
sreqHigh = savedSreqHigh;
|
||||||
} else {
|
} else {
|
||||||
req = new Request(asid, addr, size, flags, masterId(), this->pc.instAddr(),
|
req = new Request(asid, addr, size, flags, masterId(), this->pc.instAddr(),
|
||||||
thread->contextId());
|
thread->contextId(), threadNumber);
|
||||||
|
|
||||||
req->taskId(cpu->taskId());
|
req->taskId(cpu->taskId());
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,7 @@ CheckerCPU::readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags)
|
||||||
// Need to account for multiple accesses like the Atomic and TimingSimple
|
// Need to account for multiple accesses like the Atomic and TimingSimple
|
||||||
while (1) {
|
while (1) {
|
||||||
memReq = new Request(0, addr, size, flags, masterId,
|
memReq = new Request(0, addr, size, flags, masterId,
|
||||||
thread->pcState().instAddr(), tc->contextId());
|
thread->pcState().instAddr(), tc->contextId(), 0);
|
||||||
|
|
||||||
// translate to physical address
|
// translate to physical address
|
||||||
fault = dtb->translateFunctional(memReq, tc, BaseTLB::Read);
|
fault = dtb->translateFunctional(memReq, tc, BaseTLB::Read);
|
||||||
|
@ -243,7 +243,7 @@ CheckerCPU::writeMem(uint8_t *data, unsigned size,
|
||||||
// Need to account for a multiple access like Atomic and Timing CPUs
|
// Need to account for a multiple access like Atomic and Timing CPUs
|
||||||
while (1) {
|
while (1) {
|
||||||
memReq = new Request(0, addr, size, flags, masterId,
|
memReq = new Request(0, addr, size, flags, masterId,
|
||||||
thread->pcState().instAddr(), tc->contextId());
|
thread->pcState().instAddr(), tc->contextId(), 0);
|
||||||
|
|
||||||
// translate to physical address
|
// translate to physical address
|
||||||
fault = dtb->translateFunctional(memReq, tc, BaseTLB::Write);
|
fault = dtb->translateFunctional(memReq, tc, BaseTLB::Write);
|
||||||
|
|
|
@ -248,7 +248,8 @@ Checker<Impl>::verify(DynInstPtr &completed_inst)
|
||||||
sizeof(MachInst),
|
sizeof(MachInst),
|
||||||
0,
|
0,
|
||||||
masterId,
|
masterId,
|
||||||
fetch_PC, thread->contextId());
|
fetch_PC, thread->contextId(),
|
||||||
|
unverifiedInst->threadNumber);
|
||||||
memReq->setVirt(0, fetch_PC, sizeof(MachInst),
|
memReq->setVirt(0, fetch_PC, sizeof(MachInst),
|
||||||
Request::INST_FETCH, masterId, thread->instAddr());
|
Request::INST_FETCH, masterId, thread->instAddr());
|
||||||
|
|
||||||
|
|
|
@ -1027,7 +1027,7 @@ BaseKvmCPU::doMMIOAccess(Addr paddr, void *data, int size, bool write)
|
||||||
syncThreadContext();
|
syncThreadContext();
|
||||||
|
|
||||||
Request mmio_req(paddr, size, Request::UNCACHEABLE, dataMasterId());
|
Request mmio_req(paddr, size, Request::UNCACHEABLE, dataMasterId());
|
||||||
mmio_req.setContext(tc->contextId());
|
mmio_req.setThreadContext(tc->contextId(), 0);
|
||||||
// Some architectures do need to massage physical addresses a bit
|
// Some architectures do need to massage physical addresses a bit
|
||||||
// before they are inserted into the memory system. This enables
|
// before they are inserted into the memory system. This enables
|
||||||
// APIC accesses on x86 and m5ops where supported through a MMIO
|
// APIC accesses on x86 and m5ops where supported through a MMIO
|
||||||
|
|
|
@ -1346,7 +1346,7 @@ X86KvmCPU::handleKvmExitIO()
|
||||||
|
|
||||||
Request io_req(pAddr, kvm_run.io.size, Request::UNCACHEABLE,
|
Request io_req(pAddr, kvm_run.io.size, Request::UNCACHEABLE,
|
||||||
dataMasterId());
|
dataMasterId());
|
||||||
io_req.setContext(tc->contextId());
|
io_req.setThreadContext(tc->contextId(), 0);
|
||||||
|
|
||||||
const MemCmd cmd(isWrite ? MemCmd::WriteReq : MemCmd::ReadReq);
|
const MemCmd cmd(isWrite ? MemCmd::WriteReq : MemCmd::ReadReq);
|
||||||
// Temporarily lock and migrate to the event queue of the
|
// Temporarily lock and migrate to the event queue of the
|
||||||
|
|
|
@ -287,8 +287,6 @@ MinorCPU::activateContext(ThreadID thread_id)
|
||||||
threads[thread_id]->activate();
|
threads[thread_id]->activate();
|
||||||
wakeupOnEvent(Minor::Pipeline::CPUStageId);
|
wakeupOnEvent(Minor::Pipeline::CPUStageId);
|
||||||
pipeline->wakeupFetch();
|
pipeline->wakeupFetch();
|
||||||
|
|
||||||
BaseCPU::activateContext(thread_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -297,8 +295,6 @@ MinorCPU::suspendContext(ThreadID thread_id)
|
||||||
DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id);
|
DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id);
|
||||||
|
|
||||||
threads[thread_id]->suspend();
|
threads[thread_id]->suspend();
|
||||||
|
|
||||||
BaseCPU::suspendContext(thread_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -135,7 +135,8 @@ Fetch1::fetchLine()
|
||||||
"%s addr: 0x%x pc: %s line_offset: %d request_size: %d\n",
|
"%s addr: 0x%x pc: %s line_offset: %d request_size: %d\n",
|
||||||
request_id, aligned_pc, pc, line_offset, request_size);
|
request_id, aligned_pc, pc, line_offset, request_size);
|
||||||
|
|
||||||
request->request.setContext(cpu.threads[0]->getTC()->contextId());
|
request->request.setThreadContext(cpu.threads[0]->getTC()->contextId(),
|
||||||
|
/* thread id */ 0);
|
||||||
request->request.setVirt(0 /* asid */,
|
request->request.setVirt(0 /* asid */,
|
||||||
aligned_pc, request_size, Request::INST_FETCH, cpu.instMasterId(),
|
aligned_pc, request_size, Request::INST_FETCH, cpu.instMasterId(),
|
||||||
/* I've no idea why we need the PC, but give it */
|
/* I've no idea why we need the PC, but give it */
|
||||||
|
|
|
@ -422,7 +422,7 @@ LSQ::SplitDataRequest::makeFragmentRequests()
|
||||||
|
|
||||||
Request *fragment = new Request();
|
Request *fragment = new Request();
|
||||||
|
|
||||||
fragment->setContext(request.contextId());
|
fragment->setThreadContext(request.contextId(), /* thread id */ 0);
|
||||||
fragment->setVirt(0 /* asid */,
|
fragment->setVirt(0 /* asid */,
|
||||||
fragment_addr, fragment_size, request.getFlags(),
|
fragment_addr, fragment_size, request.getFlags(),
|
||||||
request.masterId(),
|
request.masterId(),
|
||||||
|
@ -1070,8 +1070,7 @@ LSQ::tryToSend(LSQRequestPtr request)
|
||||||
|
|
||||||
if (request->request.isMmappedIpr()) {
|
if (request->request.isMmappedIpr()) {
|
||||||
ThreadContext *thread =
|
ThreadContext *thread =
|
||||||
cpu.getContext(cpu.contextToThread(
|
cpu.getContext(request->request.threadId());
|
||||||
request->request.contextId()));
|
|
||||||
|
|
||||||
if (request->isLoad) {
|
if (request->isLoad) {
|
||||||
DPRINTF(MinorMem, "IPR read inst: %s\n", *(request->inst));
|
DPRINTF(MinorMem, "IPR read inst: %s\n", *(request->inst));
|
||||||
|
@ -1503,7 +1502,7 @@ LSQ::pushRequest(MinorDynInstPtr inst, bool isLoad, uint8_t *data,
|
||||||
inst->traceData->setMem(addr, size, flags);
|
inst->traceData->setMem(addr, size, flags);
|
||||||
|
|
||||||
int cid = cpu.threads[inst->id.threadId]->getTC()->contextId();
|
int cid = cpu.threads[inst->id.threadId]->getTC()->contextId();
|
||||||
request->request.setContext(cid);
|
request->request.setThreadContext(cid, /* thread id */ 0);
|
||||||
request->request.setVirt(0 /* asid */,
|
request->request.setVirt(0 /* asid */,
|
||||||
addr, size, flags, cpu.dataMasterId(),
|
addr, size, flags, cpu.dataMasterId(),
|
||||||
/* I've no idea why we need the PC, but give it */
|
/* I've no idea why we need the PC, but give it */
|
||||||
|
|
|
@ -735,8 +735,6 @@ FullO3CPU<Impl>::activateContext(ThreadID tid)
|
||||||
lastActivatedCycle = curTick();
|
lastActivatedCycle = curTick();
|
||||||
|
|
||||||
_status = Running;
|
_status = Running;
|
||||||
|
|
||||||
BaseCPU::activateContext(tid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -757,8 +755,6 @@ FullO3CPU<Impl>::suspendContext(ThreadID tid)
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINTF(Quiesce, "Suspending Context\n");
|
DPRINTF(Quiesce, "Suspending Context\n");
|
||||||
|
|
||||||
BaseCPU::suspendContext(tid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Impl>
|
template <class Impl>
|
||||||
|
|
|
@ -378,7 +378,7 @@ template<class Impl>
|
||||||
void
|
void
|
||||||
DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
|
DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
ThreadID tid = cpu->contextToThread(pkt->req->contextId());
|
ThreadID tid = pkt->req->threadId();
|
||||||
|
|
||||||
DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n", tid);
|
DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n", tid);
|
||||||
assert(!cpu->switchedOut());
|
assert(!cpu->switchedOut());
|
||||||
|
@ -622,7 +622,7 @@ DefaultFetch<Impl>::fetchCacheLine(Addr vaddr, ThreadID tid, Addr pc)
|
||||||
RequestPtr mem_req =
|
RequestPtr mem_req =
|
||||||
new Request(tid, fetchBufferBlockPC, fetchBufferSize,
|
new Request(tid, fetchBufferBlockPC, fetchBufferSize,
|
||||||
Request::INST_FETCH, cpu->instMasterId(), pc,
|
Request::INST_FETCH, cpu->instMasterId(), pc,
|
||||||
cpu->thread[tid]->contextId());
|
cpu->thread[tid]->contextId(), tid);
|
||||||
|
|
||||||
mem_req->taskId(cpu->taskId());
|
mem_req->taskId(cpu->taskId());
|
||||||
|
|
||||||
|
@ -640,7 +640,7 @@ template <class Impl>
|
||||||
void
|
void
|
||||||
DefaultFetch<Impl>::finishTranslation(const Fault &fault, RequestPtr mem_req)
|
DefaultFetch<Impl>::finishTranslation(const Fault &fault, RequestPtr mem_req)
|
||||||
{
|
{
|
||||||
ThreadID tid = cpu->contextToThread(mem_req->contextId());
|
ThreadID tid = mem_req->threadId();
|
||||||
Addr fetchBufferBlockPC = mem_req->getVaddr();
|
Addr fetchBufferBlockPC = mem_req->getVaddr();
|
||||||
|
|
||||||
assert(!cpu->switchedOut());
|
assert(!cpu->switchedOut());
|
||||||
|
|
|
@ -334,7 +334,7 @@ Fault
|
||||||
LSQ<Impl>::read(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh,
|
LSQ<Impl>::read(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh,
|
||||||
int load_idx)
|
int load_idx)
|
||||||
{
|
{
|
||||||
ThreadID tid = cpu->contextToThread(req->contextId());
|
ThreadID tid = req->threadId();
|
||||||
|
|
||||||
return thread[tid].read(req, sreqLow, sreqHigh, load_idx);
|
return thread[tid].read(req, sreqLow, sreqHigh, load_idx);
|
||||||
}
|
}
|
||||||
|
@ -344,7 +344,7 @@ Fault
|
||||||
LSQ<Impl>::write(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh,
|
LSQ<Impl>::write(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh,
|
||||||
uint8_t *data, int store_idx)
|
uint8_t *data, int store_idx)
|
||||||
{
|
{
|
||||||
ThreadID tid = cpu->contextToThread(req->contextId());
|
ThreadID tid = req->threadId();
|
||||||
|
|
||||||
return thread[tid].write(req, sreqLow, sreqHigh, data, store_idx);
|
return thread[tid].write(req, sreqLow, sreqHigh, data, store_idx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -347,8 +347,7 @@ LSQ<Impl>::recvTimingResp(PacketPtr pkt)
|
||||||
DPRINTF(LSQ, "Got error packet back for address: %#X\n",
|
DPRINTF(LSQ, "Got error packet back for address: %#X\n",
|
||||||
pkt->getAddr());
|
pkt->getAddr());
|
||||||
|
|
||||||
thread[cpu->contextToThread(pkt->req->contextId())]
|
thread[pkt->req->threadId()].completeDataAccess(pkt);
|
||||||
.completeDataAccess(pkt);
|
|
||||||
|
|
||||||
if (pkt->isInvalidate()) {
|
if (pkt->isInvalidate()) {
|
||||||
// This response also contains an invalidate; e.g. this can be the case
|
// This response also contains an invalidate; e.g. this can be the case
|
||||||
|
|
|
@ -78,7 +78,7 @@ LocalBP::reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LocalBP::btbUpdate(ThreadID tid, Addr branch_addr, void * &bp_history)
|
LocalBP::btbUpdate(Addr branch_addr, void * &bp_history)
|
||||||
{
|
{
|
||||||
// Place holder for a function that is called to update predictor history when
|
// Place holder for a function that is called to update predictor history when
|
||||||
// a BTB entry is invalid or not found.
|
// a BTB entry is invalid or not found.
|
||||||
|
@ -86,7 +86,7 @@ LocalBP::btbUpdate(ThreadID tid, Addr branch_addr, void * &bp_history)
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
LocalBP::lookup(ThreadID tid, Addr branch_addr, void * &bp_history)
|
LocalBP::lookup(Addr branch_addr, void * &bp_history)
|
||||||
{
|
{
|
||||||
bool taken;
|
bool taken;
|
||||||
uint8_t counter_val;
|
uint8_t counter_val;
|
||||||
|
@ -117,8 +117,7 @@ LocalBP::lookup(ThreadID tid, Addr branch_addr, void * &bp_history)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LocalBP::update(ThreadID tid, Addr branch_addr, bool taken, void *bp_history,
|
LocalBP::update(Addr branch_addr, bool taken, void *bp_history, bool squashed)
|
||||||
bool squashed)
|
|
||||||
{
|
{
|
||||||
assert(bp_history == NULL);
|
assert(bp_history == NULL);
|
||||||
unsigned local_predictor_idx;
|
unsigned local_predictor_idx;
|
||||||
|
@ -153,7 +152,7 @@ LocalBP::getLocalIndex(Addr &branch_addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LocalBP::uncondBranch(ThreadID tid, Addr pc, void *&bp_history)
|
LocalBP::uncondBranch(Addr pc, void *&bp_history)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ class LocalBP : public BPredUnit
|
||||||
*/
|
*/
|
||||||
LocalBP(const LocalBPParams *params);
|
LocalBP(const LocalBPParams *params);
|
||||||
|
|
||||||
virtual void uncondBranch(ThreadID tid, Addr pc, void * &bp_history);
|
virtual void uncondBranch(Addr pc, void * &bp_history);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks up the given address in the branch predictor and returns
|
* Looks up the given address in the branch predictor and returns
|
||||||
|
@ -75,7 +75,7 @@ class LocalBP : public BPredUnit
|
||||||
* @param bp_history Pointer to any bp history state.
|
* @param bp_history Pointer to any bp history state.
|
||||||
* @return Whether or not the branch is taken.
|
* @return Whether or not the branch is taken.
|
||||||
*/
|
*/
|
||||||
bool lookup(ThreadID tid, Addr branch_addr, void * &bp_history);
|
bool lookup(Addr branch_addr, void * &bp_history);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the branch predictor to Not Taken if a BTB entry is
|
* Updates the branch predictor to Not Taken if a BTB entry is
|
||||||
|
@ -84,20 +84,19 @@ class LocalBP : public BPredUnit
|
||||||
* @param bp_history Pointer to any bp history state.
|
* @param bp_history Pointer to any bp history state.
|
||||||
* @return Whether or not the branch is taken.
|
* @return Whether or not the branch is taken.
|
||||||
*/
|
*/
|
||||||
void btbUpdate(ThreadID tid, Addr branch_addr, void * &bp_history);
|
void btbUpdate(Addr branch_addr, void * &bp_history);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the branch predictor with the actual result of a branch.
|
* Updates the branch predictor with the actual result of a branch.
|
||||||
* @param branch_addr The address of the branch to update.
|
* @param branch_addr The address of the branch to update.
|
||||||
* @param taken Whether or not the branch was taken.
|
* @param taken Whether or not the branch was taken.
|
||||||
*/
|
*/
|
||||||
void update(ThreadID tid, Addr branch_addr, bool taken, void *bp_history,
|
void update(Addr branch_addr, bool taken, void *bp_history, bool squashed);
|
||||||
bool squashed);
|
|
||||||
|
|
||||||
void retireSquashed(ThreadID tid, void *bp_history)
|
void retireSquashed(void *bp_history)
|
||||||
{ assert(bp_history == NULL); }
|
{ assert(bp_history == NULL); }
|
||||||
|
|
||||||
void squash(ThreadID tid, void *bp_history)
|
void squash(void *bp_history)
|
||||||
{ assert(bp_history == NULL); }
|
{ assert(bp_history == NULL); }
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
|
@ -42,16 +42,6 @@ class BranchPredictor(SimObject):
|
||||||
RASSize = Param.Unsigned(16, "RAS size")
|
RASSize = Param.Unsigned(16, "RAS size")
|
||||||
instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by")
|
instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by")
|
||||||
|
|
||||||
useIndirect = Param.Bool(True, "Use indirect branch predictor")
|
|
||||||
indirectHashGHR = Param.Bool(True, "Hash branch predictor GHR")
|
|
||||||
indirectHashTargets = Param.Bool(True, "Hash path history targets")
|
|
||||||
indirectSets = Param.Unsigned(256, "Cache sets for indirect predictor")
|
|
||||||
indirectWays = Param.Unsigned(2, "Ways for indirect predictor")
|
|
||||||
indirectTagSize = Param.Unsigned(16, "Indirect target cache tag bits")
|
|
||||||
indirectPathLength = Param.Unsigned(3,
|
|
||||||
"Previous indirect targets to use for path history")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LocalBP(BranchPredictor):
|
class LocalBP(BranchPredictor):
|
||||||
type = 'LocalBP'
|
type = 'LocalBP'
|
||||||
|
|
|
@ -35,11 +35,9 @@ if env['TARGET_ISA'] == 'null':
|
||||||
|
|
||||||
SimObject('BranchPredictor.py')
|
SimObject('BranchPredictor.py')
|
||||||
|
|
||||||
DebugFlag('Indirect')
|
|
||||||
Source('bpred_unit.cc')
|
Source('bpred_unit.cc')
|
||||||
Source('2bit_local.cc')
|
Source('2bit_local.cc')
|
||||||
Source('btb.cc')
|
Source('btb.cc')
|
||||||
Source('indirect.cc')
|
|
||||||
Source('ras.cc')
|
Source('ras.cc')
|
||||||
Source('tournament.cc')
|
Source('tournament.cc')
|
||||||
Source ('bi_mode.cc')
|
Source ('bi_mode.cc')
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
|
|
||||||
BiModeBP::BiModeBP(const BiModeBPParams *params)
|
BiModeBP::BiModeBP(const BiModeBPParams *params)
|
||||||
: BPredUnit(params),
|
: BPredUnit(params),
|
||||||
globalHistoryReg(params->numThreads, 0),
|
globalHistoryReg(0),
|
||||||
globalHistoryBits(ceilLog2(params->globalPredictorSize)),
|
globalHistoryBits(ceilLog2(params->globalPredictorSize)),
|
||||||
choicePredictorSize(params->choicePredictorSize),
|
choicePredictorSize(params->choicePredictorSize),
|
||||||
choiceCtrBits(params->choiceCtrBits),
|
choiceCtrBits(params->choiceCtrBits),
|
||||||
|
@ -77,23 +77,23 @@ BiModeBP::BiModeBP(const BiModeBPParams *params)
|
||||||
* chooses the taken array and the taken array predicts taken.
|
* chooses the taken array and the taken array predicts taken.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
BiModeBP::uncondBranch(ThreadID tid, Addr pc, void * &bpHistory)
|
BiModeBP::uncondBranch(Addr pc, void * &bpHistory)
|
||||||
{
|
{
|
||||||
BPHistory *history = new BPHistory;
|
BPHistory *history = new BPHistory;
|
||||||
history->globalHistoryReg = globalHistoryReg[tid];
|
history->globalHistoryReg = globalHistoryReg;
|
||||||
history->takenUsed = true;
|
history->takenUsed = true;
|
||||||
history->takenPred = true;
|
history->takenPred = true;
|
||||||
history->notTakenPred = true;
|
history->notTakenPred = true;
|
||||||
history->finalPred = true;
|
history->finalPred = true;
|
||||||
bpHistory = static_cast<void*>(history);
|
bpHistory = static_cast<void*>(history);
|
||||||
updateGlobalHistReg(tid, true);
|
updateGlobalHistReg(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BiModeBP::squash(ThreadID tid, void *bpHistory)
|
BiModeBP::squash(void *bpHistory)
|
||||||
{
|
{
|
||||||
BPHistory *history = static_cast<BPHistory*>(bpHistory);
|
BPHistory *history = static_cast<BPHistory*>(bpHistory);
|
||||||
globalHistoryReg[tid] = history->globalHistoryReg;
|
globalHistoryReg = history->globalHistoryReg;
|
||||||
|
|
||||||
delete history;
|
delete history;
|
||||||
}
|
}
|
||||||
|
@ -108,12 +108,12 @@ BiModeBP::squash(ThreadID tid, void *bpHistory)
|
||||||
* direction predictors for the final branch prediction.
|
* direction predictors for the final branch prediction.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
BiModeBP::lookup(ThreadID tid, Addr branchAddr, void * &bpHistory)
|
BiModeBP::lookup(Addr branchAddr, void * &bpHistory)
|
||||||
{
|
{
|
||||||
unsigned choiceHistoryIdx = ((branchAddr >> instShiftAmt)
|
unsigned choiceHistoryIdx = ((branchAddr >> instShiftAmt)
|
||||||
& choiceHistoryMask);
|
& choiceHistoryMask);
|
||||||
unsigned globalHistoryIdx = (((branchAddr >> instShiftAmt)
|
unsigned globalHistoryIdx = (((branchAddr >> instShiftAmt)
|
||||||
^ globalHistoryReg[tid])
|
^ globalHistoryReg)
|
||||||
& globalHistoryMask);
|
& globalHistoryMask);
|
||||||
|
|
||||||
assert(choiceHistoryIdx < choicePredictorSize);
|
assert(choiceHistoryIdx < choicePredictorSize);
|
||||||
|
@ -128,7 +128,7 @@ BiModeBP::lookup(ThreadID tid, Addr branchAddr, void * &bpHistory)
|
||||||
bool finalPrediction;
|
bool finalPrediction;
|
||||||
|
|
||||||
BPHistory *history = new BPHistory;
|
BPHistory *history = new BPHistory;
|
||||||
history->globalHistoryReg = globalHistoryReg[tid];
|
history->globalHistoryReg = globalHistoryReg;
|
||||||
history->takenUsed = choicePrediction;
|
history->takenUsed = choicePrediction;
|
||||||
history->takenPred = takenGHBPrediction;
|
history->takenPred = takenGHBPrediction;
|
||||||
history->notTakenPred = notTakenGHBPrediction;
|
history->notTakenPred = notTakenGHBPrediction;
|
||||||
|
@ -141,15 +141,15 @@ BiModeBP::lookup(ThreadID tid, Addr branchAddr, void * &bpHistory)
|
||||||
|
|
||||||
history->finalPred = finalPrediction;
|
history->finalPred = finalPrediction;
|
||||||
bpHistory = static_cast<void*>(history);
|
bpHistory = static_cast<void*>(history);
|
||||||
updateGlobalHistReg(tid, finalPrediction);
|
updateGlobalHistReg(finalPrediction);
|
||||||
|
|
||||||
return finalPrediction;
|
return finalPrediction;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BiModeBP::btbUpdate(ThreadID tid, Addr branchAddr, void * &bpHistory)
|
BiModeBP::btbUpdate(Addr branchAddr, void * &bpHistory)
|
||||||
{
|
{
|
||||||
globalHistoryReg[tid] &= (historyRegisterMask & ~ULL(1));
|
globalHistoryReg &= (historyRegisterMask & ~ULL(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only the selected direction predictor will be updated with the final
|
/* Only the selected direction predictor will be updated with the final
|
||||||
|
@ -159,8 +159,7 @@ BiModeBP::btbUpdate(ThreadID tid, Addr branchAddr, void * &bpHistory)
|
||||||
* the direction predictors makes a correct final prediction.
|
* the direction predictors makes a correct final prediction.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
BiModeBP::update(ThreadID tid, Addr branchAddr, bool taken, void *bpHistory,
|
BiModeBP::update(Addr branchAddr, bool taken, void *bpHistory, bool squashed)
|
||||||
bool squashed)
|
|
||||||
{
|
{
|
||||||
if (bpHistory) {
|
if (bpHistory) {
|
||||||
BPHistory *history = static_cast<BPHistory*>(bpHistory);
|
BPHistory *history = static_cast<BPHistory*>(bpHistory);
|
||||||
|
@ -219,11 +218,11 @@ BiModeBP::update(ThreadID tid, Addr branchAddr, bool taken, void *bpHistory,
|
||||||
|
|
||||||
if (squashed) {
|
if (squashed) {
|
||||||
if (taken) {
|
if (taken) {
|
||||||
globalHistoryReg[tid] = (history->globalHistoryReg << 1) | 1;
|
globalHistoryReg = (history->globalHistoryReg << 1) | 1;
|
||||||
} else {
|
} else {
|
||||||
globalHistoryReg[tid] = (history->globalHistoryReg << 1);
|
globalHistoryReg = (history->globalHistoryReg << 1);
|
||||||
}
|
}
|
||||||
globalHistoryReg[tid] &= historyRegisterMask;
|
globalHistoryReg &= historyRegisterMask;
|
||||||
} else {
|
} else {
|
||||||
delete history;
|
delete history;
|
||||||
}
|
}
|
||||||
|
@ -231,24 +230,18 @@ BiModeBP::update(ThreadID tid, Addr branchAddr, bool taken, void *bpHistory,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BiModeBP::retireSquashed(ThreadID tid, void *bp_history)
|
BiModeBP::retireSquashed(void *bp_history)
|
||||||
{
|
{
|
||||||
BPHistory *history = static_cast<BPHistory*>(bp_history);
|
BPHistory *history = static_cast<BPHistory*>(bp_history);
|
||||||
delete history;
|
delete history;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
|
||||||
BiModeBP::getGHR(ThreadID tid, void *bp_history) const
|
|
||||||
{
|
|
||||||
return static_cast<BPHistory*>(bp_history)->globalHistoryReg;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BiModeBP::updateGlobalHistReg(ThreadID tid, bool taken)
|
BiModeBP::updateGlobalHistReg(bool taken)
|
||||||
{
|
{
|
||||||
globalHistoryReg[tid] = taken ? (globalHistoryReg[tid] << 1) | 1 :
|
globalHistoryReg = taken ? (globalHistoryReg << 1) | 1 :
|
||||||
(globalHistoryReg[tid] << 1);
|
(globalHistoryReg << 1);
|
||||||
globalHistoryReg[tid] &= historyRegisterMask;
|
globalHistoryReg &= historyRegisterMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
BiModeBP*
|
BiModeBP*
|
||||||
|
|
|
@ -57,17 +57,15 @@ class BiModeBP : public BPredUnit
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BiModeBP(const BiModeBPParams *params);
|
BiModeBP(const BiModeBPParams *params);
|
||||||
void uncondBranch(ThreadID tid, Addr pc, void * &bp_history);
|
void uncondBranch(Addr pc, void * &bp_history);
|
||||||
void squash(ThreadID tid, void *bp_history);
|
void squash(void *bp_history);
|
||||||
bool lookup(ThreadID tid, Addr branch_addr, void * &bp_history);
|
bool lookup(Addr branch_addr, void * &bp_history);
|
||||||
void btbUpdate(ThreadID tid, Addr branch_addr, void * &bp_history);
|
void btbUpdate(Addr branch_addr, void * &bp_history);
|
||||||
void update(ThreadID tid, Addr branch_addr, bool taken, void *bp_history,
|
void update(Addr branch_addr, bool taken, void *bp_history, bool squashed);
|
||||||
bool squashed);
|
void retireSquashed(void *bp_history);
|
||||||
void retireSquashed(ThreadID tid, void *bp_history);
|
|
||||||
unsigned getGHR(ThreadID tid, void *bp_history) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateGlobalHistReg(ThreadID tid, bool taken);
|
void updateGlobalHistReg(bool taken);
|
||||||
|
|
||||||
struct BPHistory {
|
struct BPHistory {
|
||||||
unsigned globalHistoryReg;
|
unsigned globalHistoryReg;
|
||||||
|
@ -96,7 +94,7 @@ class BiModeBP : public BPredUnit
|
||||||
// not-taken direction predictors
|
// not-taken direction predictors
|
||||||
std::vector<SatCounter> notTakenCounters;
|
std::vector<SatCounter> notTakenCounters;
|
||||||
|
|
||||||
std::vector<unsigned> globalHistoryReg;
|
unsigned globalHistoryReg;
|
||||||
unsigned globalHistoryBits;
|
unsigned globalHistoryBits;
|
||||||
unsigned historyRegisterMask;
|
unsigned historyRegisterMask;
|
||||||
|
|
||||||
|
|
|
@ -59,18 +59,8 @@ BPredUnit::BPredUnit(const Params *params)
|
||||||
predHist(numThreads),
|
predHist(numThreads),
|
||||||
BTB(params->BTBEntries,
|
BTB(params->BTBEntries,
|
||||||
params->BTBTagSize,
|
params->BTBTagSize,
|
||||||
params->instShiftAmt,
|
params->instShiftAmt),
|
||||||
params->numThreads),
|
|
||||||
RAS(numThreads),
|
RAS(numThreads),
|
||||||
useIndirect(params->useIndirect),
|
|
||||||
iPred(params->indirectHashGHR,
|
|
||||||
params->indirectHashTargets,
|
|
||||||
params->indirectSets,
|
|
||||||
params->indirectWays,
|
|
||||||
params->indirectTagSize,
|
|
||||||
params->indirectPathLength,
|
|
||||||
params->instShiftAmt,
|
|
||||||
params->numThreads),
|
|
||||||
instShiftAmt(params->instShiftAmt)
|
instShiftAmt(params->instShiftAmt)
|
||||||
{
|
{
|
||||||
for (auto& r : RAS)
|
for (auto& r : RAS)
|
||||||
|
@ -126,27 +116,6 @@ BPredUnit::regStats()
|
||||||
.name(name() + ".RASInCorrect")
|
.name(name() + ".RASInCorrect")
|
||||||
.desc("Number of incorrect RAS predictions.")
|
.desc("Number of incorrect RAS predictions.")
|
||||||
;
|
;
|
||||||
|
|
||||||
indirectLookups
|
|
||||||
.name(name() + ".indirectLookups")
|
|
||||||
.desc("Number of indirect predictor lookups.")
|
|
||||||
;
|
|
||||||
|
|
||||||
indirectHits
|
|
||||||
.name(name() + ".indirectHits")
|
|
||||||
.desc("Number of indirect target hits.")
|
|
||||||
;
|
|
||||||
|
|
||||||
indirectMisses
|
|
||||||
.name(name() + ".indirectMisses")
|
|
||||||
.desc("Number of indirect misses.")
|
|
||||||
;
|
|
||||||
|
|
||||||
indirectMispredicted
|
|
||||||
.name(name() + "indirectMispredcited")
|
|
||||||
.desc("Number of mispredicted indirect branches.")
|
|
||||||
;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProbePoints::PMUUPtr
|
ProbePoints::PMUUPtr
|
||||||
|
@ -195,10 +164,10 @@ BPredUnit::predict(const StaticInstPtr &inst, const InstSeqNum &seqNum,
|
||||||
DPRINTF(Branch, "[tid:%i]: Unconditional control.\n", tid);
|
DPRINTF(Branch, "[tid:%i]: Unconditional control.\n", tid);
|
||||||
pred_taken = true;
|
pred_taken = true;
|
||||||
// Tell the BP there was an unconditional branch.
|
// Tell the BP there was an unconditional branch.
|
||||||
uncondBranch(tid, pc.instAddr(), bp_history);
|
uncondBranch(pc.instAddr(), bp_history);
|
||||||
} else {
|
} else {
|
||||||
++condPredicted;
|
++condPredicted;
|
||||||
pred_taken = lookup(tid, pc.instAddr(), bp_history);
|
pred_taken = lookup(pc.instAddr(), bp_history);
|
||||||
|
|
||||||
DPRINTF(Branch, "[tid:%i]: [sn:%i] Branch predictor"
|
DPRINTF(Branch, "[tid:%i]: [sn:%i] Branch predictor"
|
||||||
" predicted %i for PC %s\n", tid, seqNum, pred_taken, pc);
|
" predicted %i for PC %s\n", tid, seqNum, pred_taken, pc);
|
||||||
|
@ -246,59 +215,31 @@ BPredUnit::predict(const StaticInstPtr &inst, const InstSeqNum &seqNum,
|
||||||
tid, pc, pc, RAS[tid].topIdx());
|
tid, pc, pc, RAS[tid].topIdx());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst->isDirectCtrl() || !useIndirect) {
|
if (BTB.valid(pc.instAddr(), tid)) {
|
||||||
// Check BTB on direct branches
|
++BTBHits;
|
||||||
if (BTB.valid(pc.instAddr(), tid)) {
|
|
||||||
++BTBHits;
|
|
||||||
|
|
||||||
// If it's not a return, use the BTB to get target addr.
|
// If it's not a return, use the BTB to get the target addr.
|
||||||
target = BTB.lookup(pc.instAddr(), tid);
|
target = BTB.lookup(pc.instAddr(), tid);
|
||||||
|
|
||||||
DPRINTF(Branch, "[tid:%i]: Instruction %s predicted"
|
DPRINTF(Branch, "[tid:%i]: Instruction %s predicted"
|
||||||
" target is %s.\n", tid, pc, target);
|
" target is %s.\n", tid, pc, target);
|
||||||
|
|
||||||
} else {
|
|
||||||
DPRINTF(Branch, "[tid:%i]: BTB doesn't have a "
|
|
||||||
"valid entry.\n",tid);
|
|
||||||
pred_taken = false;
|
|
||||||
// The Direction of the branch predictor is altered
|
|
||||||
// because the BTB did not have an entry
|
|
||||||
// The predictor needs to be updated accordingly
|
|
||||||
if (!inst->isCall() && !inst->isReturn()) {
|
|
||||||
btbUpdate(tid, pc.instAddr(), bp_history);
|
|
||||||
DPRINTF(Branch, "[tid:%i]:[sn:%i] btbUpdate"
|
|
||||||
" called for %s\n", tid, seqNum, pc);
|
|
||||||
} else if (inst->isCall() && !inst->isUncondCtrl()) {
|
|
||||||
RAS[tid].pop();
|
|
||||||
predict_record.pushedRAS = false;
|
|
||||||
}
|
|
||||||
TheISA::advancePC(target, inst);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
predict_record.wasIndirect = true;
|
DPRINTF(Branch, "[tid:%i]: BTB doesn't have a "
|
||||||
++indirectLookups;
|
"valid entry.\n",tid);
|
||||||
//Consult indirect predictor on indirect control
|
pred_taken = false;
|
||||||
if (iPred.lookup(pc.instAddr(), getGHR(tid, bp_history),
|
// The Direction of the branch predictor is altered because the
|
||||||
target, tid)) {
|
// BTB did not have an entry
|
||||||
// Indirect predictor hit
|
// The predictor needs to be updated accordingly
|
||||||
++indirectHits;
|
if (!inst->isCall() && !inst->isReturn()) {
|
||||||
DPRINTF(Branch, "[tid:%i]: Instruction %s predicted "
|
btbUpdate(pc.instAddr(), bp_history);
|
||||||
"indirect target is %s.\n", tid, pc, target);
|
DPRINTF(Branch, "[tid:%i]:[sn:%i] btbUpdate"
|
||||||
} else {
|
" called for %s\n", tid, seqNum, pc);
|
||||||
++indirectMisses;
|
} else if (inst->isCall() && !inst->isUncondCtrl()) {
|
||||||
pred_taken = false;
|
RAS[tid].pop();
|
||||||
DPRINTF(Branch, "[tid:%i]: Instruction %s no indirect "
|
predict_record.pushedRAS = false;
|
||||||
"target.\n", tid, pc);
|
|
||||||
if (!inst->isCall() && !inst->isReturn()) {
|
|
||||||
|
|
||||||
} else if (inst->isCall() && !inst->isUncondCtrl()) {
|
|
||||||
RAS[tid].pop();
|
|
||||||
predict_record.pushedRAS = false;
|
|
||||||
}
|
|
||||||
TheISA::advancePC(target, inst);
|
|
||||||
}
|
}
|
||||||
iPred.recordIndirect(pc.instAddr(), target.instAddr(), seqNum,
|
TheISA::advancePC(target, inst);
|
||||||
tid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -346,7 +287,7 @@ BPredUnit::predictInOrder(const StaticInstPtr &inst, const InstSeqNum &seqNum,
|
||||||
DPRINTF(Branch, "[tid:%i] Unconditional control.\n", tid);
|
DPRINTF(Branch, "[tid:%i] Unconditional control.\n", tid);
|
||||||
pred_taken = true;
|
pred_taken = true;
|
||||||
// Tell the BP there was an unconditional branch.
|
// Tell the BP there was an unconditional branch.
|
||||||
uncondBranch(tid, instPC.instAddr(), bp_history);
|
uncondBranch(instPC.instAddr(), bp_history);
|
||||||
|
|
||||||
if (inst->isReturn() && RAS[tid].empty()) {
|
if (inst->isReturn() && RAS[tid].empty()) {
|
||||||
DPRINTF(Branch, "[tid:%i] RAS is empty, predicting "
|
DPRINTF(Branch, "[tid:%i] RAS is empty, predicting "
|
||||||
|
@ -356,7 +297,7 @@ BPredUnit::predictInOrder(const StaticInstPtr &inst, const InstSeqNum &seqNum,
|
||||||
} else {
|
} else {
|
||||||
++condPredicted;
|
++condPredicted;
|
||||||
|
|
||||||
pred_taken = lookup(tid, predPC.instAddr(), bp_history);
|
pred_taken = lookup(predPC.instAddr(), bp_history);
|
||||||
}
|
}
|
||||||
|
|
||||||
PredictorHistory predict_record(seqNum, predPC.instAddr(), pred_taken,
|
PredictorHistory predict_record(seqNum, predPC.instAddr(), pred_taken,
|
||||||
|
@ -446,16 +387,14 @@ BPredUnit::update(const InstSeqNum &done_sn, ThreadID tid)
|
||||||
DPRINTF(Branch, "[tid:%i]: Committing branches until "
|
DPRINTF(Branch, "[tid:%i]: Committing branches until "
|
||||||
"[sn:%lli].\n", tid, done_sn);
|
"[sn:%lli].\n", tid, done_sn);
|
||||||
|
|
||||||
iPred.commit(done_sn, tid);
|
|
||||||
while (!predHist[tid].empty() &&
|
while (!predHist[tid].empty() &&
|
||||||
predHist[tid].back().seqNum <= done_sn) {
|
predHist[tid].back().seqNum <= done_sn) {
|
||||||
// Update the branch predictor with the correct results.
|
// Update the branch predictor with the correct results.
|
||||||
if (!predHist[tid].back().wasSquashed) {
|
if (!predHist[tid].back().wasSquashed) {
|
||||||
update(tid, predHist[tid].back().pc,
|
update(predHist[tid].back().pc, predHist[tid].back().predTaken,
|
||||||
predHist[tid].back().predTaken,
|
predHist[tid].back().bpHistory, false);
|
||||||
predHist[tid].back().bpHistory, false);
|
|
||||||
} else {
|
} else {
|
||||||
retireSquashed(tid, predHist[tid].back().bpHistory);
|
retireSquashed(predHist[tid].back().bpHistory);
|
||||||
}
|
}
|
||||||
|
|
||||||
predHist[tid].pop_back();
|
predHist[tid].pop_back();
|
||||||
|
@ -467,7 +406,6 @@ BPredUnit::squash(const InstSeqNum &squashed_sn, ThreadID tid)
|
||||||
{
|
{
|
||||||
History &pred_hist = predHist[tid];
|
History &pred_hist = predHist[tid];
|
||||||
|
|
||||||
iPred.squash(squashed_sn, tid);
|
|
||||||
while (!pred_hist.empty() &&
|
while (!pred_hist.empty() &&
|
||||||
pred_hist.front().seqNum > squashed_sn) {
|
pred_hist.front().seqNum > squashed_sn) {
|
||||||
if (pred_hist.front().usedRAS) {
|
if (pred_hist.front().usedRAS) {
|
||||||
|
@ -486,7 +424,7 @@ BPredUnit::squash(const InstSeqNum &squashed_sn, ThreadID tid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This call should delete the bpHistory.
|
// This call should delete the bpHistory.
|
||||||
squash(tid, pred_hist.front().bpHistory);
|
squash(pred_hist.front().bpHistory);
|
||||||
|
|
||||||
DPRINTF(Branch, "[tid:%i]: Removing history for [sn:%i] "
|
DPRINTF(Branch, "[tid:%i]: Removing history for [sn:%i] "
|
||||||
"PC %s.\n", tid, pred_hist.front().seqNum,
|
"PC %s.\n", tid, pred_hist.front().seqNum,
|
||||||
|
@ -546,14 +484,9 @@ BPredUnit::squash(const InstSeqNum &squashed_sn,
|
||||||
|
|
||||||
if ((*hist_it).usedRAS) {
|
if ((*hist_it).usedRAS) {
|
||||||
++RASIncorrect;
|
++RASIncorrect;
|
||||||
DPRINTF(Branch, "[tid:%i]: Incorrect RAS [sn:%i]\n",
|
|
||||||
tid, hist_it->seqNum);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Have to get GHR here because the update deletes bpHistory
|
update((*hist_it).pc, actually_taken,
|
||||||
unsigned ghr = getGHR(tid, hist_it->bpHistory);
|
|
||||||
|
|
||||||
update(tid, (*hist_it).pc, actually_taken,
|
|
||||||
pred_hist.front().bpHistory, true);
|
pred_hist.front().bpHistory, true);
|
||||||
hist_it->wasSquashed = true;
|
hist_it->wasSquashed = true;
|
||||||
|
|
||||||
|
@ -565,15 +498,12 @@ BPredUnit::squash(const InstSeqNum &squashed_sn,
|
||||||
RAS[tid].pop();
|
RAS[tid].pop();
|
||||||
hist_it->usedRAS = true;
|
hist_it->usedRAS = true;
|
||||||
}
|
}
|
||||||
if (hist_it->wasIndirect) {
|
|
||||||
++indirectMispredicted;
|
|
||||||
iPred.recordTarget(hist_it->seqNum, ghr, corrTarget, tid);
|
|
||||||
} else {
|
|
||||||
DPRINTF(Branch,"[tid: %i] BTB Update called for [sn:%i]"
|
|
||||||
" PC: %s\n", tid,hist_it->seqNum, hist_it->pc);
|
|
||||||
|
|
||||||
BTB.update((*hist_it).pc, corrTarget, tid);
|
DPRINTF(Branch,"[tid: %i] BTB Update called for [sn:%i]"
|
||||||
}
|
" PC: %s\n", tid,hist_it->seqNum, hist_it->pc);
|
||||||
|
|
||||||
|
BTB.update((*hist_it).pc, corrTarget, tid);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
//Actually not Taken
|
//Actually not Taken
|
||||||
if (hist_it->usedRAS) {
|
if (hist_it->usedRAS) {
|
||||||
|
|
|
@ -52,7 +52,6 @@
|
||||||
#include "base/statistics.hh"
|
#include "base/statistics.hh"
|
||||||
#include "base/types.hh"
|
#include "base/types.hh"
|
||||||
#include "cpu/pred/btb.hh"
|
#include "cpu/pred/btb.hh"
|
||||||
#include "cpu/pred/indirect.hh"
|
|
||||||
#include "cpu/pred/ras.hh"
|
#include "cpu/pred/ras.hh"
|
||||||
#include "cpu/inst_seq.hh"
|
#include "cpu/inst_seq.hh"
|
||||||
#include "cpu/static_inst.hh"
|
#include "cpu/static_inst.hh"
|
||||||
|
@ -98,7 +97,7 @@ class BPredUnit : public SimObject
|
||||||
TheISA::PCState &predPC, ThreadID tid);
|
TheISA::PCState &predPC, ThreadID tid);
|
||||||
|
|
||||||
// @todo: Rename this function.
|
// @todo: Rename this function.
|
||||||
virtual void uncondBranch(ThreadID tid, Addr pc, void * &bp_history) = 0;
|
virtual void uncondBranch(Addr pc, void * &bp_history) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells the branch predictor to commit any updates until the given
|
* Tells the branch predictor to commit any updates until the given
|
||||||
|
@ -133,7 +132,7 @@ class BPredUnit : public SimObject
|
||||||
* @param bp_history Pointer to the history object. The predictor
|
* @param bp_history Pointer to the history object. The predictor
|
||||||
* will need to update any state and delete the object.
|
* will need to update any state and delete the object.
|
||||||
*/
|
*/
|
||||||
virtual void squash(ThreadID tid, void *bp_history) = 0;
|
virtual void squash(void *bp_history) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks up a given PC in the BP to see if it is taken or not taken.
|
* Looks up a given PC in the BP to see if it is taken or not taken.
|
||||||
|
@ -142,7 +141,7 @@ class BPredUnit : public SimObject
|
||||||
* has the branch predictor state associated with the lookup.
|
* has the branch predictor state associated with the lookup.
|
||||||
* @return Whether the branch is taken or not taken.
|
* @return Whether the branch is taken or not taken.
|
||||||
*/
|
*/
|
||||||
virtual bool lookup(ThreadID tid, Addr instPC, void * &bp_history) = 0;
|
virtual bool lookup(Addr instPC, void * &bp_history) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If a branch is not taken, because the BTB address is invalid or missing,
|
* If a branch is not taken, because the BTB address is invalid or missing,
|
||||||
|
@ -152,7 +151,7 @@ class BPredUnit : public SimObject
|
||||||
* @param bp_history Pointer that will be set to an object that
|
* @param bp_history Pointer that will be set to an object that
|
||||||
* has the branch predictor state associated with the lookup.
|
* has the branch predictor state associated with the lookup.
|
||||||
*/
|
*/
|
||||||
virtual void btbUpdate(ThreadID tid, Addr instPC, void * &bp_history) = 0;
|
virtual void btbUpdate(Addr instPC, void * &bp_history) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks up a given PC in the BTB to see if a matching entry exists.
|
* Looks up a given PC in the BTB to see if a matching entry exists.
|
||||||
|
@ -180,15 +179,15 @@ class BPredUnit : public SimObject
|
||||||
* squash operation.
|
* squash operation.
|
||||||
* @todo Make this update flexible enough to handle a global predictor.
|
* @todo Make this update flexible enough to handle a global predictor.
|
||||||
*/
|
*/
|
||||||
virtual void update(ThreadID tid, Addr instPC, bool taken,
|
virtual void update(Addr instPC, bool taken, void *bp_history,
|
||||||
void *bp_history, bool squashed) = 0;
|
bool squashed) = 0;
|
||||||
/**
|
/**
|
||||||
* Deletes the associated history with a branch, performs no predictor
|
* Deletes the associated history with a branch, performs no predictor
|
||||||
* updates. Used for branches that mispredict and update tables but
|
* updates. Used for branches that mispredict and update tables but
|
||||||
* are still speculative and later retire.
|
* are still speculative and later retire.
|
||||||
* @param bp_history History to delete associated with this predictor
|
* @param bp_history History to delete associated with this predictor
|
||||||
*/
|
*/
|
||||||
virtual void retireSquashed(ThreadID tid, void *bp_history) = 0;
|
virtual void retireSquashed(void *bp_history) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the BTB with the target of a branch.
|
* Updates the BTB with the target of a branch.
|
||||||
|
@ -198,9 +197,6 @@ class BPredUnit : public SimObject
|
||||||
void BTBUpdate(Addr instPC, const TheISA::PCState &target)
|
void BTBUpdate(Addr instPC, const TheISA::PCState &target)
|
||||||
{ BTB.update(instPC, target, 0); }
|
{ BTB.update(instPC, target, 0); }
|
||||||
|
|
||||||
|
|
||||||
virtual unsigned getGHR(ThreadID tid, void* bp_history) const { return 0; }
|
|
||||||
|
|
||||||
void dump();
|
void dump();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -214,7 +210,7 @@ class BPredUnit : public SimObject
|
||||||
ThreadID _tid)
|
ThreadID _tid)
|
||||||
: seqNum(seq_num), pc(instPC), bpHistory(bp_history), RASTarget(0),
|
: seqNum(seq_num), pc(instPC), bpHistory(bp_history), RASTarget(0),
|
||||||
RASIndex(0), tid(_tid), predTaken(pred_taken), usedRAS(0), pushedRAS(0),
|
RASIndex(0), tid(_tid), predTaken(pred_taken), usedRAS(0), pushedRAS(0),
|
||||||
wasCall(0), wasReturn(0), wasSquashed(0), wasIndirect(0)
|
wasCall(0), wasReturn(0), wasSquashed(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool operator==(const PredictorHistory &entry) const {
|
bool operator==(const PredictorHistory &entry) const {
|
||||||
|
@ -259,9 +255,6 @@ class BPredUnit : public SimObject
|
||||||
|
|
||||||
/** Whether this instruction has already mispredicted/updated bp */
|
/** Whether this instruction has already mispredicted/updated bp */
|
||||||
bool wasSquashed;
|
bool wasSquashed;
|
||||||
|
|
||||||
/** Wether this instruction was an indirect branch */
|
|
||||||
bool wasIndirect;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::deque<PredictorHistory> History;
|
typedef std::deque<PredictorHistory> History;
|
||||||
|
@ -283,12 +276,6 @@ class BPredUnit : public SimObject
|
||||||
/** The per-thread return address stack. */
|
/** The per-thread return address stack. */
|
||||||
std::vector<ReturnAddrStack> RAS;
|
std::vector<ReturnAddrStack> RAS;
|
||||||
|
|
||||||
/** Option to disable indirect predictor. */
|
|
||||||
const bool useIndirect;
|
|
||||||
|
|
||||||
/** The indirect target predictor. */
|
|
||||||
IndirectPredictor iPred;
|
|
||||||
|
|
||||||
/** Stat for number of BP lookups. */
|
/** Stat for number of BP lookups. */
|
||||||
Stats::Scalar lookups;
|
Stats::Scalar lookups;
|
||||||
/** Stat for number of conditional branches predicted. */
|
/** Stat for number of conditional branches predicted. */
|
||||||
|
@ -308,15 +295,6 @@ class BPredUnit : public SimObject
|
||||||
/** Stat for number of times the RAS is incorrect. */
|
/** Stat for number of times the RAS is incorrect. */
|
||||||
Stats::Scalar RASIncorrect;
|
Stats::Scalar RASIncorrect;
|
||||||
|
|
||||||
/** Stat for the number of indirect target lookups.*/
|
|
||||||
Stats::Scalar indirectLookups;
|
|
||||||
/** Stat for the number of indirect target hits.*/
|
|
||||||
Stats::Scalar indirectHits;
|
|
||||||
/** Stat for the number of indirect target misses.*/
|
|
||||||
Stats::Scalar indirectMisses;
|
|
||||||
/** Stat for the number of indirect target mispredictions.*/
|
|
||||||
Stats::Scalar indirectMispredicted;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Number of bits to shift instructions by for predictor addresses. */
|
/** Number of bits to shift instructions by for predictor addresses. */
|
||||||
const unsigned instShiftAmt;
|
const unsigned instShiftAmt;
|
||||||
|
|
|
@ -35,12 +35,10 @@
|
||||||
|
|
||||||
DefaultBTB::DefaultBTB(unsigned _numEntries,
|
DefaultBTB::DefaultBTB(unsigned _numEntries,
|
||||||
unsigned _tagBits,
|
unsigned _tagBits,
|
||||||
unsigned _instShiftAmt,
|
unsigned _instShiftAmt)
|
||||||
unsigned _num_threads)
|
|
||||||
: numEntries(_numEntries),
|
: numEntries(_numEntries),
|
||||||
tagBits(_tagBits),
|
tagBits(_tagBits),
|
||||||
instShiftAmt(_instShiftAmt),
|
instShiftAmt(_instShiftAmt)
|
||||||
log2NumThreads(floorLog2(_num_threads))
|
|
||||||
{
|
{
|
||||||
DPRINTF(Fetch, "BTB: Creating BTB object.\n");
|
DPRINTF(Fetch, "BTB: Creating BTB object.\n");
|
||||||
|
|
||||||
|
@ -71,12 +69,10 @@ DefaultBTB::reset()
|
||||||
|
|
||||||
inline
|
inline
|
||||||
unsigned
|
unsigned
|
||||||
DefaultBTB::getIndex(Addr instPC, ThreadID tid)
|
DefaultBTB::getIndex(Addr instPC)
|
||||||
{
|
{
|
||||||
// Need to shift PC over by the word offset.
|
// Need to shift PC over by the word offset.
|
||||||
return ((instPC >> instShiftAmt)
|
return (instPC >> instShiftAmt) & idxMask;
|
||||||
^ (tid << (tagShiftAmt - instShiftAmt - log2NumThreads)))
|
|
||||||
& idxMask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
|
@ -89,7 +85,7 @@ DefaultBTB::getTag(Addr instPC)
|
||||||
bool
|
bool
|
||||||
DefaultBTB::valid(Addr instPC, ThreadID tid)
|
DefaultBTB::valid(Addr instPC, ThreadID tid)
|
||||||
{
|
{
|
||||||
unsigned btb_idx = getIndex(instPC, tid);
|
unsigned btb_idx = getIndex(instPC);
|
||||||
|
|
||||||
Addr inst_tag = getTag(instPC);
|
Addr inst_tag = getTag(instPC);
|
||||||
|
|
||||||
|
@ -110,7 +106,7 @@ DefaultBTB::valid(Addr instPC, ThreadID tid)
|
||||||
TheISA::PCState
|
TheISA::PCState
|
||||||
DefaultBTB::lookup(Addr instPC, ThreadID tid)
|
DefaultBTB::lookup(Addr instPC, ThreadID tid)
|
||||||
{
|
{
|
||||||
unsigned btb_idx = getIndex(instPC, tid);
|
unsigned btb_idx = getIndex(instPC);
|
||||||
|
|
||||||
Addr inst_tag = getTag(instPC);
|
Addr inst_tag = getTag(instPC);
|
||||||
|
|
||||||
|
@ -128,7 +124,7 @@ DefaultBTB::lookup(Addr instPC, ThreadID tid)
|
||||||
void
|
void
|
||||||
DefaultBTB::update(Addr instPC, const TheISA::PCState &target, ThreadID tid)
|
DefaultBTB::update(Addr instPC, const TheISA::PCState &target, ThreadID tid)
|
||||||
{
|
{
|
||||||
unsigned btb_idx = getIndex(instPC, tid);
|
unsigned btb_idx = getIndex(instPC);
|
||||||
|
|
||||||
assert(btb_idx < numEntries);
|
assert(btb_idx < numEntries);
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ class DefaultBTB
|
||||||
* @param instShiftAmt Offset amount for instructions to ignore alignment.
|
* @param instShiftAmt Offset amount for instructions to ignore alignment.
|
||||||
*/
|
*/
|
||||||
DefaultBTB(unsigned numEntries, unsigned tagBits,
|
DefaultBTB(unsigned numEntries, unsigned tagBits,
|
||||||
unsigned instShiftAmt, unsigned numThreads);
|
unsigned instShiftAmt);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ class DefaultBTB
|
||||||
* @param inst_PC The branch to look up.
|
* @param inst_PC The branch to look up.
|
||||||
* @return Returns the index into the BTB.
|
* @return Returns the index into the BTB.
|
||||||
*/
|
*/
|
||||||
inline unsigned getIndex(Addr instPC, ThreadID tid);
|
inline unsigned getIndex(Addr instPC);
|
||||||
|
|
||||||
/** Returns the tag bits of a given address.
|
/** Returns the tag bits of a given address.
|
||||||
* @param inst_PC The branch's address.
|
* @param inst_PC The branch's address.
|
||||||
|
@ -125,9 +125,6 @@ class DefaultBTB
|
||||||
|
|
||||||
/** Number of bits to shift PC when calculating tag. */
|
/** Number of bits to shift PC when calculating tag. */
|
||||||
unsigned tagShiftAmt;
|
unsigned tagShiftAmt;
|
||||||
|
|
||||||
/** Log2 NumThreads used for hashing threadid */
|
|
||||||
unsigned log2NumThreads;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __CPU_PRED_BTB_HH__
|
#endif // __CPU_PRED_BTB_HH__
|
||||||
|
|
|
@ -1,185 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2014 ARM Limited
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* Authors: Mitch Hayenga
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "cpu/pred/indirect.hh"
|
|
||||||
|
|
||||||
#include "base/intmath.hh"
|
|
||||||
#include "debug/Indirect.hh"
|
|
||||||
|
|
||||||
IndirectPredictor::IndirectPredictor(bool hash_ghr, bool hash_targets,
|
|
||||||
unsigned num_sets, unsigned num_ways,
|
|
||||||
unsigned tag_bits, unsigned path_len, unsigned inst_shift,
|
|
||||||
unsigned num_threads)
|
|
||||||
: hashGHR(hash_ghr), hashTargets(hash_targets),
|
|
||||||
numSets(num_sets), numWays(num_ways), tagBits(tag_bits),
|
|
||||||
pathLength(path_len), instShift(inst_shift)
|
|
||||||
{
|
|
||||||
if (!isPowerOf2(numSets)) {
|
|
||||||
panic("Indirect predictor requires power of 2 number of sets");
|
|
||||||
}
|
|
||||||
|
|
||||||
threadInfo.resize(num_threads);
|
|
||||||
|
|
||||||
targetCache.resize(numSets);
|
|
||||||
for (unsigned i = 0; i < numSets; i++) {
|
|
||||||
targetCache[i].resize(numWays);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
IndirectPredictor::lookup(Addr br_addr, unsigned ghr, TheISA::PCState& target,
|
|
||||||
ThreadID tid)
|
|
||||||
{
|
|
||||||
Addr set_index = getSetIndex(br_addr, ghr, tid);
|
|
||||||
Addr tag = getTag(br_addr);
|
|
||||||
|
|
||||||
assert(set_index < numSets);
|
|
||||||
|
|
||||||
DPRINTF(Indirect, "Looking up %x (set:%d)\n", br_addr, set_index);
|
|
||||||
const auto &iset = targetCache[set_index];
|
|
||||||
for (auto way = iset.begin(); way != iset.end(); ++way) {
|
|
||||||
if (way->tag == tag) {
|
|
||||||
DPRINTF(Indirect, "Hit %x (target:%s)\n", br_addr, way->target);
|
|
||||||
target = way->target;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DPRINTF(Indirect, "Miss %x\n", br_addr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
IndirectPredictor::recordIndirect(Addr br_addr, Addr tgt_addr,
|
|
||||||
InstSeqNum seq_num, ThreadID tid)
|
|
||||||
{
|
|
||||||
DPRINTF(Indirect, "Recording %x seq:%d\n", br_addr, seq_num);
|
|
||||||
HistoryEntry entry(br_addr, tgt_addr, seq_num);
|
|
||||||
threadInfo[tid].pathHist.push_back(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
IndirectPredictor::commit(InstSeqNum seq_num, ThreadID tid)
|
|
||||||
{
|
|
||||||
DPRINTF(Indirect, "Committing seq:%d\n", seq_num);
|
|
||||||
ThreadInfo &t_info = threadInfo[tid];
|
|
||||||
|
|
||||||
if (t_info.pathHist.empty()) return;
|
|
||||||
|
|
||||||
if (t_info.headHistEntry < t_info.pathHist.size() &&
|
|
||||||
t_info.pathHist[t_info.headHistEntry].seqNum <= seq_num) {
|
|
||||||
if (t_info.headHistEntry >= pathLength) {
|
|
||||||
t_info.pathHist.pop_front();
|
|
||||||
} else {
|
|
||||||
++t_info.headHistEntry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
IndirectPredictor::squash(InstSeqNum seq_num, ThreadID tid)
|
|
||||||
{
|
|
||||||
DPRINTF(Indirect, "Squashing seq:%d\n", seq_num);
|
|
||||||
ThreadInfo &t_info = threadInfo[tid];
|
|
||||||
auto squash_itr = t_info.pathHist.begin();
|
|
||||||
while (squash_itr != t_info.pathHist.end()) {
|
|
||||||
if (squash_itr->seqNum > seq_num) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++squash_itr;
|
|
||||||
}
|
|
||||||
if (squash_itr != t_info.pathHist.end()) {
|
|
||||||
DPRINTF(Indirect, "Squashing series starting with sn:%d\n",
|
|
||||||
squash_itr->seqNum);
|
|
||||||
}
|
|
||||||
t_info.pathHist.erase(squash_itr, t_info.pathHist.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
IndirectPredictor::recordTarget(InstSeqNum seq_num, unsigned ghr,
|
|
||||||
const TheISA::PCState& target, ThreadID tid)
|
|
||||||
{
|
|
||||||
ThreadInfo &t_info = threadInfo[tid];
|
|
||||||
|
|
||||||
// Should have just squashed so this branch should be the oldest
|
|
||||||
auto hist_entry = *(t_info.pathHist.rbegin());
|
|
||||||
// Temporarily pop it off the history so we can calculate the set
|
|
||||||
t_info.pathHist.pop_back();
|
|
||||||
Addr set_index = getSetIndex(hist_entry.pcAddr, ghr, tid);
|
|
||||||
Addr tag = getTag(hist_entry.pcAddr);
|
|
||||||
hist_entry.targetAddr = target.instAddr();
|
|
||||||
t_info.pathHist.push_back(hist_entry);
|
|
||||||
|
|
||||||
assert(set_index < numSets);
|
|
||||||
|
|
||||||
auto &iset = targetCache[set_index];
|
|
||||||
for (auto way = iset.begin(); way != iset.end(); ++way) {
|
|
||||||
if (way->tag == tag) {
|
|
||||||
DPRINTF(Indirect, "Updating Target (seq: %d br:%x set:%d target:"
|
|
||||||
"%s)\n", seq_num, hist_entry.pcAddr, set_index, target);
|
|
||||||
way->target = target;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINTF(Indirect, "Allocating Target (seq: %d br:%x set:%d target:%s)\n",
|
|
||||||
seq_num, hist_entry.pcAddr, set_index, target);
|
|
||||||
// Did not find entry, random replacement
|
|
||||||
auto &way = iset[rand() % numWays];
|
|
||||||
way.tag = tag;
|
|
||||||
way.target = target;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline Addr
|
|
||||||
IndirectPredictor::getSetIndex(Addr br_addr, unsigned ghr, ThreadID tid)
|
|
||||||
{
|
|
||||||
ThreadInfo &t_info = threadInfo[tid];
|
|
||||||
|
|
||||||
Addr hash = br_addr >> instShift;
|
|
||||||
if (hashGHR) {
|
|
||||||
hash ^= ghr;
|
|
||||||
}
|
|
||||||
if (hashTargets) {
|
|
||||||
unsigned hash_shift = floorLog2(numSets) / pathLength;
|
|
||||||
for (int i = t_info.pathHist.size()-1, p = 0;
|
|
||||||
i >= 0 && p < pathLength; i--, p++) {
|
|
||||||
hash ^= (t_info.pathHist[i].targetAddr >>
|
|
||||||
(instShift + p*hash_shift));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hash & (numSets-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Addr
|
|
||||||
IndirectPredictor::getTag(Addr br_addr)
|
|
||||||
{
|
|
||||||
return (br_addr >> instShift) & ((0x1<<tagBits)-1);
|
|
||||||
}
|
|
|
@ -1,97 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2014 ARM Limited
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* Authors: Mitch Hayenga
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __CPU_PRED_INDIRECT_HH__
|
|
||||||
#define __CPU_PRED_INDIRECT_HH__
|
|
||||||
|
|
||||||
#include <deque>
|
|
||||||
|
|
||||||
#include "arch/isa_traits.hh"
|
|
||||||
#include "config/the_isa.hh"
|
|
||||||
#include "cpu/inst_seq.hh"
|
|
||||||
|
|
||||||
class IndirectPredictor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
IndirectPredictor(bool hash_ghr, bool hash_targets,
|
|
||||||
unsigned num_sets, unsigned num_ways,
|
|
||||||
unsigned tag_bits, unsigned path_len,
|
|
||||||
unsigned inst_shift, unsigned num_threads);
|
|
||||||
bool lookup(Addr br_addr, unsigned ghr, TheISA::PCState& br_target,
|
|
||||||
ThreadID tid);
|
|
||||||
void recordIndirect(Addr br_addr, Addr tgt_addr, InstSeqNum seq_num,
|
|
||||||
ThreadID tid);
|
|
||||||
void commit(InstSeqNum seq_num, ThreadID tid);
|
|
||||||
void squash(InstSeqNum seq_num, ThreadID tid);
|
|
||||||
void recordTarget(InstSeqNum seq_num, unsigned ghr,
|
|
||||||
const TheISA::PCState& target, ThreadID tid);
|
|
||||||
|
|
||||||
private:
|
|
||||||
const bool hashGHR;
|
|
||||||
const bool hashTargets;
|
|
||||||
const unsigned numSets;
|
|
||||||
const unsigned numWays;
|
|
||||||
const unsigned tagBits;
|
|
||||||
const unsigned pathLength;
|
|
||||||
const unsigned instShift;
|
|
||||||
|
|
||||||
struct IPredEntry
|
|
||||||
{
|
|
||||||
IPredEntry() : tag(0), target(0) { }
|
|
||||||
Addr tag;
|
|
||||||
TheISA::PCState target;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<std::vector<IPredEntry> > targetCache;
|
|
||||||
|
|
||||||
Addr getSetIndex(Addr br_addr, unsigned ghr, ThreadID tid);
|
|
||||||
Addr getTag(Addr br_addr);
|
|
||||||
|
|
||||||
struct HistoryEntry
|
|
||||||
{
|
|
||||||
HistoryEntry(Addr br_addr, Addr tgt_addr, InstSeqNum seq_num)
|
|
||||||
: pcAddr(br_addr), targetAddr(tgt_addr), seqNum(seq_num) { }
|
|
||||||
Addr pcAddr;
|
|
||||||
Addr targetAddr;
|
|
||||||
InstSeqNum seqNum;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct ThreadInfo {
|
|
||||||
ThreadInfo() : headHistEntry(0) { }
|
|
||||||
|
|
||||||
std::deque<HistoryEntry> pathHist;
|
|
||||||
unsigned headHistEntry;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<ThreadInfo> threadInfo;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // __CPU_PRED_INDIRECT_HH__
|
|
|
@ -52,7 +52,6 @@ TournamentBP::TournamentBP(const TournamentBPParams *params)
|
||||||
localHistoryBits(ceilLog2(params->localPredictorSize)),
|
localHistoryBits(ceilLog2(params->localPredictorSize)),
|
||||||
globalPredictorSize(params->globalPredictorSize),
|
globalPredictorSize(params->globalPredictorSize),
|
||||||
globalCtrBits(params->globalCtrBits),
|
globalCtrBits(params->globalCtrBits),
|
||||||
globalHistory(params->numThreads, 0),
|
|
||||||
globalHistoryBits(
|
globalHistoryBits(
|
||||||
ceilLog2(params->globalPredictorSize) >
|
ceilLog2(params->globalPredictorSize) >
|
||||||
ceilLog2(params->choicePredictorSize) ?
|
ceilLog2(params->choicePredictorSize) ?
|
||||||
|
@ -93,6 +92,8 @@ TournamentBP::TournamentBP(const TournamentBPParams *params)
|
||||||
for (int i = 0; i < globalPredictorSize; ++i)
|
for (int i = 0; i < globalPredictorSize; ++i)
|
||||||
globalCtrs[i].setBits(globalCtrBits);
|
globalCtrs[i].setBits(globalCtrBits);
|
||||||
|
|
||||||
|
//Clear the global history
|
||||||
|
globalHistory = 0;
|
||||||
// Set up the global history mask
|
// Set up the global history mask
|
||||||
// this is equivalent to mask(log2(globalPredictorSize)
|
// this is equivalent to mask(log2(globalPredictorSize)
|
||||||
globalHistoryMask = globalPredictorSize - 1;
|
globalHistoryMask = globalPredictorSize - 1;
|
||||||
|
@ -144,18 +145,18 @@ TournamentBP::calcLocHistIdx(Addr &branch_addr)
|
||||||
|
|
||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
TournamentBP::updateGlobalHistTaken(ThreadID tid)
|
TournamentBP::updateGlobalHistTaken()
|
||||||
{
|
{
|
||||||
globalHistory[tid] = (globalHistory[tid] << 1) | 1;
|
globalHistory = (globalHistory << 1) | 1;
|
||||||
globalHistory[tid] = globalHistory[tid] & historyRegisterMask;
|
globalHistory = globalHistory & historyRegisterMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
TournamentBP::updateGlobalHistNotTaken(ThreadID tid)
|
TournamentBP::updateGlobalHistNotTaken()
|
||||||
{
|
{
|
||||||
globalHistory[tid] = (globalHistory[tid] << 1);
|
globalHistory = (globalHistory << 1);
|
||||||
globalHistory[tid] = globalHistory[tid] & historyRegisterMask;
|
globalHistory = globalHistory & historyRegisterMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
|
@ -176,18 +177,18 @@ TournamentBP::updateLocalHistNotTaken(unsigned local_history_idx)
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TournamentBP::btbUpdate(ThreadID tid, Addr branch_addr, void * &bp_history)
|
TournamentBP::btbUpdate(Addr branch_addr, void * &bp_history)
|
||||||
{
|
{
|
||||||
unsigned local_history_idx = calcLocHistIdx(branch_addr);
|
unsigned local_history_idx = calcLocHistIdx(branch_addr);
|
||||||
//Update Global History to Not Taken (clear LSB)
|
//Update Global History to Not Taken (clear LSB)
|
||||||
globalHistory[tid] &= (historyRegisterMask & ~ULL(1));
|
globalHistory &= (historyRegisterMask & ~ULL(1));
|
||||||
//Update Local History to Not Taken
|
//Update Local History to Not Taken
|
||||||
localHistoryTable[local_history_idx] =
|
localHistoryTable[local_history_idx] =
|
||||||
localHistoryTable[local_history_idx] & (localPredictorMask & ~ULL(1));
|
localHistoryTable[local_history_idx] & (localPredictorMask & ~ULL(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TournamentBP::lookup(ThreadID tid, Addr branch_addr, void * &bp_history)
|
TournamentBP::lookup(Addr branch_addr, void * &bp_history)
|
||||||
{
|
{
|
||||||
bool local_prediction;
|
bool local_prediction;
|
||||||
unsigned local_history_idx;
|
unsigned local_history_idx;
|
||||||
|
@ -203,16 +204,16 @@ TournamentBP::lookup(ThreadID tid, Addr branch_addr, void * &bp_history)
|
||||||
local_prediction = localCtrs[local_predictor_idx].read() > localThreshold;
|
local_prediction = localCtrs[local_predictor_idx].read() > localThreshold;
|
||||||
|
|
||||||
//Lookup in the global predictor to get its branch prediction
|
//Lookup in the global predictor to get its branch prediction
|
||||||
global_prediction = globalThreshold <
|
global_prediction =
|
||||||
globalCtrs[globalHistory[tid] & globalHistoryMask].read();
|
globalCtrs[globalHistory & globalHistoryMask].read() > globalThreshold;
|
||||||
|
|
||||||
//Lookup in the choice predictor to see which one to use
|
//Lookup in the choice predictor to see which one to use
|
||||||
choice_prediction = choiceThreshold <
|
choice_prediction =
|
||||||
choiceCtrs[globalHistory[tid] & choiceHistoryMask].read();
|
choiceCtrs[globalHistory & choiceHistoryMask].read() > choiceThreshold;
|
||||||
|
|
||||||
// Create BPHistory and pass it back to be recorded.
|
// Create BPHistory and pass it back to be recorded.
|
||||||
BPHistory *history = new BPHistory;
|
BPHistory *history = new BPHistory;
|
||||||
history->globalHistory = globalHistory[tid];
|
history->globalHistory = globalHistory;
|
||||||
history->localPredTaken = local_prediction;
|
history->localPredTaken = local_prediction;
|
||||||
history->globalPredTaken = global_prediction;
|
history->globalPredTaken = global_prediction;
|
||||||
history->globalUsed = choice_prediction;
|
history->globalUsed = choice_prediction;
|
||||||
|
@ -226,21 +227,21 @@ TournamentBP::lookup(ThreadID tid, Addr branch_addr, void * &bp_history)
|
||||||
// all histories.
|
// all histories.
|
||||||
if (choice_prediction) {
|
if (choice_prediction) {
|
||||||
if (global_prediction) {
|
if (global_prediction) {
|
||||||
updateGlobalHistTaken(tid);
|
updateGlobalHistTaken();
|
||||||
updateLocalHistTaken(local_history_idx);
|
updateLocalHistTaken(local_history_idx);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
updateGlobalHistNotTaken(tid);
|
updateGlobalHistNotTaken();
|
||||||
updateLocalHistNotTaken(local_history_idx);
|
updateLocalHistNotTaken(local_history_idx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (local_prediction) {
|
if (local_prediction) {
|
||||||
updateGlobalHistTaken(tid);
|
updateGlobalHistTaken();
|
||||||
updateLocalHistTaken(local_history_idx);
|
updateLocalHistTaken(local_history_idx);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
updateGlobalHistNotTaken(tid);
|
updateGlobalHistNotTaken();
|
||||||
updateLocalHistNotTaken(local_history_idx);
|
updateLocalHistNotTaken(local_history_idx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -248,11 +249,11 @@ TournamentBP::lookup(ThreadID tid, Addr branch_addr, void * &bp_history)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TournamentBP::uncondBranch(ThreadID tid, Addr pc, void * &bp_history)
|
TournamentBP::uncondBranch(Addr pc, void * &bp_history)
|
||||||
{
|
{
|
||||||
// Create BPHistory and pass it back to be recorded.
|
// Create BPHistory and pass it back to be recorded.
|
||||||
BPHistory *history = new BPHistory;
|
BPHistory *history = new BPHistory;
|
||||||
history->globalHistory = globalHistory[tid];
|
history->globalHistory = globalHistory;
|
||||||
history->localPredTaken = true;
|
history->localPredTaken = true;
|
||||||
history->globalPredTaken = true;
|
history->globalPredTaken = true;
|
||||||
history->globalUsed = true;
|
history->globalUsed = true;
|
||||||
|
@ -260,12 +261,12 @@ TournamentBP::uncondBranch(ThreadID tid, Addr pc, void * &bp_history)
|
||||||
history->localHistory = invalidPredictorIndex;
|
history->localHistory = invalidPredictorIndex;
|
||||||
bp_history = static_cast<void *>(history);
|
bp_history = static_cast<void *>(history);
|
||||||
|
|
||||||
updateGlobalHistTaken(tid);
|
updateGlobalHistTaken();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TournamentBP::update(ThreadID tid, Addr branch_addr, bool taken,
|
TournamentBP::update(Addr branch_addr, bool taken, void *bp_history,
|
||||||
void *bp_history, bool squashed)
|
bool squashed)
|
||||||
{
|
{
|
||||||
unsigned local_history_idx;
|
unsigned local_history_idx;
|
||||||
unsigned local_predictor_idx M5_VAR_USED;
|
unsigned local_predictor_idx M5_VAR_USED;
|
||||||
|
@ -331,15 +332,15 @@ TournamentBP::update(ThreadID tid, Addr branch_addr, bool taken,
|
||||||
}
|
}
|
||||||
if (squashed) {
|
if (squashed) {
|
||||||
if (taken) {
|
if (taken) {
|
||||||
globalHistory[tid] = (history->globalHistory << 1) | 1;
|
globalHistory = (history->globalHistory << 1) | 1;
|
||||||
globalHistory[tid] = globalHistory[tid] & historyRegisterMask;
|
globalHistory = globalHistory & historyRegisterMask;
|
||||||
if (old_local_pred_valid) {
|
if (old_local_pred_valid) {
|
||||||
localHistoryTable[local_history_idx] =
|
localHistoryTable[local_history_idx] =
|
||||||
(history->localHistory << 1) | 1;
|
(history->localHistory << 1) | 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
globalHistory[tid] = (history->globalHistory << 1);
|
globalHistory = (history->globalHistory << 1);
|
||||||
globalHistory[tid] = globalHistory[tid] & historyRegisterMask;
|
globalHistory = globalHistory & historyRegisterMask;
|
||||||
if (old_local_pred_valid) {
|
if (old_local_pred_valid) {
|
||||||
localHistoryTable[local_history_idx] =
|
localHistoryTable[local_history_idx] =
|
||||||
history->localHistory << 1;
|
history->localHistory << 1;
|
||||||
|
@ -358,19 +359,19 @@ TournamentBP::update(ThreadID tid, Addr branch_addr, bool taken,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TournamentBP::retireSquashed(ThreadID tid, void *bp_history)
|
TournamentBP::retireSquashed(void *bp_history)
|
||||||
{
|
{
|
||||||
BPHistory *history = static_cast<BPHistory *>(bp_history);
|
BPHistory *history = static_cast<BPHistory *>(bp_history);
|
||||||
delete history;
|
delete history;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TournamentBP::squash(ThreadID tid, void *bp_history)
|
TournamentBP::squash(void *bp_history)
|
||||||
{
|
{
|
||||||
BPHistory *history = static_cast<BPHistory *>(bp_history);
|
BPHistory *history = static_cast<BPHistory *>(bp_history);
|
||||||
|
|
||||||
// Restore global history to state prior to this branch.
|
// Restore global history to state prior to this branch.
|
||||||
globalHistory[tid] = history->globalHistory;
|
globalHistory = history->globalHistory;
|
||||||
|
|
||||||
// Restore local history
|
// Restore local history
|
||||||
if (history->localHistoryIdx != invalidPredictorIndex) {
|
if (history->localHistoryIdx != invalidPredictorIndex) {
|
||||||
|
@ -387,12 +388,6 @@ TournamentBPParams::create()
|
||||||
return new TournamentBP(this);
|
return new TournamentBP(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
|
||||||
TournamentBP::getGHR(ThreadID tid, void *bp_history) const
|
|
||||||
{
|
|
||||||
return static_cast<BPHistory *>(bp_history)->globalHistory;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
int
|
int
|
||||||
TournamentBP::BPHistory::newCount = 0;
|
TournamentBP::BPHistory::newCount = 0;
|
||||||
|
|
|
@ -77,7 +77,7 @@ class TournamentBP : public BPredUnit
|
||||||
* @param bp_history Pointer that will be set to the BPHistory object.
|
* @param bp_history Pointer that will be set to the BPHistory object.
|
||||||
* @return Whether or not the branch is taken.
|
* @return Whether or not the branch is taken.
|
||||||
*/
|
*/
|
||||||
bool lookup(ThreadID tid, Addr branch_addr, void * &bp_history);
|
bool lookup(Addr branch_addr, void * &bp_history);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Records that there was an unconditional branch, and modifies
|
* Records that there was an unconditional branch, and modifies
|
||||||
|
@ -85,7 +85,7 @@ class TournamentBP : public BPredUnit
|
||||||
* global history stored in it.
|
* global history stored in it.
|
||||||
* @param bp_history Pointer that will be set to the BPHistory object.
|
* @param bp_history Pointer that will be set to the BPHistory object.
|
||||||
*/
|
*/
|
||||||
void uncondBranch(ThreadID tid, Addr pc, void * &bp_history);
|
void uncondBranch(Addr pc, void * &bp_history);
|
||||||
/**
|
/**
|
||||||
* Updates the branch predictor to Not Taken if a BTB entry is
|
* Updates the branch predictor to Not Taken if a BTB entry is
|
||||||
* invalid or not found.
|
* invalid or not found.
|
||||||
|
@ -93,7 +93,7 @@ class TournamentBP : public BPredUnit
|
||||||
* @param bp_history Pointer to any bp history state.
|
* @param bp_history Pointer to any bp history state.
|
||||||
* @return Whether or not the branch is taken.
|
* @return Whether or not the branch is taken.
|
||||||
*/
|
*/
|
||||||
void btbUpdate(ThreadID tid, Addr branch_addr, void * &bp_history);
|
void btbUpdate(Addr branch_addr, void * &bp_history);
|
||||||
/**
|
/**
|
||||||
* Updates the branch predictor with the actual result of a branch.
|
* Updates the branch predictor with the actual result of a branch.
|
||||||
* @param branch_addr The address of the branch to update.
|
* @param branch_addr The address of the branch to update.
|
||||||
|
@ -103,19 +103,19 @@ class TournamentBP : public BPredUnit
|
||||||
* @param squashed is set when this function is called during a squash
|
* @param squashed is set when this function is called during a squash
|
||||||
* operation.
|
* operation.
|
||||||
*/
|
*/
|
||||||
void update(ThreadID tid, Addr branch_addr, bool taken, void *bp_history,
|
void update(Addr branch_addr, bool taken, void *bp_history, bool squashed);
|
||||||
bool squashed);
|
|
||||||
|
|
||||||
void retireSquashed(ThreadID tid, void *bp_history);
|
void retireSquashed(void *bp_history);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores the global branch history on a squash.
|
* Restores the global branch history on a squash.
|
||||||
* @param bp_history Pointer to the BPHistory object that has the
|
* @param bp_history Pointer to the BPHistory object that has the
|
||||||
* previous global branch history in it.
|
* previous global branch history in it.
|
||||||
*/
|
*/
|
||||||
void squash(ThreadID tid, void *bp_history);
|
void squash(void *bp_history);
|
||||||
|
|
||||||
unsigned getGHR(ThreadID tid, void *bp_history) const;
|
/** Returns the global history. */
|
||||||
|
inline unsigned readGlobalHist() { return globalHistory; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
|
@ -132,10 +132,10 @@ class TournamentBP : public BPredUnit
|
||||||
inline unsigned calcLocHistIdx(Addr &branch_addr);
|
inline unsigned calcLocHistIdx(Addr &branch_addr);
|
||||||
|
|
||||||
/** Updates global history as taken. */
|
/** Updates global history as taken. */
|
||||||
inline void updateGlobalHistTaken(ThreadID tid);
|
inline void updateGlobalHistTaken();
|
||||||
|
|
||||||
/** Updates global history as not taken. */
|
/** Updates global history as not taken. */
|
||||||
inline void updateGlobalHistNotTaken(ThreadID tid);
|
inline void updateGlobalHistNotTaken();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates local histories as taken.
|
* Updates local histories as taken.
|
||||||
|
@ -209,7 +209,7 @@ class TournamentBP : public BPredUnit
|
||||||
/** Global history register. Contains as much history as specified by
|
/** Global history register. Contains as much history as specified by
|
||||||
* globalHistoryBits. Actual number of bits used is determined by
|
* globalHistoryBits. Actual number of bits used is determined by
|
||||||
* globalHistoryMask and choiceHistoryMask. */
|
* globalHistoryMask and choiceHistoryMask. */
|
||||||
std::vector<unsigned> globalHistory;
|
unsigned globalHistory;
|
||||||
|
|
||||||
/** Number of bits for the global history. Determines maximum number of
|
/** Number of bits for the global history. Determines maximum number of
|
||||||
entries in global and choice predictor tables. */
|
entries in global and choice predictor tables. */
|
||||||
|
|
|
@ -87,9 +87,9 @@ AtomicSimpleCPU::init()
|
||||||
BaseSimpleCPU::init();
|
BaseSimpleCPU::init();
|
||||||
|
|
||||||
int cid = threadContexts[0]->contextId();
|
int cid = threadContexts[0]->contextId();
|
||||||
ifetch_req.setContext(cid);
|
ifetch_req.setThreadContext(cid, 0);
|
||||||
data_read_req.setContext(cid);
|
data_read_req.setThreadContext(cid, 0);
|
||||||
data_write_req.setContext(cid);
|
data_write_req.setThreadContext(cid, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
AtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p)
|
AtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p)
|
||||||
|
@ -247,8 +247,6 @@ AtomicSimpleCPU::activateContext(ThreadID thread_num)
|
||||||
== activeThreads.end()) {
|
== activeThreads.end()) {
|
||||||
activeThreads.push_back(thread_num);
|
activeThreads.push_back(thread_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseCPU::activateContext(thread_num);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -275,7 +273,6 @@ AtomicSimpleCPU::suspendContext(ThreadID thread_num)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseCPU::suspendContext(thread_num);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -557,9 +554,9 @@ AtomicSimpleCPU::tick()
|
||||||
if (numThreads > 1) {
|
if (numThreads > 1) {
|
||||||
ContextID cid = threadContexts[curThread]->contextId();
|
ContextID cid = threadContexts[curThread]->contextId();
|
||||||
|
|
||||||
ifetch_req.setContext(cid);
|
ifetch_req.setThreadContext(cid, curThread);
|
||||||
data_read_req.setContext(cid);
|
data_read_req.setThreadContext(cid, curThread);
|
||||||
data_write_req.setContext(cid);
|
data_write_req.setThreadContext(cid, curThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleExecContext& t_info = *threadInfo[curThread];
|
SimpleExecContext& t_info = *threadInfo[curThread];
|
||||||
|
|
|
@ -218,8 +218,6 @@ TimingSimpleCPU::activateContext(ThreadID thread_num)
|
||||||
== activeThreads.end()) {
|
== activeThreads.end()) {
|
||||||
activeThreads.push_back(thread_num);
|
activeThreads.push_back(thread_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseCPU::activateContext(thread_num);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -245,8 +243,6 @@ TimingSimpleCPU::suspendContext(ThreadID thread_num)
|
||||||
deschedule(fetchEvent);
|
deschedule(fetchEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseCPU::suspendContext(thread_num);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -423,6 +419,7 @@ TimingSimpleCPU::initiateMemRead(Addr addr, unsigned size, unsigned flags)
|
||||||
|
|
||||||
Fault fault;
|
Fault fault;
|
||||||
const int asid = 0;
|
const int asid = 0;
|
||||||
|
const ThreadID tid = curThread;
|
||||||
const Addr pc = thread->instAddr();
|
const Addr pc = thread->instAddr();
|
||||||
unsigned block_size = cacheLineSize();
|
unsigned block_size = cacheLineSize();
|
||||||
BaseTLB::Mode mode = BaseTLB::Read;
|
BaseTLB::Mode mode = BaseTLB::Read;
|
||||||
|
@ -430,8 +427,9 @@ TimingSimpleCPU::initiateMemRead(Addr addr, unsigned size, unsigned flags)
|
||||||
if (traceData)
|
if (traceData)
|
||||||
traceData->setMem(addr, size, flags);
|
traceData->setMem(addr, size, flags);
|
||||||
|
|
||||||
RequestPtr req = new Request(asid, addr, size, flags, dataMasterId(), pc,
|
RequestPtr req = new Request(asid, addr, size,
|
||||||
thread->contextId());
|
flags, dataMasterId(), pc,
|
||||||
|
thread->contextId(), tid);
|
||||||
|
|
||||||
req->taskId(taskId());
|
req->taskId(taskId());
|
||||||
|
|
||||||
|
@ -496,6 +494,7 @@ TimingSimpleCPU::writeMem(uint8_t *data, unsigned size,
|
||||||
|
|
||||||
uint8_t *newData = new uint8_t[size];
|
uint8_t *newData = new uint8_t[size];
|
||||||
const int asid = 0;
|
const int asid = 0;
|
||||||
|
const ThreadID tid = curThread;
|
||||||
const Addr pc = thread->instAddr();
|
const Addr pc = thread->instAddr();
|
||||||
unsigned block_size = cacheLineSize();
|
unsigned block_size = cacheLineSize();
|
||||||
BaseTLB::Mode mode = BaseTLB::Write;
|
BaseTLB::Mode mode = BaseTLB::Write;
|
||||||
|
@ -511,8 +510,9 @@ TimingSimpleCPU::writeMem(uint8_t *data, unsigned size,
|
||||||
if (traceData)
|
if (traceData)
|
||||||
traceData->setMem(addr, size, flags);
|
traceData->setMem(addr, size, flags);
|
||||||
|
|
||||||
RequestPtr req = new Request(asid, addr, size, flags, dataMasterId(), pc,
|
RequestPtr req = new Request(asid, addr, size,
|
||||||
thread->contextId());
|
flags, dataMasterId(), pc,
|
||||||
|
thread->contextId(), tid);
|
||||||
|
|
||||||
req->taskId(taskId());
|
req->taskId(taskId());
|
||||||
|
|
||||||
|
@ -614,7 +614,7 @@ TimingSimpleCPU::fetch()
|
||||||
_status = BaseSimpleCPU::Running;
|
_status = BaseSimpleCPU::Running;
|
||||||
Request *ifetch_req = new Request();
|
Request *ifetch_req = new Request();
|
||||||
ifetch_req->taskId(taskId());
|
ifetch_req->taskId(taskId());
|
||||||
ifetch_req->setContext(thread->contextId());
|
ifetch_req->setThreadContext(thread->contextId(), curThread);
|
||||||
setupFetchRequest(ifetch_req);
|
setupFetchRequest(ifetch_req);
|
||||||
DPRINTF(SimpleCPU, "Translating address %#x\n", ifetch_req->getVaddr());
|
DPRINTF(SimpleCPU, "Translating address %#x\n", ifetch_req->getVaddr());
|
||||||
thread->itb->translateTiming(ifetch_req, thread->getTC(),
|
thread->itb->translateTiming(ifetch_req, thread->getTC(),
|
||||||
|
|
|
@ -245,7 +245,7 @@ MemTest::tick()
|
||||||
bool do_functional = (random_mt.random(0, 100) < percentFunctional) &&
|
bool do_functional = (random_mt.random(0, 100) < percentFunctional) &&
|
||||||
!uncacheable;
|
!uncacheable;
|
||||||
Request *req = new Request(paddr, 1, flags, masterId);
|
Request *req = new Request(paddr, 1, flags, masterId);
|
||||||
req->setContext(id);
|
req->setThreadContext(id, 0);
|
||||||
|
|
||||||
outstandingAddrs.insert(paddr);
|
outstandingAddrs.insert(paddr);
|
||||||
|
|
||||||
|
|
|
@ -243,7 +243,7 @@ NetworkTest::generatePkt()
|
||||||
// generate packet for virtual network 1
|
// generate packet for virtual network 1
|
||||||
requestType = MemCmd::ReadReq;
|
requestType = MemCmd::ReadReq;
|
||||||
flags.set(Request::INST_FETCH);
|
flags.set(Request::INST_FETCH);
|
||||||
req = new Request(0, 0x0, access_size, flags, masterId, 0x0, 0);
|
req = new Request(0, 0x0, access_size, flags, masterId, 0x0, 0, 0);
|
||||||
req->setPaddr(paddr);
|
req->setPaddr(paddr);
|
||||||
} else { // if (randomReqType == 2)
|
} else { // if (randomReqType == 2)
|
||||||
// generate packet for virtual network 2
|
// generate packet for virtual network 2
|
||||||
|
@ -251,7 +251,7 @@ NetworkTest::generatePkt()
|
||||||
req = new Request(paddr, access_size, flags, masterId);
|
req = new Request(paddr, access_size, flags, masterId);
|
||||||
}
|
}
|
||||||
|
|
||||||
req->setContext(id);
|
req->setThreadContext(id,0);
|
||||||
|
|
||||||
//No need to do functional simulation
|
//No need to do functional simulation
|
||||||
//We just do timing simulation of the network
|
//We just do timing simulation of the network
|
||||||
|
|
|
@ -107,7 +107,7 @@ Check::initiatePrefetch()
|
||||||
// Prefetches are assumed to be 0 sized
|
// Prefetches are assumed to be 0 sized
|
||||||
Request *req = new Request(m_address, 0, flags,
|
Request *req = new Request(m_address, 0, flags,
|
||||||
m_tester_ptr->masterId(), curTick(), m_pc);
|
m_tester_ptr->masterId(), curTick(), m_pc);
|
||||||
req->setContext(index);
|
req->setThreadContext(index, 0);
|
||||||
|
|
||||||
PacketPtr pkt = new Packet(req, cmd);
|
PacketPtr pkt = new Packet(req, cmd);
|
||||||
// despite the oddity of the 0 size (questionable if this should
|
// despite the oddity of the 0 size (questionable if this should
|
||||||
|
@ -180,7 +180,7 @@ Check::initiateAction()
|
||||||
Request *req = new Request(writeAddr, 1, flags, m_tester_ptr->masterId(),
|
Request *req = new Request(writeAddr, 1, flags, m_tester_ptr->masterId(),
|
||||||
curTick(), m_pc);
|
curTick(), m_pc);
|
||||||
|
|
||||||
req->setContext(index);
|
req->setThreadContext(index, 0);
|
||||||
Packet::Command cmd;
|
Packet::Command cmd;
|
||||||
|
|
||||||
// 1 out of 8 chance, issue an atomic rather than a write
|
// 1 out of 8 chance, issue an atomic rather than a write
|
||||||
|
@ -245,7 +245,7 @@ Check::initiateCheck()
|
||||||
Request *req = new Request(m_address, CHECK_SIZE, flags,
|
Request *req = new Request(m_address, CHECK_SIZE, flags,
|
||||||
m_tester_ptr->masterId(), curTick(), m_pc);
|
m_tester_ptr->masterId(), curTick(), m_pc);
|
||||||
|
|
||||||
req->setContext(index);
|
req->setThreadContext(index, 0);
|
||||||
PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
|
PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
|
||||||
uint8_t *dataArray = new uint8_t[CHECK_SIZE];
|
uint8_t *dataArray = new uint8_t[CHECK_SIZE];
|
||||||
pkt->dataDynamic(dataArray);
|
pkt->dataDynamic(dataArray);
|
||||||
|
|
|
@ -627,7 +627,7 @@ TraceCPU::ElasticDataGen::executeMemReq(GraphNode* node_ptr)
|
||||||
// Create a request and the packet containing request
|
// Create a request and the packet containing request
|
||||||
Request* req = new Request(node_ptr->physAddr, node_ptr->size,
|
Request* req = new Request(node_ptr->physAddr, node_ptr->size,
|
||||||
node_ptr->flags, masterID, node_ptr->seqNum,
|
node_ptr->flags, masterID, node_ptr->seqNum,
|
||||||
ContextID(0));
|
ContextID(0), ThreadID(0));
|
||||||
req->setPC(node_ptr->pc);
|
req->setPC(node_ptr->pc);
|
||||||
// If virtual address is valid, set the asid and virtual address fields
|
// If virtual address is valid, set the asid and virtual address fields
|
||||||
// of the request.
|
// of the request.
|
||||||
|
@ -1123,7 +1123,7 @@ TraceCPU::FixedRetryGen::send(Addr addr, unsigned size, const MemCmd& cmd,
|
||||||
req->setPC(pc);
|
req->setPC(pc);
|
||||||
|
|
||||||
// If this is not done it triggers assert in L1 cache for invalid contextId
|
// If this is not done it triggers assert in L1 cache for invalid contextId
|
||||||
req->setContext(ContextID(0));
|
req->setThreadContext(ContextID(0), ThreadID(0));
|
||||||
|
|
||||||
// Embed it in a packet
|
// Embed it in a packet
|
||||||
PacketPtr pkt = new Packet(req, cmd);
|
PacketPtr pkt = new Packet(req, cmd);
|
||||||
|
|
|
@ -1,128 +0,0 @@
|
||||||
# Copyright (c) 2016 ARM Limited
|
|
||||||
# All rights reserved
|
|
||||||
#
|
|
||||||
# The license below extends only to copyright in the software and shall
|
|
||||||
# not be construed as granting a license to any other intellectual
|
|
||||||
# property including but not limited to intellectual property relating
|
|
||||||
# to a hardware implementation of the functionality of the software
|
|
||||||
# licensed hereunder. You may use the software subject to the license
|
|
||||||
# terms below provided that you ensure that this notice is replicated
|
|
||||||
# unmodified and in its entirety in all distributions of the software,
|
|
||||||
# modified or unmodified, in source code or in binary form.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
# Author: David Guillen Fandos
|
|
||||||
|
|
||||||
/*! \page gem5PowerModel Gem5 Power & Thermal model
|
|
||||||
|
|
||||||
\tableofcontents
|
|
||||||
|
|
||||||
This document gives an overview of the power and thermal modelling
|
|
||||||
infrastructure in Gem5. The purpose is to give a high level view of
|
|
||||||
all the pieces involved and how they interact with each other and
|
|
||||||
the simulator.
|
|
||||||
|
|
||||||
\section gem5_PM_CD Class overview
|
|
||||||
|
|
||||||
Classes involved in the power model are:
|
|
||||||
|
|
||||||
- PowerModel: Represents a power model for a hardware component.
|
|
||||||
|
|
||||||
- PowerModelState: Represents a power model for a hardware component
|
|
||||||
in a certain power state. It is an abstract class that defines an
|
|
||||||
interface that must be implemented for each model.
|
|
||||||
|
|
||||||
- MathExprPowerModel: Simple implementation of PowerModelState that
|
|
||||||
assumes that power can be modeled using a simple power
|
|
||||||
|
|
||||||
Classes involved in the thermal model are:
|
|
||||||
|
|
||||||
- ThermalModel: Contains the system thermal model logic and state.
|
|
||||||
It performs the power query and temperature update. It also enables
|
|
||||||
gem5 to query for temperature (for OS reporting).
|
|
||||||
|
|
||||||
- ThermalDomain: Represents an entity that generates heat. It's
|
|
||||||
essentially a group of SimObjects grouped under a SubSystem component
|
|
||||||
that have its own thermal behaviour.
|
|
||||||
|
|
||||||
- ThermalNode: Represents a node in the thermal circuital equivalent.
|
|
||||||
The node has a temperature and interacts with other nodes through
|
|
||||||
connections (thermal resistors and capacitors).
|
|
||||||
|
|
||||||
- ThermalReference: Temperature reference for the thermal model
|
|
||||||
(essentially a thermal node with a fixed temperature), can be used
|
|
||||||
to model air or any other constant temperature domains.
|
|
||||||
|
|
||||||
- ThermalEntity: A thermal component that connects two thermal nodes
|
|
||||||
and models a thermal impedance between them. This class is just an
|
|
||||||
abstract interface.
|
|
||||||
|
|
||||||
- ThermalResistor: Implements ThermalEntity to model a thermal resistance
|
|
||||||
between the two nodes it connects. Thermal resistances model the
|
|
||||||
capacity of a material to transfer heat (units in K/W).
|
|
||||||
|
|
||||||
- ThermalCapacitor. Implements ThermalEntity to model a thermal
|
|
||||||
capacitance. Thermal capacitors are used to model material's thermal
|
|
||||||
capacitance, this is, the ability to change a certain material
|
|
||||||
temperature (units in J/K).
|
|
||||||
|
|
||||||
\section gem5_thermal Thermal model
|
|
||||||
|
|
||||||
The thermal model works by creating a circuital equivalent of the
|
|
||||||
simulated platform. Each node in the circuit has a temperature (as
|
|
||||||
voltage equivalent) and power flows between nodes (as current in a
|
|
||||||
circuit).
|
|
||||||
|
|
||||||
To build this equivalent temperature model the platform is required
|
|
||||||
to group the power actors (any component that has a power model)
|
|
||||||
under SubSystems and attach ThermalDomains to those subsystems.
|
|
||||||
Other components might also be created (like ThermalReferences) and
|
|
||||||
connected all together by creating thermal entities (capacitors and
|
|
||||||
resistors).
|
|
||||||
|
|
||||||
Last step to conclude the thermal model is to create the ThermalModel
|
|
||||||
instance itself and attach all the instances used to it, so it can
|
|
||||||
properly update them at runtime. Only one thermal model instance is
|
|
||||||
supported right now and it will automatically report temperature when
|
|
||||||
appropriate (ie. platform sensor devices).
|
|
||||||
|
|
||||||
\section gem5_power Power model
|
|
||||||
|
|
||||||
Every ClockedObject has a power model associated. If this power model is
|
|
||||||
non-null power will be calculated at every stats dump (although it might
|
|
||||||
be possible to force power evaluation at any other point, if the power
|
|
||||||
model uses the stats, it is a good idea to keep both events in sync).
|
|
||||||
The definition of a power model is quite vague in the sense that it is
|
|
||||||
as flexible as users want it to be. The only enforced contraints so far
|
|
||||||
is the fact that a power model has several power state models, one for
|
|
||||||
each possible power state for that hardware block. When it comes to compute
|
|
||||||
power consumption the power is just the weighted average of each power model.
|
|
||||||
|
|
||||||
A power state model is essentially an interface that allows us to define two
|
|
||||||
power functions for dynamic and static. As an example implementation a class
|
|
||||||
called MathExprPowerModel has been provided. This implementation allows the
|
|
||||||
user to define a power model as an equation involving several statistics.
|
|
||||||
There's also some automatic (or "magic") variables such as "temp", which
|
|
||||||
reports temperature.
|
|
3
src/mem/cache/prefetch/queued.cc
vendored
3
src/mem/cache/prefetch/queued.cc
vendored
|
@ -122,7 +122,8 @@ QueuedPrefetcher::notify(const PacketPtr &pkt)
|
||||||
pf_pkt->allocate();
|
pf_pkt->allocate();
|
||||||
|
|
||||||
if (pkt->req->hasContextId()) {
|
if (pkt->req->hasContextId()) {
|
||||||
pf_req->setContext(pkt->req->contextId());
|
pf_req->setThreadContext(pkt->req->contextId(),
|
||||||
|
pkt->req->threadId());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tagPrefetch && pkt->req->hasPC()) {
|
if (tagPrefetch && pkt->req->hasPC()) {
|
||||||
|
|
|
@ -257,13 +257,14 @@ class Request
|
||||||
VALID_PC = 0x00000010,
|
VALID_PC = 0x00000010,
|
||||||
/** Whether or not the context ID is valid. */
|
/** Whether or not the context ID is valid. */
|
||||||
VALID_CONTEXT_ID = 0x00000020,
|
VALID_CONTEXT_ID = 0x00000020,
|
||||||
|
VALID_THREAD_ID = 0x00000040,
|
||||||
/** Whether or not the sc result is valid. */
|
/** Whether or not the sc result is valid. */
|
||||||
VALID_EXTRA_DATA = 0x00000080,
|
VALID_EXTRA_DATA = 0x00000080,
|
||||||
/**
|
/**
|
||||||
* These flags are *not* cleared when a Request object is reused
|
* These flags are *not* cleared when a Request object is reused
|
||||||
* (assigned a new address).
|
* (assigned a new address).
|
||||||
*/
|
*/
|
||||||
STICKY_PRIVATE_FLAGS = VALID_CONTEXT_ID
|
STICKY_PRIVATE_FLAGS = VALID_CONTEXT_ID | VALID_THREAD_ID
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -338,8 +339,10 @@ class Request
|
||||||
* store conditional or the compare value for a CAS. */
|
* store conditional or the compare value for a CAS. */
|
||||||
uint64_t _extraData;
|
uint64_t _extraData;
|
||||||
|
|
||||||
/** The context ID (for statistics, locks, and wakeups). */
|
/** The context ID (for statistics, typically). */
|
||||||
ContextID _contextId;
|
ContextID _contextId;
|
||||||
|
/** The thread ID (id within this CPU) */
|
||||||
|
ThreadID _threadId;
|
||||||
|
|
||||||
/** program counter of initiating access; for tracing/debugging */
|
/** program counter of initiating access; for tracing/debugging */
|
||||||
Addr _pc;
|
Addr _pc;
|
||||||
|
@ -360,21 +363,21 @@ class Request
|
||||||
Request()
|
Request()
|
||||||
: _paddr(0), _size(0), _masterId(invldMasterId), _time(0),
|
: _paddr(0), _size(0), _masterId(invldMasterId), _time(0),
|
||||||
_taskId(ContextSwitchTaskId::Unknown), _asid(0), _vaddr(0),
|
_taskId(ContextSwitchTaskId::Unknown), _asid(0), _vaddr(0),
|
||||||
_extraData(0), _contextId(0), _pc(0),
|
_extraData(0), _contextId(0), _threadId(0), _pc(0),
|
||||||
_reqInstSeqNum(0), atomicOpFunctor(nullptr), translateDelta(0),
|
_reqInstSeqNum(0), atomicOpFunctor(nullptr), translateDelta(0),
|
||||||
accessDelta(0), depth(0)
|
accessDelta(0), depth(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Request(Addr paddr, unsigned size, Flags flags, MasterID mid,
|
Request(Addr paddr, unsigned size, Flags flags, MasterID mid,
|
||||||
InstSeqNum seq_num, ContextID cid)
|
InstSeqNum seq_num, ContextID cid, ThreadID tid)
|
||||||
: _paddr(0), _size(0), _masterId(invldMasterId), _time(0),
|
: _paddr(0), _size(0), _masterId(invldMasterId), _time(0),
|
||||||
_taskId(ContextSwitchTaskId::Unknown), _asid(0), _vaddr(0),
|
_taskId(ContextSwitchTaskId::Unknown), _asid(0), _vaddr(0),
|
||||||
_extraData(0), _contextId(0), _pc(0),
|
_extraData(0), _contextId(0), _threadId(0), _pc(0),
|
||||||
_reqInstSeqNum(seq_num), atomicOpFunctor(nullptr), translateDelta(0),
|
_reqInstSeqNum(seq_num), atomicOpFunctor(nullptr), translateDelta(0),
|
||||||
accessDelta(0), depth(0)
|
accessDelta(0), depth(0)
|
||||||
{
|
{
|
||||||
setPhys(paddr, size, flags, mid, curTick());
|
setPhys(paddr, size, flags, mid, curTick());
|
||||||
setContext(cid);
|
setThreadContext(cid, tid);
|
||||||
privateFlags.set(VALID_INST_SEQ_NUM);
|
privateFlags.set(VALID_INST_SEQ_NUM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,7 +389,7 @@ class Request
|
||||||
Request(Addr paddr, unsigned size, Flags flags, MasterID mid)
|
Request(Addr paddr, unsigned size, Flags flags, MasterID mid)
|
||||||
: _paddr(0), _size(0), _masterId(invldMasterId), _time(0),
|
: _paddr(0), _size(0), _masterId(invldMasterId), _time(0),
|
||||||
_taskId(ContextSwitchTaskId::Unknown), _asid(0), _vaddr(0),
|
_taskId(ContextSwitchTaskId::Unknown), _asid(0), _vaddr(0),
|
||||||
_extraData(0), _contextId(0), _pc(0),
|
_extraData(0), _contextId(0), _threadId(0), _pc(0),
|
||||||
_reqInstSeqNum(0), atomicOpFunctor(nullptr), translateDelta(0),
|
_reqInstSeqNum(0), atomicOpFunctor(nullptr), translateDelta(0),
|
||||||
accessDelta(0), depth(0)
|
accessDelta(0), depth(0)
|
||||||
{
|
{
|
||||||
|
@ -396,7 +399,7 @@ class Request
|
||||||
Request(Addr paddr, unsigned size, Flags flags, MasterID mid, Tick time)
|
Request(Addr paddr, unsigned size, Flags flags, MasterID mid, Tick time)
|
||||||
: _paddr(0), _size(0), _masterId(invldMasterId), _time(0),
|
: _paddr(0), _size(0), _masterId(invldMasterId), _time(0),
|
||||||
_taskId(ContextSwitchTaskId::Unknown), _asid(0), _vaddr(0),
|
_taskId(ContextSwitchTaskId::Unknown), _asid(0), _vaddr(0),
|
||||||
_extraData(0), _contextId(0), _pc(0),
|
_extraData(0), _contextId(0), _threadId(0), _pc(0),
|
||||||
_reqInstSeqNum(0), atomicOpFunctor(nullptr), translateDelta(0),
|
_reqInstSeqNum(0), atomicOpFunctor(nullptr), translateDelta(0),
|
||||||
accessDelta(0), depth(0)
|
accessDelta(0), depth(0)
|
||||||
{
|
{
|
||||||
|
@ -407,7 +410,7 @@ class Request
|
||||||
Addr pc)
|
Addr pc)
|
||||||
: _paddr(0), _size(0), _masterId(invldMasterId), _time(0),
|
: _paddr(0), _size(0), _masterId(invldMasterId), _time(0),
|
||||||
_taskId(ContextSwitchTaskId::Unknown), _asid(0), _vaddr(0),
|
_taskId(ContextSwitchTaskId::Unknown), _asid(0), _vaddr(0),
|
||||||
_extraData(0), _contextId(0), _pc(pc),
|
_extraData(0), _contextId(0), _threadId(0), _pc(pc),
|
||||||
_reqInstSeqNum(0), atomicOpFunctor(nullptr), translateDelta(0),
|
_reqInstSeqNum(0), atomicOpFunctor(nullptr), translateDelta(0),
|
||||||
accessDelta(0), depth(0)
|
accessDelta(0), depth(0)
|
||||||
{
|
{
|
||||||
|
@ -416,15 +419,15 @@ class Request
|
||||||
}
|
}
|
||||||
|
|
||||||
Request(int asid, Addr vaddr, unsigned size, Flags flags, MasterID mid,
|
Request(int asid, Addr vaddr, unsigned size, Flags flags, MasterID mid,
|
||||||
Addr pc, ContextID cid)
|
Addr pc, ContextID cid, ThreadID tid)
|
||||||
: _paddr(0), _size(0), _masterId(invldMasterId), _time(0),
|
: _paddr(0), _size(0), _masterId(invldMasterId), _time(0),
|
||||||
_taskId(ContextSwitchTaskId::Unknown), _asid(0), _vaddr(0),
|
_taskId(ContextSwitchTaskId::Unknown), _asid(0), _vaddr(0),
|
||||||
_extraData(0), _contextId(0), _pc(0),
|
_extraData(0), _contextId(0), _threadId(0), _pc(0),
|
||||||
_reqInstSeqNum(0), atomicOpFunctor(nullptr), translateDelta(0),
|
_reqInstSeqNum(0), atomicOpFunctor(nullptr), translateDelta(0),
|
||||||
accessDelta(0), depth(0)
|
accessDelta(0), depth(0)
|
||||||
{
|
{
|
||||||
setVirt(asid, vaddr, size, flags, mid, pc);
|
setVirt(asid, vaddr, size, flags, mid, pc);
|
||||||
setContext(cid);
|
setThreadContext(cid, tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
Request(int asid, Addr vaddr, int size, Flags flags, MasterID mid, Addr pc,
|
Request(int asid, Addr vaddr, int size, Flags flags, MasterID mid, Addr pc,
|
||||||
|
@ -432,7 +435,7 @@ class Request
|
||||||
: atomicOpFunctor(atomic_op)
|
: atomicOpFunctor(atomic_op)
|
||||||
{
|
{
|
||||||
setVirt(asid, vaddr, size, flags, mid, pc);
|
setVirt(asid, vaddr, size, flags, mid, pc);
|
||||||
setContext(cid);
|
setThreadContext(cid, tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Request()
|
~Request()
|
||||||
|
@ -443,13 +446,14 @@ class Request
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up Context numbers.
|
* Set up CPU and thread numbers.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
setContext(ContextID context_id)
|
setThreadContext(ContextID context_id, ThreadID tid)
|
||||||
{
|
{
|
||||||
_contextId = context_id;
|
_contextId = context_id;
|
||||||
privateFlags.set(VALID_CONTEXT_ID);
|
_threadId = tid;
|
||||||
|
privateFlags.set(VALID_CONTEXT_ID|VALID_THREAD_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -697,6 +701,14 @@ class Request
|
||||||
return _contextId;
|
return _contextId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Accessor function for thread ID. */
|
||||||
|
ThreadID
|
||||||
|
threadId() const
|
||||||
|
{
|
||||||
|
assert(privateFlags.isSet(VALID_THREAD_ID));
|
||||||
|
return _threadId;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
setPC(Addr pc)
|
setPC(Addr pc)
|
||||||
{
|
{
|
||||||
|
|
|
@ -66,9 +66,6 @@ class ClockedObject(SimObject):
|
||||||
# parent's clock domain by default
|
# parent's clock domain by default
|
||||||
clk_domain = Param.ClockDomain(Parent.clk_domain, "Clock domain")
|
clk_domain = Param.ClockDomain(Parent.clk_domain, "Clock domain")
|
||||||
|
|
||||||
# Power model for this ClockedObject
|
|
||||||
power_model = Param.PowerModel(NULL, "Power model")
|
|
||||||
|
|
||||||
# Provide initial power state, should ideally get redefined in startup
|
# Provide initial power state, should ideally get redefined in startup
|
||||||
# routine
|
# routine
|
||||||
default_p_state = Param.PwrState("UNDEFINED", "Default Power State")
|
default_p_state = Param.PwrState("UNDEFINED", "Default Power State")
|
||||||
|
|
|
@ -70,7 +70,6 @@ Source('linear_solver.cc')
|
||||||
Source('system.cc')
|
Source('system.cc')
|
||||||
Source('dvfs_handler.cc')
|
Source('dvfs_handler.cc')
|
||||||
Source('clocked_object.cc')
|
Source('clocked_object.cc')
|
||||||
Source('mathexpr.cc')
|
|
||||||
|
|
||||||
if env['TARGET_ISA'] != 'null':
|
if env['TARGET_ISA'] != 'null':
|
||||||
SimObject('InstTracer.py')
|
SimObject('InstTracer.py')
|
||||||
|
|
|
@ -41,17 +41,6 @@
|
||||||
#include "sim/clocked_object.hh"
|
#include "sim/clocked_object.hh"
|
||||||
|
|
||||||
#include "base/misc.hh"
|
#include "base/misc.hh"
|
||||||
#include "sim/power/power_model.hh"
|
|
||||||
|
|
||||||
ClockedObject::ClockedObject(const ClockedObjectParams *p) :
|
|
||||||
SimObject(p), Clocked(*p->clk_domain),
|
|
||||||
_currPwrState(p->default_p_state),
|
|
||||||
prvEvalTick(0)
|
|
||||||
{
|
|
||||||
// Register the power_model with the object
|
|
||||||
if (p->power_model)
|
|
||||||
p->power_model->setClockedObject(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ClockedObject::serialize(CheckpointOut &cp) const
|
ClockedObject::serialize(CheckpointOut &cp) const
|
||||||
|
|
|
@ -236,7 +236,11 @@ class ClockedObject
|
||||||
: public SimObject, public Clocked
|
: public SimObject, public Clocked
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ClockedObject(const ClockedObjectParams *p);
|
ClockedObject(const ClockedObjectParams *p)
|
||||||
|
: SimObject(p), Clocked(*p->clk_domain),
|
||||||
|
_currPwrState(p->default_p_state),
|
||||||
|
prvEvalTick(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
/** Parameters of ClockedObject */
|
/** Parameters of ClockedObject */
|
||||||
typedef ClockedObjectParams Params;
|
typedef ClockedObjectParams Params;
|
||||||
|
|
|
@ -1,175 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2015 ARM Limited
|
|
||||||
* All rights reserved
|
|
||||||
*
|
|
||||||
* The license below extends only to copyright in the software and shall
|
|
||||||
* not be construed as granting a license to any other intellectual
|
|
||||||
* property including but not limited to intellectual property relating
|
|
||||||
* to a hardware implementation of the functionality of the software
|
|
||||||
* licensed hereunder. You may use the software subject to the license
|
|
||||||
* terms below provided that you ensure that this notice is replicated
|
|
||||||
* unmodified and in its entirety in all distributions of the software,
|
|
||||||
* modified or unmodified, in source code or in binary form.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* Authors: David Guillen Fandos
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "sim/mathexpr.hh"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <regex>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "base/misc.hh"
|
|
||||||
|
|
||||||
MathExpr::MathExpr(std::string expr)
|
|
||||||
: ops(
|
|
||||||
std::array<OpSearch, uNeg + 1> {
|
|
||||||
OpSearch {true, bAdd, 0, '+', [] (double a, double b) { return a + b; } },
|
|
||||||
OpSearch {true, bSub, 0, '-', [] (double a, double b) { return a - b; } },
|
|
||||||
OpSearch {true, bMul, 1, '*', [] (double a, double b) { return a * b; } },
|
|
||||||
OpSearch {true, bDiv, 1, '/', [] (double a, double b) { return a / b; } },
|
|
||||||
OpSearch {false,uNeg, 2, '-', [] (double a, double b) { return -b; } },
|
|
||||||
OpSearch {true, bPow, 3, '^', [] (double a, double b) { return std::pow(a,b); } },
|
|
||||||
})
|
|
||||||
{
|
|
||||||
// Cleanup
|
|
||||||
expr.erase(remove_if(expr.begin(), expr.end(), isspace), expr.end());
|
|
||||||
|
|
||||||
root = MathExpr::parse(expr);
|
|
||||||
panic_if(!root, "Invalid expression\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function parses a string expression into an expression tree.
|
|
||||||
* It will look for operators in priority order to recursively build the
|
|
||||||
* tree, respecting parenthesization.
|
|
||||||
* Constants can be expressed in any format accepted by std::stod, whereas
|
|
||||||
* variables are essentially [A-Za-z0-9\.$\\]+
|
|
||||||
*/
|
|
||||||
MathExpr::Node *
|
|
||||||
MathExpr::parse(std::string expr) {
|
|
||||||
if (expr.size() == 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// From low to high priority
|
|
||||||
int par = 0;
|
|
||||||
for (unsigned p = 0; p < MAX_PRIO; p++) {
|
|
||||||
for (int i = expr.size() - 1; i >= 0; i--) {
|
|
||||||
if (expr[i] == ')')
|
|
||||||
par++;
|
|
||||||
if (expr[i] == '(')
|
|
||||||
par--;
|
|
||||||
|
|
||||||
if (par < 0) return NULL;
|
|
||||||
if (par > 0) continue;
|
|
||||||
|
|
||||||
for (unsigned opt = 0; opt < ops.size(); opt++) {
|
|
||||||
if (ops[opt].priority != p) continue;
|
|
||||||
if (ops[opt].c == expr[i]) {
|
|
||||||
// Try to parse each side
|
|
||||||
Node *l = NULL;
|
|
||||||
if (ops[opt].binary)
|
|
||||||
l = parse(expr.substr(0, i));
|
|
||||||
Node *r = parse(expr.substr(i + 1));
|
|
||||||
if ((l && r) || (!ops[opt].binary && r)) {
|
|
||||||
// Match!
|
|
||||||
Node *n = new Node();
|
|
||||||
n->op = ops[opt].op;
|
|
||||||
n->l = l;
|
|
||||||
n->r = r;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove trivial parenthesis
|
|
||||||
if (expr.size() >= 2 && expr[0] == '(' && expr[expr.size() - 1] == ')')
|
|
||||||
return parse(expr.substr(1, expr.size() - 2));
|
|
||||||
|
|
||||||
// Match a number
|
|
||||||
{
|
|
||||||
char *sptr;
|
|
||||||
double v = strtod(expr.c_str(), &sptr);
|
|
||||||
if (sptr != expr.c_str()) {
|
|
||||||
Node *n = new Node();
|
|
||||||
n->op = sValue;
|
|
||||||
n->value = v;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match a variable
|
|
||||||
{
|
|
||||||
bool contains_non_alpha = false;
|
|
||||||
for (auto & c: expr)
|
|
||||||
contains_non_alpha = contains_non_alpha or
|
|
||||||
!( (c >= 'a' && c <= 'z') ||
|
|
||||||
(c >= 'A' && c <= 'Z') ||
|
|
||||||
(c >= '0' && c <= '9') ||
|
|
||||||
c == '$' || c == '\\' || c == '.' || c == '_');
|
|
||||||
|
|
||||||
if (!contains_non_alpha) {
|
|
||||||
Node * n = new Node();
|
|
||||||
n->op = sVariable;
|
|
||||||
n->variable = expr;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
double
|
|
||||||
MathExpr::eval(const Node *n, EvalCallback fn) const {
|
|
||||||
if (!n)
|
|
||||||
return 0;
|
|
||||||
else if (n->op == sValue)
|
|
||||||
return n->value;
|
|
||||||
else if (n->op == sVariable)
|
|
||||||
return fn(n->variable);
|
|
||||||
|
|
||||||
for (auto & opt : ops)
|
|
||||||
if (opt.op == n->op)
|
|
||||||
return opt.fn( eval(n->l, fn), eval(n->r, fn) );
|
|
||||||
|
|
||||||
panic("Invalid node!\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
MathExpr::toStr(Node *n, std::string prefix) const {
|
|
||||||
std::string ret;
|
|
||||||
ret += prefix + "|-- " + n->toStr() + "\n";
|
|
||||||
if (n->r)
|
|
||||||
ret += toStr(n->r, prefix + "| ");
|
|
||||||
if (n->l)
|
|
||||||
ret += toStr(n->l, prefix + "| ");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,127 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2015 ARM Limited
|
|
||||||
* All rights reserved
|
|
||||||
*
|
|
||||||
* The license below extends only to copyright in the software and shall
|
|
||||||
* not be construed as granting a license to any other intellectual
|
|
||||||
* property including but not limited to intellectual property relating
|
|
||||||
* to a hardware implementation of the functionality of the software
|
|
||||||
* licensed hereunder. You may use the software subject to the license
|
|
||||||
* terms below provided that you ensure that this notice is replicated
|
|
||||||
* unmodified and in its entirety in all distributions of the software,
|
|
||||||
* modified or unmodified, in source code or in binary form.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* Authors: David Guillen Fandos
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __SIM_MATHEXPR_HH__
|
|
||||||
#define __SIM_MATHEXPR_HH__
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <functional>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
class MathExpr {
|
|
||||||
public:
|
|
||||||
|
|
||||||
MathExpr(std::string expr);
|
|
||||||
|
|
||||||
typedef std::function<double(std::string)> EvalCallback;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints an ASCII representation of the expression tree
|
|
||||||
*
|
|
||||||
* @return A string containing the ASCII representation of the expression
|
|
||||||
*/
|
|
||||||
std::string toStr() const { return toStr(root, ""); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Evaluates the expression
|
|
||||||
*
|
|
||||||
* @param fn A callback funcion to evaluate variables
|
|
||||||
*
|
|
||||||
* @return The value for this expression
|
|
||||||
*/
|
|
||||||
double eval(EvalCallback fn) const { return eval(root, fn); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum Operator {
|
|
||||||
bAdd, bSub, bMul, bDiv, bPow, uNeg, sValue, sVariable, nInvalid
|
|
||||||
};
|
|
||||||
|
|
||||||
// Match operators
|
|
||||||
const int MAX_PRIO = 4;
|
|
||||||
typedef double (*binOp)(double, double);
|
|
||||||
struct OpSearch {
|
|
||||||
bool binary;
|
|
||||||
Operator op;
|
|
||||||
int priority;
|
|
||||||
char c;
|
|
||||||
binOp fn;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Operator list */
|
|
||||||
std::array<OpSearch, uNeg + 1> ops;
|
|
||||||
|
|
||||||
class Node {
|
|
||||||
public:
|
|
||||||
Node() : op(nInvalid), l(0), r(0), value(0) {}
|
|
||||||
std::string toStr() const {
|
|
||||||
const char opStr[] = {'+', '-', '*', '/', '^', '-'};
|
|
||||||
switch (op) {
|
|
||||||
case nInvalid:
|
|
||||||
return "INVALID";
|
|
||||||
case sVariable:
|
|
||||||
return variable;
|
|
||||||
case sValue:
|
|
||||||
return std::to_string(value);
|
|
||||||
default:
|
|
||||||
return std::string(1, opStr[op]);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Operator op;
|
|
||||||
Node *l, *r;
|
|
||||||
double value;
|
|
||||||
std::string variable;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Root node */
|
|
||||||
Node * root;
|
|
||||||
|
|
||||||
/** Parse and create nodes from string */
|
|
||||||
Node *parse(std::string expr);
|
|
||||||
|
|
||||||
/** Print tree as string */
|
|
||||||
std::string toStr(Node *n, std::string prefix) const;
|
|
||||||
|
|
||||||
/** Eval a node */
|
|
||||||
double eval(const Node *n, EvalCallback fn) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
# Copyright (c) 2015 ARM Limited
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
# The license below extends only to copyright in the software and shall
|
|
||||||
# not be construed as granting a license to any other intellectual
|
|
||||||
# property including but not limited to intellectual property relating
|
|
||||||
# to a hardware implementation of the functionality of the software
|
|
||||||
# licensed hereunder. You may use the software subject to the license
|
|
||||||
# terms below provided that you ensure that this notice is replicated
|
|
||||||
# unmodified and in its entirety in all distributions of the software,
|
|
||||||
# modified or unmodified, in source code or in binary form.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
# Authors: David Guillen Fandos
|
|
||||||
|
|
||||||
from m5.SimObject import SimObject
|
|
||||||
from m5.params import *
|
|
||||||
from PowerModelState import PowerModelState
|
|
||||||
|
|
||||||
# Represents a power model for a simobj
|
|
||||||
class MathExprPowerModel(PowerModelState):
|
|
||||||
type = 'MathExprPowerModel'
|
|
||||||
cxx_header = "sim/power/mathexpr_powermodel.hh"
|
|
||||||
|
|
||||||
# Equations for dynamic and static power
|
|
||||||
# Equations may use gem5 stats ie. "1.1*ipc + 2.3*l2_cache.overall_misses"
|
|
||||||
# It is possible to use automatic variables such as "temp"
|
|
||||||
# You may also use stat names (relative path to the simobject)
|
|
||||||
dyn = Param.String("", "Expression for the dynamic power")
|
|
||||||
st = Param.String("", "Expression for the static power")
|
|
|
@ -1,61 +0,0 @@
|
||||||
# Copyright (c) 2015 ARM Limited
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
# The license below extends only to copyright in the software and shall
|
|
||||||
# not be construed as granting a license to any other intellectual
|
|
||||||
# property including but not limited to intellectual property relating
|
|
||||||
# to a hardware implementation of the functionality of the software
|
|
||||||
# licensed hereunder. You may use the software subject to the license
|
|
||||||
# terms below provided that you ensure that this notice is replicated
|
|
||||||
# unmodified and in its entirety in all distributions of the software,
|
|
||||||
# modified or unmodified, in source code or in binary form.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
# Authors: David Guillen Fandos
|
|
||||||
|
|
||||||
from m5.SimObject import SimObject
|
|
||||||
from m5.params import *
|
|
||||||
from m5.proxy import Parent
|
|
||||||
|
|
||||||
# Represents a power model for a simobj
|
|
||||||
# The model itself is also a SimObject so we can make use some
|
|
||||||
# nice features available such as Parent.any
|
|
||||||
class PowerModel(SimObject):
|
|
||||||
type = 'PowerModel'
|
|
||||||
cxx_header = "sim/power/power_model.hh"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def export_methods(cls, code):
|
|
||||||
code('''
|
|
||||||
double getDynamicPower() const;
|
|
||||||
double getStaticPower() const;
|
|
||||||
''')
|
|
||||||
|
|
||||||
# Keep a list of every model for every power state
|
|
||||||
pm = VectorParam.PowerModelState([], "List of per-state power models.")
|
|
||||||
|
|
||||||
# Need a reference to the system so we can query the thermal domain
|
|
||||||
# about temperature (temperature is needed for leakage calculation)
|
|
||||||
subsystem = Param.SubSystem(Parent.any, "subsystem")
|
|
|
@ -1,55 +0,0 @@
|
||||||
# Copyright (c) 2015 ARM Limited
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
# The license below extends only to copyright in the software and shall
|
|
||||||
# not be construed as granting a license to any other intellectual
|
|
||||||
# property including but not limited to intellectual property relating
|
|
||||||
# to a hardware implementation of the functionality of the software
|
|
||||||
# licensed hereunder. You may use the software subject to the license
|
|
||||||
# terms below provided that you ensure that this notice is replicated
|
|
||||||
# unmodified and in its entirety in all distributions of the software,
|
|
||||||
# modified or unmodified, in source code or in binary form.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
# Authors: David Guillen Fandos
|
|
||||||
|
|
||||||
from m5.SimObject import SimObject
|
|
||||||
from m5.params import *
|
|
||||||
|
|
||||||
# Represents a power model for a simobj
|
|
||||||
class PowerModelState(SimObject):
|
|
||||||
type = 'PowerModelState'
|
|
||||||
cxx_header = "sim/power/power_model.hh"
|
|
||||||
abstract = True
|
|
||||||
cxx_class = 'PowerModelState'
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def export_methods(cls, code):
|
|
||||||
code('''
|
|
||||||
double getDynamicPower() const;
|
|
||||||
double getStaticPower() const;
|
|
||||||
''')
|
|
||||||
|
|
||||||
|
|
|
@ -30,14 +30,9 @@
|
||||||
|
|
||||||
Import('*')
|
Import('*')
|
||||||
|
|
||||||
SimObject('MathExprPowerModel.py')
|
|
||||||
SimObject('PowerModel.py')
|
|
||||||
SimObject('PowerModelState.py')
|
|
||||||
SimObject('ThermalDomain.py')
|
SimObject('ThermalDomain.py')
|
||||||
SimObject('ThermalModel.py')
|
SimObject('ThermalModel.py')
|
||||||
|
|
||||||
Source('power_model.cc')
|
|
||||||
Source('mathexpr_powermodel.cc')
|
|
||||||
Source('thermal_domain.cc')
|
Source('thermal_domain.cc')
|
||||||
Source('thermal_model.cc')
|
Source('thermal_model.cc')
|
||||||
|
|
||||||
|
|
|
@ -1,102 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2015 ARM Limited
|
|
||||||
* All rights reserved
|
|
||||||
*
|
|
||||||
* The license below extends only to copyright in the software and shall
|
|
||||||
* not be construed as granting a license to any other intellectual
|
|
||||||
* property including but not limited to intellectual property relating
|
|
||||||
* to a hardware implementation of the functionality of the software
|
|
||||||
* licensed hereunder. You may use the software subject to the license
|
|
||||||
* terms below provided that you ensure that this notice is replicated
|
|
||||||
* unmodified and in its entirety in all distributions of the software,
|
|
||||||
* modified or unmodified, in source code or in binary form.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* Authors: David Guillen Fandos
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "sim/power/mathexpr_powermodel.hh"
|
|
||||||
|
|
||||||
#include "base/statistics.hh"
|
|
||||||
#include "params/MathExprPowerModel.hh"
|
|
||||||
#include "sim/mathexpr.hh"
|
|
||||||
#include "sim/power/thermal_model.hh"
|
|
||||||
#include "sim/sim_object.hh"
|
|
||||||
|
|
||||||
MathExprPowerModel::MathExprPowerModel(const Params *p)
|
|
||||||
: PowerModelState(p), dyn_expr(p->dyn), st_expr(p->st)
|
|
||||||
{
|
|
||||||
// Calculate the name of the object we belong to
|
|
||||||
std::vector<std::string> path;
|
|
||||||
tokenize(path, name(), '.', true);
|
|
||||||
// It's something like xyz.power_model.pm2
|
|
||||||
assert(path.size() > 2);
|
|
||||||
for (unsigned i = 0; i < path.size() - 2; i++)
|
|
||||||
basename += path[i] + ".";
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MathExprPowerModel::startup()
|
|
||||||
{
|
|
||||||
// Create a map with stats and pointers for quick access
|
|
||||||
// Has to be done here, since we need access to the statsList
|
|
||||||
for (auto & i: Stats::statsList())
|
|
||||||
if (i->name.find(basename) == 0)
|
|
||||||
stats_map[i->name.substr(basename.size())] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
double
|
|
||||||
MathExprPowerModel::getStatValue(const std::string &name) const
|
|
||||||
{
|
|
||||||
using namespace Stats;
|
|
||||||
|
|
||||||
// Automatic variables:
|
|
||||||
if (name == "temp")
|
|
||||||
return _temp;
|
|
||||||
|
|
||||||
// Try to cast the stat, only these are supported right now
|
|
||||||
Info *info = stats_map.at(name);
|
|
||||||
|
|
||||||
ScalarInfo *si = dynamic_cast<ScalarInfo*>(info);
|
|
||||||
if (si)
|
|
||||||
return si->value();
|
|
||||||
FormulaInfo *fi = dynamic_cast<FormulaInfo*>(info);
|
|
||||||
if (fi)
|
|
||||||
return fi->total();
|
|
||||||
|
|
||||||
panic("Unknown stat type!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MathExprPowerModel::regStats()
|
|
||||||
{
|
|
||||||
PowerModelState::regStats();
|
|
||||||
}
|
|
||||||
|
|
||||||
MathExprPowerModel*
|
|
||||||
MathExprPowerModelParams::create()
|
|
||||||
{
|
|
||||||
return new MathExprPowerModel(this);
|
|
||||||
}
|
|
|
@ -1,111 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2015 ARM Limited
|
|
||||||
* All rights reserved
|
|
||||||
*
|
|
||||||
* The license below extends only to copyright in the software and shall
|
|
||||||
* not be construed as granting a license to any other intellectual
|
|
||||||
* property including but not limited to intellectual property relating
|
|
||||||
* to a hardware implementation of the functionality of the software
|
|
||||||
* licensed hereunder. You may use the software subject to the license
|
|
||||||
* terms below provided that you ensure that this notice is replicated
|
|
||||||
* unmodified and in its entirety in all distributions of the software,
|
|
||||||
* modified or unmodified, in source code or in binary form.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* Authors: David Guillen Fandos
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __SIM_MATHEXPR_POWERMODEL_PM_HH__
|
|
||||||
#define __SIM_MATHEXPR_POWERMODEL_PM_HH__
|
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#include "base/statistics.hh"
|
|
||||||
#include "params/MathExprPowerModel.hh"
|
|
||||||
#include "sim/mathexpr.hh"
|
|
||||||
#include "sim/power/power_model.hh"
|
|
||||||
#include "sim/sim_object.hh"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Equation power model. The power is represented as a combination
|
|
||||||
* of some stats and automatic variables (like temperature).
|
|
||||||
*/
|
|
||||||
class MathExprPowerModel : public PowerModelState
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
typedef MathExprPowerModelParams Params;
|
|
||||||
MathExprPowerModel(const Params *p);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the dynamic power consumption.
|
|
||||||
*
|
|
||||||
* @return Power (Watts) consumed by this object (dynamic component)
|
|
||||||
*/
|
|
||||||
double getDynamicPower() const {
|
|
||||||
return dyn_expr.eval(
|
|
||||||
std::bind(&MathExprPowerModel::getStatValue,
|
|
||||||
this, std::placeholders::_1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the static power consumption.
|
|
||||||
*
|
|
||||||
* @return Power (Watts) consumed by this object (static component)
|
|
||||||
*/
|
|
||||||
double getStaticPower() const {
|
|
||||||
return st_expr.eval(
|
|
||||||
std::bind(&MathExprPowerModel::getStatValue,
|
|
||||||
this, std::placeholders::_1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the value for a variable (maps to a stat)
|
|
||||||
*
|
|
||||||
* @param name Name of the variable to retrieve the value from
|
|
||||||
*
|
|
||||||
* @return Power (Watts) consumed by this object (static component)
|
|
||||||
*/
|
|
||||||
double getStatValue(const std::string & name) const;
|
|
||||||
|
|
||||||
void startup();
|
|
||||||
|
|
||||||
void regStats();
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
// Math expressions for dynamic and static power
|
|
||||||
MathExpr dyn_expr, st_expr;
|
|
||||||
|
|
||||||
// Basename of the object in the gem5 stats hierachy
|
|
||||||
std::string basename;
|
|
||||||
|
|
||||||
// Map that contains relevant stats for this power model
|
|
||||||
std::unordered_map<std::string, Stats::Info*> stats_map;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,138 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2015 ARM Limited
|
|
||||||
* All rights reserved
|
|
||||||
*
|
|
||||||
* The license below extends only to copyright in the software and shall
|
|
||||||
* not be construed as granting a license to any other intellectual
|
|
||||||
* property including but not limited to intellectual property relating
|
|
||||||
* to a hardware implementation of the functionality of the software
|
|
||||||
* licensed hereunder. You may use the software subject to the license
|
|
||||||
* terms below provided that you ensure that this notice is replicated
|
|
||||||
* unmodified and in its entirety in all distributions of the software,
|
|
||||||
* modified or unmodified, in source code or in binary form.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* Authors: David Guillen Fandos
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "sim/power/power_model.hh"
|
|
||||||
|
|
||||||
#include "base/statistics.hh"
|
|
||||||
#include "params/PowerModel.hh"
|
|
||||||
#include "params/PowerModelState.hh"
|
|
||||||
#include "sim/sim_object.hh"
|
|
||||||
#include "sim/sub_system.hh"
|
|
||||||
|
|
||||||
PowerModelState::PowerModelState(const Params *p)
|
|
||||||
: SimObject(p), _temp(0), clocked_object(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PowerModel::PowerModel(const Params *p)
|
|
||||||
: SimObject(p), states_pm(p->pm), subsystem(p->subsystem),
|
|
||||||
clocked_object(NULL)
|
|
||||||
{
|
|
||||||
panic_if(subsystem == NULL,
|
|
||||||
"Subsystem is NULL! This is not acceptable for a PowerModel!\n");
|
|
||||||
subsystem->registerPowerProducer(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
PowerModel::setClockedObject(ClockedObject * clkobj)
|
|
||||||
{
|
|
||||||
this->clocked_object = clkobj;
|
|
||||||
|
|
||||||
for (auto & pms: states_pm)
|
|
||||||
pms->setClockedObject(clkobj);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
PowerModel::thermalUpdateCallback(const double & temp)
|
|
||||||
{
|
|
||||||
for (auto & pms: states_pm)
|
|
||||||
pms->setTemperature(temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
PowerModel::regProbePoints()
|
|
||||||
{
|
|
||||||
thermalListener.reset(new ThermalProbeListener (
|
|
||||||
*this, this->subsystem->getProbeManager(), "thermalUpdate"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
PowerModel*
|
|
||||||
PowerModelParams::create()
|
|
||||||
{
|
|
||||||
return new PowerModel(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
double
|
|
||||||
PowerModel::getDynamicPower() const
|
|
||||||
{
|
|
||||||
assert(clocked_object);
|
|
||||||
|
|
||||||
std::vector<double> w = clocked_object->pwrStateWeights();
|
|
||||||
|
|
||||||
// Same number of states (excluding UNDEFINED)
|
|
||||||
assert(w.size() - 1 == states_pm.size());
|
|
||||||
|
|
||||||
// Make sure we have no UNDEFINED state
|
|
||||||
warn_if(w[Enums::PwrState::UNDEFINED] > 0,
|
|
||||||
"SimObject in UNDEFINED power state! Power figures might be wrong!\n");
|
|
||||||
|
|
||||||
double power = 0;
|
|
||||||
for (unsigned i = 0; i < states_pm.size(); i++)
|
|
||||||
if (w[i + 1] > 0.0f)
|
|
||||||
power += states_pm[i]->getDynamicPower() * w[i + 1];
|
|
||||||
|
|
||||||
return power;
|
|
||||||
}
|
|
||||||
|
|
||||||
double
|
|
||||||
PowerModel::getStaticPower() const
|
|
||||||
{
|
|
||||||
assert(clocked_object);
|
|
||||||
|
|
||||||
std::vector<double> w = clocked_object->pwrStateWeights();
|
|
||||||
|
|
||||||
// Same number of states (excluding UNDEFINED)
|
|
||||||
assert(w.size() - 1 == states_pm.size());
|
|
||||||
|
|
||||||
// Make sure we have no UNDEFINED state
|
|
||||||
if (w[0] > 0)
|
|
||||||
warn("SimObject in UNDEFINED power state! "
|
|
||||||
"Power figures might be wrong!\n");
|
|
||||||
|
|
||||||
// We have N+1 states, being state #0 the default 'UNDEFINED' state
|
|
||||||
double power = 0;
|
|
||||||
for (unsigned i = 0; i < states_pm.size(); i++)
|
|
||||||
// Don't evaluate power if the object hasn't been in that state
|
|
||||||
// This fixes issues with NaNs and similar.
|
|
||||||
if (w[i + 1] > 0.0f)
|
|
||||||
power += states_pm[i]->getStaticPower() * w[i + 1];
|
|
||||||
|
|
||||||
return power;
|
|
||||||
}
|
|
|
@ -1,188 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2015 ARM Limited
|
|
||||||
* All rights reserved
|
|
||||||
*
|
|
||||||
* The license below extends only to copyright in the software and shall
|
|
||||||
* not be construed as granting a license to any other intellectual
|
|
||||||
* property including but not limited to intellectual property relating
|
|
||||||
* to a hardware implementation of the functionality of the software
|
|
||||||
* licensed hereunder. You may use the software subject to the license
|
|
||||||
* terms below provided that you ensure that this notice is replicated
|
|
||||||
* unmodified and in its entirety in all distributions of the software,
|
|
||||||
* modified or unmodified, in source code or in binary form.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* Authors: David Guillen Fandos
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __SIM_POWER_POWER_MODEL_HH__
|
|
||||||
#define __SIM_POWER_POWER_MODEL_HH__
|
|
||||||
|
|
||||||
#include "base/statistics.hh"
|
|
||||||
#include "params/PowerModel.hh"
|
|
||||||
#include "params/PowerModelState.hh"
|
|
||||||
#include "sim/power/thermal_model.hh"
|
|
||||||
#include "sim/probe/probe.hh"
|
|
||||||
#include "sim/sim_object.hh"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A PowerModelState is an abstract class used as interface to get power
|
|
||||||
* figures out of SimObjects
|
|
||||||
*/
|
|
||||||
class PowerModelState : public SimObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
typedef PowerModelStateParams Params;
|
|
||||||
PowerModelState(const Params *p);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the dynamic power consumption.
|
|
||||||
*
|
|
||||||
* @return Power (Watts) consumed by this object (dynamic component)
|
|
||||||
*/
|
|
||||||
virtual double getDynamicPower() const = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the static power consumption.
|
|
||||||
*
|
|
||||||
* @return Power (Watts) consumed by this object (static component)
|
|
||||||
*/
|
|
||||||
virtual double getStaticPower() const = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Temperature update.
|
|
||||||
*
|
|
||||||
* @param temp Current temperature of the HW part (Celsius)
|
|
||||||
*/
|
|
||||||
virtual void setTemperature(double temp) { _temp = temp; }
|
|
||||||
|
|
||||||
void setClockedObject(ClockedObject * clkobj) {
|
|
||||||
clocked_object = clkobj;
|
|
||||||
}
|
|
||||||
|
|
||||||
void regStats() {
|
|
||||||
dynamicPower
|
|
||||||
.method(this, &PowerModelState::getDynamicPower)
|
|
||||||
.name(params()->name + ".dynamic_power")
|
|
||||||
.desc("Dynamic power for this object (Watts)")
|
|
||||||
;
|
|
||||||
|
|
||||||
staticPower
|
|
||||||
.method(this, &PowerModelState::getStaticPower)
|
|
||||||
.name(params()->name + ".static_power")
|
|
||||||
.desc("Static power for this object (Watts)")
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Stats::Value dynamicPower, staticPower;
|
|
||||||
|
|
||||||
/** Current temperature */
|
|
||||||
double _temp;
|
|
||||||
|
|
||||||
/** The clocked object we belong to */
|
|
||||||
ClockedObject * clocked_object;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A PowerModel is a class containing a power model for a SimObject.
|
|
||||||
* The PM describes the power consumption for every power state.
|
|
||||||
*/
|
|
||||||
class PowerModel : public SimObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
typedef PowerModelParams Params;
|
|
||||||
PowerModel(const Params *p);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the dynamic power consumption.
|
|
||||||
*
|
|
||||||
* @return Power (Watts) consumed by this object (dynamic component)
|
|
||||||
*/
|
|
||||||
double getDynamicPower() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the static power consumption.
|
|
||||||
*
|
|
||||||
* @return Power (Watts) consumed by this object (static component)
|
|
||||||
*/
|
|
||||||
double getStaticPower() const;
|
|
||||||
|
|
||||||
void regStats() {
|
|
||||||
dynamicPower
|
|
||||||
.method(this, &PowerModel::getDynamicPower)
|
|
||||||
.name(params()->name + ".dynamic_power")
|
|
||||||
.desc("Dynamic power for this power state")
|
|
||||||
;
|
|
||||||
|
|
||||||
staticPower
|
|
||||||
.method(this, &PowerModel::getStaticPower)
|
|
||||||
.name(params()->name + ".static_power")
|
|
||||||
.desc("Static power for this power state")
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setClockedObject(ClockedObject *clkobj);
|
|
||||||
|
|
||||||
virtual void regProbePoints();
|
|
||||||
|
|
||||||
void thermalUpdateCallback(const double & temp);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/** Listener class to catch thermal events */
|
|
||||||
class ThermalProbeListener : public ProbeListenerArgBase<double>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ThermalProbeListener(PowerModel &_pm, ProbeManager *pm,
|
|
||||||
const std::string &name)
|
|
||||||
: ProbeListenerArgBase(pm, name), pm(_pm) {}
|
|
||||||
|
|
||||||
void notify(const double &temp)
|
|
||||||
{
|
|
||||||
pm.thermalUpdateCallback(temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
PowerModel ±
|
|
||||||
};
|
|
||||||
|
|
||||||
Stats::Value dynamicPower, staticPower;
|
|
||||||
|
|
||||||
/** Actual power models (one per power state) */
|
|
||||||
std::vector<PowerModelState*> states_pm;
|
|
||||||
|
|
||||||
/** Listener to catch temperature changes in the SubSystem */
|
|
||||||
std::unique_ptr<ThermalProbeListener> thermalListener;
|
|
||||||
|
|
||||||
/** The subsystem this power model belongs to */
|
|
||||||
SubSystem * subsystem;
|
|
||||||
|
|
||||||
/** The clocked object we belong to */
|
|
||||||
ClockedObject * clocked_object;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -108,8 +108,7 @@ LinearEquation
|
||||||
ThermalDomain::getEquation(ThermalNode * tn, unsigned n, double step) const
|
ThermalDomain::getEquation(ThermalNode * tn, unsigned n, double step) const
|
||||||
{
|
{
|
||||||
LinearEquation eq(n);
|
LinearEquation eq(n);
|
||||||
double power = subsystem->getDynamicPower() + subsystem->getStaticPower();
|
|
||||||
if (tn == node)
|
if (tn == node)
|
||||||
eq[eq.cnt()] = power;
|
eq[eq.cnt()] = 1.75f; // Fake 1.75 Watts for now, to be changed to PM
|
||||||
return eq;
|
return eq;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2015 ARM Limited
|
* Copyright (c) 2014 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -37,11 +37,8 @@
|
||||||
* Authors: Geoffrey Blake
|
* Authors: Geoffrey Blake
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sim/sub_system.hh"
|
|
||||||
|
|
||||||
#include "params/SubSystem.hh"
|
#include "params/SubSystem.hh"
|
||||||
#include "sim/sub_system.hh"
|
#include "sim/sub_system.hh"
|
||||||
#include "sim/power/power_model.hh"
|
|
||||||
#include "sim/power/thermal_domain.hh"
|
#include "sim/power/thermal_domain.hh"
|
||||||
|
|
||||||
SubSystem::SubSystem(const Params *p)
|
SubSystem::SubSystem(const Params *p)
|
||||||
|
@ -52,24 +49,6 @@ SubSystem::SubSystem(const Params *p)
|
||||||
p->thermal_domain->setSubSystem(this);
|
p->thermal_domain->setSubSystem(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
|
||||||
SubSystem::getDynamicPower() const
|
|
||||||
{
|
|
||||||
double ret = 0.0f;
|
|
||||||
for (auto &obj: powerProducers)
|
|
||||||
ret += obj->getDynamicPower();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
double
|
|
||||||
SubSystem::getStaticPower() const
|
|
||||||
{
|
|
||||||
double ret = 0.0f;
|
|
||||||
for (auto &obj: powerProducers)
|
|
||||||
ret += obj->getStaticPower();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
SubSystem *
|
SubSystem *
|
||||||
SubSystemParams::create()
|
SubSystemParams::create()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2015 ARM Limited
|
* Copyright (c) 2014 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -45,14 +45,10 @@
|
||||||
#ifndef __SIM_SUB_SYSTEM_HH__
|
#ifndef __SIM_SUB_SYSTEM_HH__
|
||||||
#define __SIM_SUB_SYSTEM_HH__
|
#define __SIM_SUB_SYSTEM_HH__
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "params/SubSystem.hh"
|
#include "params/SubSystem.hh"
|
||||||
#include "sim/power/thermal_domain.hh"
|
#include "sim/power/thermal_domain.hh"
|
||||||
#include "sim/sim_object.hh"
|
#include "sim/sim_object.hh"
|
||||||
|
|
||||||
class PowerModel;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The SubSystem simobject does nothing, it is just a container for
|
* The SubSystem simobject does nothing, it is just a container for
|
||||||
* other simobjects used by the configuration system
|
* other simobjects used by the configuration system
|
||||||
|
@ -62,17 +58,6 @@ class SubSystem : public SimObject
|
||||||
public:
|
public:
|
||||||
typedef SubSystemParams Params;
|
typedef SubSystemParams Params;
|
||||||
SubSystem(const Params *p);
|
SubSystem(const Params *p);
|
||||||
|
|
||||||
double getDynamicPower() const;
|
|
||||||
|
|
||||||
double getStaticPower() const;
|
|
||||||
|
|
||||||
void registerPowerProducer(PowerModel *pm) {
|
|
||||||
powerProducers.push_back(pm);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::vector<PowerModel*> powerProducers;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue