cpu: Stop treating TraceCPU as a BaseCPU
This is fixing a recently reported issue [1] where it is not possible to use the TraceCPU to replay elastic traces It requires some architectural data structures (like ArchMMU, ArchDecoder...) which are no longer defined in the BaseCPU class at compilation time. Which Arch version should be used for a class (TraceCPU) that is supposed to be ISA agnostic ? Does it really make sense to define them for the TraceCPU? Those classes are not used anyway during trace replay and their sole purpose would just be to comply to the BaseCPU interface. As there is no elegant way to make things work, this patch stops treating the TraceCPU as a BaseCPU. While it philosophically makes sense to treat the TraceCPU as a common CPU (it sort of replays pre-executed instructions), a case can be made for considering it more like a traffic generator. [1]: https://github.com/gem5/gem5/issues/301 Change-Id: I7438169e8cc7fb6272731efb336ed2cf271c0844 Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2013 - 2016 ARM Limited
|
||||
# Copyright (c) 2013 - 2016, 2023 Arm Limited
|
||||
# All rights reserved.
|
||||
#
|
||||
# The license below extends only to copyright in the software and shall
|
||||
@@ -34,10 +34,11 @@
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from m5.params import *
|
||||
from m5.objects.BaseCPU import BaseCPU
|
||||
from m5.proxy import *
|
||||
from m5.objects.ClockedObject import ClockedObject
|
||||
|
||||
|
||||
class TraceCPU(BaseCPU):
|
||||
class TraceCPU(ClockedObject):
|
||||
"""Trace CPU model which replays traces generated in a prior simulation
|
||||
using DerivO3CPU or its derived classes. It interfaces with L1 caches.
|
||||
"""
|
||||
@@ -54,13 +55,14 @@ class TraceCPU(BaseCPU):
|
||||
def require_caches(cls):
|
||||
return True
|
||||
|
||||
def addPMU(self, pmu=None):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def support_take_over(cls):
|
||||
return True
|
||||
|
||||
system = Param.System(Parent.any, "system object")
|
||||
|
||||
icache_port = RequestPort("Instruction Port")
|
||||
dcache_port = RequestPort("Data Port")
|
||||
instTraceFile = Param.String("", "Instruction trace file")
|
||||
dataTraceFile = Param.String("", "Data dependency trace file")
|
||||
sizeStoreBuffer = Param.Unsigned(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013 - 2016 ARM Limited
|
||||
* Copyright (c) 2013 - 2016, 2023 Arm Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
@@ -47,7 +47,8 @@ namespace gem5
|
||||
int TraceCPU::numTraceCPUs = 0;
|
||||
|
||||
TraceCPU::TraceCPU(const TraceCPUParams ¶ms)
|
||||
: BaseCPU(params),
|
||||
: ClockedObject(params),
|
||||
cacheLineSize(params.system->cacheLineSize()),
|
||||
icachePort(this),
|
||||
dcachePort(this),
|
||||
instRequestorID(params.system->getRequestorId(this, "inst")),
|
||||
@@ -109,7 +110,7 @@ TraceCPU::init()
|
||||
DPRINTF(TraceCPUData, "Data memory request trace file is \"%s\".\n",
|
||||
dataTraceFile);
|
||||
|
||||
BaseCPU::init();
|
||||
ClockedObject::init();
|
||||
|
||||
// Get the send tick of the first instruction read request
|
||||
Tick first_icache_tick = icacheGen.init();
|
||||
@@ -176,7 +177,7 @@ TraceCPU::schedDcacheNext()
|
||||
DPRINTF(TraceCPUData, "DcacheGen event.\n");
|
||||
|
||||
// Update stat for numCycles
|
||||
baseStats.numCycles = clockEdge() / clockPeriod();
|
||||
traceStats.numCycles = clockEdge() / clockPeriod();
|
||||
|
||||
dcacheGen.execute();
|
||||
if (dcacheGen.isExecComplete()) {
|
||||
@@ -216,7 +217,7 @@ TraceCPU::checkAndSchedExitEvent()
|
||||
ADD_STAT(cpi, statistics::units::Rate<
|
||||
statistics::units::Cycle, statistics::units::Count>::get(),
|
||||
"Cycles per micro-op used as a proxy for CPI",
|
||||
trace->baseStats.numCycles / numOps)
|
||||
trace->traceStats.numCycles / numOps)
|
||||
{
|
||||
cpi.precision(6);
|
||||
}
|
||||
@@ -591,7 +592,7 @@ TraceCPU::ElasticDataGen::executeMemReq(GraphNode* node_ptr)
|
||||
// stat counting this is useful to keep a check on how frequently this
|
||||
// happens. If required the code could be revised to mimick splitting such
|
||||
// a request into two.
|
||||
unsigned blk_size = owner.cacheLineSize();
|
||||
unsigned blk_size = owner.cacheLineSize;
|
||||
Addr blk_offset = (node_ptr->physAddr & (Addr)(blk_size - 1));
|
||||
if (!(blk_offset + node_ptr->size <= blk_size)) {
|
||||
node_ptr->size = blk_size - blk_offset;
|
||||
@@ -1152,6 +1153,20 @@ TraceCPU::schedDcacheNextEvent(Tick when)
|
||||
|
||||
}
|
||||
|
||||
Port &
|
||||
TraceCPU::getPort(const std::string &if_name, PortID idx)
|
||||
{
|
||||
// Get the right port based on name. This applies to all the
|
||||
// subclasses of the base CPU and relies on their implementation
|
||||
// of getDataPort and getInstPort.
|
||||
if (if_name == "dcache_port")
|
||||
return getDataPort();
|
||||
else if (if_name == "icache_port")
|
||||
return getInstPort();
|
||||
else
|
||||
return ClockedObject::getPort(if_name, idx);
|
||||
}
|
||||
|
||||
bool
|
||||
TraceCPU::IcachePort::recvTimingResp(PacketPtr pkt)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013 - 2016 ARM Limited
|
||||
* Copyright (c) 2013 - 2016, 2023 Arm Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
@@ -48,10 +48,13 @@
|
||||
#include "cpu/base.hh"
|
||||
#include "debug/TraceCPUData.hh"
|
||||
#include "debug/TraceCPUInst.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/request.hh"
|
||||
#include "params/TraceCPU.hh"
|
||||
#include "proto/inst_dep_record.pb.h"
|
||||
#include "proto/packet.pb.h"
|
||||
#include "proto/protoio.hh"
|
||||
#include "sim/clocked_object.hh"
|
||||
#include "sim/sim_events.hh"
|
||||
|
||||
namespace gem5
|
||||
@@ -66,8 +69,7 @@ namespace gem5
|
||||
* simulation compared to the detailed cpu model and good correlation when the
|
||||
* same trace is used for playback on different memory sub-systems.
|
||||
*
|
||||
* The TraceCPU inherits from BaseCPU so some virtual methods need to be
|
||||
* defined. It has two port subclasses inherited from RequestPort for
|
||||
* The TraceCPU has two port subclasses inherited from RequestPort for
|
||||
* instruction and data ports. It issues the memory requests deducing the
|
||||
* timing from the trace and without performing real execution of micro-ops. As
|
||||
* soon as the last dependency for an instruction is complete, its
|
||||
@@ -139,7 +141,7 @@ namespace gem5
|
||||
* exit.
|
||||
*/
|
||||
|
||||
class TraceCPU : public BaseCPU
|
||||
class TraceCPU : public ClockedObject
|
||||
{
|
||||
|
||||
public:
|
||||
@@ -147,15 +149,6 @@ class TraceCPU : public BaseCPU
|
||||
|
||||
void init();
|
||||
|
||||
/**
|
||||
* This is a pure virtual function in BaseCPU. As we don't know how many
|
||||
* insts are in the trace but only know how how many micro-ops are we
|
||||
* cannot count this stat.
|
||||
*
|
||||
* @return 0
|
||||
*/
|
||||
Counter totalInsts() const { return 0; }
|
||||
|
||||
/**
|
||||
* Return totalOps as the number of committed micro-ops plus the
|
||||
* speculatively issued loads that are modelled in the TraceCPU replay.
|
||||
@@ -170,9 +163,6 @@ class TraceCPU : public BaseCPU
|
||||
*/
|
||||
void updateNumOps(uint64_t rob_num);
|
||||
|
||||
/* Pure virtual function in BaseCPU. Do nothing. */
|
||||
void wakeup(ThreadID tid=0) { return; }
|
||||
|
||||
/*
|
||||
* When resuming from checkpoint in FS mode, the TraceCPU takes over from
|
||||
* the old cpu. This function overrides the takeOverFrom() function in the
|
||||
@@ -303,6 +293,9 @@ class TraceCPU : public BaseCPU
|
||||
TraceCPU* owner;
|
||||
};
|
||||
|
||||
/** Cache the cache line size that we get from the system */
|
||||
const unsigned int cacheLineSize;
|
||||
|
||||
/** Port to connect to L1 instruction cache. */
|
||||
IcachePort icachePort;
|
||||
|
||||
@@ -1112,6 +1105,8 @@ class TraceCPU : public BaseCPU
|
||||
|
||||
/** Stat for number of simulated micro-ops. */
|
||||
statistics::Scalar numOps;
|
||||
/** Number of CPU cycles simulated */
|
||||
statistics::Scalar numCycles;
|
||||
/** Stat for the CPI. This is really cycles per
|
||||
* micro-op and not inst. */
|
||||
statistics::Formula cpi;
|
||||
@@ -1125,6 +1120,18 @@ class TraceCPU : public BaseCPU
|
||||
/** Used to get a reference to the dcache port. */
|
||||
Port &getDataPort() { return dcachePort; }
|
||||
|
||||
/**
|
||||
* Get a port on this CPU. All CPUs have a data and
|
||||
* instruction port, and this method uses getDataPort and
|
||||
* getInstPort of the subclasses to resolve the two ports.
|
||||
*
|
||||
* @param if_name the port name
|
||||
* @param idx ignored index
|
||||
*
|
||||
* @return a reference to the port with the given name
|
||||
*/
|
||||
Port &getPort(const std::string &if_name,
|
||||
PortID idx=InvalidPortID) override;
|
||||
};
|
||||
|
||||
} // namespace gem5
|
||||
|
||||
Reference in New Issue
Block a user