Pregunta

¿Cuál es la forma más sencilla de crear un perfil de un script PHP?

Me encantaría agregar algo que me muestre un volcado de todas las llamadas a funciones y cuánto tiempo tardaron, pero también estoy de acuerdo con poner algo alrededor de funciones específicas.

Intenté experimentar con el microtiempo función:

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

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

pero eso a veces me da resultados negativos.Además, es un montón de problemas esparcir eso por todo mi código.

¿Fue útil?

Solución

El PECL APD La extensión se utiliza de la siguiente manera:

<?php
apd_set_pprof_trace();

//rest of the script
?>

Después, analice el archivo generado usando pprofp.

Salida de ejemplo:

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

Advertencia:la última versión de APD es de 2004, la extensión ya no se mantiene y tiene varios problemas de compatibilidad (ver comentarios).

Otros consejos

Quieres xdebug Creo.Instálelo en el servidor, enciéndalo, bombee la salida a través kcachegrind (para Linux) o wincachegrind (para Windows) y le mostrará algunos gráficos bonitos que detallan los tiempos exactos, los recuentos y el uso de la memoria (pero necesitará otra extensión para eso).

Es genial, en serio :D

No se necesitan extensiones, simplemente use estas dos funciones para crear perfiles 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("&nbsp;&nbsp;&nbsp;%f<br>", $prof_timing[$i+1]-$prof_timing[$i]);
    }
    echo "<b>{$prof_names[$size-1]}</b><br>";
}

Aquí hay un ejemplo, llamando a prof_flag() con una descripción en cada punto de control y a prof_print() al 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();

La salida se ve así:

Comenzar
   0.004303
Conectarse a la base de datos
   0.003518
Realizar consulta
   0.000308
Recuperar datos
   0.000009
Cerrar base de datos
   0.000049
Hecho

Publicación cruzada de mi referencia de la versión beta de SO Documentation que se desconecta.

Creación de perfiles con XDebug

Una extensión de PHP llamada Xdebug está disponible para ayudar creación de perfiles de aplicaciones PHP, así como depuración en tiempo de ejecución.Cuando se ejecuta el generador de perfiles, la salida se escribe en un archivo en formato binario llamado "cachegrind".Hay aplicaciones disponibles en cada plataforma para analizar estos archivos. No es necesario realizar cambios en el código de la aplicación para realizar esta creación de perfiles.

Para habilitar la creación de perfiles, instale la extensión y ajuste la configuración de php.ini.Algunas distribuciones de Linux vienen con paquetes estándar (p. ej.ubuntu php-xdebug paquete).En nuestro ejemplo, ejecutaremos el perfil opcionalmente en función de un parámetro de solicitud.Esto nos permite mantener la configuración estática y activar el generador de perfiles solo cuando sea necesario.

# 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"

A continuación, utilice un cliente web para realizar una solicitud a la URL de su aplicación que desea perfilar, p.

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

A medida que la página se procesa, escribirá en un archivo con un nombre similar a

/tmp/cachegrind.out.12345

De forma predeterminada, el número en el nombre del archivo es la identificación del proceso que lo escribió.Esto es configurable con el xdebug.profiler_output_name configuración.

Tenga en cuenta que escribirá un archivo por cada solicitud/proceso PHP que se ejecute.Entonces, por ejemplo, si desea analizar la publicación de un formulario, se escribirá un perfil para la solicitud GET para mostrar el formulario HTML.El parámetro XDEBUG_PROFILE deberá pasarse a la solicitud POST posterior para analizar la segunda solicitud que procesa el formulario.Por lo tanto, al crear perfiles, a veces es más fácil ejecutar curl para PUBLICAR un formulario directamente.

Analizando el resultado

Una vez escrito, el caché del perfil puede ser leído por una aplicación como KCachegrind o Webgrind.PHPStorm, un popular IDE de PHP, también puede mostrar estos datos de perfil.

KCachegrind

KCachegrind, por ejemplo, mostrará información que incluye:

  • Funciones ejecutadas
  • Tiempo de llamada, tanto en sí mismo como incluyendo llamadas a funciones posteriores.
  • Número de veces que se llama cada función
  • Gráficos de llamadas
  • Enlaces al código fuente

Qué buscar

Obviamente, el ajuste del rendimiento es muy específico de los casos de uso de cada aplicación.En general es bueno buscar:

  • Llamadas repetidas a la misma función que no esperarías ver.Para funciones que procesan y consultan datos, estas podrían ser oportunidades excelentes para que su aplicación almacene en caché.
  • Funciones de ejecución lenta.¿Dónde pasa la aplicación la mayor parte de su tiempo?La mejor recompensa al ajustar el rendimiento es centrarse en aquellas partes de la aplicación que consumen más tiempo.

Nota:Xdebug, y en particular sus funciones de creación de perfiles, consumen muchos recursos y ralentizan la ejecución de PHP.Se recomienda no ejecutarlos en un entorno de servidor de producción.

Si restar microtiempos te da resultados negativos, intenta usar la función con el argumento true (microtime(true)).Con true, la función devuelve un flotante en lugar de una cadena (como lo hace si se llama sin argumentos).

Honestamente, voy a argumentar que usar NewRelic para crear perfiles es lo mejor.

Es una extensión PHP que no parece ralentizar el tiempo de ejecución en absoluto y ellos hacen el monitoreo por usted, lo que permite un desglose decente.En la versión costosa, permiten un profundo desglose (pero no podemos permitirnos su modelo de precios).

Aún así, incluso con el plan gratuito/estándar, es obvio y simple dónde está la mayor parte de los frutos maduros.También me gusta que pueda darte una idea sobre las interacciones de la base de datos.

screenshot of one of the interfaces when profiling

PECL XHPROF Parece interesante también.Tiene interfaz HTML en la que se puede hacer clic para ver informes y bastante sencillo documentación.Aunque todavía tengo que probarlo.

Perfil de pobre, no se requieren extensiones.Admite perfiles anidados y porcentaje del total:

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;
}

Ejemplo:

<?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());

Rendimientos:

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
  ]
]

Me gusta usar phpDebug para crear perfiles.http://phpdebug.sourceforge.net/www/index.html

Genera todo el tiempo/uso de memoria para cualquier SQL utilizado, así como todos los archivos incluidos.Obviamente, funciona mejor en código abstracto.

Para perfiles de funciones y clases, simplemente usaré microtime() + get_memory_usage() + get_peak_memory_usage().

Yo daría desafiantemente Fuego negro un intento.

Existe este virtualBox que he creado usando marioneta, para probar diferentes marcos php que vienen con BlackFire, no dude en bifurcarlos y/o distribuirlos si es necesario :)

https://github.com/webit4me/PHPFrameworks

Para la evaluación comparativa, como en su ejemplo, utilizo el pera punto de referencia paquete.Estableces marcadores para medir.La clase también proporciona algunas ayudas para la presentación, o puede procesar los datos como mejor le parezca.

De hecho, lo tengo envuelto en otra clase con un método __destruct.Cuando sale un script, la salida se registra a través de log4php en syslog, por lo que tengo muchos datos de rendimiento con los que trabajar.

XDebug no es estable y no siempre está disponible para una versión particular de PHP.Por ejemplo, en algunos servidores todavía ejecuto php-5.1.6, es lo que viene con RedHat RHEL5 (y por cierto todavía recibo actualizaciones para todos los problemas importantes), y XDebug reciente ni siquiera se compila con este php.Así que terminé cambiándome a Depurador DBGEs evaluación comparativa de php proporciona sincronización para funciones, métodos, módulos e incluso líneas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top