arch,cpu,sim: Add mechanism to partially print vector regs (#1234)
Currently, gem5's inst tracer prints the whole vector register container by default. The size of vector register containers in gem5 is the maximum size allowed by the ISA. For vector-length agnostic (VLA) vector registers, this means ARM SVE vector container is 2048 bits long, and RISC-V vector container is 65535 bits long. Note that VLA implementation in gem5 allows the vector length to be varied within the limit specified by the ISAs. However, in most use cases of gem5, the vector length is much less than 65535 bits. This causes two issues: (1) the vector container requires allocating and moving around a large amount of unused data while only a fraction of it is used, and (2) printing the execution trace of a vector register results in a wall of text with a small amount of useful data. This change addresses the problem (2) by providing a mechanism to limit the amount data printed by the instruction tracer. This is done by adding a function printing the first X bits of a vector register container, where X is the vector length determined at runtime, as opposed to the vector container size, which is determined at compilation time. Change-Id: I815fa5aa738373510afcfb0d544a5b19c40dc0c7 --------- Signed-off-by: Hoa Nguyen <hn@hnpl.org>
This commit is contained in:
@@ -115,10 +115,15 @@ ExeTracerRecord::traceInst(const StaticInstPtr &inst, bool ran)
|
||||
}
|
||||
|
||||
if (debug::ExecResult && dataStatus != DataInvalid) {
|
||||
if (dataStatus == DataReg)
|
||||
ccprintf(outs, " D=%s", data.asReg.asString());
|
||||
else
|
||||
if (dataStatus == DataReg) {
|
||||
if (vectorLengthInBytes > 0 && inst->isVector()) {
|
||||
outs << " D=" << data.asReg.asString(vectorLengthInBytes);
|
||||
} else {
|
||||
ccprintf(outs, " D=%s", data.asReg.asString());
|
||||
}
|
||||
} else {
|
||||
ccprintf(outs, " D=%#018x", data.asInt);
|
||||
}
|
||||
}
|
||||
|
||||
if (debug::ExecEffAddr && getMemValid())
|
||||
|
||||
@@ -66,6 +66,7 @@ class ExeTracerRecord : public InstRecord
|
||||
: InstRecord(_when, _thread, _staticInst, _pc, _macroStaticInst),
|
||||
tracer(_tracer)
|
||||
{
|
||||
vectorLengthInBytes = _thread->getIsaPtr()->getVectorLengthInBytes();
|
||||
}
|
||||
|
||||
void traceInst(const StaticInstPtr &inst, bool ran);
|
||||
@@ -74,6 +75,7 @@ class ExeTracerRecord : public InstRecord
|
||||
|
||||
protected:
|
||||
const ExeTracer &tracer;
|
||||
int64_t vectorLengthInBytes;
|
||||
};
|
||||
|
||||
class ExeTracer : public InstTracer
|
||||
|
||||
@@ -176,6 +176,13 @@ class InstResult
|
||||
return _regClass->valString(®);
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
asString(const int64_t& num_bytes) const
|
||||
{
|
||||
assert(blob());
|
||||
return _regClass->valString(getBlob(), num_bytes);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gem5
|
||||
|
||||
@@ -56,7 +56,7 @@ RegClassOps::regName(const RegId &id) const
|
||||
}
|
||||
|
||||
std::string
|
||||
RegClassOps::valString(const void *val, size_t size) const
|
||||
RegClassOps::valString(const void *val, const size_t& size) const
|
||||
{
|
||||
// If this is just a RegVal, or could be interpreted as one, print it
|
||||
// that way.
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
|
||||
#include "arch/generic/vec_reg.hh"
|
||||
#include "base/cprintf.hh"
|
||||
#include "base/debug.hh"
|
||||
#include "base/intmath.hh"
|
||||
@@ -170,7 +171,7 @@ class RegClassOps
|
||||
/** Print the name of the register specified in id. */
|
||||
virtual std::string regName(const RegId &id) const;
|
||||
/** Print the value of a register pointed to by val of size size. */
|
||||
virtual std::string valString(const void *val, size_t size) const;
|
||||
virtual std::string valString(const void *val, const size_t& size) const;
|
||||
/** Flatten register id id using information in the ISA object isa. */
|
||||
virtual RegId
|
||||
flatten(const BaseISA &isa, const RegId &id) const
|
||||
@@ -246,6 +247,11 @@ class RegClass
|
||||
{
|
||||
return _ops->valString(val, regBytes());
|
||||
}
|
||||
std::string
|
||||
valString(const void *val, const uint64_t& num_bytes) const
|
||||
{
|
||||
return _ops->valString(val, std::min(regBytes(), num_bytes));
|
||||
}
|
||||
RegId
|
||||
flatten(const BaseISA &isa, const RegId &id) const
|
||||
{
|
||||
@@ -354,15 +360,30 @@ RegClass::operator[](RegIndex idx) const
|
||||
return RegId(*this, idx);
|
||||
}
|
||||
|
||||
// Type matching for gem5::VecRegContainer class
|
||||
// This is used in TypedRegClassOps.
|
||||
template<typename>
|
||||
struct is_vec_reg_container : std::false_type {};
|
||||
template<std::size_t SIZE>
|
||||
struct is_vec_reg_container<gem5::VecRegContainer<SIZE>> : std::true_type {};
|
||||
|
||||
template <typename ValueType>
|
||||
class TypedRegClassOps : public RegClassOps
|
||||
{
|
||||
public:
|
||||
std::string
|
||||
valString(const void *val, size_t size) const override
|
||||
valString(const void *val, const size_t& size) const override
|
||||
{
|
||||
assert(size == sizeof(ValueType));
|
||||
return csprintf("%s", *(const ValueType *)val);
|
||||
if constexpr (is_vec_reg_container<ValueType>::value) {
|
||||
if (size == sizeof(ValueType)) {
|
||||
return csprintf("%s", *(const ValueType *)val);
|
||||
} else {
|
||||
return ((const ValueType *)val)->getString(size);
|
||||
}
|
||||
} else {
|
||||
assert(size == sizeof(ValueType));
|
||||
return csprintf("%s", *(const ValueType *)val);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user