ホームページ  >  記事  >  バックエンド開発  >  CPU スパイクの原因となる可能性のある PHP のコード行を素早く特定する_PHP チュートリアル

CPU スパイクの原因となる可能性のある PHP のコード行を素早く特定する_PHP チュートリアル

WBOY
WBOYオリジナル
2016-07-13 10:13:00833ブラウズ

CPU サージの問題を引き起こす可能性のある PHP のコード行をすばやく見つけます

CPU が 100% に近い場合、私の考えは、まず CPU サージの原因を見つけることです。問題がある可能性があるコード スニペットを特定するためにプロセスが実行しているコード。次に、問題のあるコード部分を注意深く分析して原因を特定します。

プログラムが c または c++ で書かれている場合、実行されているコード行を簡単に見つけることができます。ただし、プログラムは PHP で記述されています。問題がある可能性のあるコード行をどのように見つければよいでしょうか? この問題は、この記事で解決されます。

背景知識:

phpがインタプリタ言語であることは誰もが知っています。ユーザーが記述した PHP コードはオペコードを生成し、インタープリタ エンジンによって解釈されて実行されます。解釈実行プロセス中に、実行プロセス中に使用されるさまざまなデータを含むグローバル変数が存在します。それはexecutor_globalsです。彼の型定義は、ソース コードの Zend/zend_globals.h ファイルにあります。

コードは次のとおりです

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;

/* シンボル テーブル キャッシュ */
ハッシュテーブル *symtable_cache[SYMTABLE_CACHE_SIZE];
ハッシュテーブル **symtable_cache_limit;
ハッシュテーブル **symtable_cache_ptr;

zend_op **opline_ptr;

ハッシュテーブル *active_symbol_table;
HashTablesymbol_table; /* メインシンボルテーブル */

HashTable Included_files; /* ファイルは既に組み込まれています */

JMP_BUF *救済;

int error_reporting;
int orig_error_reporting;
int exit_status;

zend_op_array *active_op_array;

ハッシュテーブル *関数テーブル; /* 関数記号テーブル */
ハッシュテーブル *クラステーブル; /* クラステーブル */
ハッシュテーブル *zend_constants; /* 定数テーブル */

zend_class_entry *スコープ;
zend_class_entry *コールドスコープ; /* 呼び出しクラスのスコープ */

zval *これ;

長い精度;

intticks_count;

zend_bool in_execution;
ハッシュテーブル *in_autoload;
zend_function *autoload_func;
zend_bool full_tables_cleanup;

/* 拡張情報サポート用 */
zend_bool no_extensions;

#ifdef ZEND_WIN32
zend_bool がタイムアウトしました;
OSVERSIONINFOEX windows_version_info;
#endif

ハッシュテーブルの通常リスト;
ハッシュテーブルの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 ユーザー例外ハンドラー;

zend_error_handling_t error_handling;
zend_class_entry *例外クラス;

/* タイムアウトのサポート */
int timeout_秒;

int lambda_count;

ハッシュテーブル *ini_directives;
ハッシュテーブル *modified_ini_directives;

zend_objects_store オブジェクトストア;
zval *例外、*prev_例外;
zend_op *opline_before_例外;
zend_op 例外_op[3];

struct _zend_execute_data *current_execute_data;

struct _zend_module_entry *current_module;

zend_property_info std_property_info;

zend_bool アクティブ;

void *saved_fpu_cw;

無効 *予約済み[ZEND_MAX_RESERVED_RESOURCES];
};

ここでは、私たちにとってより重要な 2 つの変数、active_op_array と current_execute_data についてのみ説明します。

active_op_array 変数には、エンジンが実行している op_array が格納されます (op_array が何であるかを知りたい場合は、クリックして表示してください)。 op_array のデータ型の定義は Zend/zend_compile.h にあります。

コードは次のとおりです

struct _zend_op_array {
/* 共通要素 */
zend_uchar タイプ;
char *関数名;
zend_class_entry *スコープ;
zend_uint fn_flags;
Union _zend_function *プロトタイプ;
zend_uint num_args;
zend_uint required_num_args;
zend_arg_info *arg_info;
zend_bool pass_rest_by_reference;
unsigned char return_reference;
/* 共通要素の終わり */

zend_bool doned_pa​​ss_two;

zend_uint *refcount;

zend_op *オペコード;
zend_uint 最後、サイズ;

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;

zend_op *start_op;
int backpatch_count;

zend_uint this_var;

char *ファイル名;
zend_uint line_start;
zend_uint line_end;
char *doc_comment;
zend_uint doc_comment_len;
zend_uint 初期バインディング; /* 遅延した宣言のリンクされたリスト */

無効 *予約済み[ZEND_MAX_RESERVED_RESOURCES];
};

定義を読んだ後は、これ以上言う必要はありません。定義中の filename と function_name にはそれぞれ実行中のファイル名とメソッド名が保存されます。

Current_execute_dataは、実行中のop_arrayのexecute_dataを保存します。 execute_data は、各 op_array の実行中に一部のデータを保存します。 Zend/zend_compile.h で定義されています:

コードは次のとおりです
struct _zend_execute_data {
struct _zend_op *opline;
zend_function_state function_state;
zend_function *fbc; /* 呼び出される関数 */
zend_class_entry *called_scope;
zend_op_array *op_array;
zval *オブジェクト;
Union _temp_variable *Ts;
zval ***CV;
ハッシュテーブル *symbol_table;
struct _zend_execute_data *prev_execute_data;
zval *old_error_reporting;
zend_bool ネストされた;
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;
};

定義内のoplineは実行されるオペコードです。オペコードの構造は次のように定義されます:

コードは次のとおりです
struct _zend_op {
opcode_handler_t ハンドラー;
znode の結果;
znode op1;
znode op2;
ulong 拡張値;
uint lineno;
zend_uchar オペコード;
};

lineno はオペコードに対応する行番号です。

説明例:

上記のデータ構造定義を読んだ後、実行される PHP のファイル名、メソッド名、行番号を確認する方法はもうわかりましたか? まだ疑問がある場合は、以下の例を見てください。次のコードを含むファイル test.php を作成します:

コードは次のとおりです
関数 test1(){
while(true){
睡眠(1);
}
}
テスト1();
?>

phpスクリプトをcliモードで実行すると、実行時に追加されるプロセス番号は14973です。 gdb コマンドを使用してプロセスをデバッグします。

コードは次のとおりです
$sudo gdb -p 14973
(gdb) print (char *)executor_globals.active_op_array->ファイル名
$1 = 0x9853a34 "/home/xinhailong/test/php/test.php"
(gdb) print (char *)executor_globals.active_op_array->function_name
$2 = 0x9854db8 "テスト1"
(gdb) print executor_globals->current_execute_data->opline->lineno
3 ドル = 4

明らかに、4行目のsleepメソッドを実行しています。

上記の方法が面倒な場合は、.gdbinit ファイルを使用できます。このファイルは、php ソース コードのルート ディレクトリにあります。使用方法:

コードは次のとおりです
$sudo gdb -p 14973
(gdb) ソース /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)

余談:

php5.6 以降、phpdbg ツールが php に統合されています。 gdb が C 言語プログラムをデバッグするのと同じように、PHP プログラムをデバッグできます。ご興味がございましたら、以下のリンクを開いてご覧ください

www.bkjia.com本当http://www.bkjia.com/PHPjc/918726.html技術記事 CPU スパイクの原因となる可能性のある PHP のコード行をすばやく見つける CPU が 100% に近い場合、まずプロセスが実行しているコード行を見つけるのが良いでしょうか。 、...
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。