ruby: tag and data cache access support
authorJoel Hestness <hestness@cs.utexas.edu>
Wed, 11 Jul 2012 05:51:54 +0000 (22:51 -0700)
committerJoel Hestness <hestness@cs.utexas.edu>
Wed, 11 Jul 2012 05:51:54 +0000 (22:51 -0700)
Updates to Ruby to support statistics counting of cache accesses.  This feature
serves multiple purposes beyond simple stats collection.  It provides the
foundation for ruby to model the cache tag and data arrays as physical
resources, as well as provide the necessary input data for McPAT power
modeling.

20 files changed:
src/mem/SConscript
src/mem/protocol/RubySlicc_Exports.sm
src/mem/protocol/RubySlicc_Types.sm
src/mem/ruby/system/CacheMemory.cc
src/mem/ruby/system/CacheMemory.hh
src/mem/ruby/system/DMASequencer.cc
src/mem/ruby/system/DMASequencer.hh
src/mem/ruby/system/DirectoryMemory.cc
src/mem/ruby/system/DirectoryMemory.hh
src/mem/ruby/system/MemoryControl.cc
src/mem/ruby/system/MemoryControl.hh
src/mem/ruby/system/Sequencer.cc
src/mem/ruby/system/Sequencer.hh
src/mem/slicc/ast/TransitionDeclAST.py
src/mem/slicc/ast/TypeFieldEnumAST.py
src/mem/slicc/parser.py
src/mem/slicc/symbols/RequestType.py [new file with mode: 0644]
src/mem/slicc/symbols/StateMachine.py
src/mem/slicc/symbols/Transition.py
src/mem/slicc/symbols/__init__.py

index 1961204f7222e955b00a827404c08efd799fbd04..caa7fe501f20f69936644878f0c8061e4b586440 100644 (file)
@@ -85,6 +85,7 @@ DebugFlag('RubySequencer')
 DebugFlag('RubySlicc')
 DebugFlag('RubySystem')
 DebugFlag('RubyTester')
