Forma mais simples de analisar um programa de PHP
tentei experimentar com a função microtime :
$then = microtime();
myFunc();
$now = microtime();
echo sprintf("Elapsed: %f", $now-$then);
Mas isso às vezes dá-me resultados negativos. Além disso, dá muito trabalho espalhar isso pelo meu código.
12 answers
A extensão dePECL APD é utilizada do seguinte modo:
<?php
apd_set_pprof_trace();
//rest of the script
?>
Depois, analisar o ficheiro gerado usando pprofp
.
Exemplo de saída:
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
Você quer xdebug Eu acho. Instalá-lo no servidor, ative-a, bomba de saída através kcachegrind (para linux) ou wincachegrind (para windows) e ele vai mostrar-lhe alguns bonitos gráficos que detalham os intervalos exatos, contagens e o uso de memória (mas você vai precisar de outra extensão para que).
É o máximo, a sério.Não são necessárias extensões, basta usar estas duas funções para um perfil simples.
// 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(" %f<br>", $prof_timing[$i+1]-$prof_timing[$i]);
}
echo "<b>{$prof_names[$size-1]}</b><br>";
}
Aqui está um exemplo, chamando prof_flag () com uma descrição em cada checkpoint, e prof_print () no final:
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();
A saída parece-se com esta:
Início
0.004303
Ligue para DB
0.003518
Executar a consulta
0.000308
Recuperar dados
0.000009
Fechar DB
0.000049
Feito
Se subtrair microtimes lhe der resultados negativos, tente usar a função com o argumento true
(microtime(true)
). Com true
, a função devolve um 'float' em vez de um 'string' (como acontece se for chamado sem argumentos).
cruza a minha referência da documentação beta que está a ficar offline.
Análise de perfis com XDebug
Está disponível uma extensão para o PHP chamada Xdebug para ajudar em a traçar o perfil das aplicações do PHP, assim como a depuração em tempo de execução. Ao executar o profiler, a saída é escrita para um arquivo em um formato binário chamado "cachegrind". As aplicações estão disponíveis em cada plataforma para analisar esses arquivos. não são necessárias alterações ao código de aplicação para execute este perfil.
Para activar o perfil, instalar a extensão e ajustar o php.configurações ini. Algumas distribuições Linux vêm com pacotes padrão(por exemplo, pacote Ubuntu php-xdebug
). No nosso exemplo, executaremos o perfil opcionalmente com base num parâmetro de pedido. Isso nos permite manter as configurações estáticas e ligar o profiler apenas quando necessário.
# 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"
Em seguida, use um cliente web para fazer um pedido ao URL da sua aplicação que deseja traçar, por exemplo
http://example.com/article/1?XDEBUG_PROFILE=1
Como a página processes it will write to a file with a name similar to
/tmp/cachegrind.out.12345
Por padrão, o número no nome do ficheiro é o id do processo que o escreveu. Isto é configurável com a configuração xdebug.profiler_output_name
.
Note que ele irá escrever um arquivo para cada pedido / processo de PHP que é executado. Assim, por exemplo, se você deseja analisar um post de formulário, um perfil será escrito para o pedido GET para exibir o formulário HTML. O parâmetro XDEBUG_ profile terá de ser passado para a publicação subsequente pedido para analisar o segundo pedido que processa o formulário. Portanto, quando o perfil é às vezes mais fácil de executar curl para postar um formulário diretamente.
Analisando a saída
Uma vez escrita a 'cache' de perfis pode ser lida por uma aplicação como KCachegrind ou Webgrind . PHPStorm, um IDE PHP popular, também pode mostrar estes dados de análise .
O KCachegrind, por exemplo, irá mostrar informações incluindo:
- funções executadas
- Tempo de chamada, tanto em si como inclusivo de chamadas de funções subsequentes
- Número de vezes que cada função é chamada
- gráficos de chamadas
- ligações ao código-fonte
O que procurar
É óbvio que a sintonização de desempenho é muito específica dos casos de utilização de cada aplicação. Em geral, é bom olhar para:
- Chamadas repetidas para a mesma função que não esperava ver. Para funções que processam e consulta dados estes podem ser oportunidades principais para o seu aplicativo para cache.
- funções de execução lenta. Onde é que a aplicação passa a maior parte do seu tempo? o melhor pagamento em ajuste de desempenho está focando nas partes da aplicação que consomem mais tempo.
Nota : o Xdebug, e em particular as suas características de perfil, são muito intensivos em recursos e atrasam a execução do PHP. Recomenda-se que estes não sejam executados numa produção ambiente do servidor.
PECL XHPROF também parece interessante. Tem interface HTML clicável para ver relatórios e documentação bastante simples . Ainda não o testei.
Ele emite toda a utilização de tempo / memória para qualquer SQL usado, bem como todos os arquivos incluídos. Obviamente, funciona melhor em código que é abstraído.
Para funções e perfis de classe vou usar microtime()
+ get_memory_usage()
+ get_peak_memory_usage()
.
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;
}
Exemplo:
<?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());
Rendimentos:
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
]
]
Para o benchmarking, como no seu exemplo, eu uso o pacotepear Benchmark . Você coloca marcadores para medir. A classe também fornece alguns ajudantes de apresentação, ou você pode processar os dados como quiser.
Tenho-o embrulhado noutra classe com um método de destruição. Quando um script sai, a saída é registrada através de log4php para syslog, então eu tenho um monte de dados de desempenho para trabalhar.O XDebug não é estável e nem sempre está disponível para uma versão específica do php. Por exemplo, em alguns servidores que ainda executo o php-5.1.6, -- é o que vem com o RedHat RHEL5( e o btw ainda recebe atualizações para todas as questões importantes), e o xdebug recente nem sequer compila com este php. Por isso acabei por mudar para o depurador DBG A sua análise comparativa do php fornece o tempo para funções, métodos, módulos e linhas pares.