Home >Backend Development >PHP Tutorial >Quickly identify the lines of code in PHP that may cause CPU spikes_PHP Tutorial

Quickly identify the lines of code in PHP that may cause CPU spikes_PHP Tutorial

WBOY
WBOYOriginal
2016-07-13 10:13:00862browse

Quickly find the lines of code in PHP that may cause the CPU surge problem

When the CPU is close to 100%, how do you find the cause of the CPU surge? My idea is, first Find the line of code that the process is executing to identify the potentially problematic section of code. Then, carefully analyze the problematic code segment to find out the cause.

If your program is written in c or c++, then you can easily find the line of code being executed. However, the program is written in PHP, how to find the lines of code that may have problems? This problem is what this article will solve.

Background knowledge:

Everyone knows that php is an interpreted language. The PHP code written by the user will generate opcode, which will be interpreted and executed by the interpreter engine. During the interpretation execution process, there is a global variable that contains various data used during the execution process. It is executor_globals. His type definition can be found in the Zend/zend_globals.h file of the source code.

The code is as follows

struct _zend_executor_globals {
zval **return_value_ptr_ptr;

zval uninitialized_zval;
zval *uninitialized_zval_ptr;

zval error_zval;
zval *error_zval_ptr;

zend_ptr_stack arg_types_stack;

/* symbol table cache */
HashTable *symtable_cache[SYMTABLE_CACHE_SIZE];
HashTable **symtable_cache_limit;
HashTable **symtable_cache_ptr;

zend_op **opline_ptr;

HashTable *active_symbol_table;
HashTable symbol_table; /* main symbol table */

HashTable included_files; /* files already included */

JMP_BUF *bailout;

int error_reporting;
int orig_error_reporting;
int exit_status;

zend_op_array *active_op_array;

HashTable *function_table; /* function symbol table */
HashTable *class_table; /* class table */
HashTable *zend_constants; /* constants table */

zend_class_entry *scope;
zend_class_entry *called_scope; /* Scope of the calling class */

zval *This;

long precision;

int ticks_count;

zend_bool in_execution;
HashTable *in_autoload;
zend_function *autoload_func;
zend_bool full_tables_cleanup;

/* for extended information support */
zend_bool no_extensions;

#ifdef ZEND_WIN32
zend_bool timed_out;
OSVERSIONINFOEX windows_version_info;
#endif

HashTable regular_list;
HashTable persistent_list;

zend_vm_stack argument_stack;

int user_error_handler_error_reporting;
zval *user_error_handler;
zval *user_exception_handler;
zend_stack user_error_handlers_error_reporting;
zend_ptr_stack user_error_handlers;
zend_ptr_stack user_exception_handlers;

zend_error_handling_t error_handling;
zend_class_entry *exception_class;

/* timeout support */
int timeout_seconds;

int lambda_count;

HashTable *ini_directives;
HashTable *modified_ini_directives;

zend_objects_store objects_store;
zval *exception, *prev_exception;
zend_op *opline_before_exception;
zend_op exception_op[3];

struct _zend_execute_data *current_execute_data;

struct _zend_module_entry *current_module;

zend_property_info std_property_info;

zend_bool active;

void *saved_fpu_cw;

void *reserved[ZEND_MAX_RESERVED_RESOURCES];
};

Here we only talk about two variables that are more important to us, active_op_array and current_execute_data.

The active_op_array variable stores the op_array that the engine is executing (if you want to know what op_array is, please click to view). There is a definition of the data type of op_array in Zend/zend_compile.h.

The code is as follows

struct _zend_op_array {
/* Common elements */
zend_uchar type;
char *function_name;
zend_class_entry *scope;
zend_uint fn_flags;
union _zend_function *prototype;
zend_uint num_args;
zend_uint required_num_args;
zend_arg_info *arg_info;
zend_bool pass_rest_by_reference;
unsigned char return_reference;
/* END of common elements */

zend_bool done_pass_two;

zend_uint *refcount;

zend_op *opcodes;
zend_uint last, size;

zend_compiled_variable *vars;
int last_var, size_var;

zend_uint T;

zend_brk_cont_element *brk_cont_array;
int last_brk_cont;
int current_brk_cont;

zend_try_catch_element *try_catch_array;
int last_try_catch;

/* static variables support */
HashTable *static_variables;

zend_op *start_op;
int backpatch_count;

zend_uint this_var;

char *filename;
zend_uint line_start;
zend_uint line_end;
char *doc_comment;
zend_uint doc_comment_len;
zend_uint early_binding; /* the linked list of delayed declarations */

void *reserved[ZEND_MAX_RESERVED_RESOURCES];
};

After reading the definition, I don’t need to say more. In the definition, filename and function_name save the file name and method name being executed respectively.

Current_execute_data saves the execute_data of the op_array being executed. execute_data saves some data during the execution of each op_array. It is defined in, Zend/zend_compile.h:

代码如下  
struct _zend_execute_data {
struct _zend_op *opline;
zend_function_state function_state;
zend_function *fbc; /* Function Being Called */
zend_class_entry *called_scope;
zend_op_array *op_array;
zval *object;
union _temp_variable *Ts;
zval ***CVs;
HashTable *symbol_table;
struct _zend_execute_data *prev_execute_data;
zval *old_error_reporting;
zend_bool nested;
zval **original_return_value;
zend_class_entry *current_scope;
zend_class_entry *current_called_scope;
zval *current_this;
zval *current_object;
struct _zend_op *call_opline;
};

The opline in the definition is the opcode being executed. The structure of opcode is defined as follows:

代码如下  
struct _zend_op {
opcode_handler_t handler;
znode result;
znode op1;
znode op2;
ulong extended_value;
uint lineno;
zend_uchar opcode;
};

Where lineno is the line number corresponding to opcode.

Example description:

After reading the above data structure definition, do you already know how to find the file name, method name and line number of PHP being executed? If you still have questions, then look at the following example. Create a file test.php with the following code:

代码如下  
function test1(){
while(true){
sleep(1);
}
}
test1();
?>

Execute the php script in cli mode, and the process number added to the execution is 14973. We use the gdb command to debug the process.

代码如下  
$sudo gdb -p 14973
(gdb) print (char *)executor_globals.active_op_array->filename
= 0x9853a34 "/home/xinhailong/test/php/test.php"
(gdb) print (char *)executor_globals.active_op_array->function_name
= 0x9854db8 "test1"
(gdb) print executor_globals->current_execute_data->opline->lineno
= 4

Obviously, he is executing the sleep method on the fourth line.

If you find the above method troublesome, you can use the .gdbinit file. This file is in the root directory of the php source code. How to use:

代码如下  
$sudo gdb -p 14973
(gdb) source /home/xinhailong/.gdbinit
(gdb) zbacktrace
[0xa453f34] sleep(1) /home/xinhailong/test/php/test.php:4
[0xa453ed0] test1() /home/xinhailong/test/php/test.php:7
(gdb)

Digression:

Starting from php5.6, a phpdbg tool is integrated into php. You can debug PHP programs just like gdb debugs C language programs. If you are interested, you can open the link below to take a look

www.bkjia.comtruehttp: //www.bkjia.com/PHPjc/918726.htmlTechArticleQuickly find out the code lines in php that may cause cpu surge problem. When the cpu is close to 100%, how do you find the cause? The reason for the CPU surge? My idea is to first find the line of code that the process is executing...
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn