[php] PHP 스크립트를 프로파일 링하는 가장 간단한 방법

PHP 스크립트를 프로파일 링하는 가장 쉬운 방법은 무엇입니까?

나는 모든 기능 호출의 덤프와 시간이 얼마나 걸렸는지를 보여주기를 원하지만 특정 기능 주위에 무언가를 넣는 것으로도 괜찮습니다.

마이크로 타임 기능을 실험 해 보았습니다 .

$then = microtime();
myFunc();
$now = microtime();

echo sprintf("Elapsed:  %f", $now-$then);

하지만 때로는 부정적인 결과가 나옵니다. 또한 내 코드 전체에 뿌리는 것은 많은 문제입니다.



답변

PECL APD를 다음과 같이 확장이 사용된다 :

<?php
apd_set_pprof_trace();

//rest of the script
?>

그런 다음을 사용하여 생성 된 파일을 구문 분석하십시오 pprofp.

출력 예 :

Trace for /home/dan/testapd.php
Total Elapsed Time = 0.00
Total System Time  = 0.00
Total User Time    = 0.00


Real         User        System             secs/    cumm
%Time (excl/cumm)  (excl/cumm)  (excl/cumm) Calls    call    s/call  Memory Usage Name
--------------------------------------------------------------------------------------
100.0 0.00 0.00  0.00 0.00  0.00 0.00     1  0.0000   0.0009            0 main
56.9 0.00 0.00  0.00 0.00  0.00 0.00     1  0.0005   0.0005            0 apd_set_pprof_trace
28.0 0.00 0.00  0.00 0.00  0.00 0.00    10  0.0000   0.0000            0 preg_replace
14.3 0.00 0.00  0.00 0.00  0.00 0.00    10  0.0000   0.0000            0 str_replace

경고 : 최신 APD 릴리스는 2004 년이며, 확장 은 더 이상 유지되지 않으며 다양한 호환성 문제가 있습니다 (주석 참조).


답변

당신은 내가 생각하는 xdebug를 원한다 . 서버에 설치하고 전원을 켜고 kcachegrind (Linux의 경우) 또는 wincachegrind (Windows의 경우) 를 통해 출력을 펌핑 하면 정확한 타이밍, 카운트 및 메모리 사용량을 자세히 보여주는 몇 가지 예쁜 차트가 표시됩니다 (그러나 다른 확장 프로그램이 필요합니다).

그것은 심각하게 흔들린다 : D


답변

확장이 필요하지 않습니다. 간단한 프로파일 링을 위해이 두 기능을 사용하십시오.

// Call this at each point of interest, passing a descriptive string
function prof_flag($str)
{
    global $prof_timing, $prof_names;
    $prof_timing[] = microtime(true);
    $prof_names[] = $str;
}

// Call this when you're done and want to see the results
function prof_print()
{
    global $prof_timing, $prof_names;
    $size = count($prof_timing);
    for($i=0;$i<$size - 1; $i++)
    {
        echo "<b>{$prof_names[$i]}</b><br>";
        echo sprintf("&nbsp;&nbsp;&nbsp;%f<br>", $prof_timing[$i+1]-$prof_timing[$i]);
    }
    echo "<b>{$prof_names[$size-1]}</b><br>";
}

다음은 각 검사 점에 설명이 있고 prof_print ()가 끝에있는 prof_flag ()를 호출하는 예입니다.

prof_flag("Start");

   include '../lib/database.php';
   include '../lib/helper_func.php';

prof_flag("Connect to DB");

   connect_to_db();

prof_flag("Perform query");

   // Get all the data

   $select_query = "SELECT * FROM data_table";
   $result = mysql_query($select_query);

prof_flag("Retrieve data");

   $rows = array();
   $found_data=false;
   while($r = mysql_fetch_assoc($result))
   {
       $found_data=true;
       $rows[] = $r;
   }

prof_flag("Close DB");

   mysql_close();   //close database connection

prof_flag("Done");
prof_print();

출력은 다음과 같습니다.

시작
   0.004303
DB에 연결
   0.003518
쿼리 수행
   0.000308
데이터 검색
   0.000009
닫기 DB
   0.000049
완료


답변

오프라인으로 진행중인 SO Documentation 베타에서 내 참조를 교차 게시합니다.

XDebug로 프로파일 링

Xdebug라는 PHP 확장을 사용하여 PHP 디버깅 및 런타임 디버깅 을 지원할 수 있습니다 . 프로파일 러를 실행할 때 출력은 “cachegrind”라는 이진 형식으로 파일에 기록됩니다. 이러한 파일을 분석하기 위해 각 플랫폼에서 응용 프로그램을 사용할 수 있습니다. 이 프로파일 링을 수행하기 위해 애플리케이션 코드를 변경할 필요가 없습니다.

프로파일 링을 활성화하려면 확장 기능을 설치하고 php.ini 설정을 조정하십시오. 일부 Linux 배포판에는 표준 패키지 (예 : Ubuntu php-xdebug패키지)가 제공됩니다. 이 예에서는 요청 매개 변수를 기반으로 선택적으로 프로파일을 실행합니다. 이를 통해 설정을 정적으로 유지하고 필요한 경우에만 프로파일 러를 켤 수 있습니다.

# php.ini settings
# Set to 1 to turn it on for every request
xdebug.profiler_enable = 0
# Let's use a GET/POST parameter to turn on the profiler
xdebug.profiler_enable_trigger = 1
# The GET/POST value we will pass; empty for any value
xdebug.profiler_enable_trigger_value = ""
# Output cachegrind files to /tmp so our system cleans them up later
xdebug.profiler_output_dir = "/tmp"
xdebug.profiler_output_name = "cachegrind.out.%p"

