diff --git a/src/mem/SConscript b/src/mem/SConscript --- a/src/mem/SConscript +++ b/src/mem/SConscript @@ -85,6 +85,7 @@ 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 --- a/src/mem/protocol/RubySlicc_Exports.sm +++ b/src/mem/protocol/RubySlicc_Exports.sm @@ -176,6 +176,29 @@ NULL, desc="null request type"; } +enumeration(CacheAccessType, desc="...", default="CacheAccessType_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(DirectoryAccessType, desc="...", default="DirectoryAccessType_NULL") { + Default, desc="Replace this with access_types passed to the Directory Ruby object"; +} + +enumeration(DMASequencerAccessType, desc="...", default="DMASequencerAccessType_NULL") { + Default, desc="Replace this with access_types passed to the DMA Ruby object"; +} + +enumeration(MemoryControlAccessType, desc="...", default="MemoryControlAccessType_NULL") { + Default, desc="Replace this with access_types passed to the DMA Ruby object"; +} + +enumeration(SequencerAccessType, desc="...", default="SequencerAccessType_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 --- a/src/mem/protocol/RubySlicc_Types.sm +++ b/src/mem/protocol/RubySlicc_Types.sm @@ -108,6 +108,7 @@ void checkCoherence(Address); void profileNack(Address, int, int, uint64); void evictionCallback(Address); + void recordAccess(SequencerAccessType); } structure(RubyRequest, desc="...", interface="Message", external="yes") { @@ -130,6 +131,7 @@ AbstractEntry lookup(Address); bool isPresent(Address); void invalidateBlock(Address); + void recordAccess(DirectoryAccessType); } structure(AbstractCacheEntry, primitive="yes", external = "yes") { @@ -151,6 +153,7 @@ PrefetchBit); void setMRU(Address); + void recordAccess(CacheAccessType); } structure (WireBuffer, inport="yes", outport="yes", external = "yes") { @@ -158,12 +161,13 @@ } structure (MemoryControl, inport="yes", outport="yes", external = "yes") { - + void recordAccess(CacheAccessType); } structure (DMASequencer, external = "yes") { void ackCallback(); void dataCallback(DataBlock); + void recordAccess(CacheAccessType); } structure (TimerTable, inport="yes", external = "yes") { diff --git a/src/mem/ruby/system/CacheMemory.hh b/src/mem/ruby/system/CacheMemory.hh --- 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/CacheAccessType.hh" #include "mem/protocol/GenericRequestType.hh" #include "mem/protocol/RubyRequest.hh" #include "mem/ruby/common/DataBlock.hh" @@ -115,6 +117,14 @@ void clearStats() const; void printStats(std::ostream& out) const; + void recordAccess(CacheAccessType accessType); + 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/CacheMemory.cc b/src/mem/ruby/system/CacheMemory.cc --- 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 @@ return m_cache[cacheSet][loc]->m_locked == context; } +void +CacheMemory::recordAccess(CacheAccessType accessType) { + DPRINTF(RubyStats, "Recorded statistic: %s\n", + CacheAccessType_to_string(accessType)); + switch(accessType) { + case CacheAccessType_DataArrayRead: + numDataArrayReads++; + return; + case CacheAccessType_DataArrayWrite: + numDataArrayWrites++; + return; + case CacheAccessType_TagArrayRead: + numTagArrayReads++; + return; + case CacheAccessType_TagArrayWrite: + numTagArrayWrites++; + return; + default: + warn("CacheMemory access_type not found: %s", + CacheAccessType_to_string(accessType)); + } +} + +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/DMASequencer.hh b/src/mem/ruby/system/DMASequencer.hh --- a/src/mem/ruby/system/DMASequencer.hh +++ b/src/mem/ruby/system/DMASequencer.hh @@ -31,6 +31,7 @@ #include +#include "mem/protocol/DMASequencerAccessType.hh" #include "mem/ruby/common/DataBlock.hh" #include "mem/ruby/system/RubyPort.hh" #include "params/DMASequencer.hh" @@ -65,6 +66,8 @@ void printConfig(std::ostream & out); + void recordAccess(DMASequencerAccessType accessType); + private: void issueNext(); diff --git a/src/mem/ruby/system/DMASequencer.cc b/src/mem/ruby/system/DMASequencer.cc --- 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 @@ { } +void +DMASequencer::recordAccess(DMASequencerAccessType accessType) { + DPRINTF(RubyStats, "Recorded statistic: %s\n", + DMASequencerAccessType_to_string(accessType)); +} + DMASequencer * DMASequencerParams::create() { diff --git a/src/mem/ruby/system/DirectoryMemory.hh b/src/mem/ruby/system/DirectoryMemory.hh --- 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/DirectoryAccessType.hh" #include "mem/ruby/slicc_interface/AbstractEntry.hh" #include "mem/ruby/system/MemoryVector.hh" #include "mem/ruby/system/SparseMemory.hh" @@ -66,6 +67,8 @@ void print(std::ostream& out) const; void printStats(std::ostream& out) const; + void recordAccess(DirectoryAccessType accessType); + private: // Private copy constructor and assignment operator DirectoryMemory(const DirectoryMemory& obj); diff --git a/src/mem/ruby/system/DirectoryMemory.cc b/src/mem/ruby/system/DirectoryMemory.cc --- 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 @@ } } +void +DirectoryMemory::recordAccess(DirectoryAccessType accessType) { + DPRINTF(RubyStats, "Recorded statistic: %s\n", + DirectoryAccessType_to_string(accessType)); +} + DirectoryMemory * RubyDirectoryMemoryParams::create() { diff --git a/src/mem/ruby/system/MemoryControl.hh b/src/mem/ruby/system/MemoryControl.hh --- 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/MemoryControlAccessType.hh" #include "mem/ruby/common/Consumer.hh" #include "mem/ruby/profiler/MemCntrlProfiler.hh" #include "mem/ruby/slicc_interface/Message.hh" @@ -95,6 +96,8 @@ virtual int getRanksPerDimm() = 0; virtual int getDimmsPerChannel() = 0; + virtual void recordAccess(MemoryControlAccessType accessType); + protected: class MemCntrlEvent : public Event { diff --git a/src/mem/ruby/system/MemoryControl.cc b/src/mem/ruby/system/MemoryControl.cc --- 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() {}; +void +MemoryControl::recordStatistic(MemoryControlStatisticType stat) { + DPRINTF(RubyStats, "Recorded statistic: %s\n", + MemoryControlStatisticType_to_string(stat)); +} + RubyMemoryControl * RubyMemoryControlParams::create() { diff --git a/src/mem/ruby/system/Sequencer.hh b/src/mem/ruby/system/Sequencer.hh --- 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/SequencerAccessType.hh" #include "mem/ruby/common/Address.hh" #include "mem/ruby/common/Consumer.hh" #include "mem/ruby/system/RubyPort.hh" @@ -119,6 +120,8 @@ void removeRequest(SequencerRequest* request); void evictionCallback(const Address& address); + void recordAccess(SequencerAccessType accessType); + private: void issueRequest(PacketPtr pkt, RubyRequestType type); diff --git a/src/mem/ruby/system/Sequencer.cc b/src/mem/ruby/system/Sequencer.cc --- 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" @@ -731,6 +732,13 @@ } void +Sequencer::recordAccess(SequencerAccessType accessType) { + DPRINTF(RubyStats, "Recorded statistic: %s\n", + SequencerAccessType_to_string(accessType)); +} + + +void Sequencer::evictionCallback(const Address& address) { ruby_eviction_callback(address); diff --git a/src/mem/slicc/ast/TransitionDeclAST.py b/src/mem/slicc/ast/TransitionDeclAST.py --- a/src/mem/slicc/ast/TransitionDeclAST.py +++ b/src/mem/slicc/ast/TransitionDeclAST.py @@ -29,9 +29,11 @@ from slicc.symbols import Transition class TransitionDeclAST(DeclAST): - def __init__(self, slicc, states, events, next_state, pairs, actions): + def __init__(self, slicc, access_types, states, events, next_state, pairs, + actions): super(TransitionDeclAST, self).__init__(slicc, pairs) + self.access_types = access_types self.states = states self.events = events self.next_state = next_state @@ -51,6 +53,12 @@ self.error("Invalid action: %s is not part of machine: %s" % \ (action, machine)) + for access_type in self.access_types: + if access_type not in machine.access_types: + self.error("Invalid protocol access type: " \ + "%s is not part of machine: %s" % \ + (access_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 @@ 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.access_types, self.location, + self.pairs) machine.addTransition(t) diff --git a/src/mem/slicc/ast/TypeFieldEnumAST.py b/src/mem/slicc/ast/TypeFieldEnumAST.py --- 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, AccessType class TypeFieldEnumAST(TypeFieldAST): def __init__(self, slicc, field_id, pairs_ast): @@ -54,3 +54,10 @@ 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) == "AccessType": + if not machine: + self.error("AccessType declaration not part of a machine.") + s = AccessType(self.symtab, self.field_id, self.location, + self.pairs) + machine.addAccessType(s) diff --git a/src/mem/slicc/parser.py b/src/mem/slicc/parser.py --- a/src/mem/slicc/parser.py +++ b/src/mem/slicc/parser.py @@ -270,11 +270,19 @@ 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/AccessType.py b/src/mem/slicc/symbols/AccessType.py --- /dev/null +++ b/src/mem/slicc/symbols/AccessType.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 AccessType(Symbol): + def __repr__(self): + return "[AccessType: %s]" % self.ident + +__all__ = [ "AccessType" ] diff --git a/src/mem/slicc/symbols/StateMachine.py b/src/mem/slicc/symbols/StateMachine.py --- a/src/mem/slicc/symbols/StateMachine.py +++ b/src/mem/slicc/symbols/StateMachine.py @@ -61,6 +61,7 @@ self.states = orderdict() self.events = orderdict() self.actions = orderdict() + self.access_types = orderdict() self.transitions = [] self.in_ports = [] self.functions = [] @@ -97,6 +98,10 @@ self.actions[action.ident] = action + def addAccessType(self, access_type): + assert self.table is None + self.access_types[access_type.ident] = access_type + def addTransition(self, trans): assert self.table is None self.transitions.append(trans) @@ -989,6 +994,10 @@ code = self.symtab.codeFormatter() ident = self.ident + outputAccess_types = True + if len(self.access_types) == 0: + outputAccess_types = False + code(''' // Auto generated C++ code started by $__file__:$__line__ // ${ident}: ${{self.short}} @@ -1003,6 +1012,12 @@ #include "mem/protocol/${ident}_Controller.hh" #include "mem/protocol/${ident}_Event.hh" #include "mem/protocol/${ident}_State.hh" +''') + + if outputAccess_types: + code('''#include "mem/protocol/${ident}_AccessType.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 @@ case('next_state = ${ident}_State_${ns_ident};') actions = trans.actions + access_types = trans.access_types # Check for resources case_sorter = [] @@ -1229,6 +1245,10 @@ for c in sorted(case_sorter): case("$c") + # Record access types for this transition + for access_type in access_types: + case('recordAccessType(${ident}_AccessType_${{access_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 --- a/src/mem/slicc/symbols/Transition.py +++ b/src/mem/slicc/symbols/Transition.py @@ -29,7 +29,7 @@ class Transition(Symbol): def __init__(self, table, machine, state, event, nextState, actions, - location, pairs): + access_types, location, pairs): ident = "%s|%s" % (state, event) super(Transition, self).__init__(table, ident, location, pairs) @@ -37,6 +37,7 @@ self.event = machine.events[event] self.nextState = machine.states[nextState] self.actions = [ machine.actions[a] for a in actions ] + self.access_types = [ machine.access_types[s] for s in access_types ] self.resources = {} for action in self.actions: diff --git a/src/mem/slicc/symbols/__init__.py b/src/mem/slicc/symbols/__init__.py --- a/src/mem/slicc/symbols/__init__.py +++ b/src/mem/slicc/symbols/__init__.py @@ -30,6 +30,7 @@ from slicc.symbols.Event import Event from slicc.symbols.Func import Func from slicc.symbols.State import State +from slicc.symbols.AccessType import AccessType from slicc.symbols.StateMachine import StateMachine from slicc.symbols.Symbol import Symbol from slicc.symbols.SymbolTable import SymbolTable