2010-03-21 8 views
38

sé que puedo usar gprof a mi código de referencia.Linux C++: ¿cómo perder tiempo de perfil debido a errores de caché?

Sin embargo, tengo este problema - Tengo un puntero inteligente que tiene un nivel extra de indirección (pensar en él como un objeto proxy).

Como resultado, tengo esta capa adicional de que los efectos más o menos todas las funciones, y tornillos con el almacenamiento en caché.

¿Hay una manera de medir el tiempo de mis desechos de CPU debido a fallos de caché?

Gracias!

Respuesta

11

Se puede encontrar una herramienta que tiene acceso a los contadores de rendimiento de la CPU. Probablemente hay un registro en cada núcleo que cuenta L1, L2, etc. Alternativamente, Cachegrind realiza una simulación de ciclo por ciclo.

Sin embargo, no creo que sería perspicaz. Sus objetos proxy son presumiblemente modificados por sus propios métodos. Un generador de perfiles convencional le dirá cuánto tiempo están tomando esos métodos. Ninguna herramienta de perfil le diría cómo mejoraría el rendimiento sin esa fuente de contaminación de la memoria caché. Se trata de reducir el tamaño y la estructura del conjunto de trabajo del programa, lo que no es fácil de extrapolar.

Una rápida búsqueda en Google nos salió boost::intrusive_ptr la que pueden interesarle. No parece apoyar algo así como weak_ptr, pero la conversión de su programa podría ser trivial, y luego se sabría a ciencia cierta el costo de los recuentos árbitro no intrusivos.

+1

De hecho, no es posible utilizar un 'weak_ptr' con un contador intrusiva como un contador autorizado se destruyó con el objeto ... y por lo que el' weak_ptr' no tiene manera de comprobar si el objeto o no es válido sin acceder realmente a él. –

+0

@ Matthieu: Si se sabe que el gráfico de dependencia es un ciclo único, creo que puede usar el enlace de cada objeto (debe haber solo uno) como indicador de validez. Para el propósito de la destrucción de todos modos. Atravesar un gráfico aleatorio requeriría almacenamiento local de subprocesos, pero eso no es imposible. – Potatoswatter

2

Mi consejo sería utilizar PTU (Performance Tuning Utility) de Intel.

Esta utilidad es el descendiente directo de VTune y proporcionan el mejor generador de perfiles de muestreo disponible disponible. Podrá rastrear dónde está pasando la CPU o perder tiempo (con la ayuda de los eventos de hardware disponibles), y esto sin desaceleración de su aplicación o perturbación del perfil. Y, por supuesto, podrá recopilar todos los eventos de errores de línea de caché que esté buscando.

+0

El problema es que la contaminación del caché causará errores en todo el lugar. ¿Qué patrón hay para buscar? – Potatoswatter

+0

Lo primero que debe averiguar es: ¿realmente hay un problema en su aplicación particular? Perfile su aplicación como lo usaría un usuario, luego verifique el informe donde se encuentran sus cuellos de botella. Es posible que encuentre una gran cantidad de L2 Cache Line Miss, pero podría ser causada por otras partes de su aplicación y descubrir otros problemas que no le preocupan. No significa que no tenga un problema con sus punteros inteligentes, pero está escondido detrás de más cuellos de botella. Dígame cómo funciona. Me gustaría ayudar con cualquier problema de rendimiento. –

15

Usted podría intentar cachegrind y es kcachegrind front-end.

+1

Cachegrind funciona muy bien. – caf

5

Depende de qué sistema operativo y la CPU que está utilizando. P.ej. para Mac OS X y x86 o ppc, Shark hará un perfil de caché. Lo mismo para Zoom en Linux.

+0

Desafortunadamente, Shark ya no es compatible con Apple, por lo que no funcionará durante mucho más tiempo a medida que salgan nuevas versiones de OSX/iOS. [Zoom] (http://www.rotateright.com) todavía se desarrolla/actualiza activamente y obtuvo un lanzamiento importante hace unos meses. – federal

+1

@federal: de hecho, es triste que Shark ahora haya caído en un estado de abandono: los instrumentos simplemente no sirven para el tipo de tareas en las que Shark se destacó. Decidí seguir con Snow Leopard y Xcode 3.2.6 durante el tiempo que realmente puedo, tal vez en uno o dos años Xcode 4.x e Instrumentos serán más útiles. –

+0

ACTUALIZACIÓN: Zoom (v3.0) ahora perfiles en Mac OS X y Linux. Shark se ha ido oficialmente. – federal

5

Si se está utilizando un procesador AMD, puede obtener CodeAnalyst, aparentemente libre como la cerveza.

2

Otra herramienta para crear perfiles basados ​​en contadores de rendimiento de la CPU es oprofile. Puede ver sus resultados usando kcachegrind.

2

Aquí es una especie de general answer.

Por ejemplo, si su programa está gastando, digamos, el 50% de su tiempo en caché falla, entonces 50% del tiempo cuando lo pausa el contador del programa estará en los lugares exactos donde está esperando la memoria recuperaciones que están causando el caché falla.

+0

Sin embargo, pasar el 50% del tiempo con el contador del programa en el momento de la jubilación está apuntando a una falla del caché NO es lo mismo que decir que el programa está perdiendo el 50% del tiempo en fallas del caché o que el programa duplicará la velocidad si todos los errores de caché fueron eliminados. En una máquina especulativa, una falla de caché no puede detener la jubilación, pero puede detener otra instrucción que en sí misma detiene la jubilación. –

+0

@KrazyGlew: Estoy seguro de que tienes razón en que los arquitectos del chip, en su loable búsqueda de velocidad, han hecho que sea menos fácil rastrear qué código les está causando dolores de cabeza :) –

