Use more compact representation for packed arrays.

- for packed arrays we store just an array of zvals without keys.
- the elements of packed array are accessible throuf as ht->arPacked[i]
  instead of ht->arData[i]
- in addition to general ZEND_HASH_FOREACH_* macros, we introduced similar
  familied for packed (ZEND_HASH_PACKED_FORECH_*) and real hashes
  (ZEND_HASH_MAP_FOREACH_*)
- introduced an additional family of macros to access elements of array
  (packed or real hashes) ZEND_ARRAY_ELEMET_SIZE, ZEND_ARRAY_ELEMET_EX,
  ZEND_ARRAY_ELEMET, ZEND_ARRAY_NEXT_ELEMENT, ZEND_ARRAY_PREV_ELEMENT
- zend_hash_minmax() prototype was changed to compare only values

Because of smaller data set, this patch may show performance improvement
on some apps and benchmarks that use packed arrays. (~1% on PHP-Parser)

TODO:
    - sapi/phpdbg needs special support for packed arrays (WATCH_ON_BUCKET).
    - zend_hash_sort_ex() may require converting packed arrays to hash.
This commit is contained in:
Dmitry Stogov 2021-11-03 15:18:26 +03:00
parent 0eb603e3bb
commit 90b7bde615
89 changed files with 3302 additions and 1664 deletions

View file

