ruby: set: reimplement using std::bitset
The current Set data structure is slow and therefore is being reimplemented using std::bitset. A maximum limit of 64 is being set on the number of controllers of each type. This means that for simulating a system with more controllers of a given type, one would need to change the value of the variable NUMBER_BITS_PER_SET
This commit is contained in:
@@ -26,11 +26,6 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// NetDest specifies the network destination of a Message
|
||||
// This is backward compatible with the Set class that was previously
|
||||
// used to specify network destinations.
|
||||
// NetDest supports both node networks and component networks
|
||||
|
||||
#ifndef __MEM_RUBY_COMMON_NETDEST_HH__
|
||||
#define __MEM_RUBY_COMMON_NETDEST_HH__
|
||||
|
||||
@@ -40,6 +35,7 @@
|
||||
#include "mem/ruby/common/Set.hh"
|
||||
#include "mem/ruby/common/MachineID.hh"
|
||||
|
||||
// NetDest specifies the network destination of a Message
|
||||
class NetDest
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -38,5 +38,4 @@ Source('Consumer.cc')
|
||||
Source('DataBlock.cc')
|
||||
Source('Histogram.cc')
|
||||
Source('NetDest.cc')
|
||||
Source('Set.cc')
|
||||
Source('SubBlock.cc')
|
||||
|
||||
@@ -1,341 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// modified (rewritten) 05/20/05 by Dan Gibson to accomimdate FASTER
|
||||
// >32 bit set sizes
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
#include "base/misc.hh"
|
||||
#include "mem/ruby/common/Set.hh"
|
||||
|
||||
Set::Set()
|
||||
{
|
||||
m_p_nArray = NULL;
|
||||
m_nArrayLen = 0;
|
||||
m_nSize = 0;
|
||||
}
|
||||
|
||||
Set::Set(const Set& obj)
|
||||
{
|
||||
m_p_nArray = NULL;
|
||||
setSize(obj.m_nSize);
|
||||
|
||||
// copy from the host to this array
|
||||
for (int i = 0; i < m_nArrayLen; i++)
|
||||
m_p_nArray[i] = obj.m_p_nArray[i];
|
||||
}
|
||||
|
||||
Set::Set(int size)
|
||||
{
|
||||
m_p_nArray = NULL;
|
||||
m_nArrayLen = 0;
|
||||
m_nSize = 0;
|
||||
if (size > 0)
|
||||
setSize(size);
|
||||
}
|
||||
|
||||
Set::~Set()
|
||||
{
|
||||
if (m_p_nArray && m_p_nArray != &m_p_nArray_Static[0])
|
||||
delete [] m_p_nArray;
|
||||
m_p_nArray = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
Set::clearExcess()
|
||||
{
|
||||
// now just ensure that no bits over the maximum size were set
|
||||
#ifdef _LP64
|
||||
unsigned long mask = 0x7FFFFFFFFFFFFFFF;
|
||||
#else
|
||||
unsigned long mask = 0x7FFFFFFF;
|
||||
#endif
|
||||
|
||||
// the number of populated spaces in the higest-order array slot
|
||||
// is: m_nSize % LONG_BITS, so the uppermost LONG_BITS -
|
||||
// m_nSize%64 bits should be cleared
|
||||
if ((m_nSize % LONG_BITS) != 0) {
|
||||
for (int j = 0; j < 64 - (m_nSize & INDEX_MASK); j++) {
|
||||
m_p_nArray[m_nArrayLen - 1] &= mask;
|
||||
mask = mask >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function should set all the bits in the current set that are
|
||||
* already set in the parameter set
|
||||
*/
|
||||
void
|
||||
Set::addSet(const Set& set)
|
||||
{
|
||||
assert(getSize()==set.getSize());
|
||||
for (int i = 0; i < m_nArrayLen; i++)
|
||||
m_p_nArray[i] |= set.m_p_nArray[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* This function clears bits that are =1 in the parameter set
|
||||
*/
|
||||
void
|
||||
Set::removeSet(const Set& set)
|
||||
{
|
||||
assert(m_nSize == set.m_nSize);
|
||||
for (int i = 0; i < m_nArrayLen; i++)
|
||||
m_p_nArray[i] &= ~set.m_p_nArray[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* this function sets all bits in the set
|
||||
*/
|
||||
void
|
||||
Set::broadcast()
|
||||
{
|
||||
for (int i = 0; i < m_nArrayLen; i++)
|
||||
m_p_nArray[i] = -1; // note that -1 corresponds to all 1's in 2's comp.
|
||||
|
||||
clearExcess();
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the population count of 1's in the set
|
||||
*/
|
||||
int
|
||||
Set::count() const
|
||||
{
|
||||
int counter = 0;
|
||||
|
||||
for (int i = 0; i < m_nArrayLen; i++) {
|
||||
unsigned long mask = 0x01;
|
||||
|
||||
for (int j = 0; j < LONG_BITS; j++) {
|
||||
// FIXME - significant performance loss when array
|
||||
// population << LONG_BITS
|
||||
if ((m_p_nArray[i] & mask) != 0) {
|
||||
counter++;
|
||||
}
|
||||
mask = mask << 1;
|
||||
}
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function checks for set equality
|
||||
*/
|
||||
bool
|
||||
Set::isEqual(const Set& set) const
|
||||
{
|
||||
assert(m_nSize == set.m_nSize);
|
||||
|
||||
for (int i = 0; i < m_nArrayLen; i++)
|
||||
if (m_p_nArray[i] != set.m_p_nArray[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the NodeID (int) of the least set bit
|
||||
*/
|
||||
NodeID
|
||||
Set::smallestElement() const
|
||||
{
|
||||
assert(count() > 0);
|
||||
for (int i = 0; i < m_nArrayLen; i++) {
|
||||
if (m_p_nArray[i] != 0) {
|
||||
// the least-set bit must be in here
|
||||
unsigned long x = m_p_nArray[i];
|
||||
|
||||
for (int j = 0; j < LONG_BITS; j++) {
|
||||
if (x & 1) {
|
||||
return LONG_BITS * i + j;
|
||||
}
|
||||
|
||||
x = x >> 1;
|
||||
}
|
||||
|
||||
panic("No smallest element of an empty set.");
|
||||
}
|
||||
}
|
||||
|
||||
panic("No smallest element of an empty set.");
|
||||
}
|
||||
|
||||
/*
|
||||
* this function returns true iff all bits are set
|
||||
*/
|
||||
bool
|
||||
Set::isBroadcast() const
|
||||
{
|
||||
// check the fully-loaded words by equal to 0xffffffff
|
||||
// only the last word may not be fully loaded, it is not
|
||||
// fully loaded iff m_nSize % 32 or 64 !=0 => fully loaded iff
|
||||
// m_nSize % 32 or 64 == 0
|
||||
|
||||
int max = (m_nSize % LONG_BITS) == 0 ? m_nArrayLen : m_nArrayLen - 1;
|
||||
for (int i = 0; i < max; i++) {
|
||||
if (m_p_nArray[i] != -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// now check the last word, which may not be fully loaded
|
||||
unsigned long mask = 1;
|
||||
for (int j = 0; j < (m_nSize % LONG_BITS); j++) {
|
||||
if ((mask & m_p_nArray[m_nArrayLen-1]) == 0) {
|
||||
return false;
|
||||
}
|
||||
mask = mask << 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* this function returns true iff no bits are set
|
||||
*/
|
||||
bool
|
||||
Set::isEmpty() const
|
||||
{
|
||||
// here we can simply check if all = 0, since we ensure
|
||||
// that "extra slots" are all zero
|
||||
for (int i = 0; i < m_nArrayLen ; i++)
|
||||
if (m_p_nArray[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// returns the logical OR of "this" set and orSet
|
||||
Set
|
||||
Set::OR(const Set& orSet) const
|
||||
{
|
||||
Set result(m_nSize);
|
||||
assert(m_nSize == orSet.m_nSize);
|
||||
for (int i = 0; i < m_nArrayLen; i++)
|
||||
result.m_p_nArray[i] = m_p_nArray[i] | orSet.m_p_nArray[i];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// returns the logical AND of "this" set and andSet
|
||||
Set
|
||||
Set::AND(const Set& andSet) const
|
||||
{
|
||||
Set result(m_nSize);
|
||||
assert(m_nSize == andSet.m_nSize);
|
||||
|
||||
for (int i = 0; i < m_nArrayLen; i++) {
|
||||
result.m_p_nArray[i] = m_p_nArray[i] & andSet.m_p_nArray[i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns false if a bit is set in the parameter set that is NOT set
|
||||
* in this set
|
||||
*/
|
||||
bool
|
||||
Set::isSuperset(const Set& test) const
|
||||
{
|
||||
assert(m_nSize == test.m_nSize);
|
||||
|
||||
for (int i = 0; i < m_nArrayLen; i++)
|
||||
if (((test.m_p_nArray[i] & m_p_nArray[i]) | ~test.m_p_nArray[i]) != -1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Set::setSize(int size)
|
||||
{
|
||||
m_nSize = size;
|
||||
m_nArrayLen = (m_nSize + LONG_BITS - 1) / LONG_BITS;
|
||||
|
||||
// decide whether to use dynamic or static alloction
|
||||
if (m_nArrayLen <= NUMBER_WORDS_PER_SET) {
|
||||
// constant defined in RubySystem.hh
|
||||
// its OK to use the static allocation, and it will
|
||||
// probably be faster (as m_nArrayLen is already in the
|
||||
// cache and they will probably share the same cache line)
|
||||
|
||||
// if switching from dyanamic to static allocation (which
|
||||
// is probably rare, but why not be complete?), must delete
|
||||
// the dynamically allocated space
|
||||
if (m_p_nArray && m_p_nArray != &m_p_nArray_Static[0])
|
||||
delete [] m_p_nArray;
|
||||
|
||||
m_p_nArray = &m_p_nArray_Static[0];
|
||||
} else {
|
||||
// can't use static allocation...simply not enough room
|
||||
// so dynamically allocate some space
|
||||
if (m_p_nArray && m_p_nArray != &m_p_nArray_Static[0])
|
||||
delete [] m_p_nArray;
|
||||
|
||||
m_p_nArray = new unsigned long[m_nArrayLen];
|
||||
}
|
||||
|
||||
clear();
|
||||
}
|
||||
|
||||
Set&
|
||||
Set::operator=(const Set& obj)
|
||||
{
|
||||
if (this != &obj) {
|
||||
// resize this item
|
||||
setSize(obj.getSize());
|
||||
|
||||
// copy the elements from obj to this
|
||||
for (int i = 0; i < m_nArrayLen; i++)
|
||||
m_p_nArray[i] = obj.m_p_nArray[i];
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
Set::print(std::ostream& out) const
|
||||
{
|
||||
if (!m_p_nArray) {
|
||||
out << "[Set {Empty}]";
|
||||
return;
|
||||
}
|
||||
|
||||
out << "[Set (" << m_nSize << ")";
|
||||
for (int i = m_nArrayLen - 1; i >= 0; i--) {
|
||||
out << csprintf(" 0x%08X", m_p_nArray[i]);
|
||||
}
|
||||
out << " ]";
|
||||
}
|
||||
@@ -32,129 +32,192 @@
|
||||
#ifndef __MEM_RUBY_COMMON_SET_HH__
|
||||
#define __MEM_RUBY_COMMON_SET_HH__
|
||||
|
||||
#include <bitset>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
#include "base/misc.hh"
|
||||
#include "mem/ruby/common/TypeDefines.hh"
|
||||
|
||||
/*
|
||||
* This defines the number of longs (32-bits on 32 bit machines,
|
||||
* 64-bit on 64-bit AMD machines) to use to hold the set...
|
||||
* the default is 4, allowing 128 or 256 different members
|
||||
* of the set.
|
||||
*
|
||||
* This should never need to be changed for correctness reasons,
|
||||
* though increasing it will increase performance for larger
|
||||
* set sizes at the cost of a (much) larger memory footprint
|
||||
*
|
||||
*/
|
||||
const int NUMBER_WORDS_PER_SET = 1;
|
||||
// Change for systems with more than 64 controllers of a particular type.
|
||||
const int NUMBER_BITS_PER_SET = 64;
|
||||
|
||||
class Set
|
||||
{
|
||||
private:
|
||||
int m_nSize; // the number of bits in this set
|
||||
int m_nArrayLen; // the number of 32-bit words that are
|
||||
// held in the array
|
||||
|
||||
// Changed 5/24/05 for static allocation of array
|
||||
// note that "long" corresponds to 32 bits on a 32-bit machine,
|
||||
// 64 bits if the -m64 parameter is passed to g++, which it is
|
||||
// for an AMD opteron under our configuration
|
||||
|
||||
// an word array to hold the bits in the set
|
||||
unsigned long *m_p_nArray;
|
||||
unsigned long m_p_nArray_Static[NUMBER_WORDS_PER_SET];
|
||||
|
||||
static const int LONG_BITS =
|
||||
std::numeric_limits<unsigned long>::digits + 1;
|
||||
static const int INDEX_SHIFT = LONG_BITS == 64 ? 6 : 5;
|
||||
static const int INDEX_MASK = (1 << INDEX_SHIFT) - 1;
|
||||
|
||||
void clearExcess();
|
||||
// Number of bits in use in this set.
|
||||
int m_nSize;
|
||||
std::bitset<NUMBER_BITS_PER_SET> bits;
|
||||
|
||||
public:
|
||||
Set();
|
||||
Set(int size);
|
||||
Set(const Set& obj);
|
||||
~Set();
|
||||
Set() : m_nSize(0) {}
|
||||
|
||||
Set& operator=(const Set& obj);
|
||||
Set(int size) : m_nSize(size)
|
||||
{
|
||||
if (size > NUMBER_BITS_PER_SET)
|
||||
fatal("Number of bits(%d) < size specified(%d). "
|
||||
"Increase the number of bits and recompile.\n",
|
||||
NUMBER_BITS_PER_SET, size);
|
||||
}
|
||||
|
||||
Set(const Set& obj) : m_nSize(obj.m_nSize), bits(obj.bits) {}
|
||||
~Set() {}
|
||||
|
||||
Set& operator=(const Set& obj)
|
||||
{
|
||||
m_nSize = obj.m_nSize;
|
||||
bits = obj.bits;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
add(NodeID index)
|
||||
{
|
||||
m_p_nArray[index >> INDEX_SHIFT] |=
|
||||
(((unsigned long) 1) << (index & INDEX_MASK));
|
||||
bits.set(index);
|
||||
}
|
||||
|
||||
void addSet(const Set& set);
|
||||
/*
|
||||
* This function should set all the bits in the current set that are
|
||||
* already set in the parameter set
|
||||
*/
|
||||
void
|
||||
addSet(const Set& obj)
|
||||
{
|
||||
assert(m_nSize == obj.m_nSize);
|
||||
bits |= obj.bits;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function clears bits that are =1 in the parameter set
|
||||
*/
|
||||
void
|
||||
remove(NodeID index)
|
||||
{
|
||||
m_p_nArray[index >> INDEX_SHIFT] &=
|
||||
~(((unsigned long)1) << (index & INDEX_MASK));
|
||||
bits.reset(index);
|
||||
}
|
||||
|
||||
void removeSet(const Set& set);
|
||||
|
||||
/*
|
||||
* This function clears bits that are =1 in the parameter set
|
||||
*/
|
||||
void
|
||||
clear()
|
||||
removeSet(const Set& obj)
|
||||
{
|
||||
for (int i = 0; i < m_nArrayLen; i++)
|
||||
m_p_nArray[i] = 0;
|
||||
assert(m_nSize == obj.m_nSize);
|
||||
bits &= (~obj.bits);
|
||||
}
|
||||
|
||||
void broadcast();
|
||||
int count() const;
|
||||
bool isEqual(const Set& set) const;
|
||||
void clear() { bits.reset(); }
|
||||
|
||||
/*
|
||||
* this function sets all bits in the set
|
||||
*/
|
||||
void broadcast()
|
||||
{
|
||||
bits.set();
|
||||
for (int j = m_nSize; j < NUMBER_BITS_PER_SET; ++j) {
|
||||
bits.reset(j);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the population count of 1's in the set
|
||||
*/
|
||||
int count() const { return bits.count(); }
|
||||
|
||||
/*
|
||||
* This function checks for set equality
|
||||
*/
|
||||
bool
|
||||
isEqual(const Set& obj) const
|
||||
{
|
||||
assert(m_nSize == obj.m_nSize);
|
||||
return bits == obj.bits;
|
||||
}
|
||||
|
||||
// return the logical OR of this set and orSet
|
||||
Set OR(const Set& orSet) const;
|
||||
Set
|
||||
OR(const Set& obj) const
|
||||
{
|
||||
assert(m_nSize == obj.m_nSize);
|
||||
Set r(m_nSize);
|
||||
r.bits = bits | obj.bits;
|
||||
return r;
|
||||
};
|
||||
|
||||
// return the logical AND of this set and andSet
|
||||
Set AND(const Set& andSet) const;
|
||||
Set
|
||||
AND(const Set& obj) const
|
||||
{
|
||||
assert(m_nSize == obj.m_nSize);
|
||||
Set r(m_nSize);
|
||||
r.bits = bits & obj.bits;
|
||||
return r;
|
||||
}
|
||||
|
||||
// Returns true if the intersection of the two sets is empty
|
||||
bool
|
||||
intersectionIsEmpty(const Set& other_set) const
|
||||
intersectionIsEmpty(const Set& obj) const
|
||||
{
|
||||
for (int i = 0; i < m_nArrayLen; i++)
|
||||
if (m_p_nArray[i] & other_set.m_p_nArray[i])
|
||||
return false;
|
||||
return true;
|
||||
std::bitset<NUMBER_BITS_PER_SET> r = bits & obj.bits;
|
||||
return r.none();
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns false if a bit is set in the parameter set that is NOT set
|
||||
* in this set
|
||||
*/
|
||||
bool
|
||||
isSuperset(const Set& test) const
|
||||
{
|
||||
assert(m_nSize == test.m_nSize);
|
||||
std::bitset<NUMBER_BITS_PER_SET> r = bits | test.bits;
|
||||
return (r == bits);
|
||||
}
|
||||
|
||||
bool isSuperset(const Set& test) const;
|
||||
bool isSubset(const Set& test) const { return test.isSuperset(*this); }
|
||||
|
||||
bool isElement(NodeID element) const { return bits.test(element); }
|
||||
|
||||
/*
|
||||
* this function returns true iff all bits in use are set
|
||||
*/
|
||||
bool
|
||||
isElement(NodeID element) const
|
||||
isBroadcast() const
|
||||
{
|
||||
return (m_p_nArray[element>>INDEX_SHIFT] &
|
||||
(((unsigned long)1) << (element & INDEX_MASK))) != 0;
|
||||
return (bits.count() == m_nSize);
|
||||
}
|
||||
|
||||
bool isBroadcast() const;
|
||||
bool isEmpty() const;
|
||||
bool isEmpty() const { return bits.none(); }
|
||||
|
||||
NodeID smallestElement() const;
|
||||
|
||||
void setSize(int size);
|
||||
|
||||
NodeID
|
||||
elementAt(int index) const
|
||||
NodeID smallestElement() const
|
||||
{
|
||||
if (isElement(index))
|
||||
return (NodeID)true;
|
||||
else
|
||||
return 0;
|
||||
for (int i = 0; i < m_nSize; ++i) {
|
||||
if (bits.test(i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
panic("No smallest element of an empty set.");
|
||||
}
|
||||
|
||||
bool elementAt(int index) const { return bits[index]; }
|
||||
|
||||
int getSize() const { return m_nSize; }
|
||||
|
||||
void print(std::ostream& out) const;
|
||||
void
|
||||
setSize(int size)
|
||||
{
|
||||
if (size > NUMBER_BITS_PER_SET)
|
||||
fatal("Number of bits(%d) < size specified(%d). "
|
||||
"Increase the number of bits and recompile.\n",
|
||||
NUMBER_BITS_PER_SET, size);
|
||||
m_nSize = size;
|
||||
bits.reset();
|
||||
}
|
||||
|
||||
void print(std::ostream& out) const
|
||||
{
|
||||
out << "[Set (" << m_nSize << "): " << bits << "]";
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream&
|
||||
|
||||
Reference in New Issue
Block a user