From 524c22041d128eff899bc7d5d535dcffdc55e980 Mon Sep 17 00:00:00 2001 From: Tuan Ta Date: Mon, 30 Apr 2018 14:35:39 -0400 Subject: [PATCH] mem-ruby: add slicc stm to defer enqueueing a message 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 Reviewed-by: Jason Lowe-Power Maintainer: Jason Lowe-Power Tested-by: kokoro --- src/mem/ruby/network/MessageBuffer.cc | 30 +++++++ src/mem/ruby/network/MessageBuffer.hh | 22 +++++ src/mem/ruby/protocol/RubySlicc_Types.sm | 6 +- .../slicc/ast/DeferEnqueueingStatementAST.py | 82 +++++++++++++++++++ src/mem/slicc/ast/__init__.py | 1 + src/mem/slicc/parser.py | 5 ++ 6 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 src/mem/slicc/ast/DeferEnqueueingStatementAST.py diff --git a/src/mem/ruby/network/MessageBuffer.cc b/src/mem/ruby/network/MessageBuffer.cc index f5562dc6b..6e14de176 100644 --- a/src/mem/ruby/network/MessageBuffer.cc +++ b/src/mem/ruby/network/MessageBuffer.cc @@ -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& 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 { diff --git a/src/mem/ruby/network/MessageBuffer.hh b/src/mem/ruby/network/MessageBuffer.hh index 0e11529bb..01c0767e2 100644 --- a/src/mem/ruby/network/MessageBuffer.hh +++ b/src/mem/ruby/network/MessageBuffer.hh @@ -51,6 +51,7 @@ #include #include #include +#include #include #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> 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 diff --git a/src/mem/ruby/protocol/RubySlicc_Types.sm b/src/mem/ruby/protocol/RubySlicc_Types.sm index 831a322af..bcadc3dc4 100644 --- a/src/mem/ruby/protocol/RubySlicc_Types.sm +++ b/src/mem/ruby/protocol/RubySlicc_Types.sm @@ -49,9 +49,13 @@ // 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 index 000000000..40b9a4c52 --- /dev/null +++ b/src/mem/slicc/ast/DeferEnqueueingStatementAST.py @@ -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) diff --git a/src/mem/slicc/ast/__init__.py b/src/mem/slicc/ast/__init__.py index e3169e8b5..c41010400 100644 --- a/src/mem/slicc/ast/__init__.py +++ b/src/mem/slicc/ast/__init__.py @@ -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 * diff --git a/src/mem/slicc/parser.py b/src/mem/slicc/parser.py index 846a74f03..643eec65d 100644 --- a/src/mem/slicc/parser.py +++ b/src/mem/slicc/parser.py @@ -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]) -- 2.30.2