xhprof的工作原理
xhprof是php的第三方擴展,工作在zend層,以動態加載的方式被加載。php在解釋執行的過程中,首先被解釋成對應的token碼,而后,編譯成字節碼(這里的字節碼不是機器碼,在PHP里面稱其為opcode碼)。xhprof就在php被加載,loading,引起自身extension的時候一起被加載,解釋,編譯。
xhprof本身通過對zend層函數處理相關的結構體的定義,比如:
zend_module_entry xhprof_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"xhprof", /* Name of the extension */
xhprof_functions, /* List of functions exposed */
PHP_MINIT(xhprof), /* Module init callback */
PHP_MSHUTDOWN(xhprof), /* Module shutdown callback */
PHP_RINIT(xhprof), /* Request init callback */
PHP_RSHUTDOWN(xhprof), /* Request shutdown callback */
PHP_MINFO(xhprof), /* Module info callback */
#if ZEND_MODULE_API_NO >= 20010901
XHPROF_VERSION,
#endif
STANDARD_MODULE_PROPERTIES
};
來完成xhprof自定義的函數的初始化,完成xhprof本身的callback機制的注冊。
在安裝xhprof的過程中,我們需要去定義xhprof報告的輸出目錄,并且我們設置的時候,變量的名稱只能是:xhprof.output_dir原因就在于在xhprof.c的文件中,對于php_ini_entry的設定就是
PHP_INI_BEGIN()
/* output directory:
* Currently this is not used by the extension itself.
* But some implementations of iXHProfRuns interface might
* choose to save/restore XHProf profiler runs in the
* directory specified by this ini setting.
*/
PHP_INI_ENTRY("xhprof.output_dir", "", PHP_INI_ALL, NULL)
PHP_INI_END()這里完成的對php.ini里有關xhprof的配置節的定義方式和方法。相關解釋如下:
如果想要為你的模塊創建一個 .ini 文件的配置節,可以使用宏 PHP_INI_BEGIN() 來標識這個節的開始,并用 PHP_INI_END() 表示該配置節已經結束。然后在兩者之間我們用 PHP_INI_ENTRY() 來創建具體的配置項。HP_INI_ENTRY() 總共接收 4 個參數:配置項名稱、初始值、改變這些值所需的權限以及在值改變時用于接收通知的函數句柄。配置項名稱和初始值必須是一個字符串,即使它們是一個整數。HP_INI_SYSTEM 只允許在 php.ini 中改變這些值;PHP_INI_USER 允許用戶在運行時通過像 .htaccess 這樣的附加文件來重寫其值;而 PHP_INI_ALL 則允許隨意更改。
前面提到xhprof是在config.m4里面,作為$ext_shared的方式被動態加載進入zend層工作的,所以,這里還需要用zend_get_module進行一些處理。zend_get_module的作用為:
ZEND_GET_MODULE (extension_name)
Description:
Provides additional C code used if you want to build a dynamic loaded extension.
到這里,如果xhprof安裝正常,那么就已經完成了php在啟動的過程中,xhprof作為extension,被加載的方式的定義,和具體的方法的定義了。
前面大體是xhprof在安裝后,是工作在哪一層?以何種方式被引入php?怎么被引入的?相關理解和解釋,下面再看看xhprof是怎么收集到函數的執行性能profile數據的,例如cpu、memory的使用等信息數據
PHP_FUNCTION(xhprof_enable) {
long xhprof_flags = 0; /* XHProf flags */
zval *optional_array = NULL; /* optional array arg: for future use */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
"|lz", &xhprof_flags, &optional_array) == FAILURE) {
return;
}
hp_get_ignored_functions_from_arg(optional_array);
這個函數里面是對xhprof_enable函數體的實現,在我們需要對一個函數進行xhprof的時候,需要在最開始進行xhprof_enable()的調用,enable里面可以傳參數也可以默認為空,這里zend_parse_parameters的參數中,"ZEND_NUM_ARGS() TSRMLS_CC"部分基本是固定打法,接著的部分 代表參數的相應類型。在這里"|lz"的意思是$xhprof_flags is long typeof,$optional_array is array typeof).
zend_parse_parameters 詳解
自動生成的PHP函數周圍包含了一些注釋,這些注釋用于自動生成代碼文檔和vi、Emacs等編輯器的代碼折疊。函數自身的定義使用了宏PHP_FUNCTION(),該宏可以生成一個適合于Zend引擎的函數原型。邏輯本身分成語義各部分,取得調用函數的參數和邏輯本身。為了獲得函數傳遞的參數,可以使用zend_parse_parameters()API函數
所以如果獲取xhprof_enable傳入的參數如果失敗,則會直接return。到下面,則是對hp_get_ignored_functions_from_arg的調用,看名字應該是對要忽略的函數名的獲取,從該函數的本身內容
static void hp_get_ignored_functions_from_arg(zval *args) {
if (args != NULL) {
zval *zresult = NULL;
zresult = hp_zval_at_key("ignored_functions", args);
hp_globals.ignored_function_names = hp_strings_in_zval(zresult);
} else {
hp_globals.ignored_function_names = NULL;
}
}可以看出,這個函數的確是對需要忽略的函數名的獲取。
這里插一腳,php之所以可以在使用變量前不需要對該變量進行提前定義,是因為在php的zend引擎中有這么一個東西zval,在php里面,zend用它來作為一個容器,來處理所有的外部變量,還是直接貼一段代碼,大家一起來看
原文轉自:http://blog.csdn.net/yzongyu/article/details/8457209