Pregunta

Algunas de las plataformas en las que desarrollo, no tienen herramientas de creación de perfiles. Estoy buscando sugerencias / técnicas que haya utilizado personalmente para ayudarlo a identificar puntos de acceso, sin el uso de un generador de perfiles.

El idioma de destino es C ++.

Estoy interesado en lo que ha usado personalmente.

¿Fue útil?

Solución

He encontrado lo siguiente bastante útil:

#ifdef PROFILING
# define PROFILE_CALL(x) do{ \
    const DWORD t1 = timeGetTime(); \
    x; \
    const DWORD t2 = timeGetTime(); \
    std::cout << "Call to '" << #x << "' took " << (t2 - t1) << " ms.\n"; \
  }while(false)
#else
# define PROFILE_CALL(x) x
#endif

Que se puede usar en la función de llamada como tal:

PROFILE_CALL(renderSlow(world));
int r = 0;
PROFILE_CALL(r = readPacketSize());

Otros consejos

No es broma: además de descartar tiempos para std :: cout y otros enfoques orientados a texto / datos, también uso la función Beep (). Hay algo acerca de escuchar la brecha de silencio entre dos '' Beep '' puntos de control que causan un tipo diferente de impresión.

Es como la diferencia entre mirar una partitura escrita y ESCUCHAR la música. Es como la diferencia entre leer rgb (255,0,0) y ver rojo de bomberos.

Entonces, en este momento, tengo una aplicación cliente / servidor y con pitidos de diferentes frecuencias, marcando donde el cliente envía el mensaje, donde el servidor comienza su respuesta, termina su respuesta, donde la respuesta ingresa primero al cliente, etc. Naturalmente, puedo tener una idea de dónde se pasa el tiempo.

En esencia, si una herramienta de creación de perfiles no está disponible, emula lo que habría hecho un generador de perfiles. Inserta contadores en funciones que considera interesantes y cuenta cuántas veces, y potencialmente con qué tamaño / tipo de argumentos se llaman.

Si tiene acceso a cualquier temporizador en su plataforma, puede iniciarlo / detenerlo al comienzo / final de dichas funciones para obtener también información sobre el tiempo de ejecución, si el código no lo aclara. Esto le dará el mayor rendimiento de su dinero en código complejo, ya que generalmente habrá demasiadas funciones para instrumentarlos a todos. En cambio, puede obtener el tiempo dedicado a ciertas secciones de código dedicando un temporizador a cada una.

Estas dos técnicas en tándem pueden formar un enfoque iterativo, donde encontrará la sección amplia de código que consume la mayoría de sus ciclos utilizando temporizadores, luego instrumenta las funciones individuales con una granularidad más fina para afinar el problema.

Si es algo de duración suficientemente larga (por ejemplo, un minuto o más), ejecuto el software en un depurador y luego lo rompo algunas veces y veo dónde se rompe el depurador, esto da una idea muy aproximada de lo que está funcionando el software a (por ejemplo, si rompes 10 veces y están todos en el mismo lugar, ¡esto te dice algo interesante!). Muy tosco y listo, pero no requiere herramientas, instrumentación, etc.

No estoy seguro de qué plataformas tenía en mente, pero en los microcontroladores integrados, a veces es útil girar una línea de salida digital de repuesto y medir el ancho del pulso usando un osciloscopio, contador / temporizador o analizador lógico.

Usaría la regla 80/20 y pondría temporizadores alrededor de puntos de acceso o rutas de llamadas interesantes. Debe tener una idea general de dónde estarán los cuellos de botella (o al menos la mayoría de las rutas de ejecución) y usar el temporizador de alta resolución dependiente de la plataforma apropiado (QueryPerformanceCounters, gettimeofday, etc.).

Por lo general, no me molesto con nada en el inicio o el apagado (a menos que sea necesario) y tendré "puntos de estrangulamiento" bien definidos, por lo general pasar mensajes o algún tipo de cálculo algorítmico. En general, he descubierto que los sumideros / srcs de mensajes (sumideros más), las colas, los mutexes y los simples mensajes (algoritmos, bucles) generalmente representan la mayor parte de la latencia en una ruta de ejecución.

¿Estás usando Visual Studio?

Puede usar los modificadores / Gh y / GH. Aquí hay un ejemplo de inspección de pila

Estas banderas le permiten, archivo por archivo, registrar funciones no decoradas que se llaman cada vez que se ingresa y / o deja un método en tiempo de ejecución.

Luego puede registrar toda la información de creación de perfiles, no solo la información de temporización. Volcados de pila, dirección de llamada, dirección de retorno, etc. Lo cual es importante, porque es posible que desee saber que 'la función X usó el tiempo Y bajo la función Z' y no solo el tiempo total empleado en la función X.

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