다음으로 웹 클라이언트를 사용하여 프로파일 링하려는 애플리케이션의 URL을 요청하십시오. 예 :

http://example.com/article/1?XDEBUG_PROFILE=1

페이지가 처리됨에 따라 비슷한 이름의 파일에 기록됩니다

/tmp/cachegrind.out.12345

기본적으로 파일 이름의 숫자는 파일 이름을 쓴 프로세스 ID입니다. 이것은 xdebug.profiler_output_name설정 으로 구성 할 수 있습니다.

실행되는 PHP 요청 / 프로세스마다 하나의 파일을 작성합니다. 예를 들어, 양식 게시물을 분석하려는 경우 HTML 양식을 표시하기 위해 GET 요청에 대해 하나의 프로파일이 작성됩니다. XDEBUG_PROFILE 매개 변수는 양식을 처리하는 두 번째 요청을 분석하기 위해 후속 POST 요청으로 전달되어야합니다. 따라서 프로파일 링 할 때 curl을 실행하여 양식을 직접 POST하는 것이 더 쉬운 경우가 있습니다.

출력 분석

작성된 후 KCachegrind 또는 Webgrind 와 같은 응용 프로그램에서 프로파일 캐시를 읽을 수 있습니다 . 널리 사용되는 PHP IDE 인 PHPStorm 도이 프로파일 링 데이터를 표시 할 수 있습니다 .

KCachegrind

예를 들어 KCachegrind는 다음과 같은 정보를 표시합니다.

  • 실행 된 기능
  • 자체 및 후속 함수 호출을 포함한 호출 시간
  • 각 함수가 호출 된 횟수
  • 통화 그래프
  • 소스 코드에 대한 링크

찾아야 할 것

분명히 성능 조정은 각 응용 프로그램의 사용 사례에 따라 매우 다릅니다. 일반적으로 다음을 찾는 것이 좋습니다.

  • 예상치 못한 동일한 함수를 반복해서 호출합니다. 데이터를 처리하고 쿼리하는 함수의 경우 응용 프로그램이 캐시 할 수있는 주요 기회가 될 수 있습니다.
  • 느리게 실행되는 기능. 응용 프로그램은 대부분의 시간을 어디에 소비합니까? 성능 조정에서 가장 좋은 결과는 가장 많은 시간을 소비하는 애플리케이션 부분에 초점을 맞추는 것입니다.

참고 : Xdebug, 특히 프로파일 링 기능은 리소스를 많이 사용하며 PHP 실행 속도를 늦 춥니 다. 프로덕션 서버 환경에서는이를 실행하지 않는 것이 좋습니다.


답변

마이크로 타임을 빼면 부정적인 결과가 나오면 인수 true( microtime(true)) 와 함께 함수를 사용해보십시오 . 을 사용 true하면 함수가 문자열 대신 부동 소수점을 반환합니다 (인수없이 호출 된 것처럼).


답변

솔직히, 프로파일 링을 위해 NewRelic을 사용하는 것이 가장 좋습니다.

그것은 런타임을 전혀 늦추지 않는 PHP 확장이며 적절한 모니터링을 허용합니다. 비싼 버전에서는 무거운 드릴 다운을 허용하지만 가격 모델을 감당할 수는 없습니다.

그럼에도 불구하고, 무료 / 표준 계획이 있더라도, 매달린 과일의 대부분이 어디에 있는지 분명하고 간단합니다. 또한 DB 인터랙션에 대한 아이디어를 제공 할 수도 있습니다.

프로파일 링시 인터페이스 중 하나의 스크린 샷


답변

불쌍한 남자의 프로파일 링, 확장이 필요하지 않습니다. 중첩 된 프로파일 및 총 백분율을 지원합니다.

function p_open($flag) {
    global $p_times;
    if (null === $p_times)
        $p_times = [];
    if (! array_key_exists($flag, $p_times))
        $p_times[$flag] = [ 'total' => 0, 'open' => 0 ];
    $p_times[$flag]['open'] = microtime(true);
}

function p_close($flag)
{
    global $p_times;
    if (isset($p_times[$flag]['open'])) {
        $p_times[$flag]['total'] += (microtime(true) - $p_times[$flag]['open']);
        unset($p_times[$flag]['open']);
    }
}

function p_dump()
{
    global $p_times;
    $dump = [];
    $sum  = 0;
    foreach ($p_times as $flag => $info) {
        $dump[$flag]['elapsed'] = $info['total'];
        $sum += $info['total'];
    }
    foreach ($dump as $flag => $info) {
        $dump[$flag]['percent'] = $dump[$flag]['elapsed']/$sum;
    }
    return $dump;
}

예:

<?php

p_open('foo');
sleep(1);
p_open('bar');
sleep(2);
p_open('baz');
sleep(3);
p_close('baz');
sleep(2);
p_close('bar');
sleep(1);
p_close('foo');

var_dump(p_dump());

수율 :

array:3 [
  "foo" => array:2 [
    "elapsed" => 9.000766992569
    "percent" => 0.4736904954747
  ]
  "bar" => array:2 [
    "elapsed" => 7.0004580020905
    "percent" => 0.36841864946596
  ]
  "baz" => array:2 [
    "elapsed" => 3.0001420974731
    "percent" => 0.15789085505934
  ]
]