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.
This commit is contained in:
Joel Hestness
2012-07-10 22:51:54 -07:00
parent c10f348120
commit 467093ebf2
20 changed files with 210 additions and 7 deletions

View File

@@ -85,6 +85,7 @@ DebugFlag('RubySequencer')
DebugFlag('RubySlicc')
DebugFlag('RubySystem')
DebugFlag('RubyTester')
DebugFlag('RubyStats')
CompoundFlag('Ruby', [ 'RubyQueue', 'RubyNetwork', 'RubyTester',
'RubyGenerated', 'RubySlicc', 'RubySystem', 'RubyCache',

View 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";

View 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") {

View 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")
;
}

View 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;

View 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()
{

View 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();

View 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()
{

View 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);

View 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()
{

View 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
{

View 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)
{

View 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);

View 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)

View 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)

View 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"

View File

@@ -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" ]

View 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:

View 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:

View 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