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

Reply via email to