base: Add XOR-based hashed address interleaving
This patch extends the current address interleaving with basic hashing support. Instead of directly comparing a number of address bits with a matching value, it is now possible to use two independent set of address bits XOR'ed together. This avoids issues where strided address patterns are heavily biased to a subset of the interleaved ranges.
This commit is contained in:
parent
5ea60a95b3
commit
ccb512ecc1
2 changed files with 100 additions and 25 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012 ARM Limited
|
* Copyright (c) 2012, 2014 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -53,6 +53,22 @@
|
||||||
#include "base/misc.hh"
|
#include "base/misc.hh"
|
||||||
#include "base/types.hh"
|
#include "base/types.hh"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AddrRange class encapsulates an address range, and supports a
|
||||||
|
* number of tests to check if two ranges intersect, if a range
|
||||||
|
* contains a specific address etc. Besides a basic range, the
|
||||||
|
* AddrRange also support interleaved ranges, to stripe across cache
|
||||||
|
* banks, or memory controllers. The interleaving is implemented by
|
||||||
|
* allowing a number of bits of the address, at an arbitrary bit
|
||||||
|
* position, to be used as interleaving bits with an associated
|
||||||
|
* matching value. In addition, to prevent uniformly strided address
|
||||||
|
* patterns from a very biased interleaving, we also allow basic
|
||||||
|
* XOR-based hashing by specifying an additional set of bits to XOR
|
||||||
|
* with before matching.
|
||||||
|
*
|
||||||
|
* The AddrRange is also able to coalesce a number of interleaved
|
||||||
|
* ranges to a contiguous range.
|
||||||
|
*/
|
||||||
class AddrRange
|
class AddrRange
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -66,6 +82,10 @@ class AddrRange
|
||||||
/// The high bit of the slice that is used for interleaving
|
/// The high bit of the slice that is used for interleaving
|
||||||
uint8_t intlvHighBit;
|
uint8_t intlvHighBit;
|
||||||
|
|
||||||
|
/// The high bit of the slice used to XOR hash the value we match
|
||||||
|
/// against, set to 0 to disable.
|
||||||
|
uint8_t xorHighBit;
|
||||||
|
|
||||||
/// The number of bits used for interleaving, set to 0 to disable
|
/// The number of bits used for interleaving, set to 0 to disable
|
||||||
uint8_t intlvBits;
|
uint8_t intlvBits;
|
||||||
|
|
||||||
|
@ -76,18 +96,42 @@ class AddrRange
|
||||||
public:
|
public:
|
||||||
|
|
||||||
AddrRange()
|
AddrRange()
|
||||||
: _start(1), _end(0), intlvHighBit(0), intlvBits(0), intlvMatch(0)
|
: _start(1), _end(0), intlvHighBit(0), xorHighBit(0), intlvBits(0),
|
||||||
|
intlvMatch(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
AddrRange(Addr _start, Addr _end, uint8_t _intlv_high_bit,
|
AddrRange(Addr _start, Addr _end, uint8_t _intlv_high_bit,
|
||||||
uint8_t _intlv_bits, uint8_t _intlv_match)
|
uint8_t _xor_high_bit, uint8_t _intlv_bits,
|
||||||
|
uint8_t _intlv_match)
|
||||||
: _start(_start), _end(_end), intlvHighBit(_intlv_high_bit),
|
: _start(_start), _end(_end), intlvHighBit(_intlv_high_bit),
|
||||||
intlvBits(_intlv_bits), intlvMatch(_intlv_match)
|
xorHighBit(_xor_high_bit), intlvBits(_intlv_bits),
|
||||||
{}
|
intlvMatch(_intlv_match)
|
||||||
|
{
|
||||||
|
// sanity checks
|
||||||
|
fatal_if(intlvBits && intlvMatch >= ULL(1) << intlvBits,
|
||||||
|
"Match value %d does not fit in %d interleaving bits\n",
|
||||||
|
intlvMatch, intlvBits);
|
||||||
|
|
||||||
|
// ignore the XOR bits if not interleaving
|
||||||
|
if (intlvBits && xorHighBit) {
|
||||||
|
if (xorHighBit == intlvHighBit) {
|
||||||
|
fatal("XOR and interleave high bit must be different\n");
|
||||||
|
} else if (xorHighBit > intlvHighBit) {
|
||||||
|
if ((xorHighBit - intlvHighBit) < intlvBits)
|
||||||
|
fatal("XOR and interleave high bit must be at least "
|
||||||
|
"%d bits apart\n", intlvBits);
|
||||||
|
} else {
|
||||||
|
if ((intlvHighBit - xorHighBit) < intlvBits) {
|
||||||
|
fatal("Interleave and XOR high bit must be at least "
|
||||||
|
"%d bits apart\n", intlvBits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AddrRange(Addr _start, Addr _end)
|
AddrRange(Addr _start, Addr _end)
|
||||||
: _start(_start), _end(_end), intlvHighBit(0), intlvBits(0),
|
: _start(_start), _end(_end), intlvHighBit(0), xorHighBit(0),
|
||||||
intlvMatch(0)
|
intlvBits(0), intlvMatch(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,13 +141,15 @@ class AddrRange
|
||||||
* @param ranges Interleaved ranges to be merged
|
* @param ranges Interleaved ranges to be merged
|
||||||
*/
|
*/
|
||||||
AddrRange(const std::vector<AddrRange>& ranges)
|
AddrRange(const std::vector<AddrRange>& ranges)
|
||||||
: _start(1), _end(0), intlvHighBit(0), intlvBits(0), intlvMatch(0)
|
: _start(1), _end(0), intlvHighBit(0), xorHighBit(0), intlvBits(0),
|
||||||
|
intlvMatch(0)
|
||||||
{
|
{
|
||||||
if (!ranges.empty()) {
|
if (!ranges.empty()) {
|
||||||
// get the values from the first one and check the others
|
// get the values from the first one and check the others
|
||||||
_start = ranges.front()._start;
|
_start = ranges.front()._start;
|
||||||
_end = ranges.front()._end;
|
_end = ranges.front()._end;
|
||||||
intlvHighBit = ranges.front().intlvHighBit;
|
intlvHighBit = ranges.front().intlvHighBit;
|
||||||
|
xorHighBit = ranges.front().xorHighBit;
|
||||||
intlvBits = ranges.front().intlvBits;
|
intlvBits = ranges.front().intlvBits;
|
||||||
|
|
||||||
if (ranges.size() != (ULL(1) << intlvBits))
|
if (ranges.size() != (ULL(1) << intlvBits))
|
||||||
|
@ -111,21 +157,21 @@ class AddrRange
|
||||||
ranges.size(), intlvBits);
|
ranges.size(), intlvBits);
|
||||||
|
|
||||||
uint8_t match = 0;
|
uint8_t match = 0;
|
||||||
for (std::vector<AddrRange>::const_iterator r = ranges.begin();
|
for (const auto& r : ranges) {
|
||||||
r != ranges.end(); ++r) {
|
if (!mergesWith(r))
|
||||||
if (!mergesWith(*r))
|
|
||||||
fatal("Can only merge ranges with the same start, end "
|
fatal("Can only merge ranges with the same start, end "
|
||||||
"and interleaving bits\n");
|
"and interleaving bits\n");
|
||||||
|
|
||||||
if (r->intlvMatch != match)
|
if (r.intlvMatch != match)
|
||||||
fatal("Expected interleave match %d but got %d when "
|
fatal("Expected interleave match %d but got %d when "
|
||||||
"merging\n", match, r->intlvMatch);
|
"merging\n", match, r.intlvMatch);
|
||||||
++match;
|
++match;
|
||||||
}
|
}
|
||||||
|
|
||||||
// our range is complete and we can turn this into a
|
// our range is complete and we can turn this into a
|
||||||
// non-interleaved range
|
// non-interleaved range
|
||||||
intlvHighBit = 0;
|
intlvHighBit = 0;
|
||||||
|
xorHighBit = 0;
|
||||||
intlvBits = 0;
|
intlvBits = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,6 +183,11 @@ class AddrRange
|
||||||
*/
|
*/
|
||||||
bool interleaved() const { return intlvBits != 0; }
|
bool interleaved() const { return intlvBits != 0; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the range interleaving is hashed or not.
|
||||||
|
*/
|
||||||
|
bool hashed() const { return interleaved() && xorHighBit != 0; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determing the interleaving granularity of the range.
|
* Determing the interleaving granularity of the range.
|
||||||
*
|
*
|
||||||
|
@ -182,12 +233,22 @@ class AddrRange
|
||||||
*/
|
*/
|
||||||
std::string to_string() const
|
std::string to_string() const
|
||||||
{
|
{
|
||||||
if (interleaved())
|
if (interleaved()) {
|
||||||
return csprintf("[%#llx : %#llx], [%d : %d] = %d", _start, _end,
|
if (hashed()) {
|
||||||
intlvHighBit, intlvHighBit - intlvBits + 1,
|
return csprintf("[%#llx : %#llx], [%d : %d] XOR [%d : %d] = %d",
|
||||||
intlvMatch);
|
_start, _end,
|
||||||
else
|
intlvHighBit, intlvHighBit - intlvBits + 1,
|
||||||
|
xorHighBit, xorHighBit - intlvBits + 1,
|
||||||
|
intlvMatch);
|
||||||
|
} else {
|
||||||
|
return csprintf("[%#llx : %#llx], [%d : %d] = %d",
|
||||||
|
_start, _end,
|
||||||
|
intlvHighBit, intlvHighBit - intlvBits + 1,
|
||||||
|
intlvMatch);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
return csprintf("[%#llx : %#llx]", _start, _end);
|
return csprintf("[%#llx : %#llx]", _start, _end);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -202,6 +263,7 @@ class AddrRange
|
||||||
{
|
{
|
||||||
return r._start == _start && r._end == _end &&
|
return r._start == _start && r._end == _end &&
|
||||||
r.intlvHighBit == intlvHighBit &&
|
r.intlvHighBit == intlvHighBit &&
|
||||||
|
r.xorHighBit == xorHighBit &&
|
||||||
r.intlvBits == intlvBits;
|
r.intlvBits == intlvBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,10 +325,20 @@ class AddrRange
|
||||||
// check if the address is in the range and if there is either
|
// check if the address is in the range and if there is either
|
||||||
// no interleaving, or with interleaving also if the selected
|
// no interleaving, or with interleaving also if the selected
|
||||||
// bits from the address match the interleaving value
|
// bits from the address match the interleaving value
|
||||||
return a >= _start && a <= _end &&
|
bool in_range = a >= _start && a <= _end;
|
||||||
(!interleaved() ||
|
if (!interleaved()) {
|
||||||
(bits(a, intlvHighBit, intlvHighBit - intlvBits + 1) ==
|
return in_range;
|
||||||
intlvMatch));
|
} else if (in_range) {
|
||||||
|
if (!hashed()) {
|
||||||
|
return bits(a, intlvHighBit, intlvHighBit - intlvBits + 1) ==
|
||||||
|
intlvMatch;
|
||||||
|
} else {
|
||||||
|
return (bits(a, intlvHighBit, intlvHighBit - intlvBits + 1) ^
|
||||||
|
bits(a, xorHighBit, xorHighBit - intlvBits + 1)) ==
|
||||||
|
intlvMatch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -726,8 +726,9 @@ class AddrRange(ParamValue):
|
||||||
cxx_type = 'AddrRange'
|
cxx_type = 'AddrRange'
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
# Disable interleaving by default
|
# Disable interleaving and hashing by default
|
||||||
self.intlvHighBit = 0
|
self.intlvHighBit = 0
|
||||||
|
self.xorHighBit = 0
|
||||||
self.intlvBits = 0
|
self.intlvBits = 0
|
||||||
self.intlvMatch = 0
|
self.intlvMatch = 0
|
||||||
|
|
||||||
|
@ -745,6 +746,8 @@ class AddrRange(ParamValue):
|
||||||
# Now on to the optional bit
|
# Now on to the optional bit
|
||||||
if 'intlvHighBit' in kwargs:
|
if 'intlvHighBit' in kwargs:
|
||||||
self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
|
self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
|
||||||
|
if 'xorHighBit' in kwargs:
|
||||||
|
self.xorHighBit = int(kwargs.pop('xorHighBit'))
|
||||||
if 'intlvBits' in kwargs:
|
if 'intlvBits' in kwargs:
|
||||||
self.intlvBits = int(kwargs.pop('intlvBits'))
|
self.intlvBits = int(kwargs.pop('intlvBits'))
|
||||||
if 'intlvMatch' in kwargs:
|
if 'intlvMatch' in kwargs:
|
||||||
|
@ -814,8 +817,8 @@ class AddrRange(ParamValue):
|
||||||
from m5.internal.range import AddrRange
|
from m5.internal.range import AddrRange
|
||||||
|
|
||||||
return AddrRange(long(self.start), long(self.end),
|
return AddrRange(long(self.start), long(self.end),
|
||||||
int(self.intlvHighBit), int(self.intlvBits),
|
int(self.intlvHighBit), int(self.xorHighBit),
|
||||||
int(self.intlvMatch))
|
int(self.intlvBits), int(self.intlvMatch))
|
||||||
|
|
||||||
# Boolean parameter type. Python doesn't let you subclass bool, since
|
# Boolean parameter type. Python doesn't let you subclass bool, since
|
||||||
# it doesn't want to let you create multiple instances of True and
|
# it doesn't want to let you create multiple instances of True and
|
||||||
|
|
Loading…
Reference in a new issue