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:
Hoa Nguyen
2024-06-17 14:05:47 -07:00
committed by GitHub
parent fef6a97f93
commit 15e0236a8b
11 changed files with 108 additions and 13 deletions

View File

@@ -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())

View File

@@ -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

View File

@@ -176,6 +176,13 @@ class InstResult
return _regClass->valString(&reg);
}
}
std::string
asString(const int64_t& num_bytes) const
{
assert(blob());
return _regClass->valString(getBlob(), num_bytes);
}
};
} // namespace gem5

View File

@@ -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.

View File

@@ -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);
}
}
};