+0

@Mike_Dunlavey: mea culpa. Tanto como arquitecto de CPU, como arquitecto de CPU responsable de hacer posible el perfil en fallas de caché (perfiles de EMON). Pero, también soy analista de rendimiento, era analista de rendimiento antes de convertirme en arquitecto de CPU. Si supiera de una forma barata de medir exactamente cuánto tiempo se pierde por falta de memoria caché, lo habría construido. Mientras tanto, lo mejor que puedo hacer es describir lo que se mide. –

3

Continuando en la línea de la respuesta de @ Mike_Dunlavey:

En primer lugar, obtener un perfil basado en el tiempo, el uso de su herramienta favorita: VTune o PTU o OProf.

Luego, obtenga un perfil de falta de caché. La caché L1 falla, o la caché L2 falla, o ...

I.e. el primer perfil asocia un "tiempo pasado" con cada contador de programa. El segundo asocia un valor de "número de fallas de caché" con cada contador de programa.

Nota: A menudo "reduzco" los datos, resumiéndolos por función o (si tengo la tecnología) por bucle. O en contenedores de, digamos, 64 bytes. La comparación de los contadores de programa individuales a menudo no es útil, porque los contadores de rendimiento son confusos: el lugar donde ve que se informa una falta de caché suele ser varias instrucciones diferentes de las que realmente sucedieron.

Bien, ahora grafica estos dos perfiles para compararlos. Aquí hay algunos gráficos que me parecen útiles:

Gráficos "Iceberg": el eje X es PC, el eje Y positivo es el tiempo, el acceso Y negativo es el caché falla. Busca lugares que suban y bajen.

(Las gráficas "Intercaladas" también son útiles: la misma idea, eje X es PC, traza el eje Y de la falta de tiempo y caché, pero con líneas verticales estrechas de diferentes colores, típicamente rojo y azul. tanto las fallas en el tiempo como en el caché tendrán líneas rojas y azules finamente intercaladas, casi púrpuras, lo que se extiende a los errores de caché L2 y L3, todos en el mismo gráfico. Por cierto, es probable que desee "normalizar" los números, ya sea para % edad de tiempo o de caché total de accidentes, o, mejor aún, la edad% del punto de datos máxima de tiempo o de caché falla. Si tienes la escala incorrecta, no verá nada.)

gráficos XY : para cada contenedor de muestreo (PC, o función, o bucle, o ...) trace un punto cuyo La coordenada X es la hora normalizada, y cuya coordenada Y es la caché normalizada pierde. Si obtienes muchos puntos de datos en la esquina superior derecha, un gran% de tiempo de edad Y un gran% de caché de edad falla, eso es una evidencia interesante. O bien, olvide el número de puntos: si la suma de todos los porcentajes en la esquina superior es grande ...

Tenga en cuenta que, por desgracia, a menudo tiene que realizar estos análisis usted mismo. La última vez que revisé, VTune no lo hace por ti. He usado gnuplot y Excel. (Advertencia: Excel muere por encima de 64 mil puntos de datos.)


Más consejos:

Si se colocarán en línea su puntero inteligente, es posible obtener la cuenta de todo el lugar. En un mundo ideal, usted podría rastrear sus PC a la línea original del código fuente. En este caso, es posible que desee diferir un poco la reducción: observe todas las PC individuales; volver a asignarlos a líneas de código fuente; y luego mapea esos en la función original. Muchos compiladores, p. GCC, tiene opciones de tabla de símbolos que le permiten hacer esto.

Por cierto, sospecho que su problema NO es con el puntero inteligente que causa la caché. A menos que esté haciendo smart_ptr < int> en todas partes. Si está haciendo smart_ptr < Obj>, y sizeof (Obj) + es mayor que decir, 4 * sizeof (Obj *) (y si el smart_ptr en sí no es enorme), entonces no es mucho.

Es más probable que el puntero inteligente sea el nivel extra de indirección que está causando el problema.

Casualmente, estaba hablando con un tipo en el almuerzo que tenía un puntero inteligente de referencia contado que estaba usando un mango, es decir.un nivel de indirección, algo así como

