tests,mem-ruby: Enhance ruby false sharing test with Atomics

New ruby mem test includes a percentages of AMOs that will be executed randomly in ruby mem test

Change-Id: Ie95ed78e59ea773ce6b59060eaece3701fe4478c
This commit is contained in:
Víctor Soria
2023-07-24 16:20:10 +02:00
parent 6f5d877b1a
commit 4fd9d66c53
5 changed files with 81 additions and 14 deletions

View File

@@ -62,6 +62,12 @@ parser.add_argument(
default=0,
help="percentage of accesses that should be functional",
)
parser.add_argument(
"--atomic",
type=int,
default=30,
help="percentage of accesses that should be atomic",
)
parser.add_argument(
"--suppress-func-errors",
action="store_true",
@@ -105,6 +111,7 @@ cpus = [
max_loads=args.maxloads,
percent_functional=args.functional,
percent_uncacheable=0,
percent_atomic=args.atomic,
progress_interval=args.progress,
suppress_func_errors=args.suppress_func_errors,
)
@@ -133,7 +140,7 @@ else:
dmas = []
dma_ports = []
for (i, dma) in enumerate(dmas):
for i, dma in enumerate(dmas):
dma_ports.append(dma.test)
Ruby.create_system(args, False, system, dma_ports=dma_ports)
@@ -155,7 +162,7 @@ system.ruby.randomization = True
assert len(cpus) == len(system.ruby._cpu_ports)
for (i, cpu) in enumerate(cpus):
for i, cpu in enumerate(cpus):
#
# Tie the cpu memtester ports to the correct system ports
#

View File

@@ -63,6 +63,7 @@ class MemTest(ClockedObject):
percent_reads = Param.Percent(65, "Percentage reads")
percent_functional = Param.Percent(50, "Percentage functional accesses")
percent_uncacheable = Param.Percent(10, "Percentage uncacheable")
percent_atomic = Param.Percent(50, "Percentage atomics")
# Determine how often to print progress messages and what timeout
# to use for checking progress of both requests and responses

View File

@@ -94,6 +94,7 @@ MemTest::MemTest(const Params &p)
percentReads(p.percent_reads),
percentFunctional(p.percent_functional),
percentUncacheable(p.percent_uncacheable),
percentAtomic(p.percent_atomic),
requestorId(p.system->getRequestorId(this)),
blockSize(p.system->cacheLineSize()),
blockAddrMask(blockSize - 1),
@@ -115,6 +116,7 @@ MemTest::MemTest(const Params &p)
// set up counters
numReads = 0;
numWrites = 0;
numAtomics = 0;
// kick things into action
schedule(tickEvent, curTick());
@@ -142,7 +144,7 @@ MemTest::completeRequest(PacketPtr pkt, bool functional)
outstandingAddrs.erase(remove_addr);
DPRINTF(MemTest, "Completing %s at address %x (blk %x) %s\n",
pkt->isWrite() ? "write" : "read",
pkt->isWrite() ? pkt->isAtomicOp() ? "atomic" : "write" : "read",
req->getPaddr(), blockAlign(req->getPaddr()),
pkt->isError() ? "error" : "success");
@@ -153,7 +155,25 @@ MemTest::completeRequest(PacketPtr pkt, bool functional)
panic( "%s access failed at %#x\n",
pkt->isWrite() ? "Write" : "Read", req->getPaddr());
} else {
if (pkt->isRead()) {
if (pkt->isAtomicOp()) {
uint8_t ref_data = referenceData[req->getPaddr()];
if (pkt_data[0] != ref_data) {
panic("%s: read of %x (blk %x) @ cycle %d "
"returns %x, expected %x\n", name(),
req->getPaddr(), blockAlign(req->getPaddr()), curTick(),
pkt_data[0], ref_data);
}
DPRINTF(MemTest,
"Completing atomic at address %x (blk %x) value %x\n",
req->getPaddr(), blockAlign(req->getPaddr()),
pkt_data[0]);
referenceData[req->getPaddr()] =
atomicPendingData[req->getPaddr()];
numAtomics++;
stats.numAtomics++;
} else if (pkt->isRead()) {
uint8_t ref_data = referenceData[req->getPaddr()];
if (pkt_data[0] != ref_data) {
panic("%s: read of %x (blk %x) @ cycle %d "
@@ -167,9 +187,10 @@ MemTest::completeRequest(PacketPtr pkt, bool functional)
if (numReads == (uint64_t)nextProgressMessage) {
ccprintf(std::cerr,
"%s: completed %d read, %d write accesses @%d\n",
name(), numReads, numWrites, curTick());
nextProgressMessage += progressInterval;
"%s: completed %d read, %d write, "
"%d atomic accesses @%d\n",
name(), numReads, numWrites, numAtomics, curTick());
nextProgressMessage += progressInterval;
}
if (maxLoads != 0 && numReads >= maxLoads)
@@ -205,7 +226,9 @@ MemTest::MemTestStats::MemTestStats(statistics::Group *parent)
ADD_STAT(numReads, statistics::units::Count::get(),
"number of read accesses completed"),
ADD_STAT(numWrites, statistics::units::Count::get(),
"number of write accesses completed")
"number of write accesses completed"),
ADD_STAT(numAtomics, statistics::units::Count::get(),
"number of atomic accesses completed")
{
}
@@ -221,6 +244,8 @@ MemTest::tick()
unsigned cmd = random_mt.random(0, 100);
uint8_t data = random_mt.random<uint8_t>();
bool uncacheable = random_mt.random(0, 100) < percentUncacheable;
bool do_atomic = (random_mt.random(0, 100) < percentAtomic) &&
!uncacheable;
unsigned base = random_mt.random(0, 1);
Request::Flags flags;
Addr paddr;
@@ -281,13 +306,36 @@ MemTest::tick()
pkt = new Packet(req, MemCmd::ReadReq);
pkt->dataDynamic(pkt_data);
} else {
DPRINTF(MemTest, "Initiating %swrite at addr %x (blk %x) value %x\n",
do_functional ? "functional " : "", req->getPaddr(),
blockAlign(req->getPaddr()), data);
if (do_atomic) {
DPRINTF(MemTest,
"Initiating atomic at addr %x (blk %x) value %x\n",
req->getPaddr(), blockAlign(req->getPaddr()), data);
pkt = new Packet(req, MemCmd::WriteReq);
pkt->dataDynamic(pkt_data);
pkt_data[0] = data;
TypedAtomicOpFunctor<uint8_t> *_amo_op =
new AtomicGeneric3Op<uint8_t>(
data, data,
[](uint8_t* b, uint8_t a, uint8_t c){
*b = c;
});
assert(_amo_op);
AtomicOpFunctorPtr amo_op = AtomicOpFunctorPtr(_amo_op);
req->setAtomicOpFunctor(std::move(amo_op));
req->setFlags(Request::ATOMIC_RETURN_OP);
pkt = new Packet(req, MemCmd::WriteReq);
pkt->dataDynamic(pkt_data);
pkt_data[0] = data;
atomicPendingData[req->getPaddr()] = data;
} else {
DPRINTF(MemTest,
"Initiating %swrite at addr %x (blk %x) value %x\n",
do_functional ? "functional " : "", req->getPaddr(),
blockAlign(req->getPaddr()), data);
pkt = new Packet(req, MemCmd::WriteReq);
pkt->dataDynamic(pkt_data);
pkt_data[0] = data;
}
}
// there is no point in ticking if we are waiting for a retry

View File

@@ -131,6 +131,7 @@ class MemTest : public ClockedObject
const unsigned percentReads;
const unsigned percentFunctional;
const unsigned percentUncacheable;
const unsigned percentAtomic;
/** Request id for all generated traffic */
RequestorID requestorId;
@@ -138,6 +139,7 @@ class MemTest : public ClockedObject
unsigned int id;
std::unordered_set<Addr> outstandingAddrs;
std::unordered_map<Addr, uint8_t> atomicPendingData;
// store the expected value for the addresses we have touched
std::unordered_map<Addr, uint8_t> referenceData;
@@ -169,6 +171,7 @@ class MemTest : public ClockedObject
uint64_t numReads;
uint64_t numWrites;
uint64_t numAtomics;
const uint64_t maxLoads;
const bool atomic;
@@ -180,6 +183,7 @@ class MemTest : public ClockedObject
MemTestStats(statistics::Group *parent);
statistics::Scalar numReads;
statistics::Scalar numWrites;
statistics::Scalar numAtomics;
} stats;
/**

View File

@@ -757,6 +757,13 @@ class Request : public Extensible<Request>
return atomicOpFunctor.get();
}
void
setAtomicOpFunctor(AtomicOpFunctorPtr amo_op)
{
atomicOpFunctor = std::move(amo_op);
}
/**
* Accessor for hardware transactional memory abort cause.
*/