多次調用xhprof_enable方法,最后生效的配置是哪個?
當你在一次請求中多次調用xhprof_enable方法,只有第一次調用時進行的設置能生效。在調用.
xhprof_disable()后,你又可以使用xhprof_enable方法進行設置。
- $i = 0;
- function good(){
- global $i;
- $i++;
- if ($i < 2) {
- good();
- }
- }
- function func() {
- good();
- }
- $start_time = microtime(true);
- xhprof_enable(XHPROF_FLAGS_NO_BUILTINS);
- xhprof_enable(XHPROF_FLAGS_MEMORY + XHPROF_FLAGS_CPU + XHPROF_FLAGS_NO_BUILTINS);
- for ($i = 0; $i < 100; $i++) {
- func();
- }
- good();
- $rst = xhprof_disable();
- var_dump($rst);
輸出內容為:
- array(5) {
- ["good==>good@1"]=>
- array(2) {
- ["ct"]=>
- int(1)
- ["wt"]=>
- int(70)
- }
- ["func==>good"]=>
- array(2) {
- ["ct"]=>
- int(50)
- ["wt"]=>
- int(121)
- }
- ["main()==>func"]=>
- array(2) {
- ["ct"]=>
- int(50)
- ["wt"]=>
- int(135)
- }
- ["main()==>good"]=>
- array(2) {
- ["ct"]=>
- int(1)
- ["wt"]=>
- int(0)
- }
- ["main()"]=>
- array(2) {
- ["ct"]=>
- int(1)
- ["wt"]=>
- int(237)
- }
- }
可見,打印的內容,并沒有cpu和memory的信息。
輸出內容中的ct,wt,cpu,mu, pmu 都代表什么意思.
ct 表示 調用的次數
wt 表示 函數方法執行的時間耗時。相當于,在調用前記錄一個時間,函數方法調用完畢后,計算時間差。
cpu 表示 函數方法執行消耗的cpu時間。和wt的差別在于,當進程讓出cpu使用權后,將不再計算cpu時間。通過調用系統調用getrusage獲取進程的占用cpu數據。
mu 表示 函數方法所使用的內存。相當于,在調用前記錄一個內存占用,函數方法調用完畢后,計算內存差。調用的是zend_memory_usage獲取內存占用情況。
pmu 表示 函數方法所使用的內存峰值。調用的是zend_memory_peak_usage獲取內存情況。
輸出內容中good==>good@1 是什么意思
==>表示一個調用關系。由于帶@,說明是一個遞歸調用。@后面的數字是遞歸調用的深度。
如何設置xhprof_enable的參數,減少性能消耗
xhprof_enable提供了三個常量,用于設置你是否需要統計PHP內置函數,都統計那些指標。
三個常量如下:
XHPROF_FLAGS_NO_BUILTINS
設置這個常量后,將不統計PHP內置函數。畢竟PHP的內置函數性能一般都不錯。沒必要再消耗性能去統計。所以,建議設置。
XHPROF_FLAGS_CPU
設置這個常量后,會統計進程占用CPU時間。由于CPU時間是通過調用系統調用getrusage獲取,導致性能比較差。開啟這個選項后,大概性能下降一半。因此,如果對cpu耗時不是特別敏感的情況下,建議不要啟用這個選項。
XHPROF_FLAGS_MEMORY
設置這個常量后,將會統計內存占用情況。由于獲取內存情況,使用的是zend_memory_usage和zend_memory_peak_usage,并不是系統調用。因此,對性能影響不大。如果需要對內存使用情況進行分析的情況下,可以開啟。
性能分析原理
如何實現對各個函數方法性能數據記錄
目前xhprof會對,加載PHP文件,執行PHP函數方法,和執行eval方法進行性能數據記錄。正好,這些在PHP內核中,有對應的函數進行處理。當你調用xhprof_enable方法時,會把默認的方法替換為xhprof的方法。來看看相關代碼吧。
- static void hp_begin(long level, long xhprof_flags)
- {
- if (!hp_globals.enabled)
- {
- int hp_profile_flag = 1;
- hp_globals.enabled = 1;
- hp_globals.xhprof_flags = (uint32) xhprof_flags;
- /* Replace zend_compile with our proxy */
- /* 處理加載PHP文件 */
- /* 先把zend引擎默認處理方法保存到_zend_compile_file變量中。*/
- _zend_compile_file = zend_compile_file;
- /* 在把xhprof相對應的方法賦值給zend_compile_file。
- 這樣,每次加載PHP文件時,就會執行xhprof相應的方法。*/
- zend_compile_file = hp_compile_file;
- /* Replace zend_compile_string with our proxy */
- /* 處理eval代碼的執行 */
- _zend_compile_string = zend_compile_string;
- zend_compile_string = hp_compile_string;
- /*init the execute pointer*/
- /* 處理 函數方法的執行 */
- _zend_execute_ex = zend_execute_ex;
- zend_execute_ex = hp_execute_ex;
- .........
- }
- }
- /*那我們看下,hp_compile_file方法,又是如何實現的*/
- ZEND_DLEXPORT zend_op_array* hp_compile_file(zend_file_handle *file_handle, int type)
- {
- const char *filename;
- char *func;
- int len;
- zend_op_array *ret;
- int hp_profile_flag = 1;
- filename = hp_get_base_filename(file_handle->filename);
- len = sizeof("load") - 1 + strlen(filename) + 3;
- func = (char *) emalloc(len);
- snprintf(func, len, "load::%s", filename);
- //方法執行前記錄當前各項性能如數,如cpu 內存等
- BEGIN_PROFILING(&hp_globals.entries, func, hp_profile_flag);
- //開始zend引擎相應的方法,加載文件
- ret = _zend_compile_file(file_handle, type);
- if (hp_globals.entries)
- {
- //加載文件完畢后,再次記錄當前各項性能數據。以便以后計算差值。
- END_PROFILING(&hp_globals.entries, hp_profile_flag);
- } //Vevb.com
- efree(func);
- return ret;
- }
xhprof在實現的時候,性能方面做了哪些優化
獲取時間時,為了性能,使用了匯編來獲取時間戳計數器。時間秒 = 時間戳計數器值 / CPU主頻。
正是這種實現,導致目前xhprof還只適用于x86架構。此外,因為RDTSC的數據不能在CPU間同步,所以,xhprof會將進程綁定在單個CPU上。
如果SpeedStep技術是打開的,XHProf的基于RDTSC定時器的功能就不能正常工作了。這項技術在某些英特爾處理器上是可用的。[注:蘋果臺式機和筆記本電腦一般都將SpeedStep技術預設開啟。使用XHProf,您需要禁用SpeedStep技術。 ]
- inline uint64 cycle_timer()
- {
- uint32 __a, __d;
- uint64 val;
- asm volatile("rdtsc" : "=a" (__a), "=d" (__d));
- (val) = ((uint64) __a) | (((uint64) __d) << 32);
- return val;
- }
新聞熱點
疑難解答