ID: 47815
User updated by: basant dot kukreja at gmail dot com
Reported By: basant dot kukreja at gmail dot com
Status: Open
Bug Type: Performance problem
Operating System: Solaris 10
PHP Version: 5.2.9
New Comment:
diff -r 00438f7eebe4 php-5.2.9RC3/Zend/zend_compile.h
--- a/php-5.2.9RC3/Zend/zend_compile.h Tue Mar 17 11:27:02 2009 -0700
+++ b/php-5.2.9RC3/Zend/zend_compile.h Fri Mar 27 10:18:13 2009 -0700
@@ -83,6 +83,7 @@
znode op1;
znode op2;
ulong extended_value;
+ ulong hval;
uint lineno;
zend_uchar opcode;
};
diff -r 00438f7eebe4 php-5.2.9RC3/Zend/zend_execute.c
--- a/php-5.2.9RC3/Zend/zend_execute.c Tue Mar 17 11:27:02 2009 -0700
+++ b/php-5.2.9RC3/Zend/zend_execute.c Fri Mar 27 10:18:13 2009 -0700
@@ -930,11 +930,12 @@
return NULL;
}
-static inline zval **zend_fetch_dimension_address_inner(HashTable *ht,
zval *dim, int type TSRMLS_DC)
+static inline zval **zend_fetch_dimension_address_inner(HashTable *ht,
zval *dim, int type, zend_ulong hval, int usehval TSRMLS_DC)
{
zval **retval;
char *offset_key;
int offset_key_length;
+ int ret;
switch (dim->type) {
case IS_NULL:
@@ -948,7 +949,13 @@
offset_key_length = dim->value.str.len;
fetch_string_dim:
- if (zend_symtable_find(ht, offset_key,
offset_key_length+1, (void
**) &retval) == FAILURE) {
+ if (usehval) {
+ ret = zend_symtable_quick_find(ht, offset_key,
offset_key_length+1, hval, (void **) &retval);
+ }
+ else {
+ ret = zend_symtable_find(ht, offset_key,
offset_key_length+1,
(void **) &retval);
+ }
+ if (ret == FAILURE) {
switch (type) {
case BP_VAR_R:
zend_error(E_NOTICE, "Undefined
index: %s", offset_key);
@@ -1023,7 +1030,7 @@
return retval;
}
-static void zend_fetch_dimension_address(temp_variable *result, zval
**container_ptr, zval *dim, int dim_is_tmp_var, int type TSRMLS_DC)
+static void zend_fetch_dimension_address(temp_variable *result, zval
**container_ptr, zval *dim, int dim_is_tmp_var, int type, zend_ulong
hval, int usehval TSRMLS_DC)
{
zval *container;
@@ -1078,7 +1085,7 @@
new_zval->refcount--;
}
} else {
- retval =
zend_fetch_dimension_address_inner(Z_ARRVAL_P(container),
dim, type TSRMLS_CC);
+ retval =
zend_fetch_dimension_address_inner(Z_ARRVAL_P(container),
dim, type, hval, usehval TSRMLS_CC);
}
if (result) {
result->var.ptr_ptr = retval;
diff -r 00438f7eebe4 php-5.2.9RC3/Zend/zend_hash.h
--- a/php-5.2.9RC3/Zend/zend_hash.h Tue Mar 17 11:27:02 2009 -0700
+++ b/php-5.2.9RC3/Zend/zend_hash.h Fri Mar 27 10:18:13 2009 -0700
@@ -354,6 +354,12 @@
return zend_hash_find(ht, arKey, nKeyLength, pData);
}
+static inline int zend_symtable_quick_find(HashTable *ht, char *arKey,
uint nKeyLength, ulong h, void **pData)
+{
+ HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_find(ht, idx,
pData));
+ return zend_hash_quick_find(ht, arKey, nKeyLength, h, pData);
+}
+
static inline int zend_symtable_exists(HashTable *ht, char *arKey,
uint nKeyLength)
{
diff -r 00438f7eebe4 php-5.2.9RC3/Zend/zend_object_handlers.c
--- a/php-5.2.9RC3/Zend/zend_object_handlers.c Tue Mar 17 11:27:02 2009
-0700
+++ b/php-5.2.9RC3/Zend/zend_object_handlers.c Fri Mar 27 10:18:13 2009
-0700
@@ -175,24 +175,11 @@
return 0;
}
-ZEND_API struct _zend_property_info
*zend_get_property_info(zend_class_entry *ce, zval *member, int silent
TSRMLS_DC)
+static struct _zend_property_info
*zend_get_property_info_hval(zend_class_entry *ce, zval *member, int
silent, ulong h TSRMLS_DC)
{
zend_property_info *property_info = NULL;
zend_property_info *scope_property_info;
zend_bool denied_access = 0;
- ulong h;
-
- if (Z_STRVAL_P(member)[0] == '\0') {
- if (!silent) {
- if (Z_STRLEN_P(member) == 0) {
- zend_error(E_ERROR, "Cannot access empty
property");
- } else {
- zend_error(E_ERROR, "Cannot access property
started with '\\0'");
- }
- }
- return NULL;
- }
- h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1);
if (zend_hash_quick_find(&ce->properties_info, Z_STRVAL_P(member),
Z_STRLEN_P(member)+1, h, (void **) &property_info)==SUCCESS) {
if(property_info->flags & ZEND_ACC_SHADOW) {
/* if it's a shadow - go to access it's private */
@@ -244,6 +231,31 @@
return property_info;
}
+static int test_valid_string(const zval* member, int silent)
+{
+ if (Z_STRVAL_P(member)[0] == '\0') {
+ if (!silent) {
+ if (Z_STRLEN_P(member) == 0) {
+ zend_error(E_ERROR, "Cannot access empty
property");
+ } else {
+ zend_error(E_ERROR, "Cannot access property
started with '\\0'");
+ }
+ }
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+ZEND_API struct _zend_property_info
*zend_get_property_info(zend_class_entry *ce, zval *member, int silent
TSRMLS_DC)
+{
+ ulong h;
+
+ if (test_valid_string(member, silent) != SUCCESS)
+ return NULL;
+ h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1);
+ return zend_get_property_info_hval(ce, member, silent, h TSRMLS_CC);
+}
+
ZEND_API int zend_check_property_access(zend_object *zobj, char
*prop_info_name, int prop_info_name_len TSRMLS_DC)
{
@@ -293,7 +305,7 @@
return zend_hash_quick_add(zobj->guards, property_info->name,
property_info->name_length+1, property_info->h, (void**)&stub,
sizeof(stub), (void**) pguard);
}
-zval *zend_std_read_property(zval *object, zval *member, int type
TSRMLS_DC)
+zval *zend_std_read_property_hval(zval *object, zval *member, ulong
hval, int type TSRMLS_DC)
{
zend_object *zobj;
zval *tmp_member = NULL;
@@ -312,14 +324,24 @@
zval_copy_ctor(tmp_member);
convert_to_string(tmp_member);
member = tmp_member;
+ hval = zend_get_hash_value(Z_STRVAL_P(member),
Z_STRLEN_P(member));
}
+
+ if (test_valid_string(member, silent) != SUCCESS) {
+ if (!silent) {
+ zend_error(E_NOTICE,"Undefined property type for class:
%s",
zobj->ce->name);
+ }
+ retval = &EG(uninitialized_zval_ptr);
+ /* Unexpected */
+ return *retval;
+ }
+ property_info = zend_get_property_info_hval(zobj->ce, member,
(zobj->ce->__get != NULL), hval TSRMLS_CC);
#if DEBUG_OBJECT_HANDLERS
fprintf(stderr, "Read object #%d property: %s\n",
Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
#endif
/* make zend_get_property_info silent if we have getter - we may want
to use it */
- property_info = zend_get_property_info(zobj->ce, member,
(zobj->ce->__get != NULL) TSRMLS_CC);
if (!property_info || zend_hash_quick_find(zobj->properties,
property_info->name, property_info->name_length+1, property_info->h,
(void **) &retval) == FAILURE) {
zend_guard *guard;
@@ -367,6 +389,15 @@
(*retval)->refcount--;
}
return *retval;
+}
+
+zval *zend_std_read_property(zval *object, zval *member, int type
TSRMLS_DC)
+{
+ ulong hval = 0;
+ if (member->type == IS_STRING) {
+ hval = zend_get_hash_value(Z_STRVAL_P(member),
Z_STRLEN_P(member));
+ }
+ return zend_std_read_property_hval(object, member, hval, type
TSRMLS_CC);
}
diff -r 00438f7eebe4 php-5.2.9RC3/Zend/zend_opcode.c
--- a/php-5.2.9RC3/Zend/zend_opcode.c Tue Mar 17 11:27:02 2009 -0700
+++ b/php-5.2.9RC3/Zend/zend_opcode.c Fri Mar 27 10:18:13 2009 -0700
@@ -397,6 +397,32 @@
case ZEND_JMPNZ_EX:
opline->op2.u.jmp_addr =
&op_array->opcodes[opline->op2.u.opline_num];
break;
+ case ZEND_FETCH_OBJ_R:
+ case ZEND_FETCH_OBJ_IS:
+ case ZEND_FETCH_OBJ_FUNC_ARG:
+ case ZEND_FETCH_DIM_R:
+ case ZEND_FETCH_DIM_W:
+ case ZEND_FETCH_DIM_RW:
+ case ZEND_FETCH_DIM_IS:
+ case ZEND_FETCH_DIM_UNSET:
+ case ZEND_ASSIGN_DIM:
+ if ((opline->op2.op_type == IS_CONST) &&
+ (opline->op2.u.constant.type ==
IS_STRING)
+ ) {
+ zval* zop2= &opline->op2.u.constant;
+ opline->hval =
zend_get_hash_value(Z_STRVAL_P(zop2),
+
Z_STRLEN_P(zop2) +1);
+ }
+ break;
+ case ZEND_DO_FCALL:
+ if ((opline->op1.op_type == IS_CONST) &&
+ (opline->op1.u.constant.type ==
IS_STRING)
+ ) {
+ zval* zop1= &opline->op1.u.constant;
+ opline->hval =
zend_get_hash_value(Z_STRVAL_P(zop1),
+
Z_STRLEN_P(zop1) +1);
+ }
+ break;
}
ZEND_VM_SET_OPCODE_HANDLER(opline);
opline++;
diff -r 00438f7eebe4 php-5.2.9RC3/Zend/zend_vm_def.h
--- a/php-5.2.9RC3/Zend/zend_vm_def.h Tue Mar 17 11:27:02 2009 -0700
+++ b/php-5.2.9RC3/Zend/zend_vm_def.h Fri Mar 27 10:18:13 2009 -0700
@@ -418,7 +418,7 @@
zend_op *op_data = opline+1;
zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
-
zend_fetch_dimension_address(&EX_T(op_data->op2.u.var),
GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW), dim, IS_OP2_TMP_FREE(), BP_VAR_RW
TSRMLS_CC);
+
zend_fetch_dimension_address(&EX_T(op_data->op2.u.var),
GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW), dim, IS_OP2_TMP_FREE(), BP_VAR_RW, 0, 0
TSRMLS_CC);
value = get_zval_ptr(&op_data->op1,
EX(Ts), &free_op_data1,
BP_VAR_R);
var_ptr =
get_zval_ptr_ptr(&op_data->op2, EX(Ts), &free_op_data2,
BP_VAR_RW);
increment_opline = 1;
@@ -1040,13 +1040,17 @@
zend_op *opline = EX(opline);
zend_free_op free_op1, free_op2;
zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
+ int usehval = 0;
+ if (OP2_TYPE == IS_CONST) {
+ usehval = 1;
+ }
if (opline->extended_value == ZEND_FETCH_ADD_LOCK &&
OP1_TYPE != IS_CV &&
EX_T(opline->op1.u.var).var.ptr_ptr) {
PZVAL_LOCK(*EX_T(opline->op1.u.var).var.ptr_ptr);
}
-
zend_fetch_dimension_address(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var),
GET_OP1_ZVAL_PTR_PTR(BP_VAR_R), dim, IS_OP2_TMP_FREE(), BP_VAR_R
TSRMLS_CC);
+
zend_fetch_dimension_address(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var),
GET_OP1_ZVAL_PTR_PTR(BP_VAR_R), dim, IS_OP2_TMP_FREE(), BP_VAR_R,
opline->hval, usehval TSRMLS_CC);
FREE_OP2();
FREE_OP1_VAR_PTR();
ZEND_VM_NEXT_OPCODE();
@@ -1058,7 +1062,11 @@
zend_free_op free_op1, free_op2;
zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
-
zend_fetch_dimension_address(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var),
GET_OP1_ZVAL_PTR_PTR(BP_VAR_W), dim, IS_OP2_TMP_FREE(), BP_VAR_W
TSRMLS_CC);
+ int usehval = 0;
+ if (OP2_TYPE == IS_CONST) {
+ usehval = 1;
+ }
+
zend_fetch_dimension_address(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var),
GET_OP1_ZVAL_PTR_PTR(BP_VAR_W), dim, IS_OP2_TMP_FREE(), BP_VAR_W,
opline->hval, usehval TSRMLS_CC);
FREE_OP2();
if (OP1_TYPE == IS_VAR && OP1_FREE &&
READY_TO_DESTROY(free_op1.var) &&
@@ -1079,7 +1087,11 @@
zend_free_op free_op1, free_op2;
zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
-
zend_fetch_dimension_address(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var),
GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW), dim, IS_OP2_TMP_FREE(), BP_VAR_RW
TSRMLS_CC);
+ int usehval = 0;
+ if (OP2_TYPE == IS_CONST) {
+ usehval = 1;
+ }
+
zend_fetch_dimension_address(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var),
GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW), dim, IS_OP2_TMP_FREE(), BP_VAR_RW,
opline->hval, usehval TSRMLS_CC);
FREE_OP2();
if (OP1_TYPE == IS_VAR && OP1_FREE &&
READY_TO_DESTROY(free_op1.var) &&
@@ -1099,8 +1111,12 @@
zend_op *opline = EX(opline);
zend_free_op free_op1, free_op2;
zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
+ int usehval = 0;
+ if (OP2_TYPE == IS_CONST) {
+ usehval = 1;
+ }
-
zend_fetch_dimension_address(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var),
GET_OP1_ZVAL_PTR_PTR(BP_VAR_IS), dim, IS_OP2_TMP_FREE(), BP_VAR_IS
TSRMLS_CC);
+
zend_fetch_dimension_address(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var),
GET_OP1_ZVAL_PTR_PTR(BP_VAR_IS), dim, IS_OP2_TMP_FREE(), BP_VAR_IS,
opline->hval, usehval TSRMLS_CC);
FREE_OP2();
FREE_OP1_VAR_PTR();
ZEND_VM_NEXT_OPCODE();
@@ -1117,7 +1133,7 @@
zend_error_noreturn(E_ERROR, "Cannot use [] for reading");
}
dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
-
zend_fetch_dimension_address(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var),
GET_OP1_ZVAL_PTR_PTR(type), dim, IS_OP2_TMP_FREE(), type TSRMLS_CC);
+
zend_fetch_dimension_address(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var),
GET_OP1_ZVAL_PTR_PTR(type), dim, IS_OP2_TMP_FREE(), type, 0, 0
TSRMLS_CC);
FREE_OP2();
if (OP1_TYPE == IS_VAR && type == BP_VAR_W && OP1_FREE &&
READY_TO_DESTROY(free_op1.var) &&
@@ -1138,6 +1154,10 @@
zend_free_op free_op1, free_op2;
zval **container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_UNSET);
zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
+ int usehval = 0;
+ if (OP2_TYPE == IS_CONST) {
+ usehval = 1;
+ }
/* Not needed in DIM_UNSET
if (opline->extended_value == ZEND_FETCH_ADD_LOCK) {
@@ -1149,7 +1169,7 @@
SEPARATE_ZVAL_IF_NOT_REF(container);
}
}
-
zend_fetch_dimension_address(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var),
container, dim, IS_OP2_TMP_FREE(), BP_VAR_UNSET TSRMLS_CC);
+
zend_fetch_dimension_address(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var),
container, dim, IS_OP2_TMP_FREE(), BP_VAR_UNSET, opline->hval, usehval
TSRMLS_CC);
FREE_OP2();
if (OP1_TYPE == IS_VAR && OP1_FREE &&
READY_TO_DESTROY(free_op1.var) &&
@@ -1176,6 +1196,9 @@
ZEND_VM_NEXT_OPCODE();
}
+extern zval *zend_std_read_property(zval *object, zval *member, int
type TSRMLS_DC);
+extern zval *zend_std_read_property_hval(zval *object, zval *member,
ulong hval, int type TSRMLS_DC);
+
ZEND_VM_HELPER_EX(zend_fetch_property_address_read_helper,
VAR|UNUSED|CV, CONST|TMP|VAR|CV, int type)
{
zend_op *opline = EX(opline);
@@ -1216,7 +1239,14 @@
}
/* here we are sure we are dealing with an object */
- *retval = Z_OBJ_HT_P(container)->read_property(container,
offset,
type TSRMLS_CC);
+ if ((OP2_TYPE == IS_CONST) &&
Z_OBJ_HT_P(container)->read_property
== zend_std_read_property)
+ {
+ *retval = zend_std_read_property_hval(container, offset,
+
EX(opline)->hval,
+
type TSRMLS_CC);
+ } else {
+ *retval =
Z_OBJ_HT_P(container)->read_property(container, offset,
type TSRMLS_CC);
+ }
if (RETURN_VALUE_UNUSED(&opline->result) &&
((*retval)->refcount ==
0)) {
zval_dtor(*retval);
@@ -1398,7 +1428,7 @@
zend_free_op free_op2;
zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
- EX_T(opline->result.u.var).var.ptr_ptr =
zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, BP_VAR_R
TSRMLS_CC);
+ EX_T(opline->result.u.var).var.ptr_ptr =
zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, BP_VAR_R,
0, 0 TSRMLS_CC);
SELECTIVE_PZVAL_LOCK(*EX_T(opline->result.u.var).var.ptr_ptr,
&opline->result);
FREE_OP2();
}
@@ -1426,6 +1456,10 @@
zend_op *op_data = opline+1;
zend_free_op free_op1;
zval **object_ptr;
+ int usehval = 0;
+ if (OP2_TYPE == IS_CONST) {
+ usehval = 1;
+ }
if (OP1_TYPE == IS_CV || EX_T(opline->op1.u.var).var.ptr_ptr) {
/* not an array offset */
@@ -1441,7 +1475,7 @@
zval *value;
zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
- zend_fetch_dimension_address(&EX_T(op_data->op2.u.var),
object_ptr,
dim, IS_OP2_TMP_FREE(), BP_VAR_W TSRMLS_CC);
+ zend_fetch_dimension_address(&EX_T(op_data->op2.u.var),
object_ptr,
dim, IS_OP2_TMP_FREE(), BP_VAR_W, opline->hval, usehval TSRMLS_CC);
FREE_OP2();
value = get_zval_ptr(&op_data->op1, EX(Ts), &free_op_data1,
BP_VAR_R);
@@ -2098,7 +2132,7 @@
zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object),
NULL);
- if (zend_hash_find(EG(function_table), fname->value.str.val,
fname->value.str.len+1, (void **)
&EX(function_state).function)==FAILURE) {
+ if (zend_hash_quick_find(EG(function_table), fname->value.str.val,
fname->value.str.len+1, opline->hval, (void **)
&EX(function_state).function)==FAILURE) {
zend_error_noreturn(E_ERROR, "Call to undefined function %s()",
fname->value.str.val);
}
EX(object) = NULL;
Previous Comments:
------------------------------------------------------------------------
[2009-03-27 22:58:50] basant dot kukreja at gmail dot com
Description:
------------
In specweb ecommerce php benchmark, hash lookup consumes a lot of
time.
For a 30 minutes measurement :
Excl. Incl. Name
User CPU User CPU
sec. sec.
434.304 914.980 zend_fetch_dimension_address
136.195 427.119 zend_get_property_info
914 seconds (13 % of user time) are spent in
zend_fetch_dimension_address out
of total 6947 seconds.
Reproduce code:
---------------
specweb benchmark.
Expected result:
----------------
Low time spent in zend_fetch_dimension_address and
zend_get_property_info
Actual result:
--------------
Time spend in zend_fetch_dimension_address and zend_get_property_info
is very high.
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/?id=47815&edit=1