summaryrefslogtreecommitdiff
path: root/ext/opcache
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2015-04-21 00:27:21 +0300
committerDmitry Stogov <dmitry@zend.com>2015-04-21 00:27:21 +0300
commit81a9505742c7ec74e9f573c0680a2551f1add3bd (patch)
treea31705b6bb0b0820fcedb886baee5b6b73f3dbd0 /ext/opcache
parent54018ada7dd83827e4079a733e85b382e7176185 (diff)
downloadphp-git-81a9505742c7ec74e9f573c0680a2551f1add3bd.tar.gz
Compact HashTables to reduce SHM usage
Diffstat (limited to 'ext/opcache')
-rw-r--r--ext/opcache/zend_persist.c70
-rw-r--r--ext/opcache/zend_persist_calc.c12
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;