Tiago Mück has uploaded this change for review. (
https://gem5-review.googlesource.com/c/public/gem5/+/41866 )
Change subject: configs,mem-ruby: dumps network route profile
......................................................................
configs,mem-ruby: dumps network route profile
if trace_routes parameter is set when using SimpleNetwork, each
unique route used in the network is tracked and dumped in a text file
at the end of the simulation in the format:
delay_cy msg_cnt vnet src_port -> r0 -> .. -> rn -> dest_port
delay_cy is the average delay of the route. For each router the average
internal delays are also included. The dumped routes are ordered by:
delay_cy / #hops
The TraceRoutesDebug debug flag can also be use to print additional
routing information.
JIRA: https://gem5.atlassian.net/browse/GEM5-920
Change-Id: I15ac24ef28d28cf8e141522704bc47be0712b2c1
Signed-off-by: Tiago Mück <[email protected]>
---
M configs/network/Network.py
M src/mem/ruby/network/BasicRouter.hh
M src/mem/ruby/network/MessageBuffer.cc
M src/mem/ruby/network/MessageBuffer.hh
A src/mem/ruby/network/RouteProfiler.cc
A src/mem/ruby/network/RouteProfiler.hh
M src/mem/ruby/network/SConscript
M src/mem/ruby/network/simple/PerfectSwitch.cc
M src/mem/ruby/network/simple/SimpleNetwork.cc
M src/mem/ruby/network/simple/SimpleNetwork.hh
M src/mem/ruby/network/simple/SimpleNetwork.py
M src/mem/ruby/network/simple/Switch.cc
M src/mem/ruby/network/simple/Switch.hh
M src/mem/ruby/network/simple/Throttle.cc
M src/mem/ruby/structures/TimerTable.hh
M src/mem/ruby/structures/WireBuffer.hh
M src/mem/slicc/symbols/StateMachine.py
17 files changed, 541 insertions(+), 5 deletions(-)
diff --git a/configs/network/Network.py b/configs/network/Network.py
index 4a708ea..d475c16 100644
--- a/configs/network/Network.py
+++ b/configs/network/Network.py
@@ -76,6 +76,9 @@
action="store_true", default=False,
help="""SimpleNetwork links uses a separate physical
channel for each virtual network""")
+ parser.add_option("--simple-trace-routes",
+ action="store_true", default=False,
+ help="""SimpleNetwork traces latency for all
routes""")
def create_network(options, ruby):
@@ -187,6 +190,7 @@
network.physical_vnets_channels = \
[1] * int(network.number_of_virtual_networks)
network.setup_buffers()
+ network.trace_routes = options.simple_trace_routes
if InterfaceClass != None:
netifs = [InterfaceClass(id=i) \
diff --git a/src/mem/ruby/network/BasicRouter.hh
b/src/mem/ruby/network/BasicRouter.hh
index 9417342..2c5f80a 100644
--- a/src/mem/ruby/network/BasicRouter.hh
+++ b/src/mem/ruby/network/BasicRouter.hh
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2021 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) 2011 Advanced Micro Devices, Inc.
* All rights reserved.
*
@@ -45,6 +57,9 @@
void init();
void print(std::ostream& out) const;
+
+ uint32_t getID() const { return m_id; }
+
protected:
//
// ID in relation to other routers in the system
diff --git a/src/mem/ruby/network/MessageBuffer.cc
b/src/mem/ruby/network/MessageBuffer.cc
index bde4de7..d16f70d 100644
--- a/src/mem/ruby/network/MessageBuffer.cc
+++ b/src/mem/ruby/network/MessageBuffer.cc
@@ -60,6 +60,7 @@
m_randomization(p.randomization),
m_allow_zero_latency(p.allow_zero_latency),
m_routing_priority(p.routing_priority),
+ m_is_inport(false),
ADD_STAT(m_not_avail_count, "Number of times this buffer did not have "
"N slots available"),
ADD_STAT(m_buf_msgs, "Average number of messages in buffer"),
diff --git a/src/mem/ruby/network/MessageBuffer.hh
b/src/mem/ruby/network/MessageBuffer.hh
index 8c6ceda..ae9339f 100644
--- a/src/mem/ruby/network/MessageBuffer.hh
+++ b/src/mem/ruby/network/MessageBuffer.hh
@@ -96,7 +96,7 @@
bool areNSlotsAvailable(unsigned int n, Tick curTime);
int getPriority() { return m_priority_rank; }
void setPriority(int rank) { m_priority_rank = rank; }
- void setConsumer(Consumer* consumer)
+ void setConsumer(Consumer* consumer, bool is_inport = false)
{
DPRINTF(RubyQueue, "Setting consumer: %s\n", *consumer);
if (m_consumer != NULL) {
@@ -105,6 +105,7 @@
*consumer, *this, *m_consumer);
}
m_consumer = consumer;
+ m_is_inport = is_inport;
}
Consumer* getConsumer() { return m_consumer; }
@@ -186,6 +187,8 @@
int routingPriority() const { return m_routing_priority; }
+ bool isInport() { return m_is_inport; }
+
private:
void reanalyzeList(std::list<MsgPtr> &, Tick);
@@ -271,6 +274,8 @@
const int m_routing_priority;
+ bool m_is_inport;
+
int m_input_link_id;
int m_vnet_id;
diff --git a/src/mem/ruby/network/RouteProfiler.cc
b/src/mem/ruby/network/RouteProfiler.cc
new file mode 100644
index 0000000..3ff7205
--- /dev/null
+++ b/src/mem/ruby/network/RouteProfiler.cc
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2021 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.
+ *
+ * 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 "mem/ruby/network/RouteProfiler.hh"
+
+#include <cassert>
+#include <numeric>
+
+#include "base/output.hh"
+#include "debug/TraceRoutesDebug.hh"
+
+void
+RouteProfiler::profFrontEndRdy(Message* msg, BasicRouter *router,
+ MessageBuffer *src_link, int vnet)
+{
+ if (!m_enabled) return;
+
+ auto tmp = outstanting_routes.emplace(std::piecewise_construct,
+ std::forward_as_tuple(msg),
+ std::forward_as_tuple(msg, src_link, vnet));
+ OutstandingRoute &entry = tmp.first->second;
+ bool is_new = tmp.second;
+ assert(msg == entry.msg);
+ assert(vnet == entry.vnet);
+ if (is_new) {
+ assert(entry.entries.empty());
+ assert(entry.src_link == src_link);
+ }
+ if (entry.entries.empty() || (entry.entries.back().router != router)) {
+ entry.entries.emplace_back(router, curTick());
+ DPRINTFS(TraceRoutesDebug, router,
+ "Msg %#x entering router vnet=%d\n", msg, vnet);
+ }
+ assert(entry.entries.back().router == router);
+}
+
+void
+RouteProfiler::profFrontEndRdyClone(Message* msg, BasicRouter *router,
+ MessageBuffer *src_link, int vnet,
+ Message* clone_from_msg)
+{
+ if (!m_enabled) return;
+
+ auto tmp = outstanting_routes.emplace(std::piecewise_construct,
+ std::forward_as_tuple(msg),
+ std::forward_as_tuple(msg, src_link, vnet));
+ OutstandingRoute &entry = tmp.first->second;
+ bool is_new = tmp.second;
+ assert(msg == entry.msg);
+ assert(vnet == entry.vnet);
+ assert(is_new);
+ assert(entry.entries.empty());
+
+
+ auto iter = outstanting_routes.find(clone_from_msg);
+ assert(iter != outstanting_routes.end());
+ OutstandingRoute &other = iter->second;
+ assert(entry.vnet == other.vnet);
+ assert(!other.entries.empty());
+ assert(other.entries.back().router == router);
+ entry.src_link = other.src_link;
+ entry.entries = other.entries;
+ DPRINTFS(TraceRoutesDebug, router,
+ "Msg %#x cloned in router vnet=%d\n", msg, vnet);
+}
+
+
+void
+RouteProfiler::profFrontEndFwd(Message* msg, BasicRouter *router, int vnet)
+{
+ if (!m_enabled) return;
+
+ auto iter = outstanting_routes.find(msg);
+ assert(iter != outstanting_routes.end());
+ assert(!iter->second.entries.empty());
+ assert(iter->second.msg == msg);
+ assert(vnet == iter->second.vnet);
+ OutstandingRouteEntry &entry = iter->second.entries.back();
+ assert(entry.router == router);
+ entry.frontend_fwd = curTick();
+ entry.backend_rdy = 0;
+}
+
+void
+RouteProfiler::profBackEndRdy(Message* msg, BasicRouter *router, int vnet)
+{
+ if (!m_enabled) return;
+
+ auto iter = outstanting_routes.find(msg);
+ assert(iter != outstanting_routes.end());
+ assert(!iter->second.entries.empty());
+ assert(iter->second.msg == msg);
+ assert(vnet == iter->second.vnet);
+ OutstandingRouteEntry &entry = iter->second.entries.back();
+ assert(entry.router == router);
+ if (entry.backend_rdy == 0)
+ entry.backend_rdy = curTick();
+}
+
+void
+RouteProfiler::profBackEndFwd(Message* msg, BasicRouter *router, int vnet)
+{
+ if (!m_enabled) return;
+
+ auto iter = outstanting_routes.find(msg);
+ assert(iter != outstanting_routes.end());
+ assert(!iter->second.entries.empty());
+ assert(iter->second.msg == msg);
+ assert(vnet == iter->second.vnet);
+ OutstandingRouteEntry &entry = iter->second.entries.back();
+ assert(entry.router == router);
+ entry.backend_fwd = curTick();
+ DPRINTFS(TraceRoutesDebug, router,
+ "Msg %#x leaving router vnet=%d delay=%d delay_total=%d\n", msg,
vnet,
+ entry.backend_fwd - entry.frontend_rdy,
+ entry.backend_fwd - iter->second.entries.front().frontend_rdy);
+}
+
+void
+RouteProfiler::profBackEndFwdExt(Message* msg, BasicRouter *router,
+ MessageBuffer *dest_link, int vnet)
+{
+ if (!m_enabled) return;
+
+ profBackEndFwd(msg, router, vnet);
+ auto iter = outstanting_routes.find(msg);
+ OutstandingRoute &entry = iter->second;
+
+ std::string rs = genRouteString(entry, dest_link);
+
+ Route &route = routes[rs];
+
+ bool was_empty = route.src_link == nullptr;
+ if (was_empty) {
+ route.src_link = entry.src_link;
+ route.dst_link = dest_link;
+ route.vnet = vnet;
+ for (auto e : entry.entries) {
+ route.route.emplace_back();
+ auto &r = route.route.back();
+ r.router = e.router;
+ r.frontend_delay.inc(
+ router->ticksToCycles(e.frontend_fwd - e.frontend_rdy));
+ r.backend_delay.inc(
+ router->ticksToCycles(e.backend_fwd - e.frontend_fwd));
+ }
+ } else {
+ assert(route.src_link == entry.src_link);
+ assert(route.dst_link == dest_link);
+ assert(route.vnet == vnet);
+ assert(route.route.size() == entry.entries.size());
+
+ for (unsigned i = 0; i < entry.entries.size(); ++ i) {
+ auto &e = entry.entries[i];
+ auto &r = route.route[i];
+ assert(r.router == e.router);
+ r.frontend_delay.inc(
+ router->ticksToCycles(e.frontend_fwd - e.frontend_rdy));
+ r.backend_delay.inc(
+ router->ticksToCycles(e.backend_fwd - e.frontend_fwd));
+ }
+ }
+ route.total_delay.inc(router->ticksToCycles(
+ entry.entries.back().backend_fwd -
+ entry.entries.front().frontend_rdy));
+
+ if (DTRACE(TraceRoutesDebug)) {
+ std::ostringstream ss;
+ dumpRoute(route, ss);
+ DPRINTF(TraceRoutesDebug,"%s route: %s",
+ was_empty ? "New" : "Updated", ss.str());
+ }
+
+ outstanting_routes.erase(iter);
+}
+
+std::string
+RouteProfiler::genRouteString(OutstandingRoute& route,
+ MessageBuffer *dest_link)
+{
+ assert(!route.entries.empty());
+ std::stringstream ss;
+ ss << route.vnet << " " << route.src_link->name() << "->";
+ for (auto e : route.entries) ss << "R" << e.router->getID() << "->";
+ ss << dest_link->name();
+ return ss.str();
+}
+
+void
+RouteProfiler::dumpRoute(const Route& route, std::ostream &outs) const
+{
+ assert(!route.route.empty());
+ ccprintf(outs, "%.1f %d ", route.total_delay.avg(),
route.total_delay.cnt);
+ ccprintf(outs, "vnet%d %s -> ", route.vnet, route.src_link->name());
+ for (auto r : route.route){
+ ccprintf(outs, "R%d(%.1f,%.1f) -> ", r.router->getID(),
+ r.frontend_delay.avg(),
+ r.backend_delay.avg());
+ }
+ ccprintf(outs, "%s\n", route.dst_link->name());
+}
+
+void
+RouteProfiler::dumpRoutes()
+{
+ if (routes.empty())
+ return;
+
+ // use set to order map value by badness
+ typedef std::pair<std::string, Route> settype;
+ struct compare {
+ bool operator()(const settype &l, const settype &r){
+ if (l.second.badness() != r.second.badness())
+ return l.second.badness() > r.second.badness();
+ else
+ return l.first > r.first;
+ }
+ };
+
+ std::set<settype, compare> ordered(routes.begin(),
+ routes.end());
+
+ OutputStream *out = simout.open("interconnect_routes.txt",
+ std::ios_base::out);
+ inform("Dumping all routes to %s\n", out->name());
+ std::ostream &outs = *out->stream();
+
+ for (auto &val : ordered){
+ dumpRoute(val.second, outs);
+ }
+}
diff --git a/src/mem/ruby/network/RouteProfiler.hh
b/src/mem/ruby/network/RouteProfiler.hh
new file mode 100644
index 0000000..2898d1d
--- /dev/null
+++ b/src/mem/ruby/network/RouteProfiler.hh
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2021 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.
+ *
+ * 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 __MEM_RUBY_NETWORK_ROUTEPROFILER_HH__
+#define __MEM_RUBY_NETWORK_ROUTEPROFILER_HH__
+
+#include <iostream>
+#include <unordered_map>
+#include <vector>
+
+#include "mem/ruby/network/BasicLink.hh"
+#include "mem/ruby/network/BasicRouter.hh"
+#include "mem/ruby/network/MessageBuffer.hh"
+
+class RouteProfiler
+{
+
+ public:
+
+ RouteProfiler() :m_enabled(false)
+ { }
+
+ // Notifies a message is ready at a router input port
+ void profFrontEndRdy(Message* msg, BasicRouter *router,
+ MessageBuffer *src_link, int vnet);
+
+ // Notifies ready message was cloned (e.g. on multicast messages)
+ void profFrontEndRdyClone(Message* msg, BasicRouter *router,
+ MessageBuffer *src_link, int vnet,
+ Message* clone_from_msg);
+
+ // Notifies a ready message was routed to an output port buffer
+ void profFrontEndFwd(Message* msg, BasicRouter *router, int vnet);
+
+ // Notifies a message is ready at an output por buffer
+ void profBackEndRdy(Message* msg, BasicRouter *router, int vnet);
+
+ // Notifies a ready message was sent through the output link
+ void profBackEndFwd(Message* msg, BasicRouter *router, int vnet);
+
+ // Notifies a ready message was sent through the output link to
+ // its final destination
+ void profBackEndFwdExt(Message* msg, BasicRouter *router,
+ MessageBuffer *dest_link, int vnet);
+
+ // Dump all routes to file
+ void dumpRoutes();
+
+ // enable disable profiling routes
+ void enable() { m_enabled = true; }
+ void disable() { m_enabled = false; }
+
+ private:
+
+ bool m_enabled;
+
+ struct OutstandingRouteEntry {
+ BasicRouter *router;
+ Tick frontend_rdy;
+ Tick frontend_fwd;
+ Tick backend_rdy;
+ Tick backend_fwd;
+
+ OutstandingRouteEntry(BasicRouter *_router, Tick _frontend_rdy)
+ :router(_router), frontend_rdy(_frontend_rdy){}
+ };
+
+ struct OutstandingRoute {
+ Message *msg;
+ MessageBuffer *src_link;
+ int vnet;
+ std::vector<OutstandingRouteEntry> entries;
+
+ OutstandingRoute(Message *_msg, MessageBuffer *_src_link, int
_vnet)
+ :msg(_msg), src_link(_src_link), vnet(_vnet) {}
+ };
+
+ struct AvgVal {
+ double acc;
+ uint64_t cnt;
+ AvgVal() :acc(0), cnt(0) {}
+ void inc(double val) {
+ acc += val;
+ cnt += 1;
+ }
+ double avg() const { return acc/cnt; };
+ };
+
+ struct RouteEntry {
+ BasicRouter *router;
+ AvgVal frontend_delay;
+ AvgVal backend_delay;
+ };
+
+ struct Route {
+ int vnet;
+ MessageBuffer *src_link;
+ MessageBuffer *dst_link;
+ AvgVal total_delay;
+ std::vector<RouteEntry> route;
+ Route():vnet(), src_link(nullptr), dst_link(nullptr) {}
+ double badness() const { return total_delay.avg() / route.size(); }
+ };
+
+ std::unordered_map<Message*,OutstandingRoute> outstanting_routes;
+ std::unordered_map<std::string, Route> routes;
+
+ std::string genRouteString(OutstandingRoute& route,
+ MessageBuffer *dest_link);
+ void dumpRoute(const Route& route, std::ostream &outs) const;
+
+};
+
+#endif // __MEM_RUBY_NETWORK_ROUTEPROFILER_HH__
diff --git a/src/mem/ruby/network/SConscript
b/src/mem/ruby/network/SConscript
index 1e96535..acc5163 100644
--- a/src/mem/ruby/network/SConscript
+++ b/src/mem/ruby/network/SConscript
@@ -31,6 +31,8 @@
if env['PROTOCOL'] == 'None':
Return()
+DebugFlag('TraceRoutesDebug')
+
SimObject('BasicLink.py')
SimObject('BasicRouter.py')
SimObject('MessageBuffer.py')
@@ -40,4 +42,5 @@
Source('BasicRouter.cc')
Source('MessageBuffer.cc')
Source('Network.cc')
+Source('RouteProfiler.cc')
Source('Topology.cc')
diff --git a/src/mem/ruby/network/simple/PerfectSwitch.cc
b/src/mem/ruby/network/simple/PerfectSwitch.cc
index f7a4313..432d565 100644
--- a/src/mem/ruby/network/simple/PerfectSwitch.cc
+++ b/src/mem/ruby/network/simple/PerfectSwitch.cc
@@ -188,6 +188,7 @@
net_msg_ptr = msg_ptr.get();
DPRINTF(RubyNetwork, "Message: %s\n", (*net_msg_ptr));
+ m_switch->profFrontEndRdy(net_msg_ptr, buffer, vnet);
output_links.clear();
m_switch->getRoutingUnit().route(*net_msg_ptr, vnet,
@@ -241,11 +242,17 @@
if (i > 0) {
// create a private copy of the unmodified message
msg_ptr = unmodified_msg_ptr->clone();
+
+ m_switch->profFrontEndRdyClone(msg_ptr.get(), buffer,
+ vnet, net_msg_ptr);
}
// Change the internal destination set of the message so it
// knows which destinations this link is responsible for.
net_msg_ptr = msg_ptr.get();
+
+ m_switch->profFrontEndFwd(net_msg_ptr, vnet);
+
net_msg_ptr->getDestination() = output_links[i].m_destinations;
// Enqeue msg
diff --git a/src/mem/ruby/network/simple/SimpleNetwork.cc
b/src/mem/ruby/network/simple/SimpleNetwork.cc
index 97164f8..cb83286 100644
--- a/src/mem/ruby/network/simple/SimpleNetwork.cc
+++ b/src/mem/ruby/network/simple/SimpleNetwork.cc
@@ -81,6 +81,12 @@
fatal_if((physical_vnets_bandwidth.size() != vnets) &&
(physical_vnets_bandwidth.size() != 0),
"physical_vnets_bandwidth must provide BW for all vnets");
+
+ if (p.trace_routes) {
+ routeProfiler.enable();
+ // Register a callback to write the file with all routes
+ registerExitCallback([this]() { dumpRoutes(); });
+ }
}
void
@@ -255,3 +261,4 @@
{
}
+
diff --git a/src/mem/ruby/network/simple/SimpleNetwork.hh
b/src/mem/ruby/network/simple/SimpleNetwork.hh
index 28dc353..0f09786 100644
--- a/src/mem/ruby/network/simple/SimpleNetwork.hh
+++ b/src/mem/ruby/network/simple/SimpleNetwork.hh
@@ -45,6 +45,7 @@
#include <vector>
#include "mem/ruby/network/Network.hh"
+#include "mem/ruby/network/RouteProfiler.hh"
#include "params/SimpleNetwork.hh"
class NetDest;
@@ -106,7 +107,6 @@
const int m_buffer_size;
const int m_endpoint_bandwidth;
-
struct NetworkStats : public Stats::Group
{
NetworkStats(Stats::Group *parent);
@@ -115,6 +115,13 @@
Stats::Formula* m_msg_counts[MessageSizeType_NUM];
Stats::Formula* m_msg_bytes[MessageSizeType_NUM];
} networkStats;
+
+ public:
+
+ RouteProfiler routeProfiler;
+
+ void dumpRoutes() { routeProfiler.dumpRoutes(); }
+
};
inline std::ostream&
diff --git a/src/mem/ruby/network/simple/SimpleNetwork.py
b/src/mem/ruby/network/simple/SimpleNetwork.py
index c11deaa..accf9af 100644
--- a/src/mem/ruby/network/simple/SimpleNetwork.py
+++ b/src/mem/ruby/network/simple/SimpleNetwork.py
@@ -51,6 +51,7 @@
buffer_size = Param.Int(0, "default internal buffer size for links and\
routers; 0 indicates infinite buffering")
endpoint_bandwidth = Param.Int(1000, "bandwidth adjustment factor")
+ trace_routes = Param.Bool(False, "Generate trace with all used routes")
# Set to emulate multiple channels for each vnet.
# If not set, all vnets share the same physical channel.
diff --git a/src/mem/ruby/network/simple/Switch.cc
b/src/mem/ruby/network/simple/Switch.cc
index 2b7ac2f..b44ea46 100644
--- a/src/mem/ruby/network/simple/Switch.cc
+++ b/src/mem/ruby/network/simple/Switch.cc
@@ -232,3 +232,41 @@
{
}
+
+void
+Switch::profFrontEndRdy(Message* msg, MessageBuffer *src_link, int vnet)
+{
+ m_network_ptr->routeProfiler.profFrontEndRdy(msg, this, src_link,
vnet);
+}
+
+void
+Switch::profFrontEndRdyClone(Message* msg, MessageBuffer *src_link,
+ int vnet, Message* clone_from_msg)
+{
+ m_network_ptr->routeProfiler.profFrontEndRdyClone(msg, this, src_link,
+ vnet,
clone_from_msg);
+}
+
+void
+Switch::profFrontEndFwd(Message* msg, int vnet)
+{
+ m_network_ptr->routeProfiler.profFrontEndFwd(msg, this, vnet);
+}
+
+void
+Switch::profBackEndRdy(Message* msg, int vnet)
+{
+ m_network_ptr->routeProfiler.profBackEndRdy(msg, this, vnet);
+}
+
+void
+Switch::profBackEndFwd(Message* msg, int vnet)
+{
+ m_network_ptr->routeProfiler.profBackEndFwd(msg, this, vnet);
+}
+
+void
+Switch::profBackEndFwdExt(Message* msg, MessageBuffer *dest_link, int vnet)
+{
+ m_network_ptr->routeProfiler.profBackEndFwdExt(msg, this, dest_link,
vnet);
+}
diff --git a/src/mem/ruby/network/simple/Switch.hh
b/src/mem/ruby/network/simple/Switch.hh
index 7a7878c..bd5da95 100644
--- a/src/mem/ruby/network/simple/Switch.hh
+++ b/src/mem/ruby/network/simple/Switch.hh
@@ -136,6 +136,15 @@
Stats::Formula* m_msg_counts[MessageSizeType_NUM];
Stats::Formula* m_msg_bytes[MessageSizeType_NUM];
} switchStats;
+
+ void profFrontEndRdy(Message* msg, MessageBuffer *src_link, int vnet);
+ void profFrontEndRdyClone(Message* msg, MessageBuffer *src_link,
+ int vnet, Message* clone_from_msg);
+ void profFrontEndFwd(Message* msg, int vnet);
+ void profBackEndRdy(Message* msg, int vnet);
+ void profBackEndFwd(Message* msg, int vnet);
+ void profBackEndFwdExt(Message* msg, MessageBuffer *dest_link, int
vnet);
+
};
inline std::ostream&
diff --git a/src/mem/ruby/network/simple/Throttle.cc
b/src/mem/ruby/network/simple/Throttle.cc
index ed9b26f..c173516 100644
--- a/src/mem/ruby/network/simple/Throttle.cc
+++ b/src/mem/ruby/network/simple/Throttle.cc
@@ -149,6 +149,9 @@
bw_remaining = getLinkBandwidth(vnet);
}
+ if (in->isReady(current_time)) {
+ m_switch->profBackEndRdy(in->peekMsgPtr().get(), vnet);
+ }
bool ready;
while ((ready = bw_remaining > 0 &&
(in->isReady(current_time) || units_remaining > 0)) &&
@@ -171,6 +174,17 @@
in->dequeue(current_time);
out->enqueue(msg_ptr, current_time,
m_switch->cyclesToTicks(m_link_latency));
+ if (out->isInport()) {
+ m_switch->profBackEndFwdExt(net_msg_ptr, out, vnet);
+ } else {
+ m_switch->profBackEndFwd(net_msg_ptr, vnet);
+ }
+
+ // Could still have more ready but won't execute because no
more
+ // BW or output port blocked
+ if (in->isReady(current_time)) {
+ m_switch->profBackEndRdy(in->peekMsgPtr().get(), vnet);
+ }
// Count the message
(*(throttleStats.
diff --git a/src/mem/ruby/structures/TimerTable.hh
b/src/mem/ruby/structures/TimerTable.hh
index 9efe7ca..7aa82ef 100644
--- a/src/mem/ruby/structures/TimerTable.hh
+++ b/src/mem/ruby/structures/TimerTable.hh
@@ -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,7 +55,7 @@
TimerTable();
void
- setConsumer(Consumer* consumer_ptr)
+ setConsumer(Consumer* consumer_ptr, bool is_inport = false)
{
assert(m_consumer_ptr == NULL);
m_consumer_ptr = consumer_ptr;
diff --git a/src/mem/ruby/structures/WireBuffer.hh
b/src/mem/ruby/structures/WireBuffer.hh
index be861ec..63a1f76 100644
--- a/src/mem/ruby/structures/WireBuffer.hh
+++ b/src/mem/ruby/structures/WireBuffer.hh
@@ -64,7 +64,7 @@
void wakeup();
- void setConsumer(Consumer* consumer_ptr)
+ void setConsumer(Consumer* consumer_ptr, bool is_inport = false)
{
m_consumer_ptr = consumer_ptr;
}
diff --git a/src/mem/slicc/symbols/StateMachine.py
b/src/mem/slicc/symbols/StateMachine.py
index 59e54a8..5a028ec 100644
--- a/src/mem/slicc/symbols/StateMachine.py
+++ b/src/mem/slicc/symbols/StateMachine.py
@@ -681,7 +681,7 @@
code()
for port in self.in_ports:
# Set the queue consumers
- code('${{port.code}}.setConsumer(this);')
+ code('${{port.code}}.setConsumer(this, true);')
# Initialize the transition profiling
code()
--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/41866
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I15ac24ef28d28cf8e141522704bc47be0712b2c1
Gerrit-Change-Number: 41866
Gerrit-PatchSet: 1
Gerrit-Owner: Tiago Mück <[email protected]>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s