+DebugFlag('RubyStats')
 
 CompoundFlag('Ruby', [ 'RubyQueue', 'RubyNetwork', 'RubyTester',
     'RubyGenerated', 'RubySlicc', 'RubySystem', 'RubyCache',
index ca80047f7b8ebf126cd305b621474eee3b117bf0..ef752c604f0766ec657549eefee612c12b139698 100644 (file)
@@ -138,6 +138,7 @@ enumeration(RubyRequestType, desc="...", default="RubyRequestType_NULL") {
 }
 
 enumeration(SequencerRequestType, desc="...", default="SequencerRequestType_NULL") {
+  Default,    desc="Replace this with access_types passed to the DMA Ruby object";
   LD,          desc="Load";
   ST,          desc="Store";
   NULL,        desc="Invalid request type";
@@ -176,6 +177,25 @@ enumeration(GenericRequestType, desc="...", default="GenericRequestType_NULL") {
   NULL,        desc="null request type";
 }
 
+enumeration(CacheRequestType, desc="...", default="CacheRequestType_NULL") {
+  DataArrayRead,    desc="Read access to the cache's data array";
+  DataArrayWrite,   desc="Write access to the cache's data array";
+  TagArrayRead,     desc="Read access to the cache's tag array";
+  TagArrayWrite,    desc="Write access to the cache's tag array";
+}
+
+enumeration(DirectoryRequestType, desc="...", default="DirectoryRequestType_NULL") {
+  Default,    desc="Replace this with access_types passed to the Directory Ruby object";
+}
+
+enumeration(DMASequencerRequestType, desc="...", default="DMASequencerRequestType_NULL") {
+  Default,    desc="Replace this with access_types passed to the DMA Ruby object";
+}
+
+enumeration(MemoryControlRequestType, desc="...", default="MemoryControlRequestType_NULL") {
+  Default,    desc="Replace this with access_types passed to the DMA Ruby object";
+}
+
 enumeration(GenericMachineType, desc="...", default="GenericMachineType_NULL") {
   L1Cache,     desc="L1 Cache Mach";
   L2Cache,     desc="L2 Cache Mach";
index 3b90dab205eeac6d3e2a39f6bf58121f23e315fb..436b39273c528ba5b7757c23ded699364c193e1c 100644 (file)
@@ -108,6 +108,7 @@ structure (Sequencer, external = "yes") {
   void checkCoherence(Address);
   void profileNack(Address, int, int, uint64);
   void evictionCallback(Address);
+  void recordRequestType(SequencerRequestType);
 }
 
 structure(RubyRequest, desc="...", interface="Message", external="yes") {
@@ -130,6 +131,7 @@ structure (DirectoryMemory, external = "yes") {
   AbstractEntry lookup(Address);
   bool isPresent(Address);
   void invalidateBlock(Address);
+  void recordRequestType(DirectoryRequestType);
 }
 
 structure(AbstractCacheEntry, primitive="yes", external = "yes") {
@@ -151,6 +153,7 @@ structure (CacheMemory, external = "yes") {
                              PrefetchBit);
 
   void setMRU(Address);
+  void recordRequestType(CacheRequestType);
 }
 
 structure (WireBuffer, inport="yes", outport="yes", external = "yes") {
@@ -158,12 +161,13 @@ structure (WireBuffer, inport="yes", outport="yes", external = "yes") {
 }
 
 structure (MemoryControl, inport="yes", outport="yes", external = "yes") {
-
+  void recordRequestType(CacheRequestType);
 }
 
 structure (DMASequencer, external = "yes") {
   void ackCallback();
   void dataCallback(DataBlock);
+  void recordRequestType(CacheRequestType);
 }
 
 structure (TimerTable, inport="yes", external = "yes") {
index 9144a8dff3aa1430588a0ee21dbcc06ae4e7e992..a626dc13fc7bb0c29826ef86043858b57384d350 100644 (file)
@@ -29,6 +29,7 @@
 #include "base/intmath.hh"
 #include "debug/RubyCache.hh"
 #include "debug/RubyCacheTrace.hh"
+#include "debug/RubyStats.hh"
 #include "mem/protocol/AccessPermission.hh"
 #include "mem/ruby/system/CacheMemory.hh"
 #include "mem/ruby/system/System.hh"
@@ -476,3 +477,50 @@ CacheMemory::isLocked(const Address& address, int context)
     return m_cache[cacheSet][loc]->m_locked == context;
 }
 
+void
+CacheMemory::recordRequestType(CacheRequestType requestType) {
+    DPRINTF(RubyStats, "Recorded statistic: %s\n",
+            CacheRequestType_to_string(requestType));
+    switch(requestType) {
+    case CacheRequestType_DataArrayRead:
+        numDataArrayReads++;
+        return;
+    case CacheRequestType_DataArrayWrite:
+        numDataArrayWrites++;
+        return;
+    case CacheRequestType_TagArrayRead:
+        numTagArrayReads++;
+        return;
+    case CacheRequestType_TagArrayWrite:
+        numTagArrayWrites++;
+        return;
+    default:
+        warn("CacheMemory access_type not found: %s",
+             CacheRequestType_to_string(requestType));
+    }
+}
+
+void
+CacheMemory::regStats() {
+    using namespace Stats;
+
+    numDataArrayReads
+        .name(name() + ".num_data_array_reads")
+        .desc("number of data array reads")
+        ;
+
+    numDataArrayWrites
+        .name(name() + ".num_data_array_writes")
+        .desc("number of data array writes")
+        ;
+
+    numTagArrayReads
+        .name(name() + ".num_tag_array_reads")
+        .desc("number of tag array reads")
+        ;
+
+    numTagArrayWrites
+        .name(name() + ".num_tag_array_writes")
+        .desc("number of tag array writes")
+        ;
+}
index f270e88cd8ac0a71405bb31a6f71693261742b59..53cd6b2861386a938094677193820d5dc2c59b6b 100644 (file)
@@ -34,6 +34,8 @@
 #include <vector>
 
 #include "base/hashmap.hh"
+#include "base/statistics.hh"
+#include "mem/protocol/CacheRequestType.hh"
 #include "mem/protocol/GenericRequestType.hh"
 #include "mem/protocol/RubyRequest.hh"
 #include "mem/ruby/common/DataBlock.hh"
@@ -115,6 +117,14 @@ class CacheMemory : public SimObject
     void clearStats() const;
     void printStats(std::ostream& out) const;
 
+    void recordRequestType(CacheRequestType requestType);
+    void regStats();
+
+    Stats::Scalar numDataArrayReads;
+    Stats::Scalar numDataArrayWrites;
+    Stats::Scalar numTagArrayReads;
+    Stats::Scalar numTagArrayWrites;
+
   private:
     // convert a Address to its location in the cache
     Index addressToCacheSet(const Address& address) const;
index 763eb586afbf95dc7df555c623f97b1872e07bd9..b1502573b72a62f7e57644bcfb3500a86306bdbd 100644 (file)
@@ -27,6 +27,7 @@
  */
 
 #include "debug/RubyDma.hh"
+#include "debug/RubyStats.hh"
 #include "mem/protocol/SequencerMsg.hh"
 #include "mem/protocol/SequencerRequestType.hh"
 #include "mem/ruby/buffers/MessageBuffer.hh"
@@ -168,6 +169,12 @@ DMASequencer::printConfig(std::ostream & out)
 {
 }
 
+void
+DMASequencer::recordRequestType(DMASequencerRequestType requestType) {
+    DPRINTF(RubyStats, "Recorded statistic: %s\n",
+            DMASequencerRequestType_to_string(requestType));
+}
+
 DMASequencer *
 DMASequencerParams::create()
 {
index 099c1d99117e733f1c1066d77fc0d5b472121bb1..d1fb2ff4964721afe2321111c5976f4e3c3c3de3 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <ostream>
 
+#include "mem/protocol/DMASequencerRequestType.hh"
 #include "mem/ruby/common/DataBlock.hh"
 #include "mem/ruby/system/RubyPort.hh"
 #include "params/DMASequencer.hh"
@@ -65,6 +66,8 @@ class DMASequencer : public RubyPort
 
     void printConfig(std::ostream & out);
 
+    void recordRequestType(DMASequencerRequestType requestType);
+
   private:
     void issueNext();
 
index d2e00ab3b3e7fd8827e175fce585eb6e2b152039..c67babda4c598ec4d9128727fe480a5c953b5817 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "base/intmath.hh"
 #include "debug/RubyCache.hh"
+#include "debug/RubyStats.hh"
 #include "mem/ruby/slicc_interface/RubySlicc_Util.hh"
 #include "mem/ruby/system/DirectoryMemory.hh"
 #include "mem/ruby/system/System.hh"
@@ -226,6 +227,12 @@ DirectoryMemory::printStats(ostream& out) const
     }
 }
 
+void
+DirectoryMemory::recordRequestType(DirectoryRequestType requestType) {
+    DPRINTF(RubyStats, "Recorded statistic: %s\n",
+            DirectoryRequestType_to_string(requestType));
+}
+
 DirectoryMemory *
 RubyDirectoryMemoryParams::create()
 {
index 1b4d09b8e8391322a0ee734f8a511cca909d4280..61938f7c8dda3726679f392bb40865895d093a25 100644 (file)
@@ -33,6 +33,7 @@
 #include <string>
 
 #include "mem/ruby/common/Address.hh"
+#include "mem/protocol/DirectoryRequestType.hh"
 #include "mem/ruby/slicc_interface/AbstractEntry.hh"
 #include "mem/ruby/system/MemoryVector.hh"
 #include "mem/ruby/system/SparseMemory.hh"
@@ -66,6 +67,8 @@ class DirectoryMemory : public SimObject
     void print(std::ostream& out) const;
     void printStats(std::ostream& out) const;
 
+    void recordRequestType(DirectoryRequestType requestType);
+
   private:
     // Private copy constructor and assignment operator
     DirectoryMemory(const DirectoryMemory& obj);
index c3b34d96560b202591d5d8556f062647c729719a..14a34be4a5b025ab00099ebe4779cca60b2a8519 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "base/cast.hh"
 #include "base/cprintf.hh"
+#include "debug/RubyStats.hh"
 #include "mem/ruby/common/Address.hh"
 #include "mem/ruby/common/Consumer.hh"
 #include "mem/ruby/common/Global.hh"
@@ -48,6 +49,12 @@ MemoryControl::MemoryControl(const Params *p) : SimObject(p), m_event(this)
 
 MemoryControl::~MemoryControl() {};
 
+void
+MemoryControl::recordRequestType(MemoryControlRequestType request) {
+    DPRINTF(RubyStats, "Recorded request: %s\n",
+            MemoryControlRequestType_to_string(request));
+}
+
 RubyMemoryControl *
 RubyMemoryControlParams::create()
 {
index 7e35ef7a062c926bd48739496ef39800c736b1f1..6a3ca48d9e5f3107332b8460890348cb2947c891 100644 (file)
@@ -35,6 +35,7 @@
 #include <string>
 
 #include "mem/protocol/MemoryMsg.hh"
+#include "mem/protocol/MemoryControlRequestType.hh"
 #include "mem/ruby/common/Consumer.hh"
 #include "mem/ruby/profiler/MemCntrlProfiler.hh"
 #include "mem/ruby/slicc_interface/Message.hh"
@@ -95,6 +96,8 @@ class MemoryControl :
     virtual int getRanksPerDimm() = 0;
     virtual int getDimmsPerChannel() = 0;
 
+    virtual void recordRequestType(MemoryControlRequestType requestType);
+
 protected:
     class MemCntrlEvent : public Event
     {
index de7c8154b9d13bdc78958e940e5fdc50d02ff89d..8733ec514d8535784a2461923a9041a3881dbd42 100644 (file)
@@ -36,6 +36,7 @@
 #include "debug/MemoryAccess.hh"
 #include "debug/ProtocolTrace.hh"
 #include "debug/RubySequencer.hh"
+#include "debug/RubyStats.hh"
 #include "mem/protocol/PrefetchBit.hh"
 #include "mem/protocol/RubyAccessMode.hh"
 #include "mem/ruby/buffers/MessageBuffer.hh"
@@ -730,6 +731,13 @@ Sequencer::checkCoherence(const Address& addr)
 #endif
 }
 
+void
+Sequencer::recordRequestType(SequencerRequestType requestType) {
+    DPRINTF(RubyStats, "Recorded statistic: %s\n",
+            SequencerRequestType_to_string(requestType));
+}
+
+
 void
 Sequencer::evictionCallback(const Address& address)
 {
index 29625899483ca3c9ba5b53e2594cc3fb30dfe4e9..2778cf3800727bc6532832af38e56acd577f1551 100644 (file)
@@ -34,6 +34,7 @@
 #include "base/hashmap.hh"
 #include "mem/protocol/GenericMachineType.hh"
 #include "mem/protocol/RubyRequestType.hh"
+#include "mem/protocol/SequencerRequestType.hh"
 #include "mem/ruby/common/Address.hh"
 #include "mem/ruby/common/Consumer.hh"
 #include "mem/ruby/system/RubyPort.hh"
@@ -119,6 +120,8 @@ class Sequencer : public RubyPort, public Consumer
     void removeRequest(SequencerRequest* request);
     void evictionCallback(const Address& address);
 
+    void recordRequestType(SequencerRequestType requestType);
+
   private:
     void issueRequest(PacketPtr pkt, RubyRequestType type);
 
index a941d7b0c9e3efcab5924f9b5cdd839b6cecb1dd..41e5b9aff6a6b538e5ebc07052129bda378d66e5 100644 (file)
@@ -29,9 +29,11 @@ from slicc.ast.DeclAST import DeclAST
 from slicc.symbols import Transition
 
 class TransitionDeclAST(DeclAST):
-    def __init__(self, slicc, states, events, next_state, pairs, actions):
+    def __init__(self, slicc, request_types, states, events, next_state, pairs,
+                 actions):
         super(TransitionDeclAST, self).__init__(slicc, pairs)
 
+        self.request_types = request_types
         self.states = states
         self.events = events
         self.next_state = next_state
@@ -51,6 +53,12 @@ class TransitionDeclAST(DeclAST):
                 self.error("Invalid action: %s is not part of machine: %s" % \
                            (action, machine))
 
+        for request_type in self.request_types:
+            if request_type not in machine.request_types:
+                self.error("Invalid protocol access type: " \
+                           "%s is not part of machine: %s" % \
+                           (request_type, machine))
+
         for state in self.states:
             if state not in machine.states:
                 self.error("Invalid state: %s is not part of machine: %s" % \
@@ -61,5 +69,6 @@ class TransitionDeclAST(DeclAST):
                     self.error("Invalid event: %s is not part of machine: %s" % \
                                (event, machine))
                 t = Transition(self.symtab, machine, state, event, next_state,
-                               self.actions, self.location, self.pairs)
+                               self.actions, self.request_types, self.location,
+                               self.pairs)
                 machine.addTransition(t)
index 398604550b41257ab9dcf429d95fef7235149598..1255c972aa3156bf37432d4c5350b373e7c5ad1f 100644 (file)
@@ -26,7 +26,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 from slicc.ast.TypeFieldAST import TypeFieldAST
-from slicc.symbols import Event, State
+from slicc.symbols import Event, State, RequestType
 
 class TypeFieldEnumAST(TypeFieldAST):
     def __init__(self, slicc, field_id, pairs_ast):
@@ -54,3 +54,10 @@ class TypeFieldEnumAST(TypeFieldAST):
                 self.error("Event declaration not part of a machine.")
             e = Event(self.symtab, self.field_id, self.location, self.pairs)
             machine.addEvent(e)
+
+        if str(type) == "RequestType":
+            if not machine:
+                self.error("RequestType declaration not part of a machine.")
+            s = RequestType(self.symtab, self.field_id, self.location,
+                           self.pairs)
+            machine.addRequestType(s)
index f35a3691a9708bbb980134abb6769a9e5a90ae32..e4f3ba9529feec6290cb178cb867938a8ee63cd6 100644 (file)
@@ -270,11 +270,19 @@ class SLICC(Grammar):
 
     def p_decl__trans0(self, p):
         "decl : TRANS '(' idents ',' idents ',' ident pairs ')' idents"
-        p[0] = ast.TransitionDeclAST(self, p[3], p[5], p[7], p[8], p[10])
+        p[0] = ast.TransitionDeclAST(self, [], p[3], p[5], p[7], p[8], p[10])
 
     def p_decl__trans1(self, p):
         "decl : TRANS '(' idents ',' idents           pairs ')' idents"
-        p[0] = ast.TransitionDeclAST(self, p[3], p[5], None, p[6], p[8])
+        p[0] = ast.TransitionDeclAST(self, [], p[3], p[5], None, p[6], p[8])
+
+    def p_decl__trans2(self, p):
+        "decl : TRANS '(' idents ',' idents ',' ident pairs ')' idents idents"
+        p[0] = ast.TransitionDeclAST(self, p[10], p[3], p[5], p[7], p[8], p[11])
+
+    def p_decl__trans3(self, p):
+        "decl : TRANS '(' idents ',' idents           pairs ')' idents idents"
+        p[0] = ast.TransitionDeclAST(self, p[8], p[3], p[5], None, p[6], p[9])
 
     def p_decl__extern0(self, p):
         "decl : EXTERN_TYPE '(' type pairs ')' SEMI"
diff --git a/src/mem/slicc/symbols/RequestType.py b/src/mem/slicc/symbols/RequestType.py
new file mode 100644 (file)
index 0000000..dd2f4aa
--- /dev/null
@@ -0,0 +1,33 @@
+# Copyright (c) 2010 Advanced Micro Devices, Inc.
+# All rights reserved.
+#
+# 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.
+
+from slicc.symbols.Symbol import Symbol
+
+class RequestType(Symbol):
+    def __repr__(self):
+        return "[RequestType: %s]" % self.ident
+
+__all__ = [ "RequestType" ]
index 8f4676c4221e76c261bf3127f6353b81fe7b3768..230eb1b222b666447468aae24380e7ceda5f9644 100644 (file)
@@ -61,6 +61,7 @@ class StateMachine(Symbol):
         self.states = orderdict()
         self.events = orderdict()
         self.actions = orderdict()
+        self.request_types = orderdict()
         self.transitions = []
         self.in_ports = []
         self.functions = []
@@ -97,6 +98,10 @@ class StateMachine(Symbol):
 
         self.actions[action.ident] = action
 
+    def addRequestType(self, request_type):
+        assert self.table is None
+        self.request_types[request_type.ident] = request_type
+
     def addTransition(self, trans):
         assert self.table is None
         self.transitions.append(trans)
@@ -989,6 +994,10 @@ $c_ident::${{action.ident}}(const Address& addr)
         code = self.symtab.codeFormatter()
         ident = self.ident
 
+        outputRequest_types = True
+        if len(self.request_types) == 0:
+            outputRequest_types = False
+
         code('''
 // Auto generated C++ code started by $__file__:$__line__
 // ${ident}: ${{self.short}}
@@ -1003,6 +1012,12 @@ $c_ident::${{action.ident}}(const Address& addr)
 #include "mem/protocol/${ident}_Controller.hh"
 #include "mem/protocol/${ident}_Event.hh"
 #include "mem/protocol/${ident}_State.hh"
+''')
+
+        if outputRequest_types:
+            code('''#include "mem/protocol/${ident}_RequestType.hh"''')
+
+        code('''
 #include "mem/protocol/Types.hh"
 #include "mem/ruby/common/Global.hh"
 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
@@ -1210,6 +1225,7 @@ ${ident}_Controller::doTransitionWorker(${ident}_Event event,
                 case('next_state = ${ident}_State_${ns_ident};')
 
             actions = trans.actions
+            request_types = trans.request_types
 
             # Check for resources
             case_sorter = []
@@ -1229,6 +1245,10 @@ if (!%s.areNSlotsAvailable(%s))
             for c in sorted(case_sorter):
                 case("$c")
 
+            # Record access types for this transition
+            for request_type in request_types:
+                case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
+
             # Figure out if we stall
             stall = False
             for action in actions:
index 1bf09048ab43bca20f965eb7b8077eabd8f318e1..96bb0056c8c53e536fdac2b4239f9e369b566a56 100644 (file)
@@ -29,7 +29,7 @@ from slicc.symbols.Symbol import Symbol
 
 class Transition(Symbol):
     def __init__(self, table, machine, state, event, nextState, actions,
-                 location, pairs):
+                 request_types, location, pairs):
         ident = "%s|%s" % (state, event)
         super(Transition, self).__init__(table, ident, location, pairs)
 
@@ -37,6 +37,7 @@ class Transition(Symbol):
         self.event = machine.events[event]
         self.nextState = machine.states[nextState]
         self.actions = [ machine.actions[a] for a in actions ]
+        self.request_types = [ machine.request_types[s] for s in request_types ]
         self.resources = {}
 
         for action in self.actions:
index 43388a5fec6fbb3de953efef5dc9ce8927b8d7fb..0f8dde3a280a1afe4b6b13a3aeebf14b1a04d900 100644 (file)
@@ -30,6 +30,7 @@ from slicc.symbols.Action import Action
 from slicc.symbols.Event import Event
 from slicc.symbols.Func import Func
 from slicc.symbols.State import State
+from slicc.symbols.RequestType import RequestType
 from slicc.symbols.StateMachine import StateMachine
 from slicc.symbols.Symbol import Symbol
 from slicc.symbols.SymbolTable import SymbolTable