P1: ¿Qué herramientas está utilizando para la creación de perfiles de código (creación de perfiles, no evaluación comparativa)?
P2: ¿Cuánto tiempo dejas que se ejecute el código (estadísticas: cuántos pasos de tiempo)?
P3: ¿Qué tan grandes son los casos (si el caso cabe en la memoria caché, el solucionador es un orden de magnitud más rápido, pero luego extrañaré los procesos relacionados con la memoria)?
Aquí hay un ejemplo de cómo lo hago.
Separo el benchmarking (viendo cuánto tiempo lleva) del perfilado (identificando cómo hacerlo más rápido). No es importante que el perfilador sea rápido. Es importante que le diga qué arreglar.
Ni siquiera me gusta la palabra "perfil" porque evoca una imagen algo así como un histograma, donde hay una barra de costos para cada rutina, o "cuello de botella" porque implica que hay un pequeño lugar en el código que debe ser fijo. Ambas cosas implican algún tipo de tiempo y estadísticas, por lo que asume que la precisión es importante. No vale la pena renunciar a la comprensión de la precisión del tiempo.
El método que uso es una pausa aleatoria, y hay un estudio de caso completo y una presentación de diapositivas aquí . Parte de la visión del mundo del cuello de botella del perfilador es que si no encuentra nada, no se puede encontrar nada, y si encuentra algo y obtiene un cierto porcentaje de aceleración, declara la victoria y renuncia. Los fanáticos de Profiler casi nunca dicen cuánto aceleran, y los anuncios solo muestran problemas artificiales diseñados para ser fáciles de encontrar. La pausa aleatoria encuentra los problemas, ya sean fáciles o difíciles. Luego, solucionar un problema expone otros, por lo que el proceso puede repetirse, para obtener una aceleración compuesta.
En mi experiencia con numerosos ejemplos, así es como funciona: puedo encontrar un problema (haciendo una pausa aleatoria) y solucionarlo, obteniendo una aceleración de un porcentaje, digamos 30% o 1.3x. Entonces puedo hacerlo de nuevo, encontrar otro problema y solucionarlo, obteniendo otra aceleración, tal vez menos del 30%, tal vez más. Entonces puedo hacerlo de nuevo, varias veces hasta que realmente no pueda encontrar nada más que arreglar. El factor de aceleración final es el producto en ejecución de los factores individuales, y puede ser asombrosamente grande: órdenes de magnitud en algunos casos.
INSERTADO: Solo para ilustrar este último punto. Hay un ejemplo detallado aquí , con la presentación de diapositivas y todos los archivos, que muestra cómo se logró un aumento de velocidad de 730x en una serie de suspensiones de problemas. La primera versión tomó 2700 microsegundos por unidad de trabajo. El problema A se eliminó, reduciendo el tiempo a 1800 y ampliando los porcentajes de los problemas restantes en 1.5x (2700/1800). Entonces B fue eliminado. Este proceso continuó a través de seis iteraciones, resultando en casi 3 órdenes de aceleración de magnitud. Pero la técnica de creación de perfiles tiene que ser realmente eficaz, porque si no se encuentra alguno de esos problemas, es decir, si llega a un punto en el que cree incorrectamente que no se puede hacer nada más, el proceso se detiene.
INSERTADO: Para decirlo de otra manera, aquí hay un gráfico del factor de aceleración total a medida que se eliminan los problemas sucesivos:
Entonces, para Q1, para la evaluación comparativa es suficiente un temporizador simple. Para "perfilar", uso una pausa aleatoria.
P2: le doy suficiente carga de trabajo (o simplemente le doy un bucle) para que funcione lo suficiente como para pausar.
P3: Por supuesto, dele una carga de trabajo realmente grande para que no se pierda los problemas de caché. Esos aparecerán como ejemplos en el código haciendo las recuperaciones de memoria.