diff options
author | Dmitry Stogov <dmitry@zend.com> | 2015-04-21 00:27:21 +0300 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2015-04-21 00:27:21 +0300 |
commit | 81a9505742c7ec74e9f573c0680a2551f1add3bd (patch) | |
tree | a31705b6bb0b0820fcedb886baee5b6b73f3dbd0 /ext/opcache | |
parent | 54018ada7dd83827e4079a733e85b382e7176185 (diff) | |
download | php-git-81a9505742c7ec74e9f573c0680a2551f1add3bd.tar.gz |
Compact HashTables to reduce SHM usage
Diffstat (limited to 'ext/opcache')
-rw-r--r-- | ext/opcache/zend_persist.c | 70 | ||||
-rw-r--r-- | ext/opcache/zend_persist_calc.c | 12 |
2 files changed, 79 insertions, 3 deletions
diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index bb0680035b..2b94e3da7b 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -72,7 +72,7 @@ static const uint32_t uninitialized_bucket[-HT_MIN_MASK] = static void zend_hash_persist(HashTable *ht, zend_persist_func_t pPersistElement) { - uint idx; + uint32_t idx, nIndex; Bucket *p; if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) { @@ -83,6 +83,39 @@ static void zend_hash_persist(HashTable *ht, zend_persist_func_t pPersistElement void *data = HT_GET_DATA_ADDR(ht); zend_accel_store(data, HT_USED_SIZE(ht)); HT_SET_DATA_ADDR(ht, data); + } else if (ht->nNumUsed < -(int32_t)ht->nTableMask / 2) { + /* compact table */ + void *old_data = HT_GET_DATA_ADDR(ht); + Bucket *old_buckets = ht->arData; + int32_t hash_size = -(int32_t)ht->nTableMask; + + while (hash_size >> 1 > ht->nNumUsed) { + hash_size >>= 1; + } + ht->nTableMask = -hash_size; + HT_SET_DATA_ADDR(ht, ZCG(mem)); + ZCG(mem) = (void*)((char*)ZCG(mem) + (hash_size * sizeof(uint32_t)) + (ht->nNumUsed * sizeof(Bucket))); + HT_HASH_RESET(ht); + memcpy(ht->arData, old_buckets, ht->nNumUsed * sizeof(Bucket)); + efree(old_data); + + for (idx = 0; idx < ht->nNumUsed; idx++) { + p = ht->arData + idx; + if (Z_TYPE(p->val) == IS_UNDEF) continue; + + /* persist bucket and key */ + if (p->key) { + zend_accel_store_interned_string(p->key); + } + + /* persist the data itself */ + pPersistElement(&p->val); + + nIndex = p->h | ht->nTableMask; + Z_NEXT(p->val) = HT_HASH(ht, nIndex); + HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx); + } + return; } else { void *data = ZCG(mem); void *old_data = HT_GET_DATA_ADDR(ht); @@ -109,7 +142,7 @@ static void zend_hash_persist(HashTable *ht, zend_persist_func_t pPersistElement static void zend_hash_persist_immutable(HashTable *ht) { - uint idx; + uint32_t idx, nIndex; Bucket *p; if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) { @@ -118,6 +151,39 @@ static void zend_hash_persist_immutable(HashTable *ht) } if (ht->u.flags & HASH_FLAG_PACKED) { HT_SET_DATA_ADDR(ht, zend_accel_memdup(HT_GET_DATA_ADDR(ht), HT_USED_SIZE(ht))); + } else if (ht->nNumUsed < -(int32_t)ht->nTableMask / 2) { + /* compact table */ + void *old_data = HT_GET_DATA_ADDR(ht); + Bucket *old_buckets = ht->arData; + int32_t hash_size = -(int32_t)ht->nTableMask; + + while (hash_size >> 1 > ht->nNumUsed) { + hash_size >>= 1; + } + ht->nTableMask = -hash_size; + HT_SET_DATA_ADDR(ht, ZCG(mem)); + ZCG(mem) = (void*)((char*)ZCG(mem) + (hash_size * sizeof(uint32_t)) + (ht->nNumUsed * sizeof(Bucket))); + HT_HASH_RESET(ht); + memcpy(ht->arData, old_buckets, ht->nNumUsed * sizeof(Bucket)); + efree(old_data); + + for (idx = 0; idx < ht->nNumUsed; idx++) { + p = ht->arData + idx; + if (Z_TYPE(p->val) == IS_UNDEF) continue; + + /* persist bucket and key */ + if (p->key) { + zend_accel_memdup_interned_string(p->key); + } + + /* persist the data itself */ + zend_persist_zval_const(&p->val); + + nIndex = p->h | ht->nTableMask; + Z_NEXT(p->val) = HT_HASH(ht, nIndex); + HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx); + } + return; } else { void *data = ZCG(mem); diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index a2904056d3..98412109a5 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -58,7 +58,17 @@ static void zend_hash_persist_calc(HashTable *ht, void (*pPersistElement)(zval * return; } - ADD_SIZE(HT_USED_SIZE(ht)); + if (!(ht->u.flags & HASH_FLAG_PACKED) && ht->nNumUsed < -(int32_t)ht->nTableMask / 2) { + /* compact table */ + int32_t hash_size = -(int32_t)ht->nTableMask; + + while (hash_size >> 1 > ht->nNumUsed) { + hash_size >>= 1; + } + ADD_SIZE(hash_size * sizeof(uint32_t) + ht->nNumUsed * sizeof(Bucket)); + } else { + ADD_SIZE(HT_USED_SIZE(ht)); + } for (idx = 0; idx < ht->nNumUsed; idx++) { p = ht->arData + idx; |