Skip to content

Commit

Permalink
improve performance of wrap_generic_callable
Browse files Browse the repository at this point in the history
nr_php_wrap_generic_callable is used to create transient wraprecs for callables
which don't require to be named. This assumption makes it possible to stay DRY
and reuse nr_php_zval_to_function in lieu of complex pattern matching for the
type of callable. On top of that it improves performance as it now uses
nr_php_wrap_callable always instead of sometimes using nr_php_wrap_user_function
  • Loading branch information
lavarou committed Dec 1, 2023
1 parent 757de1c commit 70b6513
Showing 1 changed file with 40 additions and 69 deletions.
109 changes: 40 additions & 69 deletions agent/php_wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,42 @@
#include "php_user_instrument.h"
#include "php_wrapper.h"
#include "util_logging.h"
static char* Z_TYPE_STR(zval* zv) {

switch (Z_TYPE_P(zv)) {
case IS_NULL:
return "IS_NULL";

case IS_STRING:
return "IS_STRING";

case IS_LONG:
return "IS_LONG";

#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO /* PHP7+ */
case IS_TRUE:
return "IS_TRUE";

case IS_FALSE:
return "IS_FALSE";
#else
case IS_BOOL:
return "IS_BOOL";
#endif /* PHP7 */

case IS_DOUBLE:
return "IS_DOUBLE";

case IS_OBJECT:
return "IS_OBJECT";

case IS_ARRAY:
return "IS_ARRAY";

default:
return "UNKNOWN";
}
}

nruserfn_t* nr_php_wrap_user_function(const char* name,
size_t namelen,
Expand Down Expand Up @@ -70,77 +106,12 @@ nruserfn_t* nr_php_wrap_callable(zend_function* callable,

nruserfn_t* nr_php_wrap_generic_callable(zval* callable,
nrspecialfn_t callback TSRMLS_DC) {
#if ZEND_MODULE_API_NO < ZEND_7_0_X_API_NO
char* name = NULL;
#else
zend_string* name = NULL;
#endif
zend_fcall_info_cache fcc;
zend_fcall_info fci;

/* not calling nr_zend_is_callable because we want to additionally populate name */
if (zend_is_callable(callable, 0, &name TSRMLS_CC)) {
/* see php source code's zend_is_callable_at_frame function to see from
* where these switch cases are derived */
#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO
again:
#endif
switch (Z_TYPE_P(callable)) {
/* wrapping a string name of a callable */
case IS_STRING:
#if ZEND_MODULE_API_NO < ZEND_7_0_X_API_NO
return nr_php_wrap_user_function_with_transience(name, nr_strlen(name), callback,
NR_WRAPREC_IS_TRANSIENT TSRMLS_CC);
#else
return nr_php_wrap_user_function_with_transience(ZEND_STRING_VALUE(name),
ZEND_STRING_LEN(name), callback,
NR_WRAPREC_IS_TRANSIENT TSRMLS_CC);
#endif
zend_function* zf = nr_php_zval_to_function(callable);

/* wrapping an array where [0] is an object and [1] is the method to invoke
* the previous zend_is_callable has created the commbined object::method
* name for us to wrap */
case IS_ARRAY:
#if ZEND_MODULE_API_NO < ZEND_7_0_X_API_NO
return nr_php_wrap_user_function_with_transience(name, nr_strlen(name), callback,
NR_WRAPREC_IS_TRANSIENT TSRMLS_CC);
#else
return nr_php_wrap_user_function_with_transience(ZEND_STRING_VALUE(name),
ZEND_STRING_LEN(name), callback,
NR_WRAPREC_IS_TRANSIENT TSRMLS_CC);
#endif

/* wrapping a closure. Need to initialize fcall info in order to wrap the
* underlying zend_function object */
case IS_OBJECT:
if (SUCCESS == zend_fcall_info_init(callable, 0, &fci, &fcc,
NULL, NULL TSRMLS_CC)) {
/* nr_php_wrap_callable already sets the transience field for us */
return nr_php_wrap_callable(fcc.function_handler, callback TSRMLS_CC);
}
nrl_verbosedebug(NRL_INSTRUMENT, "Failed to initialize fcall info when wrapping");
break;

/* unwrap references */
/* PHP 5.x handles references in a different manner that do not need to be unwrapped */
#if ZEND_MODULE_API_NO >= ZEND_7_0_X_API_NO
case IS_REFERENCE:
callable = Z_REFVAL_P(callable);
goto again;
#endif
}
if (NULL != zf) {
return nr_php_wrap_callable(zf, callback);
}
#if ZEND_MODULE_API_NO < ZEND_7_0_X_API_NO
nrl_verbosedebug(NRL_INSTRUMENT,
"Failed to wrap callable: %s", name);
#else
if (NULL != name) {
nrl_verbosedebug(NRL_INSTRUMENT,
"Failed to wrap callable: %s", ZEND_STRING_VALUE(name));
} else {
nrl_verbosedebug(NRL_INSTRUMENT, "Failed to wrap callable with unknown name");
}
#endif
nrl_verbosedebug(NRL_INSTRUMENT, "Failed to cast to callable: Z_TYPE(callable)=%s", Z_TYPE_STR(callable));
return NULL;
}

Expand Down

0 comments on commit 70b6513

Please sign in to comment.