XDebug를 이용한 PHP 디버깅 – 3


Notice: Undefined index: lang in /home/taggon/www/wordpress/wp-content/plugins/wp-highlightjs/wp_highlight.js.php on line 119

이번엔 프로파일링 기능을 살펴보겠습니다. 프로파일링 기능을 이용하면 어떤 함수에서 부하가 걸렸는지 또는 어느 정도의 빈도로 실행되었는지 등을 점검할 수 있어 보다 최적화된 코드를 만들 수 있습니다.
XDebug에는 프로파일링 기능을 사용하는 두 가지 방법이 있습니다.

  1. 모든 스크립트에 대해서 자동으로 프로파일링을 하고 싶을 경우
    php.ini 파일에 xdebug.profiler_enable = 1 로 설정하면 됩니다.
  2. 특정 파일에 대해서만 프로파일링을 하고 싶을 경우
    php.ini 파일에서 xdebug.profiler_enable_trigger = 1 로 설정하고 GET 혹은 POST 방식으로 XDEBUG_PROFILE 이라는 파라미터를 전송하기만 하면 됩니다. 예를 들어 프로파일링 기능을 사용하려면, 다음과 같이 URL을 호출합니다.
    http://example.com/sample.php?XDEBUG_PROFILE=1

위의 두 방법 모두 공통으로 xdebug.profiler_output_dir 을 설정해야 합니다. 설정하지 않으면 기본으로 /tmp 가 지정되는데, 지금 우리가 보고 있는 것은 윈도우이므로 /tmp 가 유효하지 않으므로 경로를 수정해줘야 합니다.

프로파일링 파일은 CacheGrind 의 파일 포맷과 호환되도록 되어있습니다. 따라서 CacheGrind 파일을 읽을 수 있는 어플리케이션이 있으면 되는데, Linux의 KDE 환경에서는 KCacheGrind 가 있고, Windows 환경에는 WinCacheGrind가 있습니다. 기능이나 디자인 면에서는 KCacheGrind가 더 낫다고 하는데 아쉬운 대로 WinCacheGrind 를 쓰도록 하겠습니다. ^^

이제 테스트를 할 샘플 코드를 작성합니다. 샘플 코드는 재귀 호출을 이용해서 팩토리얼을 계산하는 함수입니다.


< ?php
function factorial($number) {
   $number = intval($number);
   if ($number <= 0) return false; // $number is always positive.
   if ($number <= 2) return $number;

   return $number * factorial($number-1);
}
?>
<html>
<head>
<title>factorial example</title>
</head>
<body>
<h3>Factorial maker</h3>
<form method="POST">
<input type="hidden" name="XDEBUG_PROFILE" value="1">
number : <input type="text" name="num">
<input type="submit" value="make">
</form>
Result<br>
<?php
if ($_POST['num']) {
    echo intval($_POST['num'])."! = ".factorial(intval($_POST['num']));
}
?>
</body>
</html>

이제 URL을 열어서 값을 입력해서 프로그램을 실행해봅니다. 저는 대충 15정도의 값을 줬습니다. 너무 작으면 결과를 신뢰하기 어렵고 너무 크면 숫자가 범위를 넘어가서 오류가 발생합니다. 이제서야 다른 코드로 짤걸 그랬나…하는 생각이 드는군요. ^^;;

debug08.png

프로그램을 실행하고나면 xdebug.profiler_output_dir 에서 설정한 위치에 프로파일링 파일이 생기는데 WinCacheGrind를 실행해서 이 파일을 열면 다음과 같은 화면을 볼 수 있습니다.

debug09.png

딱 보고 알 수 있는 것은 {main} 이 외에는 factorial, intval 이 실행되었고 intval 은 PHP 내장 함수네요. factorial 은 14번, intval은 16번 호출되었다는 것을 알 수 있습니다. 횟수는 factorial 이 두번이나 적지만 0.6ms의 시간이 걸린 반면에 intval 은 부하가 거의 없습니다.

debug10.png

Line by Line 탭으로 가면 실행 순서를 따라갈 수 있는데, 왼쪽의 탭에서도 가능합니다. {main}은 전체 실행시간(cumulative time)에 걸쳐 있지만(100%), 실제로 {main}의 수행시간(self time)만 따지면 7.17% 밖에 안되는 것을 알 수 있습니다. 반면에 factorial 함수는 83.47% 나 잡아먹고 있습니다. 자체 실행시간만 보면 6.49% 이지만, 재귀적으로 실행하는 함수라는 것을 생각할 때 실제로는 factorial 하나에만 전체 실행시간의 83.47% 를 사용했다는 것을 알 수 있습니다.

따라서, 이 프로그램을 개선해야한다면 가장 많은 시간을 차지하고 있는 factorial 에 대한 알고리즘이 개선되어야 할 것입니다. 다음은 수정된 factorial 프로그램을 실행한 결과로 재귀호출대신 while 문을 이용하도록 수정했습니다.

debug12.png

debug11.png

알고리즘 개선으로 당연히 호출하는 횟수도 줄었고 실행시간도 미미할만큼 줄어들었으며 프로그램에서 차지하는 부하 비중이 확실하게 줄어든 것을 알 수 있습니다.

주의! 이 글은 전체의 절반 이하의 일부 복제만 허용합니다.

  1. 저는 KCachegrind쓰고 싶어서 우분투 환경으로 왔다는… ^^

    한글로 된 문서가 별로 없어서 공부하는데 많이 힘들었는데 감사합니다!

  2. 저도 고니님 블로그를 보고 xdebug를 사용해보려는데요.

    전 autoset(php 5.16) 에 php_xdebug-2.0.0-5.1.6.dll 을 사용해서 해보려고합니다.

    근데 php.ini 파일에 xdebug의 설정값들이 들어가도록 하려면 어찌해야하는지요..

Leave a Reply