RFC: Request startup optimization

From: Date: Fri, 11 Feb 2000 15:50:26 +0000
Subject: RFC: Request startup optimization
Groups: php.version4 
Request: Send a blank email to php-version4+get-10115@lists.php.net to get a copy of this message
What? Defer the request startup until one of the module specific functions is used. Request shutdowns are avoided completely, if a module has a startup handler, but was not started up. Why? Module request startups (and respective shutdowns) can add (noticeable?) overhead to requests. How is it implemented? We use a stub function in the function_table which (a) calls the request_startup_func of the module (b) adds the module to the list of lazy_started_modules (c) sets all per-module function_table entries to their real handler Step (c) is reversed during module_registry_cleanup(), if the specific module was found in lazy_started_modules. Your comments and benchmark results are welcome. -- Regards, Sascha Schumann Consultant

Index: zend.c =================================================================== RCS file: /repository/Zend/zend.c,v retrieving revision 1.47 diff -u -r1.47 zend.c --- zend.c 2000/02/05 15:11:24 1.47 +++ zend.c 2000/02/11 15:28:04 @@ -453,13 +453,16 @@ void zend_activate_modules() { - zend_hash_apply(&module_registry, (int (*)(void *)) module_registry_request_startup); + ELS_FETCH(); + + zend_hash_init(&EG(lazy_started_modules), 0, NULL, NULL, 1); } void zend_deactivate(CLS_D ELS_DC) { zend_hash_apply(&module_registry, (int (*)(void *)) module_registry_cleanup); + zend_hash_destroy(&EG(lazy_started_modules)); shutdown_scanner(CLS_C); shutdown_executor(ELS_C); shutdown_compiler(CLS_C); Index: zend_API.c =================================================================== RCS file: /repository/Zend/zend_API.c,v retrieving revision 1.45 diff -u -r1.45 zend_API.c --- zend_API.c 2000/02/05 15:11:24 1.45 +++ zend_API.c 2000/02/11 15:28:05 @@ -728,9 +728,59 @@ return list_destructors.nNextFreeElement-1; } +#define ZEND_LAZY_FUNCTION zend_function_stub +static void zend_set_real_functions(zend_module_entry *module ELS_DC) +{ + zend_function_entry *ptr; + zend_internal_function *func; + + for (ptr = module->functions; ptr->fname; ptr++) { + if (zend_hash_find(EG(function_table), ptr->fname, strlen(ptr->fname)+1, (void **) &func)==SUCCESS) { + func->handler = func->handler_real; + } + } +} + +static void zend_function_stub(INTERNAL_FUNCTION_PARAMETERS) +{ + zend_module_entry *module; + char fake = 0; + + module = EG(last_function)->module; + +#if 1 + printf("Request startup: %s\n", module->name); +#endif + + if (module->request_startup_func(module->type, module->module_number ELS_CC)==FAILURE) { + zend_error(E_WARNING, "request_startup() for %s module failed", module->name); + exit(1); + } + + zend_hash_update(&EG(lazy_started_modules), module->name, strlen(module->name)+1, &fake, sizeof(char), NULL); + + zend_set_real_functions(module ELS_CC); + + EG(last_function)->handler_real(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + + +static void zend_set_stub_function(zend_module_entry *module ELS_DC) +{ + zend_function_entry *ptr; + zend_internal_function *func; + + for (ptr = module->functions; ptr->fname; ptr++) { + if (zend_hash_find(EG(function_table), ptr->fname, strlen(ptr->fname)+1, (void **) &func)==SUCCESS) { + func->handler = ZEND_LAZY_FUNCTION; + } + } +} + + /* registers all functions in *library_functions in the function hash */ -int zend_register_functions(zend_function_entry *functions, HashTable *function_table) +int zend_register_functions(zend_function_entry *functions, HashTable *function_table, zend_module_entry *module) { zend_function_entry *ptr = functions; zend_function function; @@ -744,8 +794,20 @@ } internal_function->type = ZEND_INTERNAL_FUNCTION; + /* safe us the lazy startup crap, if no request startup exists */ + if (module && !module->request_startup_func) + module = NULL; + + internal_function->module = module; + + if (module) + internal_function->handler = ZEND_LAZY_FUNCTION; + while (ptr->fname) { - internal_function->handler = ptr->handler; + if (module == NULL) + internal_function->handler = ptr->handler; + else + internal_function->handler_real = ptr->handler; internal_function->arg_types = ptr->func_arg_types; internal_function->function_name = ptr->fname; if (!internal_function->handler) { @@ -805,7 +867,7 @@ #if 0 zend_printf("%s: Registering module %d\n",module->name, module->module_number); #endif - if (module->functions && zend_register_functions(module->functions, NULL)==FAILURE) { + if (module->functions && zend_register_functions(module->functions, NULL, module)==FAILURE) { zend_error(E_CORE_WARNING,"%s: Unable to register functions, unable to load",module->name); return FAILURE; } @@ -857,22 +919,36 @@ return 0; } - /* for persistent modules - call request shutdown and flag NOT to erase * for temporary modules - do nothing, and flag to erase */ int module_registry_cleanup(zend_module_entry *module) { switch(module->type) { - case MODULE_PERSISTENT: + case MODULE_PERSISTENT: { + zend_bool run_shutdown = 1; + + if (module->request_startup_func) { + ELS_FETCH(); + + run_shutdown = zend_hash_exists(&EG(lazy_started_modules), module->name, strlen(module->name)+1); + + if (run_shutdown) + zend_set_stub_function(module ELS_CC); + } + if (module->request_shutdown_func) { -#if 0 - zend_printf("%s: Request shutdown\n",module->name); +#if 1 + zend_printf("Request shutdown(%d): %s \n", run_shutdown, module->name); #endif + if (!run_shutdown) + return 0; + module->request_shutdown_func(module->type, module->module_number); } return 0; break; + } case MODULE_TEMPORARY: return 1; break; @@ -906,7 +982,7 @@ if (class_entry->builtin_functions) { - zend_register_functions(class_entry->builtin_functions, &class_entry->function_table); + zend_register_functions(class_entry->builtin_functions, &class_entry->function_table, NULL); } zend_hash_update(CG(class_table), lowercase_name, class_entry->name_length+1, class_entry, sizeof(zend_class_entry), (void **) &register_class); Index: zend_API.h =================================================================== RCS file: /repository/Zend/zend_API.h,v retrieving revision 1.57 diff -u -r1.57 zend_API.h --- zend_API.h 2000/02/10 17:03:53 1.57 +++ zend_API.h 2000/02/11 15:28:05 @@ -64,7 +64,7 @@ ZEND_API int ParameterPassedByReference(int ht, uint n); -int zend_register_functions(zend_function_entry *functions, HashTable *function_table); +int zend_register_functions(zend_function_entry *functions, HashTable *function_table, zend_module_entry *); void zend_unregister_functions(zend_function_entry *functions, int count, HashTable *function_table); ZEND_API int zend_register_module(zend_module_entry *module_entry); ZEND_API zend_class_entry *register_internal_class(zend_class_entry *class_entry); Index: zend_builtin_functions.c =================================================================== RCS file: /repository/Zend/zend_builtin_functions.c,v retrieving revision 1.27 diff -u -r1.27 zend_builtin_functions.c --- zend_builtin_functions.c 2000/02/08 17:19:43 1.27 +++ zend_builtin_functions.c 2000/02/11 15:28:06 @@ -77,7 +77,7 @@ int zend_startup_builtin_functions() { - return zend_register_functions(builtin_functions, NULL); + return zend_register_functions(builtin_functions, NULL, NULL); } Index: zend_compile.h =================================================================== RCS file: /repository/Zend/zend_compile.h,v retrieving revision 1.79 diff -u -r1.79 zend_compile.h --- zend_compile.h 2000/02/04 14:45:58 1.79 +++ zend_compile.h 2000/02/11 15:28:08 @@ -126,8 +126,10 @@ unsigned char *arg_types; /* MUST be the second element of this struct */ char *function_name; /* MUST be the third element of this struct */ + struct _zend_module_entry *module; void (*handler)(INTERNAL_FUNCTION_PARAMETERS); + void (*handler_real)(INTERNAL_FUNCTION_PARAMETERS); } zend_internal_function; @@ -138,7 +140,7 @@ unsigned char *arg_types; char *function_name; } common; - + zend_op_array op_array; zend_internal_function internal_function; } zend_function; Index: zend_execute.c =================================================================== RCS file: /repository/Zend/zend_execute.c,v retrieving revision 1.161 diff -u -r1.161 zend_execute.c --- zend_execute.c 2000/02/10 17:03:53 1.161 +++ zend_execute.c 2000/02/11 15:28:09 @@ -1565,7 +1565,8 @@ if (function_state.function->type==ZEND_INTERNAL_FUNCTION) { ALLOC_ZVAL(Ts[opline->result.u.var].var.ptr); INIT_ZVAL(*(Ts[opline->result.u.var].var.ptr)); - ((zend_internal_function *) function_state.function)->handler(opline->extended_value, Ts[opline->result.u.var].var.ptr, object.ptr, return_value_used ELS_CC); + EG(last_function) = (zend_internal_function *) function_state.function; + EG(last_function)->handler(opline->extended_value, Ts[opline->result..u.var].var.ptr, object.ptr, return_value_used ELS_CC); if (object.ptr) { object.ptr->refcount--; } Index: zend_globals.h =================================================================== RCS file: /repository/Zend/zend_globals.h,v retrieving revision 1.41 diff -u -r1.41 zend_globals.h --- zend_globals.h 2000/02/04 14:45:58 1.41 +++ zend_globals.h 2000/02/11 15:28:09 @@ -179,6 +179,9 @@ zval *garbage[4]; int garbage_ptr; + + zend_internal_function *last_function; + HashTable lazy_started_modules; void *reserved[ZEND_MAX_RESERVED_RESOURCES]; #if SUPPORT_INTERACTIVE Attachment: [application/pgp-signature]
« previous php.version4 (#10115) next »