mem-ruby: add slicc stm to defer enqueueing a message
authorTuan Ta <tuan.ta@amd.com>
Mon, 30 Apr 2018 18:35:39 +0000 (14:35 -0400)
committerAnthony Gutierrez <anthony.gutierrez@amd.com>
Thu, 28 May 2020 23:07:08 +0000 (23:07 +0000)
This patch enables cache controllers to make response
messages in advance, store them in a per-address saved
map in an output message buffer and enqueue them altogether
in the future. This patch introduces new slicc statement
called defer_enqueueing. This patch would help simplify
the logic of state machines that deal with coalesing
multiple requests from different requestors.

Change-Id: I566d4004498b367764238bb251260483c5a1a5e5
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/28132
Reviewed-by: Tuan Ta <qtt2@cornell.edu>
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
src/mem/ruby/network/MessageBuffer.cc
src/mem/ruby/network/MessageBuffer.hh
src/mem/ruby/protocol/RubySlicc_Types.sm
src/mem/slicc/ast/DeferEnqueueingStatementAST.py [new file with mode: 0644]
src/mem/slicc/ast/__init__.py
src/mem/slicc/parser.py

index f5562dc6b79e12872aa21a386b423d657a0f986f..6e14de1766d8a4102feb8f5fe54b0151643c0669 100644 (file)
@@ -394,6 +394,36 @@ MessageBuffer::stallMessage(Addr addr, Tick current_time)
     m_stall_count++;
 }
 