template<typename T> class refcntptr { 
    refcnt_handle<T> handle; 
public: 
    refcntptr(T*obj) { 
     this->handle = new refcnt_handle<T>(); 
     this->handle->ptr = obj; 
     this->handle->count = 1; 
    } 
}; 
template<typename T> class refcnt_handle { 
    T* ptr; 
    int count; 
    friend refcnt_ptr<T>; 
}; 

(no me codificar de esta manera, pero sirve para la exposición.)

La indirecto doble this-> manejar-> ptr puede ser una gran problema de rendimiento O incluso un triple indirecto, this-> handle-> ptr-> campo. Por lo menos, en una máquina con 5 cachés L1 de ciclo, cada uno de estos campos-> handle-> ptr-> tomaría 10 ciclos. Y será mucho más difícil de superponer que una persecución de un solo puntero. Pero, lo que es peor, si cada uno de ellos es un caché L1, incluso si hubiera tan solo 20 ciclos para el L2 ... bueno, es mucho más difícil ocultar 2 * 20 = 40 ciclos de latencia de falta de memoria caché, que una sola falla L1.

En general, es un buen consejo para evitar los niveles de indirección en los punteros inteligentes. En lugar de señalar un identificador, al que apuntan todos los punteros inteligentes, que apunta hacia el objeto, puede hacer que el puntero inteligente sea más grande al hacer que apunte tanto al objeto como al controlador. (Que luego ya no es lo que comúnmente se llama un identificador, sino que se parece más a un objeto de información.)

E.g.

template<typename T> class refcntptr { 
    refcnt_info<T> info; 
    T* ptr; 
public: 
    refcntptr(T*obj) { 
     this->ptr = obj; 
     this->info = new refcnt_handle<T>(); 
     this->info->count = 1; 
    } 
}; 
template<typename T> class refcnt_info { 
    T* ptr; // perhaps not necessary, but useful. 
    int count; 
    friend refcnt_ptr<T>; 
}; 

Anyway - a time profile is your best friend.


Oh, sí - hardware de Intel EMON también le puede decir cuántos ciclos esperaba en un PC. Eso puede distinguir una gran cantidad de fallas L1 de un pequeño número de fallas L2.

+0

+ Mientras estemos en el tema, esto es lo que deseo que haga la CPU: cuando ingresa a un caché-espera (L1 o L2), registra la PC que lo activó. Luego, si se ha solicitado una interrupción, debería permitir que se responda, ya sea durante o justo después del caché, espere, y permita que esa información sea consultada. (Está bien si hace que la espera se reinicie). Entonces, si el software quiere obtener muchos de ellos y resumirlos, puede hacerlo. Personalmente recomiendo la parte de suma por región, porque todo lo que hace es borrar las ubicaciones precisas que explican el problema. –

+0

Desafortunadamente, en muchas máquinas, la PC (Ip en x86 land) de la instrucción que causó la falta del caché no está disponible. Está disponible la PC (IP) de la instrucción que está estancando el retiro esperando a que la falla del caché vuelva, pero no la PC que está esperando. Ni siquiera tenemos, fácil de manejar, qué espera la instrucción de bloqueo: todo lo que sabemos es que está esperando en un registro de entrada. // Ahora, algunos procesadores más recientes enrutan la PC hasta las unidades de memoria, para hacer cosas como la predicción STLF. Si todavía estuviera en Intel, ya habría hecho esto. –

+0

AMD IBS (Instruction ased Sampling) es relevante aquí. –

8

Linux es compatible con perf desde 2.6.31 en adelante. Esto le permite hacer lo siguiente:

  • compilar el código con -g tener información de depuración incluido
  • ejecutar el código, por ejemplo, el uso de la caché de último nivel se pierde contadores: perf record -e LLC-loads,LLC-load-misses yourExecutable
  • ejecución perf report
    • después de reconocer el mensaje inicial, seleccionar la línea LLC-load-misses,
    • continuación, por ejemplo, la primera función y
    • luego annotate. Debería ver las líneas (en el código de ensamblado, rodeado por el código fuente original) y un número que indica qué fracción del último nivel de caché falla para las líneas en las que se produjeron errores de caché.
+0

¿Dónde se puede encontrar una lista de eventos tales como ¿esta? – Richard

+1

'perf list' imprime la lista de eventos disponibles. La lista de eventos depende de la máquina en la que se ejecuta. En una máquina virtual que inicié sesión, recibo 10 eventos de software y dos eventos de 'Descriptor de eventos de hardware sin procesar'.En una máquina física que acabo de iniciar sesión (Xeon E5), obtengo 26 tipos de 'Eventos de caché de hardware', 10 'Tipos de eventos de hardware', 28 'Tipos de eventos de PMU de kernel', 10 'Tipos de eventos de software', dos 'Eventos de hardware sin procesar descriptor 'eventos y un' Tipo de punto de corte '. –

Cuestiones relacionadas