2011-12-09 33 views
5

Estoy tratando de capturar la pila de llamadas lo más rápido posible. En este momento esto es lo que tengo:Capture la pila de llamadas rápidamente

void* addrs[10] = {}; 
DWORD hash; 
RtlCaptureStackBackTrace(0, 10, addrs, &hash); 

for(size_t i = 0; i <10; ++i) 
{ 
    std::cout << addrs[i] << '\n'; 
} 

Esto es para uso en un sistema de seguimiento de la memoria, por lo que está perfectamente bien que termino con una matriz de direcciones si pueden más tarde (en algún evento guiado por el usuario) se convertirá en algo legible por humanos.

  • ¿Cómo puedo convertir addrs en algo legible para las personas? (ver la edición más abajo)
  • ¿Hay algo más rápido que RtlCaptureStackBackTrace?
  • ¿Hay una forma de plataforma cruzada para capturar la pila de llamadas?

Editar:

di vuelta a la direcciones en información legible por humanos mediante el uso de SymFromAddr y SymGetLineFromAddr64. Sin embargo, mi versión de new que usa CaptureStackBackTrace tarda ~ 30x más que el original y casi todo ese tiempo se debe al seguimiento de la pila. ¡Todavía estoy buscando una solución más rápida!

Respuesta

2

¿Hay una forma de plataforma cruzada para capturar la pila de llamadas?

La respuesta rápida es que, lamentablemente, no es posible. Diferentes compiladores y plataformas organizarán la pila de forma diferente, y sin la "ayuda" del compilador, no podrás rastrear con precisión la pila ... lo máximo que podrías hacer en las plataformas que usan una pila- el puntero base del cuadro sería subir la pila usando los valores en EBP o RBP, e incluso eso depende de si está ejecutando un ejecutable x86_64 de 32 bits o un ejecutable x86_64. Además, las reglas que rigen la aplicación UNIX-Binary-Interface (ABI) y Windows ABI son completamente diferentes. Así que, en general, usted va a terminar teniendo que soportar al menos cuatro posibilidades diferentes:

  1. Unix de 32 bits ABI
  2. Unix de 64 bits ABI
  3. Windows de 32 bits ABI
  4. Windows 64-bit ABI

Tenga en cuenta que el ABI de 64 bits de UNIX permite a los compiladores elegir si van a admitir o no un puntero base de un stack-frame ... entonces el uso de una base- el puntero no está garantizado; un compilador simplemente puede elegir hacer referencia a todas las variables de la pila contra el puntero de la pila sin usar un puntero base separado. Eso todavía se consideraría compatible con el ABI de 64 bits de UNIX.

Como puede ver, con todas estas posibles variaciones, va a ser muy difícil hacer un apilador de pila fiable entre plataformas. Su mejor apuesta es utilizar las herramientas disponibles para la plataforma a la que se dirige. Si necesita admitir múltiples plataformas, lamentablemente habrá algún nivel de duplicación de código a medida que utilice herramientas específicas de la plataforma para ayudarlo a realizar el seguimiento de la pila de manera confiable.

0

No hay una forma de plataforma cruzada, pero hay bibliotecas multiplataforma que funcionan. It's a common requirement for garbage collectors.

Desafortunadamente, no sé lo suficiente sobre estas bibliotecas para recomendar una. MMgc tiene algo incrustado (explicado en el enlace, arriba). Estoy seguro de que el recolector de basura de Hans Boehm tiene otro.

Estas bibliotecas, en general, se basarán en llamadas específicas de la plataforma, como RtlCaptureStackBacktrace en Windows. Me sorprendería si alguna de esas bibliotecas fuera más rápida que las llamadas específicas de la plataforma; pero también me sorprendería si alguna de esas bibliotecas fuera significativamente más lenta. La única pregunta, para mí, sería si prefiere llamar directamente a la llamada API de Windows o enrutar esa llamada a través de otra biblioteca.

Cuestiones relacionadas