mem-ruby: Allow same-cycle enqueue

Messages may be enqueued and be ready in the same cycle.

Using this feature may introduce nondeterminism in the protocol and
should be used in specific cases. A case study is to avoid needing an
additional cycle for internal protocol triggers (e.g. the All_Acks
event in src/mem/ruby/protocol/MOESI_CMP_directory-L2cache.sm).
To mitigate modeling mistakes, the 'allow_zero_latency' parameter must
be set for a MessageBuffer where this behavior is acceptable.

This changes also updates the Consumer to schedule events according to
this new behavior. The original implementation would not schedule a new
wakeup event if the wakeup for the Consumer had already been executed
in that cycle.

Additional authors:
- Tuan Ta <tuan.ta2@arm.com>

Change-Id: Ib194e7b4b4ee4b06da1baea17c0eb743f650dfdd
Signed-off-by: Tiago Mück <tiago.muck@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/31255
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Tiago Muck
2019-06-07 18:16:10 -05:00
committed by Tiago Mück
parent 52fa2b6f07
commit 6ade44d50c
5 changed files with 95 additions and 32 deletions

View File

@@ -1,4 +1,16 @@
/*
* Copyright (c) 2020 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2012 Mark D. Hill and David A. Wood
* All rights reserved.
*
@@ -30,26 +42,51 @@
using namespace std;
Consumer::Consumer(ClockedObject *_em)
: m_wakeup_event([this]{ processCurrentEvent(); },
"Consumer Event", false),
em(_em)
{ }
void
Consumer::scheduleEvent(Cycles timeDelta)
{
scheduleEventAbsolute(em->clockEdge(timeDelta));
m_wakeup_ticks.insert(em->clockEdge(timeDelta));
scheduleNextWakeup();
}
void
Consumer::scheduleEventAbsolute(Tick evt_time)
{
if (!alreadyScheduled(evt_time)) {
// This wakeup is not redundant
auto *evt = new EventFunctionWrapper(
[this]{ wakeup(); }, "Consumer Event", true);
em->schedule(evt, evt_time);
insertScheduledWakeupTime(evt_time);
}
Tick t = em->clockEdge();
set<Tick>::iterator bit = m_scheduled_wakeups.begin();
set<Tick>::iterator eit = m_scheduled_wakeups.lower_bound(t);
m_scheduled_wakeups.erase(bit,eit);
m_wakeup_ticks.insert(
divCeil(evt_time, em->clockPeriod()) * em->clockPeriod());
scheduleNextWakeup();
}
void
Consumer::scheduleNextWakeup()
{
// look for the next tick in the future to schedule
auto it = m_wakeup_ticks.lower_bound(em->clockEdge());
if (it != m_wakeup_ticks.end()) {
Tick when = *it;
assert(when >= em->clockEdge());
if (m_wakeup_event.scheduled() && (when < m_wakeup_event.when()))
em->reschedule(m_wakeup_event, when, true);
else if (!m_wakeup_event.scheduled())
em->schedule(m_wakeup_event, when);
}
}
void
Consumer::processCurrentEvent()
{
auto curr = m_wakeup_ticks.begin();
assert(em->clockEdge() == *curr);
// remove the current tick from the wakeup list, wake up, and then schedule
// the next wakeup
m_wakeup_ticks.erase(curr);
wakeup();
scheduleNextWakeup();
}

View File

@@ -1,4 +1,16 @@
/*
* Copyright (c) 2020 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved.
*
@@ -43,10 +55,7 @@
class Consumer
{
public:
Consumer(ClockedObject *_em)
: em(_em)
{
}
Consumer(ClockedObject *_em);
virtual
~Consumer()
@@ -59,13 +68,7 @@ class Consumer
bool
alreadyScheduled(Tick time)
{
return m_scheduled_wakeups.find(time) != m_scheduled_wakeups.end();
}
void
insertScheduledWakeupTime(Tick time)
{
m_scheduled_wakeups.insert(time);
return m_wakeup_ticks.find(time) != m_wakeup_ticks.end();
}
ClockedObject *
@@ -74,15 +77,19 @@ class Consumer
return em;
}
void scheduleEventAbsolute(Tick timeAbs);
void scheduleEvent(Cycles timeDelta);
private:
std::set<Tick> m_scheduled_wakeups;
std::set<Tick> m_wakeup_ticks;
EventFunctionWrapper m_wakeup_event;
ClockedObject *em;
void scheduleNextWakeup();
void processCurrentEvent();
};
inline std::ostream&
operator<<(std::ostream& out, const Consumer& obj)
{

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 ARM Limited
* Copyright (c) 2019,2020 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@@ -57,7 +57,8 @@ MessageBuffer::MessageBuffer(const Params *p)
m_max_size(p->buffer_size), m_time_last_time_size_checked(0),
m_time_last_time_enqueue(0), m_time_last_time_pop(0),
m_last_arrival_time(0), m_strict_fifo(p->ordered),
m_randomization(p->randomization)
m_randomization(p->randomization),
m_allow_zero_latency(p->allow_zero_latency)
{
m_msg_counter = 0;
m_consumer = NULL;
@@ -172,7 +173,7 @@ MessageBuffer::enqueue(MsgPtr message, Tick current_time, Tick delta)
// Calculate the arrival time of the message, that is, the first
// cycle the message can be dequeued.
assert(delta > 0);
assert((delta > 0) || m_allow_zero_latency);
Tick arrival_time = 0;
// random delays are inserted if either RubySystem level randomization flag
@@ -193,7 +194,7 @@ MessageBuffer::enqueue(MsgPtr message, Tick current_time, Tick delta)
}
// Check the arrival time
assert(arrival_time > current_time);
assert(arrival_time >= current_time);
if (m_strict_fifo) {
if (arrival_time < m_last_arrival_time) {
panic("FIFO ordering violated: %s name: %s current time: %d "

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 ARM Limited
* Copyright (c) 2019,2020 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@@ -249,6 +249,7 @@ class MessageBuffer : public SimObject
int m_priority_rank;
const bool m_strict_fifo;
const bool m_randomization;
const bool m_allow_zero_latency;
int m_input_link_id;
int m_vnet_id;

View File

@@ -1,3 +1,15 @@
# Copyright (c) 2020 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Copyright (c) 2015 Mark D. Hill and David A. Wood.
# All rights reserved.
#
@@ -39,6 +51,11 @@ class MessageBuffer(SimObject):
enqueue times (enforced to have \
random delays if RubySystem \
randomization flag is True)")
allow_zero_latency = Param.Bool(False, "Allows messages to be enqueued \
with zero latency. This is useful \
for internall trigger queues and \
should not be used if this msg. \
buffer connects different objects")
out_port = RequestPort("Request port to MessageBuffer receiver")
master = DeprecatedParam(out_port, '`master` is now called `out_port`')