I've run a bunch of experiments on HphpArray speed and am still yet to have a major breakthrough. However, there are a few clear small winners that I'm submitting with this diff. CPU instructions, CPU loads, and CPU stores are all as green as the Eternal Hunting Grounds. Speed is drowned in noise but I sususpect will be measurable on these changes combined.
Esse commit está contido em:
Andrei Alexandrescu
2013-05-20 13:53:11 -07:00
commit de Sara Golemon
commit 872d24b761
8 arquivos alterados com 86 adições e 56 exclusões
+1 -1
Ver Arquivo
@@ -360,7 +360,7 @@ Variant ArrayData::key() const {
return uninit_null();
}
Variant ArrayData::value(ssize_t &pos) const {
Variant ArrayData::value(int32_t &pos) const {
if (size_t(pos) < size_t(size())) {
return getValue(pos);
}
+23 -11
Ver Arquivo
@@ -55,14 +55,26 @@ class ArrayData : public Countable {
public:
static const ssize_t invalid_index = -1;
explicit ArrayData(ArrayKind kind, bool nonsmart = false) :
m_size(-1), m_pos(0), m_strongIterators(0), m_kind(kind),
m_nonsmart(nonsmart) {
explicit ArrayData(ArrayKind kind, bool nonsmart = false)
: m_size(-1)
, m_kind(kind)
, m_nonsmart(nonsmart)
, m_pos(0)
, m_strongIterators(nullptr) {
}
explicit ArrayData(ArrayKind kind, bool nonsmart, uint size)
: m_size(size)
, m_kind(kind)
, m_nonsmart(nonsmart)
, m_pos(size ? 0 : ArrayData::invalid_index)
, m_strongIterators(nullptr) {
}
ArrayData(const ArrayData *src, ArrayKind kind,
bool nonsmart = false) :
m_pos(src->m_pos), m_strongIterators(0), m_kind(src->m_kind),
m_nonsmart(nonsmart) {
bool nonsmart = false)
: m_kind(src->m_kind)
, m_nonsmart(nonsmart)
, m_pos(src->m_pos)
, m_strongIterators(nullptr) {
}
static HphpArray* Make(uint capacity);
@@ -184,7 +196,7 @@ class ArrayData : public Countable {
virtual Variant next();
virtual Variant end();
virtual Variant key() const;
virtual Variant value(ssize_t &pos) const;
virtual Variant value(int32_t &pos) const;
virtual Variant each();
bool isHead() const { return m_pos == iter_begin(); }
@@ -482,13 +494,13 @@ class ArrayData : public Countable {
protected:
uint m_size;
ssize_t m_pos;
private:
FullPos* m_strongIterators; // head of linked list
protected:
const ArrayKind m_kind;
AllocMode m_allocMode;
const bool m_nonsmart; // never use smartalloc to allocate Elms
int32_t m_pos;
private:
FullPos* m_strongIterators; // head of linked list
protected:
/* The 4 bytes of padding here are available to subclasses if their
* first field is also <= 4 bytes. */
+44 -33
Ver Arquivo
@@ -66,7 +66,13 @@ static const Trace::Module TRACEMOD = Trace::runtime;
* separately. Even larger tables allocate the hashtable and slots
* contiguously.
*/
IMPLEMENT_SMART_ALLOCATION(HphpArray);
void *HphpArray::SmaAllocatorInitSetup = SmartAllocatorInitSetup<HphpArray>();
void HphpArray::release() {
assert(typeid(*this) == typeid(HphpArray));
this->HphpArray::~HphpArray();
HphpArray::AllocatorType::getNoCheck()->dealloc(this);
}
//=============================================================================
// Static members.
@@ -76,55 +82,57 @@ HphpArray HphpArray::s_theEmptyArray(StaticEmptyArray);
//=============================================================================
// Helpers.
static inline size_t computeMaskFromNumElms(uint32_t numElms) {
assert(numElms <= 0x7fffffffU);
size_t lgSize = HphpArray::MinLgTableSize;
size_t maxElms = (size_t(3U)) << (lgSize-2);
assert(lgSize >= 2);
while (maxElms < numElms) {
++lgSize;
maxElms <<= 1;
static inline size_t computeMaskFromNumElms(const uint32_t n) {
if (n <= HphpArray::SmallSize) {
return HphpArray::SmallMask;
}
assert(lgSize <= 32);
// return 2^lgSize - 1
return ((size_t(1U)) << lgSize) - 1;
static_assert(HphpArray::MinLgTableSize >= 2,
"lower limit for 0.75 load factor");
uint32_t cap = (3U << (HphpArray::MinLgTableSize - 2)) * 2;
while (cap < n) {
cap *= 2;
}
return ((size_t(cap) << 2UL) & (size_t(cap) << 1UL)) - 1;
}
//=============================================================================
// Construction/destruction.
inline void HphpArray::init(uint size) {
m_size = 0;
m_tableMask = computeMaskFromNumElms(size);
size_t tableSize = computeTableSize(m_tableMask);
size_t maxElms = computeMaxElms(m_tableMask);
allocData(maxElms, tableSize);
inline uint32_t HphpArray::initWithoutHash(uint capacity) {
assert(m_size == 0);
m_tableMask = computeMaskFromNumElms(capacity);
auto const tableSize = computeTableSize(m_tableMask);
allocData(computeMaxElms(m_tableMask), tableSize);
initHash(m_hash, tableSize);
m_pos = ArrayData::invalid_index;
assert(m_pos == ArrayData::invalid_index);
return tableSize;
}
HphpArray::HphpArray(uint size) : ArrayData(kHphpArray),
m_lastE(ElmIndEmpty), m_data(nullptr), m_nextKI(0), m_hLoad(0) {
inline void HphpArray::init(uint capacity) {
assert(m_size == 0);
const auto tableSize = initWithoutHash(capacity);
initHash(m_hash, tableSize);
}
HphpArray::HphpArray(uint size) : ArrayData(kHphpArray, false, 0),
m_lastE(ElmIndEmpty), m_hLoad(0), m_nextKI(0) {
#ifdef PEDANTIC
if (size > 0x7fffffffU) {
raise_error("Cannot create an array with more than 2^31 - 1 elements");
}
#endif
assert(m_size == 0);
init(size);
}
HphpArray::HphpArray(uint size, const TypedValue* values) :
ArrayData(kHphpArray), m_lastE(ElmIndEmpty), m_data(nullptr),
m_nextKI(0), m_hLoad(0)
ArrayData(kHphpArray, false, 0), m_lastE(ElmIndEmpty),
m_hLoad(0), m_nextKI(0)
{
#ifdef PEDANTIC
if (size > 0x7fffffffU) {
raise_error("Cannot create an array with more than 2^31 - 1 elements");
}
#endif
init(size);
initWithoutHash(size);
assert(size <= m_tableMask + 1);
// append values by moving -- Caller assumes we update refcount. Values
// are in reverse order since they come from the stack, which grows down.
@@ -132,14 +140,18 @@ HphpArray::HphpArray(uint size, const TypedValue* values) :
assert(m_size == 0 && m_hLoad == 0 && m_nextKI == 0);
ElmInd* hash = m_hash;
Elm* data = m_data;
for (uint i = 0; i < size; i++) {
assert(hash[i] == HphpArray::ElmIndEmpty);
uint i = 0;
for (; i < size; i++) {
const TypedValue& tv = values[size - i - 1];
data[i].data.m_data = tv.m_data;
data[i].data.m_type = tv.m_type;
data[i].setIntKey(i);
hash[i] = i;
}
// Initialize the leftover hash
for (; i < size; i++) {
hash[i] = ElmIndEmpty;
}
m_size = size;
m_hLoad = size;
m_lastE = size - 1;
@@ -147,8 +159,8 @@ HphpArray::HphpArray(uint size, const TypedValue* values) :
if (size > 0) m_pos = 0;
}
HphpArray::HphpArray(EmptyMode) : ArrayData(kHphpArray),
m_lastE(ElmIndEmpty), m_data(nullptr), m_nextKI(0), m_hLoad(0) {
HphpArray::HphpArray(EmptyMode) : ArrayData(kHphpArray, false, 0),
m_lastE(ElmIndEmpty), m_hLoad(0), m_nextKI(0) {
init(0);
setStatic();
}
@@ -192,7 +204,7 @@ void HphpArray::dumpDebugInfo() const {
"m_tableMask = %u\tm_size = %d\tm_hLoad = %d\n"
"m_nextKI = %" PRId64 "\t\tm_lastE = %d\tm_pos = %zd\n",
m_data, m_hash, m_tableMask, m_size, m_hLoad,
m_nextKI, m_lastE, m_pos);
m_nextKI, m_lastE, size_t(m_pos));
fprintf(stderr, "Elements:\n");
ssize_t lastE = m_lastE;
Elm* elms = m_data;
@@ -394,7 +406,7 @@ Variant HphpArray::key() const {
return uninit_null();
}
Variant HphpArray::value(ssize_t& pos) const {
Variant HphpArray::value(int32_t& pos) const {
if (pos != ArrayData::invalid_index) {
Elm* e = &m_data[pos];
assert(e->data.m_type != KindOfTombstone);
@@ -703,7 +715,6 @@ void HphpArray::newElmStr(ElmInd* ei, strhash_t h, StringData* key,
}
void HphpArray::allocData(size_t maxElms, size_t tableSize) {
assert(!m_data);
if (maxElms <= SmallSize) {
m_data = m_inline_data.slots;
m_hash = m_inline_data.hash;
+9 -6
Ver Arquivo
@@ -112,7 +112,7 @@ public:
Variant next();
Variant end();
Variant key() const;
Variant value(ssize_t& pos) const;
Variant value(int32_t& pos) const;
Variant each();
// implements ArrayData
@@ -295,6 +295,7 @@ public:
// Use a minimum of an 4-element hash table. Valid range: [2..32]
static const uint32_t MinLgTableSize = 2;
static const uint32_t SmallHashSize = 1 << MinLgTableSize;
static const uint32_t SmallMask = SmallHashSize - 1;
static const uint32_t SmallSize = SmallHashSize - SmallHashSize / LoadScale;
struct InlineSlots {
@@ -356,11 +357,11 @@ private:
// +--------------------+
ElmInd m_lastE; // Index of last used element.
uint32_t m_tableMask; // Bitmask used when indexing into the hash table.
uint32_t m_hLoad; // Hash table load (# of non-empty slots).
int64_t m_nextKI; // Next integer key to use for append.
Elm* m_data; // Contains elements and hash table.
ElmInd* m_hash; // Hash table.
int64_t m_nextKI; // Next integer key to use for append.
uint32_t m_tableMask; // Bitmask used when indexing into the hash table.
uint32_t m_hLoad; // Hash table load (# of non-empty slots).
union {
InlineSlots m_inline_data;
ElmInd m_inline_hash[sizeof(m_inline_data) / sizeof(ElmInd)];
@@ -438,9 +439,11 @@ private:
void reallocData(size_t maxElms, size_t tableSize, uint oldMask);
/**
* init(size) allocates space for size elements but initializes
* as an empty array
* init(size) allocates space for size elements but initializes as
* an empty array. The "WithoutHash" version does not initialize the
* hash table and returns the hash table size.
*/
uint32_t initWithoutHash(uint size);
void init(uint size);
/**
+1 -1
Ver Arquivo
@@ -284,7 +284,7 @@ Variant ArrayShell::key() const {
return key(toPos(m_pos));
}
Variant ArrayShell::value(ssize_t &pos) const {
Variant ArrayShell::value(int32_t &pos) const {
NOT_IMPLEMENTED();
}
+5 -1
Ver Arquivo
@@ -54,6 +54,10 @@ static uint32_t toUint32(PosType pos) {
}
// Signed to pos, no change in representation.
inline PosType toPos(int32_t n) {
static_assert(sizeof(int64_t) == sizeof(PosType), "");
return static_cast<PosType>(n);
}
static PosType toPos(int64_t n) {
static_assert(sizeof(int64_t) == sizeof(PosType), "can't");
return static_cast<PosType>(n);
@@ -383,7 +387,7 @@ public:
virtual Variant next() FOLLY_OVERRIDE;
virtual Variant end() FOLLY_OVERRIDE;
virtual Variant key() const FOLLY_OVERRIDE;
virtual Variant value(ssize_t &pos) const FOLLY_OVERRIDE;
virtual Variant value(int32_t &pos) const FOLLY_OVERRIDE;
virtual Variant each() FOLLY_OVERRIDE;
virtual bool isInvalid() const FOLLY_OVERRIDE {
+1 -1
Ver Arquivo
@@ -252,7 +252,7 @@ Variant NameValueTableWrapper::key() const {
return null_variant;
}
Variant NameValueTableWrapper::value(ssize_t& pos) const {
Variant NameValueTableWrapper::value(int32_t& pos) const {
return current();
}
+2 -2
Ver Arquivo
@@ -130,7 +130,7 @@ public: // ArrayData implementation
virtual Variant end();
virtual CVarRef endRef();
virtual Variant key() const;
virtual Variant value(ssize_t &pos) const;
virtual Variant value(int32_t &pos) const;
virtual Variant each();
virtual bool validFullPos(const FullPos & fp) const;
virtual bool advanceFullPos(FullPos&);
@@ -149,7 +149,7 @@ private:
class GlobalNameValueTableWrapper : public NameValueTableWrapper {
public:
GlobalNameValueTableWrapper(NameValueTable* tab);
explicit GlobalNameValueTableWrapper(NameValueTable* tab);
Variant gvm_argc;
Variant gvm_argv;
Variant gvm__SERVER;