Pregunta

Estoy tratando de determinar qué es necesario para escribir un perfilador de línea para un idioma, como los disponibles para Python y Matlab.

Una forma ingenua de interpretar "Profiler de línea" es asumir que uno puede insertar tiempo registrando cada línea, pero la definición de una línea depende de cómo un analizador maneja el espacio en blanco, que es solo el primer problema. Parece que uno necesita usar el árbol de análisis e insertar horarios alrededor de los nodos individuales.

¿Es esta conclusión correcta? ¿Un perfilador de línea requiere el árbol de análisis, y es todo lo que se necesita (más allá del registro del tiempo)?


ACTUALIZACIÓN 1: Ofrecer una recompensa sobre esto porque la pregunta aún no está resuelta.

Actualización 2: Aquí hay un enlace para un bien conocido Python Line Profiler En caso de que sea útil para responder a esta pregunta. Todavía no he podido hacer cabezas o colas de su comportamiento en relación con el análisis. Me temo que el código para el Profiler MATLAB no es accesible.

También tenga en cuenta que se podría decir que decorar manualmente el código de entrada eliminaría la necesidad de un árbol de análisis, pero ese no es un perfilador automático.

ACTUALIZACIÓN 3: Aunque esta pregunta es el lenguaje agnóstico, esto surgió porque estoy pensando en crear tal herramienta para R (a menos que exista y no lo haya encontrado).

ACTUALIZACIÓN 4: Con respecto al uso de un perfilador de línea versus un perfilador de pila de llamadas - esta publicación relacionado con el uso de un perfilador de pila de llamadas (Rprof() En este caso) ejemplifica por qué puede ser doloroso trabajar con la pila de llamadas en lugar de analizar directamente las cosas a través de un perfilador de línea.

¿Fue útil?

Solución

Diría que sí, necesitas un árbol de análisis (y la fuente): ¿de qué otra manera sabrías qué constituye una "línea" y una declaración válida?

Sin embargo, una simplificación práctica podría ser un "perfilador de declaración" en lugar de un "perfilador de línea". En R, el árbol de análisis está fácilmente disponible: body(theFunction), por lo que debería ser bastante fácil insertar código de medición alrededor de cada declaración. Con un poco más de trabajo, puede insertarlo en un grupo de declaraciones que pertenecen a la misma línea.

En R, el cuerpo de una función cargada desde un archivo generalmente también tiene un atributo srcref que enumera la fuente de cada "línea" (en realidad cada declaración):

Aquí hay una función de muestra (ponte en "Ejemplo.r"):

f <- function(x, y=3)
{
    a <- 0; a <- 1  # Two statements on one line
    a <- (x + 1) *  # One statement on two lines
        (y + 2)

    a <- "foo       
        bar"        # One string on two lines
}

Luego en r:

source("example.R")
dput(attr(body(theFunction), "srcref"))

Qué imprime esta información de línea/columna:

list(structure(c(2L, 1L, 2L, 1L, 1L, 1L, 2L, 2L), srcfile = <environment>, class = "srcref"), 
    structure(c(3L, 2L, 3L, 7L, 9L, 14L, 3L, 3L), srcfile = <environment>, class = "srcref"), 
    structure(c(3L, 10L, 3L, 15L, 17L, 22L, 3L, 3L), srcfile = <environment>, class = "srcref"), 
    structure(c(4L, 2L, 5L, 15L, 9L, 15L, 4L, 5L), srcfile = <environment>, class = "srcref"), 
    structure(c(7L, 2L, 8L, 6L, 9L, 20L, 7L, 8L), srcfile = <environment>, class = "srcref"))

Como puede "ver" (los dos últimos números en cada estructura son la línea de inicio/finalización), las expresiones a <- 0 y a <- 1 mapa a la misma línea ...

¡Buena suerte!

Otros consejos

Suena como lo que quieres decir con Line Profiler es algo que mide el tiempo dedicado (es decir, instrumento) dentro de cada línea. Espero que lo que quieres decir con el tiempo es el tiempo de pared, porque en un software de buen tamaño real si solo miras el tiempo de la CPU te perderás mucho.

Otra forma de hacerlo es el muestreo de pila en la hora del reloj de pared, como en el Zoom y Ltprof Profilers. Dado que cada línea de una muestra de pila se puede localizar en una línea de código utilizando solo un mapa o archivo PDB, de la misma manera que los depuradores lo hacen, no es necesario analizar o modificar la fuente.

El porcentaje del tiempo tomado por una línea de código es simplemente el porcentaje de muestras de pila que lo contienen. Como está trabajando a nivel de línea, no hay necesidad de distinguir entre tiempo exclusivo (uno mismo) y tiempo inclusivo. Esto se debe a que el porcentaje de tiempo activo de la línea es lo que importa, ya sea que sea una llamada a otra función, una llamada a una función de sistema ciega o simplemente una llamada al microcódigo.

La ventaja de observar los porcentajes, en lugar de los tiempos absolutos, es que no necesita preocuparse de que la aplicación se ralentice, ya sea por el muestreo en sí o por la competencia con otros procesos, porque esas cosas no afectan los porcentajes muy mucho.

Además, no tiene que preocuparse por la recursión. Si una línea de código está en una función recursiva y aparece más de una vez en una muestra, está bien. Todavía cuenta como solo una muestra que contiene la línea. La razón por la que está bien es que si esa línea de código de alguna manera se pudiera hacer que no tome tiempo (como eliminarlo) esa muestra no habría ocurrido. Por lo tanto, las muestras que contienen esa línea se eliminarían del conjunto de muestras, y el tiempo total del programa disminuiría en la misma cantidad que la fracción de las muestras eliminadas. Eso es independientemente de la recursión.

Tampoco necesita contar cuántas veces se ejecuta una línea de código, porque el número que importa para localizar el código que debe optimizar es el porcentaje de tiempo que está activo.

Aquí es Más explicación de estos problemas.

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