From: Joel Hestness Date: Wed, 11 Jul 2012 05:51:54 +0000 (-0700) Subject: ruby: tag and data cache access support X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=467093ebf238a1954e00576daf14a9f246b51e79;p=gem5.git ruby: tag and data cache access support 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. --- diff --git a/src/mem/SConscript b/src/mem/SConscript index 1961204f7..caa7fe501 100644 --- a/src/mem/SConscript +++ b/src/mem/SConscript @@ -85,6 +85,7 @@ DebugFlag('RubySequencer') DebugFlag('RubySlicc') DebugFlag('RubySystem') DebugFlag('RubyTester') +DebugFlag('RubyStats') CompoundFlag('Ruby', [ 'RubyQueue', 'RubyNetwork', 'RubyTester', 'RubyGenerated', 'RubySlicc', 'RubySystem', 'RubyCache', diff --git a/src/mem/protocol/RubySlicc_Exports.sm b/src/mem/protocol/RubySlicc_Exports.sm index ca80047f7..ef752c604 100644 --- a/src/mem/protocol/RubySlicc_Exports.sm +++ b/src/mem/protocol/RubySlicc_Exports.sm @@ -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"; diff --git a/src/mem/protocol/RubySlicc_Types.sm b/src/mem/protocol/RubySlicc_Types.sm index 3b90dab20..436b39273 100644 --- a/src/mem/protocol/RubySlicc_Types.sm +++ b/src/mem/protocol/RubySlicc_Types.sm @@ -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") { diff --git a/src/mem/ruby/system/CacheMemory.cc b/src/mem/ruby/system/CacheMemory.cc index 9144a8dff..a626dc13f 100644 --- a/src/mem/ruby/system/CacheMemory.cc +++ b/src/mem/ruby/system/CacheMemory.cc @@ -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") + ; +} diff --git a/src/mem/ruby/system/CacheMemory.hh b/src/mem/ruby/system/CacheMemory.hh index f270e88cd..53cd6b286 100644 --- a/src/mem/ruby/system/CacheMemory.hh +++ b/src/mem/ruby/system/CacheMemory.hh @@ -34,6 +34,8 @@ #include #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; diff --git a/src/mem/ruby/system/DMASequencer.cc b/src/mem/ruby/system/DMASequencer.cc index 763eb586a..b1502573b 100644 --- a/src/mem/ruby/system/DMASequencer.cc +++ b/src/mem/ruby/system/DMASequencer.cc @@ -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() { diff --git a/src/mem/ruby/system/DMASequencer.hh b/src/mem/ruby/system/DMASequencer.hh index 099c1d991..d1fb2ff49 100644 --- a/src/mem/ruby/system/DMASequencer.hh +++ b/src/mem/ruby/system/DMASequencer.hh @@ -31,6 +31,7 @@ #include +#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(); diff --git a/src/mem/ruby/system/DirectoryMemory.cc b/src/mem/ruby/system/DirectoryMemory.cc index d2e00ab3b..c67babda4 100644 --- a/src/mem/ruby/system/DirectoryMemory.cc +++ b/src/mem/ruby/system/DirectoryMemory.cc @@ -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() { diff --git a/src/mem/ruby/system/DirectoryMemory.hh b/src/mem/ruby/system/DirectoryMemory.hh index 1b4d09b8e..61938f7c8 100644 --- a/src/mem/ruby/system/DirectoryMemory.hh +++ b/src/mem/ruby/system/DirectoryMemory.hh @@ -33,6 +33,7 @@ #include #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); diff --git a/src/mem/ruby/system/MemoryControl.cc b/src/mem/ruby/system/MemoryControl.cc index c3b34d965..14a34be4a 100644 --- a/src/mem/ruby/system/MemoryControl.cc +++ b/src/mem/ruby/system/MemoryControl.cc @@ -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() { diff --git a/src/mem/ruby/system/MemoryControl.hh b/src/mem/ruby/system/MemoryControl.hh index 7e35ef7a0..6a3ca48d9 100644 --- a/src/mem/ruby/system/MemoryControl.hh +++ b/src/mem/ruby/system/MemoryControl.hh @@ -35,6 +35,7 @@ #include #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 { diff --git a/src/mem/ruby/system/Sequencer.cc b/src/mem/ruby/system/Sequencer.cc index de7c8154b..8733ec514 100644 --- a/src/mem/ruby/system/Sequencer.cc +++ b/src/mem/ruby/system/Sequencer.cc @@ -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) { diff --git a/src/mem/ruby/system/Sequencer.hh b/src/mem/ruby/system/Sequencer.hh index 296258994..2778cf380 100644 --- a/src/mem/ruby/system/Sequencer.hh +++ b/src/mem/ruby/system/Sequencer.hh @@ -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); diff --git a/src/mem/slicc/ast/TransitionDeclAST.py b/src/mem/slicc/ast/TransitionDeclAST.py index a941d7b0c..41e5b9aff 100644 --- a/src/mem/slicc/ast/TransitionDeclAST.py +++ b/src/mem/slicc/ast/TransitionDeclAST.py @@ -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) diff --git a/src/mem/slicc/ast/TypeFieldEnumAST.py b/src/mem/slicc/ast/TypeFieldEnumAST.py index 398604550..1255c972a 100644 --- a/src/mem/slicc/ast/TypeFieldEnumAST.py +++ b/src/mem/slicc/ast/TypeFieldEnumAST.py @@ -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) diff --git a/src/mem/slicc/parser.py b/src/mem/slicc/parser.py index f35a3691a..e4f3ba952 100644 --- a/src/mem/slicc/parser.py +++ b/src/mem/slicc/parser.py @@ -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 index 000000000..dd2f4aa88 --- /dev/null +++ b/src/mem/slicc/symbols/RequestType.py @@ -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" ] diff --git a/src/mem/slicc/symbols/StateMachine.py b/src/mem/slicc/symbols/StateMachine.py index 8f4676c42..230eb1b22 100644 --- a/src/mem/slicc/symbols/StateMachine.py +++ b/src/mem/slicc/symbols/StateMachine.py @@ -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: diff --git a/src/mem/slicc/symbols/Transition.py b/src/mem/slicc/symbols/Transition.py index 1bf09048a..96bb0056c 100644 --- a/src/mem/slicc/symbols/Transition.py +++ b/src/mem/slicc/symbols/Transition.py @@ -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: diff --git a/src/mem/slicc/symbols/__init__.py b/src/mem/slicc/symbols/__init__.py index 43388a5fe..0f8dde3a2 100644 --- a/src/mem/slicc/symbols/__init__.py +++ b/src/mem/slicc/symbols/__init__.py @@ -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