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>
/*
+ * 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.
*
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);
+ m_wakeup_ticks.insert(
+ divCeil(evt_time, em->clockPeriod()) * em->clockPeriod());
+ scheduleNextWakeup();
+}
- em->schedule(evt, evt_time);
- insertScheduledWakeupTime(evt_time);
+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);
- 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);
+ // remove the current tick from the wakeup list, wake up, and then schedule
+ // the next wakeup
+ m_wakeup_ticks.erase(curr);
+ wakeup();
+ scheduleNextWakeup();
}
/*
+ * 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.
*
class Consumer
{
public:
- Consumer(ClockedObject *_em)
- : em(_em)
- {
- }
+ Consumer(ClockedObject *_em);
virtual
~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 *
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)
{
/*
- * 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
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;
// 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
}
// 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 "
/*
- * 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
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;
+# 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.
#
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`')