cpu: Adding GUPSGen ClockedObject.
This patch adds the code base to implement GUPSGen which is a ClockedObject that creates read/write requests to the memory to update elements in an array. The choosing of elements in the array follow a random distribution. Each element is read from and return as GUPSGen implements a key-value store program. Specifications are found in HPCC website from RandomAccess benchmark. link below. https://icl.cs.utk.edu/projectsfiles/hpcc/RandomAccess/ Change-Id: I5c07f230bee317fff2cceec04d15d0218e8ede9a Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/47439 Reviewed-by: Jason Lowe-Power <power.jg@gmail.com> Reviewed-by: Bobby R. Bruce <bbruce@ucdavis.edu> Maintainer: Jason Lowe-Power <power.jg@gmail.com> Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
60
src/cpu/testers/traffic_gen/GUPSGen.py
Normal file
60
src/cpu/testers/traffic_gen/GUPSGen.py
Normal file
@@ -0,0 +1,60 @@
|
||||
# Copyright (c) 2021 The Regents of the University of California.
|
||||
# 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.
|
||||
#
|
||||
|
||||
from m5.params import *
|
||||
from m5.proxy import *
|
||||
from m5.objects.ClockedObject import ClockedObject
|
||||
|
||||
class GUPSGen(ClockedObject):
|
||||
"""
|
||||
This ClockedObject implements the RandomAccess benchmark specified by HPCC
|
||||
benchmarks in https://icl.utk.edu/projectsfiles/hpcc/RandomAccess.
|
||||
"""
|
||||
type = 'GUPSGen'
|
||||
cxx_header = "cpu/testers/traffic_gen/gups_gen.hh"
|
||||
cxx_class = "gem5::GUPSGen"
|
||||
|
||||
system = Param.System(Parent.any, 'System this generator is a part of')
|
||||
|
||||
port = RequestPort('Port that should be connected to other components')
|
||||
|
||||
start_addr = Param.Addr(0, 'Start address for allocating update table,'
|
||||
' should be a multiple of block_size')
|
||||
|
||||
mem_size = Param.MemorySize('Size for allocating update table, based on'
|
||||
' randomAccess benchmark specification, this'
|
||||
' should be equal to half of total system memory'
|
||||
' ,also should be a power of 2')
|
||||
|
||||
update_limit = Param.Int(0, 'The number of updates to issue before the'
|
||||
' simulation is over')
|
||||
|
||||
request_queue_size = Param.Int(1024, 'Maximum number of parallel'
|
||||
' outstanding requests')
|
||||
|
||||
init_memory = Param.Bool(False, 'Whether or not to initialize the memory,'
|
||||
' it does not effect the performance')
|
||||
@@ -43,6 +43,7 @@ Source('base_gen.cc')
|
||||
Source('dram_gen.cc')
|
||||
Source('dram_rot_gen.cc')
|
||||
Source('exit_gen.cc')
|
||||
Source('gups_gen.cc')
|
||||
Source('hybrid_gen.cc')
|
||||
Source('idle_gen.cc')
|
||||
Source('linear_gen.cc')
|
||||
@@ -54,6 +55,9 @@ Source('strided_gen.cc')
|
||||
DebugFlag('TrafficGen')
|
||||
SimObject('BaseTrafficGen.py')
|
||||
|
||||
DebugFlag('GUPSGen')
|
||||
SimObject('GUPSGen.py')
|
||||
|
||||
if env['USE_PYTHON']:
|
||||
Source('pygen.cc', add_tags='python')
|
||||
SimObject('PyTrafficGen.py')
|
||||
|
||||
373
src/cpu/testers/traffic_gen/gups_gen.cc
Normal file
373
src/cpu/testers/traffic_gen/gups_gen.cc
Normal file
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The Regents of the University of California.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "cpu/testers/traffic_gen/gups_gen.hh"
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "base/random.hh"
|
||||
#include "debug/GUPSGen.hh"
|
||||
#include "sim/sim_exit.hh"
|
||||
|
||||
namespace gem5
|
||||
{
|
||||
|
||||
GUPSGen::GUPSGen(const GUPSGenParams& params):
|
||||
ClockedObject(params),
|
||||
nextCreateEvent([this]{ createNextReq(); }, name()),
|
||||
nextSendEvent([this]{ sendNextReq(); }, name()),
|
||||
system(params.system),
|
||||
requestorId(system->getRequestorId(this)),
|
||||
port(name() + ".port", this),
|
||||
startAddr(params.start_addr),
|
||||
memSize(params.mem_size),
|
||||
updateLimit(params.update_limit),
|
||||
elementSize(sizeof(uint64_t)), // every element in the table is a uint64_t
|
||||
reqQueueSize(params.request_queue_size),
|
||||
initMemory(params.init_memory),
|
||||
stats(this)
|
||||
{}
|
||||
|
||||
Port&
|
||||
GUPSGen::getPort(const std::string &if_name, PortID idx)
|
||||
{
|
||||
if (if_name != "port") {
|
||||
return ClockedObject::getPort(if_name, idx);
|
||||
} else {
|
||||
return port;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GUPSGen::init()
|
||||
{
|
||||
doneReading = false;
|
||||
onTheFlyRequests = 0;
|
||||
readRequests = 0;
|
||||
|
||||
tableSize = memSize / elementSize;
|
||||
numUpdates = 4 * tableSize;
|
||||
}
|
||||
|
||||
void
|
||||
GUPSGen::startup()
|
||||
{
|
||||
int block_size = 64; // Write the initial values in 64 byte blocks.
|
||||
uint64_t stride_size = block_size / elementSize;
|
||||
if (initMemory) {
|
||||
for (uint64_t start_index = 0; start_index < tableSize;
|
||||
start_index += stride_size) {
|
||||
uint8_t write_data[block_size];
|
||||
for (uint64_t offset = 0; offset < stride_size; offset++) {
|
||||
uint64_t value = start_index + offset;
|
||||
std::memcpy(write_data + offset * elementSize,
|
||||
&value, elementSize);
|
||||
}
|
||||
Addr addr = indexToAddr(start_index);
|
||||
PacketPtr pkt = getWritePacket(addr, block_size, write_data);
|
||||
port.sendFunctionalPacket(pkt);
|
||||
delete pkt;
|
||||
}
|
||||
}
|
||||
schedule(nextCreateEvent, nextCycle());
|
||||
}
|
||||
|
||||
Addr
|
||||
GUPSGen::indexToAddr (uint64_t index)
|
||||
{
|
||||
Addr ret = index * elementSize + startAddr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
PacketPtr
|
||||
GUPSGen::getReadPacket(Addr addr, unsigned int size)
|
||||
{
|
||||
RequestPtr req = std::make_shared<Request>(addr, size, 0, requestorId);
|
||||
// Dummy PC to have PC-based prefetchers latch on; get entropy into higher
|
||||
// bits
|
||||
req->setPC(((Addr)requestorId) << 2);
|
||||
|
||||
// Embed it in a packet
|
||||
PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
|
||||
pkt->allocate();
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
||||
PacketPtr
|
||||
GUPSGen::getWritePacket(Addr addr, unsigned int size, uint8_t *data)
|
||||
{
|
||||
RequestPtr req = std::make_shared<Request>(addr, size, 0,
|
||||
requestorId);
|
||||
// Dummy PC to have PC-based prefetchers latch on; get entropy into higher
|
||||
// bits
|
||||
req->setPC(((Addr)requestorId) << 2);
|
||||
|
||||
PacketPtr pkt = new Packet(req, MemCmd::WriteReq);
|
||||
pkt->allocate();
|
||||
pkt->setData(data);
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
||||
void
|
||||
GUPSGen::handleResponse(PacketPtr pkt)
|
||||
{
|
||||
onTheFlyRequests--;
|
||||
DPRINTF(GUPSGen, "%s: onTheFlyRequests: %d.\n",
|
||||
__func__, onTheFlyRequests);
|
||||
if (pkt->isWrite()) {
|
||||
DPRINTF(GUPSGen, "%s: received a write resp. pkt->addr_range: %s,"
|
||||
" pkt->data: %d\n", __func__,
|
||||
pkt->getAddrRange().to_string(),
|
||||
*pkt->getPtr<uint64_t>());
|
||||
stats.totalUpdates++;
|
||||
stats.totalWrites++;
|
||||
stats.totalBytesWritten += elementSize;
|
||||
stats.totalWriteLat += curTick() - exitTimes[pkt->req];
|
||||
|
||||
exitTimes.erase(pkt->req);
|
||||
delete pkt;
|
||||
} else {
|
||||
DPRINTF(GUPSGen, "%s: received a read resp. pkt->addr_range: %s\n",
|
||||
__func__, pkt->getAddrRange().to_string());
|
||||
|
||||
stats.totalReads++;
|
||||
stats.totalBytesRead += elementSize;
|
||||
stats.totalReadLat += curTick() - exitTimes[pkt->req];
|
||||
|
||||
exitTimes.erase(pkt->req);
|
||||
|
||||
responsePool.push(pkt);
|
||||
}
|
||||
if (doneReading && requestPool.empty() && onTheFlyRequests == 0) {
|
||||
exitSimLoop(name() + " is finished updating the memory.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((requestPool.size() < reqQueueSize) &&
|
||||
(!doneReading || !responsePool.empty()) &&
|
||||
!nextCreateEvent.scheduled())
|
||||
{
|
||||
schedule(nextCreateEvent, nextCycle());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GUPSGen::wakeUp()
|
||||
{
|
||||
if (!nextSendEvent.scheduled() && !requestPool.empty()) {
|
||||
schedule(nextSendEvent, nextCycle());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GUPSGen::createNextReq()
|
||||
{
|
||||
// Prioritize pending writes over reads
|
||||
// Write as soon as the data is read
|
||||
if (!responsePool.empty()) {
|
||||
PacketPtr pkt = responsePool.front();
|
||||
responsePool.pop();
|
||||
|
||||
uint64_t *updated_value = pkt->getPtr<uint64_t>();
|
||||
DPRINTF(GUPSGen, "%s: Read value %lu from address %s", __func__,
|
||||
*updated_value, pkt->getAddrRange().to_string());
|
||||
*updated_value ^= updateTable[pkt->req];
|
||||
updateTable.erase(pkt->req);
|
||||
Addr addr = pkt->getAddr();
|
||||
PacketPtr new_pkt = getWritePacket(addr,
|
||||
elementSize, (uint8_t*) updated_value);
|
||||
delete pkt;
|
||||
requestPool.push(new_pkt);
|
||||
} else if (!doneReading) {
|
||||
// If no writes then read
|
||||
// Check to make sure we're not reading more than we should.
|
||||
assert (readRequests < numUpdates);
|
||||
|
||||
uint64_t value = readRequests;
|
||||
uint64_t index = random_mt.random((int64_t) 0, tableSize);
|
||||
Addr addr = indexToAddr(index);
|
||||
PacketPtr pkt = getReadPacket(addr, elementSize);
|
||||
updateTable[pkt->req] = value;
|
||||
requestPool.push(pkt);
|
||||
readRequests++;
|
||||
|
||||
if (readRequests >= numUpdates) {
|
||||
DPRINTF(GUPSGen, "%s: Done creating reads.\n", __func__);
|
||||
doneReading = true;
|
||||
}
|
||||
else if (readRequests == updateLimit && updateLimit != 0) {
|
||||
DPRINTF(GUPSGen, "%s: Update limit reached.\n", __func__);
|
||||
doneReading = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!nextCreateEvent.scheduled() &&
|
||||
(requestPool.size() < reqQueueSize) &&
|
||||
(!doneReading || !responsePool.empty()))
|
||||
{
|
||||
schedule(nextCreateEvent, nextCycle());
|
||||
}
|
||||
|
||||
if (!nextSendEvent.scheduled() && !requestPool.empty()) {
|
||||
schedule(nextSendEvent, nextCycle());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GUPSGen::sendNextReq()
|
||||
{
|
||||
if (!port.blocked()) {
|
||||
PacketPtr pkt = requestPool.front();
|
||||
|
||||
exitTimes[pkt->req] = curTick();
|
||||
if (pkt->isWrite()) {
|
||||
DPRINTF(GUPSGen, "%s: Sent write pkt, pkt->addr_range: "
|
||||
"%s, pkt->data: %lu.\n", __func__,
|
||||
pkt->getAddrRange().to_string(),
|
||||
*pkt->getPtr<uint64_t>());
|
||||
} else {
|
||||
DPRINTF(GUPSGen, "%s: Sent read pkt, pkt->addr_range: %s.\n",
|
||||
__func__, pkt->getAddrRange().to_string());
|
||||
}
|
||||
port.sendTimingPacket(pkt);
|
||||
onTheFlyRequests++;
|
||||
DPRINTF(GUPSGen, "%s: onTheFlyRequests: %d.\n",
|
||||
__func__, onTheFlyRequests);
|
||||
requestPool.pop();
|
||||
}
|
||||
|
||||
if (!nextCreateEvent.scheduled() &&
|
||||
(requestPool.size() < reqQueueSize) &&
|
||||
(!doneReading || !responsePool.empty()))
|
||||
{
|
||||
schedule(nextCreateEvent, nextCycle());
|
||||
}
|
||||
|
||||
if (!nextSendEvent.scheduled()) {
|
||||
if (!requestPool.empty()) {
|
||||
schedule(nextSendEvent, nextCycle());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GUPSGen::GenPort::sendTimingPacket(PacketPtr pkt)
|
||||
{
|
||||
panic_if(_blocked, "Should never try to send if blocked MemSide!");
|
||||
|
||||
// If we can't send the packet across the port, store it for later.
|
||||
if (!sendTimingReq(pkt)) {
|
||||
DPRINTF(GUPSGen, "GenPort::%s: Packet blocked\n", __func__);
|
||||
blockedPacket = pkt;
|
||||
_blocked = true;
|
||||
} else {
|
||||
DPRINTF(GUPSGen, "GenPort::%s: Packet sent\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GUPSGen::GenPort::sendFunctionalPacket(PacketPtr pkt)
|
||||
{
|
||||
sendFunctional(pkt);
|
||||
}
|
||||
|
||||
void
|
||||
GUPSGen::GenPort::recvReqRetry()
|
||||
{
|
||||
// We should have a blocked packet if this function is called.
|
||||
DPRINTF(GUPSGen, "GenPort::%s: Received a retry.\n", __func__);
|
||||
|
||||
assert(_blocked && (blockedPacket != nullptr));
|
||||
// Try to resend it. It's possible that it fails again.
|
||||
_blocked = false;
|
||||
sendTimingPacket(blockedPacket);
|
||||
if (!_blocked){
|
||||
blockedPacket = nullptr;
|
||||
}
|
||||
|
||||
owner->wakeUp();
|
||||
}
|
||||
|
||||
bool
|
||||
GUPSGen::GenPort::recvTimingResp(PacketPtr pkt)
|
||||
{
|
||||
owner->handleResponse(pkt);
|
||||
return true;
|
||||
}
|
||||
|
||||
GUPSGen::GUPSGenStat::GUPSGenStat(GUPSGen* parent):
|
||||
Stats::Group(parent),
|
||||
ADD_STAT(totalUpdates, UNIT_COUNT,
|
||||
"Total number of updates the generator made in the memory"),
|
||||
ADD_STAT(GUPS, UNIT_RATE(Stats::Units::Count, Stats::Units::Second),
|
||||
"Rate of billion updates per second"),
|
||||
ADD_STAT(totalReads, UNIT_COUNT,
|
||||
"Total number of read requests"),
|
||||
ADD_STAT(totalBytesRead, UNIT_BYTE,
|
||||
"Total number of bytes read"),
|
||||
ADD_STAT(avgReadBW, UNIT_RATE(Stats::Units::Byte, Stats::Units::Second),
|
||||
"Average read bandwidth received from memory"),
|
||||
ADD_STAT(totalReadLat, UNIT_TICK,
|
||||
"Total latency of read requests."),
|
||||
ADD_STAT(avgReadLat, UNIT_TICK,
|
||||
"Average latency for read requests"),
|
||||
ADD_STAT(totalWrites, UNIT_COUNT,
|
||||
"Total number of write requests"),
|
||||
ADD_STAT(totalBytesWritten, UNIT_BYTE,
|
||||
"Total number of bytes written"),
|
||||
ADD_STAT(avgWriteBW, UNIT_RATE(Stats::Units::Byte, Stats::Units::Second),
|
||||
"Average write bandwidth received from memory"),
|
||||
ADD_STAT(totalWriteLat, UNIT_TICK,
|
||||
"Total latency of write requests."),
|
||||
ADD_STAT(avgWriteLat, UNIT_TICK,
|
||||
"Average latency for write requests")
|
||||
{}
|
||||
|
||||
void
|
||||
GUPSGen::GUPSGenStat::regStats()
|
||||
{
|
||||
GUPS.precision(8);
|
||||
avgReadBW.precision(2);
|
||||
avgReadLat.precision(2);
|
||||
avgWriteBW.precision(2);
|
||||
avgWriteLat.precision(2);
|
||||
|
||||
GUPS = (totalUpdates / 1e9) / simSeconds;
|
||||
|
||||
avgReadBW = totalBytesRead / simSeconds;
|
||||
avgReadLat = (totalReadLat) / totalReads;
|
||||
|
||||
avgWriteBW = totalBytesWritten / simSeconds;
|
||||
avgWriteLat = (totalWriteLat) / totalWrites;
|
||||
}
|
||||
|
||||
}
|
||||
335
src/cpu/testers/traffic_gen/gups_gen.hh
Normal file
335
src/cpu/testers/traffic_gen/gups_gen.hh
Normal file
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The Regents of the University of California.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __CPU_TESTERS_TRAFFIC_GEN_GUPS_GEN_HH__
|
||||
#define __CPU_TESTERS_TRAFFIC_GEN_GUPS_GEN_HH__
|
||||
|
||||
/**
|
||||
* @file gups_gen.hh
|
||||
* Contatins the description of the class GUPSGen. GUPSGen is a simobject
|
||||
* that will generate a memory access pattern to that of RandomAccess benchmark
|
||||
* specified by HPCC benchmarks.
|
||||
* Find more details: [https://icl.cs.utk.edu/projectsfiles/hpcc/RandomAccess/]
|
||||
*/
|
||||
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "base/statistics.hh"
|
||||
#include "mem/port.hh"
|
||||
#include "params/GUPSGen.hh"
|
||||
#include "sim/clocked_object.hh"
|
||||
#include "sim/system.hh"
|
||||
|
||||
namespace gem5
|
||||
{
|
||||
|
||||
class GUPSGen : public ClockedObject
|
||||
{
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief definition of the GenPort class which is of the type RequestPort.
|
||||
* It defines the functionalities required for outside communication of
|
||||
* memory packets from the GUPSGen simobject. It also implements
|
||||
* functionalities of receiving responses from outside.
|
||||
*/
|
||||
class GenPort : public RequestPort
|
||||
{
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief Pointer to the GUPSGen this port belongs to
|
||||
*/
|
||||
GUPSGen *owner;
|
||||
|
||||
/**
|
||||
* @brief Boolean value to remember if the port is previously blocked
|
||||
* and is occupied by a previous request, it should not accept new
|
||||
* requests if it is blocked, instead, it will be freed by a
|
||||
* recvReqRetry call from outside.
|
||||
*/
|
||||
bool _blocked;
|
||||
|
||||
/**
|
||||
* @brief Pointer to the blocked packet in the port. It is initialized
|
||||
* as nullptr and will be set to the address of the packet which is
|
||||
* blocked. It will reset upon recvReqRetry call.
|
||||
*/
|
||||
PacketPtr blockedPacket;
|
||||
|
||||
public:
|
||||
|
||||
GenPort(const std::string& name, GUPSGen *owner) :
|
||||
RequestPort(name, owner), owner(owner), _blocked(false),
|
||||
blockedPacket(nullptr)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Return whether the port is blocked.
|
||||
*
|
||||
* @return true if the port is blocked.
|
||||
* @return false if the port is free.
|
||||
*/
|
||||
bool blocked(){
|
||||
return _blocked;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function send a timing request to the port's peer
|
||||
* responsePort
|
||||
* @param pkt Pointer to the packet for the timing request
|
||||
*/
|
||||
void sendTimingPacket(PacketPtr pkt);
|
||||
|
||||
/**
|
||||
* @brief This function send a functional request to the port's peer
|
||||
* responsePort
|
||||
* @param pkt Pointer to the packet for the timing request
|
||||
*/
|
||||
void sendFunctionalPacket(PacketPtr pkt);
|
||||
|
||||
protected:
|
||||
|
||||
bool recvTimingResp(PacketPtr pkt) override;
|
||||
|
||||
void recvReqRetry() override;
|
||||
};
|
||||
|
||||
virtual void init() override;
|
||||
|
||||
virtual void startup() override;
|
||||
|
||||
/**
|
||||
* @brief Convert and index from array to its physical address
|
||||
* in the memory
|
||||
* @param index Index of the element in the array
|
||||
* @return Addr Physical address corresponding to the index.
|
||||
*/
|
||||
Addr indexToAddr (uint64_t index);
|
||||
|
||||
/**
|
||||
* @brief Generate a read request to be sent to the outside.
|
||||
*
|
||||
* @param addr Physical address to which the request is sent to
|
||||
* @param size The number of bytes to be read by the request.
|
||||
* @return Pointer to the generated packet. This packet includes
|
||||
* the request to the outside.
|
||||
*/
|
||||
PacketPtr getReadPacket(Addr addr, unsigned int size);
|
||||
|
||||
/**
|
||||
* @brief Generate a write request to be sent to the outside.
|
||||
*
|
||||
* @param addr Physical address to which the request is sent to
|
||||
* @param size The number of bytes to be written by the request.
|
||||
* @param data Pointer to the data that should be written.
|
||||
* @return Pointer to the generated packet. This packet includes
|
||||
* the request to the outside.
|
||||
*/
|
||||
PacketPtr getWritePacket(Addr addr, unsigned int size, uint8_t* data);
|
||||
|
||||
/**
|
||||
* @brief Handles the incoming responses from the outside.
|
||||
* @param pkt Pointer to the packet that includes the response.
|
||||
*/
|
||||
void handleResponse(PacketPtr pkt);
|
||||
|
||||
/**
|
||||
* @brief This function allows the port to wake its owner GUPSGen object
|
||||
* in case it has stopped working due to back pressure, it will wake up
|
||||
* as soon as back pressure is resolved.
|
||||
*/
|
||||
void wakeUp();
|
||||
|
||||
/**
|
||||
* @brief Create the next request and store in the requestPool.
|
||||
*/
|
||||
void createNextReq();
|
||||
|
||||
/**
|
||||
* @brief Corresponding event to the createNextReq function. Scheduled
|
||||
* whenever a request needs to and can be created.
|
||||
*/
|
||||
EventFunctionWrapper nextCreateEvent;
|
||||
|
||||
/**
|
||||
* @brief Send outstanding requests from requestPool to the port.
|
||||
*/
|
||||
void sendNextReq();
|
||||
|
||||
/**
|
||||
* @brief Corresponding event to the sendNextReq function. Scheduled
|
||||
* whenever a request needs to and can be sent.
|
||||
*/
|
||||
EventFunctionWrapper nextSendEvent;
|
||||
|
||||
/**
|
||||
* @brief Use an unordered map to store future updates on current reads
|
||||
* as the updated value depends on the index which is know when a read
|
||||
* request is created. The respective write will use the value stored to
|
||||
* update the value.
|
||||
*/
|
||||
std::unordered_map<RequestPtr, uint64_t> updateTable;
|
||||
|
||||
/**
|
||||
* @brief Use an unordered map to track the time at which each request
|
||||
* exits the GUPSGen. This is useful when we need to compute request
|
||||
* latency.
|
||||
*/
|
||||
std::unordered_map<RequestPtr, Tick> exitTimes;
|
||||
|
||||
/**
|
||||
* @brief A queue to store the outstanding requests whether read or write.
|
||||
* The element at the front of the queue is sent to outside everytime
|
||||
* nextSendEvent is scheduled.
|
||||
*/
|
||||
std::queue<PacketPtr> requestPool;
|
||||
|
||||
/**
|
||||
* @brief A queue to store response packets from reads. each response in
|
||||
* the response pool will generate a write request. The write request
|
||||
* updates the value of data in the response packet with its corresponding
|
||||
* value in the update table.
|
||||
*/
|
||||
std::queue<PacketPtr> responsePool;
|
||||
|
||||
/**
|
||||
* @brief The total number of updates (one read and one write) to do for
|
||||
* running the benchmark to completion.
|
||||
*/
|
||||
int64_t numUpdates;
|
||||
|
||||
/**
|
||||
* @brief Number of elements in the allocated array.
|
||||
*/
|
||||
int64_t tableSize;
|
||||
|
||||
/**
|
||||
* @brief Pointer to the system object this GUPSGen belongs to, the system
|
||||
* object is used to acquire a requestorId.
|
||||
*/
|
||||
System *const system;
|
||||
|
||||
/**
|
||||
* @brief Used to identify each requestor in a system object. Every GUPSGen
|
||||
* has its own unique requestorId.
|
||||
*/
|
||||
const RequestorID requestorId;
|
||||
|
||||
/**
|
||||
* @brief An instance of GenPort to communicate with the outside.
|
||||
*/
|
||||
GenPort port;
|
||||
|
||||
/**
|
||||
* @brief The beginning address for allocating the array.
|
||||
*/
|
||||
Addr startAddr;
|
||||
|
||||
/**
|
||||
* @brief Size of the memory in bytes that will be allocated for the array.
|
||||
*/
|
||||
const uint32_t memSize;
|
||||
|
||||
/**
|
||||
* @brief The number of updates to do before creating an exit event.
|
||||
*/
|
||||
int updateLimit;
|
||||
|
||||
/**
|
||||
* @brief size of each element in the array (in bytes). Every element
|
||||
* should be uint64_t, therefore this is equal to size_of(uint64_t) = 8
|
||||
*/
|
||||
const int elementSize;
|
||||
|
||||
/**
|
||||
* @brief The maximum number of outstanding requests (i.e. maximum length
|
||||
* of the requestPool), specified as 1024 by the HPCC benchmark.
|
||||
*/
|
||||
int reqQueueSize;
|
||||
|
||||
/**
|
||||
* @brief Boolean value to determine whether we need to initialize the
|
||||
* array with the right values, as we don't care about the values, this
|
||||
* is defaulted to false in python wrapper for this simobject.
|
||||
*/
|
||||
bool initMemory;
|
||||
|
||||
/**
|
||||
* @brief Boolean to indicate whether the generator is done creating read
|
||||
* requests, which means number of reads equal either updateLimit or
|
||||
* numUpdates.
|
||||
*/
|
||||
bool doneReading;
|
||||
|
||||
/**
|
||||
* @brief The number of requests that have existed this GUPSGen and have
|
||||
* no corresponding response (they are being serviced some where in the
|
||||
* system).
|
||||
*/
|
||||
int onTheFlyRequests;
|
||||
|
||||
/**
|
||||
* @brief The number of read requests currently created.
|
||||
*/
|
||||
int readRequests;
|
||||
|
||||
struct GUPSGenStat : public Stats::Group
|
||||
{
|
||||
GUPSGenStat(GUPSGen* parent);
|
||||
void regStats() override;
|
||||
|
||||
Stats::Scalar totalUpdates;
|
||||
Stats::Formula GUPS;
|
||||
|
||||
Stats::Scalar totalReads;
|
||||
Stats::Scalar totalBytesRead;
|
||||
Stats::Formula avgReadBW;
|
||||
Stats::Scalar totalReadLat;
|
||||
Stats::Formula avgReadLat;
|
||||
|
||||
Stats::Scalar totalWrites;
|
||||
Stats::Scalar totalBytesWritten;
|
||||
Stats::Formula avgWriteBW;
|
||||
Stats::Scalar totalWriteLat;
|
||||
Stats::Formula avgWriteLat;
|
||||
} stats;
|
||||
|
||||
public:
|
||||
|
||||
GUPSGen(const GUPSGenParams ¶ms);
|
||||
|
||||
Port &getPort(const std::string &if_name,
|
||||
PortID idx=InvalidPortID) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // __CPU_TESTERS_TRAFFIC_GEN_GUPS_GEN_HH__
|
||||
Reference in New Issue
Block a user