mem: write combining for ruby protocols
This patch adds support for write-combining in ruby.
This commit is contained in:
parent
d658b6e1cc
commit
28e353e040
10 changed files with 343 additions and 0 deletions
|
@ -39,12 +39,25 @@ external_type(Addr, primitive="yes");
|
|||
external_type(Cycles, primitive="yes", default="Cycles(0)");
|
||||
external_type(Tick, primitive="yes", default="0");
|
||||
|
||||
structure(WriteMask, external="yes", desc="...") {
|
||||
void clear();
|
||||
bool cmpMask(WriteMask);
|
||||
bool isEmpty();
|
||||
bool isFull();
|
||||
bool isOverlap(WriteMask);
|
||||
void orMask(WriteMask);
|
||||
void fillMask();
|
||||
}
|
||||
|
||||
structure(DataBlock, external = "yes", desc="..."){
|
||||
void clear();
|
||||
void copyPartial(DataBlock, int, int);
|
||||
void copyPartial(DataBlock, WriteMask);
|
||||
void atomicPartial(DataBlock, WriteMask);
|
||||
}
|
||||
|
||||
bool testAndRead(Addr addr, DataBlock datablk, Packet *pkt);
|
||||
bool testAndReadMask(Addr addr, DataBlock datablk, WriteMask mask, Packet *pkt);
|
||||
bool testAndWrite(Addr addr, DataBlock datablk, Packet *pkt);
|
||||
|
||||
// AccessPermission
|
||||
|
|
|
@ -126,6 +126,8 @@ structure(RubyRequest, desc="...", interface="Message", external="yes") {
|
|||
int Size, desc="size in bytes of access";
|
||||
PrefetchBit Prefetch, desc="Is this a prefetch request";
|
||||
int contextId, desc="this goes away but must be replace with Nilay";
|
||||
WriteMask writeMask, desc="Writethrough mask";
|
||||
DataBlock WTData, desc="Writethrough data block";
|
||||
int wfid, desc="Writethrough wavefront";
|
||||
HSAScope scope, desc="HSA scope";
|
||||
HSASegment segment, desc="HSA segment";
|
||||
|
|
|
@ -121,6 +121,7 @@ MakeInclude('common/IntVec.hh')
|
|||
MakeInclude('common/MachineID.hh')
|
||||
MakeInclude('common/NetDest.hh')
|
||||
MakeInclude('common/Set.hh')
|
||||
MakeInclude('common/WriteMask.hh')
|
||||
MakeInclude('filters/AbstractBloomFilter.hh')
|
||||
MakeInclude('network/MessageBuffer.hh')
|
||||
MakeInclude('structures/Prefetcher.hh')
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
*/
|
||||
|
||||
#include "mem/ruby/common/DataBlock.hh"
|
||||
|
||||
#include "mem/ruby/common/WriteMask.hh"
|
||||
#include "mem/ruby/system/RubySystem.hh"
|
||||
|
||||
DataBlock::DataBlock(const DataBlock &cp)
|
||||
|
@ -56,6 +58,25 @@ DataBlock::equal(const DataBlock& obj) const
|
|||
return !memcmp(m_data, obj.m_data, RubySystem::getBlockSizeBytes());
|
||||
}
|
||||
|
||||
void
|
||||
DataBlock::copyPartial(const DataBlock &dblk, const WriteMask &mask)
|
||||
{
|
||||
for (int i = 0; i < RubySystem::getBlockSizeBytes(); i++) {
|
||||
if (mask.getMask(i, 1)) {
|
||||
m_data[i] = dblk.m_data[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DataBlock::atomicPartial(const DataBlock &dblk, const WriteMask &mask)
|
||||
{
|
||||
for (int i = 0; i < RubySystem::getBlockSizeBytes(); i++) {
|
||||
m_data[i] = dblk.m_data[i];
|
||||
}
|
||||
mask.performAtomic(m_data);
|
||||
}
|
||||
|
||||
void
|
||||
DataBlock::print(std::ostream& out) const
|
||||
{
|
||||
|
@ -77,6 +98,12 @@ DataBlock::getData(int offset, int len) const
|
|||
return &m_data[offset];
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
DataBlock::getDataMod(int offset)
|
||||
{
|
||||
return &m_data[offset];
|
||||
}
|
||||
|
||||
void
|
||||
DataBlock::setData(const uint8_t *data, int offset, int len)
|
||||
{
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
class WriteMask;
|
||||
|
||||
class DataBlock
|
||||
{
|
||||
public:
|
||||
|
@ -58,8 +60,12 @@ class DataBlock
|
|||
void clear();
|
||||
uint8_t getByte(int whichByte) const;
|
||||
const uint8_t *getData(int offset, int len) const;
|
||||
uint8_t *getDataMod(int offset);
|
||||
void setByte(int whichByte, uint8_t data);
|
||||
void setData(const uint8_t *data, int offset, int len);
|
||||
void copyPartial(const DataBlock &dblk, int offset, int len);
|
||||
void copyPartial(const DataBlock &dblk, const WriteMask &mask);
|
||||
void atomicPartial(const DataBlock & dblk, const WriteMask & mask);
|
||||
bool equal(const DataBlock& obj) const;
|
||||
void print(std::ostream& out) const;
|
||||
|
||||
|
|
|
@ -41,3 +41,4 @@ Source('Histogram.cc')
|
|||
Source('IntVec.cc')
|
||||
Source('NetDest.cc')
|
||||
Source('SubBlock.cc')
|
||||
Source('WriteMask.cc')
|
||||
|
|
46
src/mem/ruby/common/WriteMask.cc
Normal file
46
src/mem/ruby/common/WriteMask.cc
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2015 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.
|
||||
*/
|
||||
|
||||
#include "mem/ruby/common/WriteMask.hh"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "mem/ruby/system/RubySystem.hh"
|
||||
|
||||
void
|
||||
WriteMask::print(std::ostream& out) const
|
||||
{
|
||||
std::string str(mSize,'0');
|
||||
for (int i = 0; i < mSize; i++) {
|
||||
str[i] = mMask[i] ? ('1') : ('0');
|
||||
}
|
||||
out << "dirty mask="
|
||||
<< str
|
||||
<< std::flush;
|
||||
}
|
||||
|
202
src/mem/ruby/common/WriteMask.hh
Normal file
202
src/mem/ruby/common/WriteMask.hh
Normal file
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* Copyright (c) 2012-15 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.
|
||||
*/
|
||||
|
||||
#ifndef __MEM_RUBY_COMMON_WRITEMASK_HH__
|
||||
#define __MEM_RUBY_COMMON_WRITEMASK_HH__
|
||||
|
||||
#include <cassert>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "mem/ruby/common/TypeDefines.hh"
|
||||
#include "mem/ruby/system/RubySystem.hh"
|
||||
|
||||
class WriteMask
|
||||
{
|
||||
public:
|
||||
WriteMask()
|
||||
: mSize(RubySystem::getBlockSizeBytes()), mMask(mSize, false),
|
||||
mAtomic(false)
|
||||
{}
|
||||
|
||||
WriteMask(int size)
|
||||
: mSize(size), mMask(size, false), mAtomic(false)
|
||||
{}
|
||||
|
||||
WriteMask(int size, std::vector<bool> & mask)
|
||||
: mSize(size), mMask(mask), mAtomic(false)
|
||||
{}
|
||||
|
||||
WriteMask(int size, std::vector<bool> &mask,
|
||||
std::vector<std::pair<int, AtomicOpFunctor*> > atomicOp)
|
||||
: mSize(size), mMask(mask), mAtomic(true), mAtomicOp(atomicOp)
|
||||
{}
|
||||
|
||||
~WriteMask()
|
||||
{}
|
||||
|
||||
void
|
||||
clear()
|
||||
{
|
||||
mMask = std::vector<bool>(mSize, false);
|
||||
}
|
||||
|
||||
bool
|
||||
test(int offset)
|
||||
{
|
||||
assert(offset < mSize);
|
||||
return mMask[offset] == true;
|
||||
}
|
||||
|
||||
void
|
||||
setMask(int offset, int len)
|
||||
{
|
||||
assert(mSize >= (offset + len));
|
||||
for (int i = 0; i < len; i++) {
|
||||
mMask[offset + i] = true;
|
||||
}
|
||||
}
|
||||
void
|
||||
fillMask()
|
||||
{
|
||||
for (int i = 0; i < mSize; i++) {
|
||||
mMask[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
getMask(int offset, int len) const
|
||||
{
|
||||
bool tmp = true;
|
||||
assert(mSize >= (offset + len));
|
||||
for (int i = 0; i < len; i++) {
|
||||
tmp = tmp & mMask.at(offset + i);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool
|
||||
isOverlap(const WriteMask &readMask) const
|
||||
{
|
||||
bool tmp = false;
|
||||
assert(mSize == readMask.mSize);
|
||||
for (int i = 0; i < mSize; i++) {
|
||||
if (readMask.mMask.at(i)) {
|
||||
tmp = tmp | mMask.at(i);
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool
|
||||
cmpMask(const WriteMask &readMask) const
|
||||
{
|
||||
bool tmp = true;
|
||||
assert(mSize == readMask.mSize);
|
||||
for (int i = 0; i < mSize; i++) {
|
||||
if (readMask.mMask.at(i)) {
|
||||
tmp = tmp & mMask.at(i);
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool isEmpty() const
|
||||
{
|
||||
for (int i = 0; i < mSize; i++) {
|
||||
if (mMask.at(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
isFull() const
|
||||
{
|
||||
for (int i = 0; i < mSize; i++) {
|
||||
if (!mMask.at(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
orMask(const WriteMask & writeMask)
|
||||
{
|
||||
assert(mSize == writeMask.mSize);
|
||||
for (int i = 0; i < mSize; i++) {
|
||||
mMask[i] = (mMask.at(i)) | (writeMask.mMask.at(i));
|
||||
}
|
||||
|
||||
if (writeMask.mAtomic) {
|
||||
mAtomic = true;
|
||||
mAtomicOp = writeMask.mAtomicOp;
|
||||
}
|
||||
}
|
||||
|
||||
void print(std::ostream& out) const;
|
||||
|
||||
void
|
||||
performAtomic(uint8_t * p) const
|
||||
{
|
||||
for (int i = 0; i < mAtomicOp.size(); i++) {
|
||||
int offset = mAtomicOp[i].first;
|
||||
AtomicOpFunctor *fnctr = mAtomicOp[i].second;
|
||||
(*fnctr)(&p[offset]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
performAtomic(DataBlock & blk) const
|
||||
{
|
||||
for (int i = 0; i < mAtomicOp.size(); i++) {
|
||||
int offset = mAtomicOp[i].first;
|
||||
uint8_t *p = blk.getDataMod(offset);
|
||||
AtomicOpFunctor *fnctr = mAtomicOp[i].second;
|
||||
(*fnctr)(p);
|
||||
}
|
||||
}
|
||||
private:
|
||||
int mSize;
|
||||
std::vector<bool> mMask;
|
||||
bool mAtomic;
|
||||
std::vector<std::pair<int, AtomicOpFunctor*> > mAtomicOp;
|
||||
};
|
||||
|
||||
inline std::ostream&
|
||||
operator<<(std::ostream& out, const WriteMask& obj)
|
||||
{
|
||||
obj.print(out);
|
||||
out << std::flush;
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif // __MEM_RUBY_COMMON_WRITEMASK_HH__
|
|
@ -40,6 +40,7 @@
|
|||
#include "mem/protocol/RubyRequestType.hh"
|
||||
#include "mem/ruby/common/Address.hh"
|
||||
#include "mem/ruby/common/DataBlock.hh"
|
||||
#include "mem/ruby/common/WriteMask.hh"
|
||||
|
||||
class RubyRequest : public Message
|
||||
{
|
||||
|
@ -54,6 +55,8 @@ class RubyRequest : public Message
|
|||
uint8_t* data;
|
||||
PacketPtr pkt;
|
||||
ContextID m_contextId;
|
||||
WriteMask m_writeMask;
|
||||
DataBlock m_WTData;
|
||||
int m_wfid;
|
||||
HSAScope m_scope;
|
||||
HSASegment m_segment;
|
||||
|
@ -99,6 +102,8 @@ class RubyRequest : public Message
|
|||
data(_data),
|
||||
pkt(_pkt),
|
||||
m_contextId(_core_id),
|
||||
m_writeMask(_wm_size,_wm_mask),
|
||||
m_WTData(_Data),
|
||||
m_wfid(_proc_id),
|
||||
m_scope(_scope),
|
||||
m_segment(_segment)
|
||||
|
@ -125,6 +130,8 @@ class RubyRequest : public Message
|
|||
data(_data),
|
||||
pkt(_pkt),
|
||||
m_contextId(_core_id),
|
||||
m_writeMask(_wm_size,_wm_mask,_atomicOps),
|
||||
m_WTData(_Data),
|
||||
m_wfid(_proc_id),
|
||||
m_scope(_scope),
|
||||
m_segment(_segment)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
|
||||
* Copyright (c) 2013 Advanced Micro Devices, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -41,6 +42,7 @@
|
|||
#include "mem/ruby/common/BoolVec.hh"
|
||||
#include "mem/ruby/common/DataBlock.hh"
|
||||
#include "mem/ruby/common/TypeDefines.hh"
|
||||
#include "mem/ruby/common/WriteMask.hh"
|
||||
|
||||
inline Cycles zero_time() { return Cycles(0); }
|
||||
|
||||
|
@ -88,6 +90,12 @@ inline int max_tokens()
|
|||
* range for the data block contains the address which the packet needs to
|
||||
* read, then the data from the data block is written to the packet. True is
|
||||
* returned if the data block was read, otherwise false is returned.
|
||||
*
|
||||
* This is used during a functional access "search the world" operation. The
|
||||
* functional access looks in every place that might hold a valid data block
|
||||
* and, if it finds one, checks to see if it is holding the address the access
|
||||
* is searching for. During the access check, the WriteMask could be in any
|
||||
* state, including empty.
|
||||
*/
|
||||
inline bool
|
||||
testAndRead(Addr addr, DataBlock& blk, Packet *pkt)
|
||||
|
@ -108,6 +116,36 @@ testAndRead(Addr addr, DataBlock& blk, Packet *pkt)
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function accepts an address, a data block, a write mask and a packet.
|
||||
* If the valid address range for the data block contains the address which
|
||||
* the packet needs to read, then the data from the data block is written to
|
||||
* the packet. True is returned if any part of the data block was read,
|
||||
* otherwise false is returned.
|
||||
*/
|
||||
inline bool
|
||||
testAndReadMask(Addr addr, DataBlock& blk, WriteMask& mask, Packet *pkt)
|
||||
{
|
||||
Addr pktLineAddr = makeLineAddress(pkt->getAddr());
|
||||
Addr lineAddr = makeLineAddress(addr);
|
||||
|
||||
if (pktLineAddr == lineAddr) {
|
||||
uint8_t *data = pkt->getPtr<uint8_t>();
|
||||
unsigned int size_in_bytes = pkt->getSize();
|
||||
unsigned startByte = pkt->getAddr() - lineAddr;
|
||||
bool was_read = false;
|
||||
|
||||
for (unsigned i = 0; i < size_in_bytes; ++i) {
|
||||
if (mask.test(i + startByte)) {
|
||||
was_read = true;
|
||||
data[i] = blk.getByte(i + startByte);
|
||||
}
|
||||
}
|
||||
return was_read;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function accepts an address, a data block and a packet. If the address
|
||||
* range for the data block contains the address which the packet needs to
|
||||
|
|
Loading…
Reference in a new issue