@ -184,7 +184,7 @@ sdlBindingPtr get_binding_from_type(sdlPtr sdl, sdlBindingType type)
return NULL;
}
ZEND_HASH_FOREACH_PTR(sdl->bindings, binding) {
ZEND_HASH_MAP_FOREACH_PTR(sdl->bindings, binding) {
if (binding->bindingType == type) {
return binding;
}
@ -1860,7 +1860,7 @@ static void sdl_serialize_attribute(sdlAttributePtr attr, HashTable *tmp_encoder
sdlExtraAttributePtr tmp;
zend_string *key;
ZEND_HASH_FOREACH_STR_KEY_PTR(attr->extraAttributes, key, tmp) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(attr->extraAttributes, key, tmp) {
sdl_serialize_key(key, out);
sdl_serialize_string(tmp->ns, out);
sdl_serialize_string(tmp->val, out);
@ -1960,7 +1960,7 @@ static void sdl_serialize_type(sdlTypePtr type, HashTable *tmp_encoders, HashTab
sdlRestrictionCharPtr tmp;
zend_string *key;
ZEND_HASH_FOREACH_STR_KEY_PTR(type->restrictions->enumeration, key, tmp) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(type->restrictions->enumeration, key, tmp) {
sdl_serialize_resriction_char(tmp, out);
sdl_serialize_key(key, out);
} ZEND_HASH_FOREACH_END();
@ -2069,7 +2069,7 @@ static void sdl_serialize_soap_body(sdlSoapBindingFunctionBodyPtr body, HashTabl
sdlSoapBindingFunctionHeaderPtr tmp;
zend_string *key;
ZEND_HASH_FOREACH_STR_KEY_PTR(body->headers, key, tmp) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(body->headers, key, tmp) {
sdl_serialize_key(key, out);
WSDL_CACHE_PUT_1(tmp->use, out);
if (tmp->use == SOAP_ENCODED) {
@ -2089,7 +2089,7 @@ static void sdl_serialize_soap_body(sdlSoapBindingFunctionBodyPtr body, HashTabl
sdlSoapBindingFunctionHeaderPtr tmp2;
zend_string *key;
ZEND_HASH_FOREACH_STR_KEY_PTR(body->headers, key, tmp2) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(body->headers, key, tmp2) {
sdl_serialize_key(key, out);
WSDL_CACHE_PUT_1(tmp2->use, out);
if (tmp2->use == SOAP_ENCODED) {
@ -2147,7 +2147,7 @@ static void add_sdl_to_cache(const char *fn, const char *uri, time_t t, sdlPtr s
sdlTypePtr tmp;
zval zv;
ZEND_HASH_FOREACH_PTR(sdl->groups, tmp) {
ZEND_HASH_MAP_FOREACH_PTR(sdl->groups, tmp) {
ZVAL_LONG(&zv, type_num);
zend_hash_str_add(&tmp_types, (char*)&tmp, sizeof(tmp), &zv);
++type_num;
@ -2181,7 +2181,7 @@ static void add_sdl_to_cache(const char *fn, const char *uri, time_t t, sdlPtr s
sdlTypePtr tmp;
zval zv;
ZEND_HASH_FOREACH_PTR(sdl->elements, tmp) {
ZEND_HASH_MAP_FOREACH_PTR(sdl->elements, tmp) {
ZVAL_LONG(&zv, type_num);
zend_hash_str_add(&tmp_types, (char*)&tmp, sizeof(tmp), &zv);
++type_num;
@ -2218,7 +2218,7 @@ static void add_sdl_to_cache(const char *fn, const char *uri, time_t t, sdlPtr s
sdlTypePtr tmp;
zend_string *key;
ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->groups, key, tmp) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(sdl->groups, key, tmp) {
sdl_serialize_key(key, out);
sdl_serialize_type(tmp, &tmp_encoders, &tmp_types, out);
} ZEND_HASH_FOREACH_END();
@ -2238,7 +2238,7 @@ static void add_sdl_to_cache(const char *fn, const char *uri, time_t t, sdlPtr s
sdlTypePtr tmp;
zend_string *key;
ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->elements, key, tmp) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(sdl->elements, key, tmp) {
sdl_serialize_key(key, out);
sdl_serialize_type(tmp, &tmp_encoders, &tmp_types, out);
} ZEND_HASH_FOREACH_END();
@ -2267,7 +2267,7 @@ static void add_sdl_to_cache(const char *fn, const char *uri, time_t t, sdlPtr s
zval zv;
zend_string *key;
ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->bindings, key, tmp) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(sdl->bindings, key, tmp) {
sdl_serialize_key(key, out);
sdl_serialize_string(tmp->name, out);
sdl_serialize_string(tmp->location, out);
@ -2295,7 +2295,7 @@ static void add_sdl_to_cache(const char *fn, const char *uri, time_t t, sdlPtr s
int function_num = 1;
zend_string *key;
ZEND_HASH_FOREACH_STR_KEY_PTR(&sdl->functions, key, tmp) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&sdl->functions, key, tmp) {
sdl_serialize_key(key, out);
sdl_serialize_string(tmp->functionName, out);
sdl_serialize_string(tmp->requestName, out);
@ -2327,7 +2327,7 @@ static void add_sdl_to_cache(const char *fn, const char *uri, time_t t, sdlPtr s
WSDL_CACHE_PUT_INT(zend_hash_num_elements(tmp->faults), out);
ZEND_HASH_FOREACH_STR_KEY_PTR(tmp->faults, key, fault) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(tmp->faults, key, fault) {
sdl_serialize_key(key, out);
sdl_serialize_string(fault->name, out);
sdl_serialize_parameters(fault->details, &tmp_encoders, &tmp_types, out);
@ -2364,7 +2364,7 @@ static void add_sdl_to_cache(const char *fn, const char *uri, time_t t, sdlPtr s
zval *function_num;
zend_string *key;
ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->requests, key, tmp) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(sdl->requests, key, tmp) {
function_num = zend_hash_str_find(&tmp_functions, (char*)&tmp, sizeof(tmp));
WSDL_CACHE_PUT_INT(Z_LVAL_P(function_num), out);
sdl_serialize_key(key, out);
@ -2444,7 +2444,7 @@ static HashTable* make_persistent_sdl_function_headers(HashTable *headers, HashT
pheaders = malloc(sizeof(HashTable));
zend_hash_init(pheaders, zend_hash_num_elements(headers), NULL, delete_header_persistent, 1);
ZEND_HASH_FOREACH_STR_KEY_PTR(headers, key, tmp) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(headers, key, tmp) {
pheader = malloc(sizeof(sdlSoapBindingFunctionHeader));
memset(pheader, 0, sizeof(sdlSoapBindingFunctionHeader));
*pheader = *tmp;
@ -2550,7 +2550,7 @@ static HashTable* make_persistent_sdl_function_faults(sdlFunctionPtr func, HashT
pfaults = malloc(sizeof(HashTable));
zend_hash_init(pfaults, zend_hash_num_elements(faults), NULL, delete_fault_persistent, 1);
ZEND_HASH_FOREACH_STR_KEY_PTR(faults, key, tmp) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(faults, key, tmp) {
pfault = malloc(sizeof(sdlFault));
memset(pfault, 0, sizeof(sdlFault));
*pfault = *tmp;
@ -2624,7 +2624,7 @@ static sdlAttributePtr make_persistent_sdl_attribute(sdlAttributePtr attr, HashT
pattr->extraAttributes = malloc(sizeof(HashTable));
zend_hash_init(pattr->extraAttributes, zend_hash_num_elements(attr->extraAttributes), NULL, delete_extra_attribute_persistent, 1);
ZEND_HASH_FOREACH_STR_KEY_PTR(attr->extraAttributes, key, tmp) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(attr->extraAttributes, key, tmp) {
if (key) {
pextra = malloc(sizeof(sdlExtraAttribute));
memset(pextra, 0, sizeof(sdlExtraAttribute));
@ -2768,7 +2768,7 @@ static sdlTypePtr make_persistent_sdl_type(sdlTypePtr type, HashTable *ptr_map,
sdlRestrictionCharPtr tmp, penum;
ptype->restrictions->enumeration = malloc(sizeof(HashTable));
zend_hash_init(ptype->restrictions->enumeration, zend_hash_num_elements(type->restrictions->enumeration), NULL, delete_restriction_var_char_persistent, 1);
ZEND_HASH_FOREACH_STR_KEY_PTR(type->restrictions->enumeration, key, tmp) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(type->restrictions->enumeration, key, tmp) {
penum = tmp;
make_persistent_restriction_char_int(&penum);
/* We have to duplicate key emalloc->malloc */
@ -2953,7 +2953,7 @@ static sdlPtr make_persistent_sdl(sdlPtr sdl)
psdl->groups = malloc(sizeof(HashTable));
zend_hash_init(psdl->groups, zend_hash_num_elements(sdl->groups), NULL, delete_type_persistent, 1);
ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->groups, key, tmp) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(sdl->groups, key, tmp) {
ptype = make_persistent_sdl_type(tmp, &ptr_map, &bp_types, &bp_encoders);
if (key) {
/* We have to duplicate key emalloc->malloc */
@ -2991,7 +2991,7 @@ static sdlPtr make_persistent_sdl(sdlPtr sdl)
psdl->elements = malloc(sizeof(HashTable));
zend_hash_init(psdl->elements, zend_hash_num_elements(sdl->elements), NULL, delete_type_persistent, 1);
ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->elements, key, tmp) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(sdl->elements, key, tmp) {
ptype = make_persistent_sdl_type(tmp, &ptr_map, &bp_types, &bp_encoders);
if (key) {
/* We have to duplicate key emalloc->malloc */
@ -3052,7 +3052,7 @@ static sdlPtr make_persistent_sdl(sdlPtr sdl)
psdl->bindings = malloc(sizeof(HashTable));
zend_hash_init(psdl->bindings, zend_hash_num_elements(sdl->bindings), NULL, delete_binding_persistent, 1);
ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->bindings, key, tmp) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(sdl->bindings, key, tmp) {
pbind = make_persistent_sdl_binding(tmp, &ptr_map);
if (key) {
/* We have to duplicate key emalloc->malloc */
@ -3069,7 +3069,7 @@ static sdlPtr make_persistent_sdl(sdlPtr sdl)
sdlFunctionPtr tmp;
sdlFunctionPtr pfunc;
ZEND_HASH_FOREACH_STR_KEY_PTR(&sdl->functions, key, tmp) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&sdl->functions, key, tmp) {
pfunc = make_persistent_sdl_function(tmp, &ptr_map);
if (key) {
/* We have to duplicate key emalloc->malloc */
@ -3089,7 +3089,7 @@ static sdlPtr make_persistent_sdl(sdlPtr sdl)
psdl->requests = malloc(sizeof(HashTable));
zend_hash_init(psdl->requests, zend_hash_num_elements(sdl->requests), NULL, NULL, 1);
ZEND_HASH_FOREACH_STR_KEY_VAL(sdl->requests, key, zv) {
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(sdl->requests, key, zv) {
tmp = Z_PTR_P(zv);
if ((preq = zend_hash_str_find_ptr(&ptr_map, (char*)&tmp, sizeof(tmp))) == NULL) {
assert(0);
@ -3352,7 +3352,7 @@ cache_in_memory:
time_t latest = t;
zend_string *latest_key = NULL, *key;
ZEND_HASH_FOREACH_STR_KEY_PTR(SOAP_GLOBAL(mem_cache), key, q) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(SOAP_GLOBAL(mem_cache), key, q) {
if (q->time < latest) {
latest = q->time;
latest_key = key;