+void
+MessageBuffer::deferEnqueueingMessage(Addr addr, MsgPtr message)
+{
+    DPRINTF(RubyQueue, "Deferring enqueueing message: %s, Address %#x\n",
+            *(message.get()), addr);
+    (m_deferred_msg_map[addr]).push_back(message);
+}
+
+void
+MessageBuffer::enqueueDeferredMessages(Addr addr, Tick curTime, Tick delay)
+{
+    assert(!isDeferredMsgMapEmpty(addr));
+    std::vector<MsgPtr>& msg_vec = m_deferred_msg_map[addr];
+    assert(msg_vec.size() > 0);
+
+    // enqueue all deferred messages associated with this address
+    for (MsgPtr m : msg_vec) {
+        enqueue(m, curTime, delay);
+    }
+
+    msg_vec.clear();
+    m_deferred_msg_map.erase(addr);
+}
+
+bool
+MessageBuffer::isDeferredMsgMapEmpty(Addr addr) const
+{
+    return m_deferred_msg_map.count(addr) == 0;
+}
+
 void
 MessageBuffer::print(ostream& out) const
 {
index 0e11529bbe7c5a1b49a4feef2273fc40fd8c0f96..01c0767e2ce8d190d89146f4de78cdd4c6a20811 100644 (file)
@@ -51,6 +51,7 @@
 #include <functional>
 #include <iostream>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 #include "base/trace.hh"
@@ -113,6 +114,19 @@ class MessageBuffer : public SimObject
 
     void enqueue(MsgPtr message, Tick curTime, Tick delta);
 
+    // Defer enqueueing a message to a later cycle by putting it aside and not
+    // enqueueing it in this cycle
+    // The corresponding controller will need to explicitly enqueue the
+    // deferred message into the message buffer. Otherwise, the message will
+    // be lost.
+    void deferEnqueueingMessage(Addr addr, MsgPtr message);
+
+    // enqueue all previously deferred messages that are associated with the
+    // input address
+    void enqueueDeferredMessages(Addr addr, Tick curTime, Tick delay);
+
+    bool isDeferredMsgMapEmpty(Addr addr) const;
+
     //! Updates the delay cycles of the message at the head of the queue,
     //! removes it from the queue and returns its total delay.
     Tick dequeue(Tick current_time, bool decrement_messages = true);
@@ -191,6 +205,14 @@ class MessageBuffer : public SimObject
      */
     StallMsgMapType m_stall_msg_map;
 
+    /**
+     * A map from line addresses to corresponding vectors of messages that
+     * are deferred for enqueueing. Messages in this map are waiting to be
+     * enqueued into the message buffer.
+     */
+    typedef std::unordered_map<Addr, std::vector<MsgPtr>> DeferredMsgMapType;
+    DeferredMsgMapType m_deferred_msg_map;
+
     /**
      * Current size of the stall map.
      * Track the number of messages held in stall map lists. This is used to
index 831a322af97df7576a67a034276d7b3bf1f86eb0..bcadc3dc4d4034383cacef23d7144397c325df52 100644 (file)
 //
 
 external_type(MessageBuffer, buffer="yes", inport="yes", outport="yes");
-external_type(OutPort, primitive="yes");
 external_type(Scalar, primitive="yes");
 
+structure(OutPort, external = "yes", primitive="yes") {
+    void enqueueDeferredMessages(Addr addr, Tick curTime, Tick delay);
+    bool isDeferredMsgMapEmpty(Addr addr);
+}
+
 structure(InPort, external = "yes", primitive="yes") {
   bool isReady(Tick current_time);
   Tick dequeue(Tick current_time);
diff --git a/src/mem/slicc/ast/DeferEnqueueingStatementAST.py b/src/mem/slicc/ast/DeferEnqueueingStatementAST.py
new file mode 100644 (file)
index 0000000..40b9a4c
--- /dev/null
@@ -0,0 +1,82 @@
+#
+# Copyright (c) 2017 Advanced Micro Devices, Inc.
+# All rights reserved.
+#
+# For use for simulation and test purposes only
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. 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.
+#
+# 3. Neither the name of the copyright holder 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 HOLDER 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.
+#
+# Authors: Tuan Ta
+#
+
+from slicc.ast.StatementAST import StatementAST
+from slicc.symbols import Var
+
+class DeferEnqueueingStatementAST(StatementAST):
+    def __init__(self, slicc, queue_name, type_ast, statements):
+        super(DeferEnqueueingStatementAST, self).__init__(slicc)
+
+        self.queue_name = queue_name
+        self.type_ast = type_ast
+        self.statements = statements
+
+    def __repr__(self):
+        return "[DeferEnqueueingStatementAst: %s %s %s]" % \
+               (self.queue_name, self.type_ast.ident, self.statements)
+
+    def generate(self, code, return_type):
+        code("{")
+        code.indent()
+        self.symtab.pushFrame()
+
+        msg_type = self.type_ast.type
+
+        # Add new local var to symbol table
+        v = Var(self.symtab, "out_msg", self.location, msg_type, "*out_msg",
+                self.pairs)
+        self.symtab.newSymbol(v)
+
+        # Declare message
+        code("std::shared_ptr<${{msg_type.c_ident}}> out_msg = "\
+             "std::make_shared<${{msg_type.c_ident}}>(clockEdge());")
+
+        # The other statements
+        t = self.statements.generate(code, None)
+        self.queue_name.assertType("OutPort")
+
+        code("(${{self.queue_name.var.code}}).deferEnqueueingMessage(addr, "\
+             "out_msg);")
+
+        # End scope
+        self.symtab.popFrame()
+        code.dedent()
+        code("}")
+
+    def findResources(self, resources):
+        var = self.queue_name.var
+        res_count = int(resources.get(var, 0))
+        resources[var] = str(res_count + 1)
index e3169e8b5898658a148fbaea53c11107ce30e1d6..c4101040079fb739f06bdfed57c933399e48f75c 100644 (file)
@@ -33,6 +33,7 @@ from slicc.ast.CheckAllocateStatementAST import *
 from slicc.ast.CheckNextCycleAST import *
 from slicc.ast.DeclAST import *
 from slicc.ast.DeclListAST import *
+from slicc.ast.DeferEnqueueingStatementAST import *
 from slicc.ast.EnqueueStatementAST import *
 from slicc.ast.EnumDeclAST import *
 from slicc.ast.EnumExprAST import *
index 846a74f030ad9684ac5f93fdd163766aac0787ed..643eec65de749244bebdf41b8c0aae91e16ade49 100644 (file)
@@ -120,6 +120,7 @@ class SLICC(Grammar):
         'void' : 'VOID',
         'new' : 'NEW',
         'OOD' : 'OOD',
+        'defer_enqueueing' : 'DEFER_ENQUEUEING',
     }
 
     literals = ':[]{}(),='
@@ -583,6 +584,10 @@ class SLICC(Grammar):
         "statement : ENQUEUE '(' var ',' type ',' expr ')' statements"
         p[0] = ast.EnqueueStatementAST(self, p[3], p[5], p[7], p[9])
 
+    def p_statement__defer_enqueueing(self, p):
+        "statement : DEFER_ENQUEUEING '(' var ',' type ')' statements"
+        p[0] = ast.DeferEnqueueingStatementAST(self, p[3], p[5], p[7])
+
     def p_statement__stall_and_wait(self, p):
         "statement : STALL_AND_WAIT '(' var ',' var ')' SEMI"
         p[0] = ast.StallAndWaitStatementAST(self, p[3], p[5])