2010-01-02 20 views
16

He escrito varias funciones de copia en busca de una buena estrategia de memoria en PowerPC. El uso de los registros Altivec o fp con sugerencias de caché (dcb *) duplica el rendimiento en un bucle de copia de bytes simple para datos grandes. Inicialmente satisfecho con eso, lancé una memcpy regular para ver cómo se comparaba ... ¡10 veces más rápido que lo mejor! No tengo intención de volver a escribir memcpy, pero espero aprender de él y acelerar varios filtros de imagen simples que pasan la mayor parte del tiempo moviendo píxeles hacia y desde la memoria.¿Qué hace que ApplePC memcpy sea tan rápido?

El análisis de tiburones revela que su bucle interno usa dcbt para captar previamente, con 4 lecturas vectoriales, luego 4 escrituras vectoriales. Después de ajustar mi mejor función para transportar también 64 bytes por iteración, la ventaja de rendimiento de memcpy sigue siendo embarazosa. Estoy usando dcbz para liberar ancho de banda, Apple no usa nada, pero ambos códigos tienden a vacilar en las tiendas.

 
prefetch 
    dcbt future 
    dcbt distant future 
load stuff 
    lvx image 
    lvx image + 16 
    lvx image + 32 
    lvx image + 48 
    image += 64 
prepare to store 
    dcbz filtered 
    dcbz filtered + 32 
store stuff 
    stvxl filtered 
    stvxl filtered + 16 
    stvxl filtered + 32 
    stvxl filtered + 48 
    filtered += 64 
repeat 

¿Alguien tiene algunas ideas sobre qué código muy similar tiene una diferencia de rendimiento tan dramático? ¡Me encantaría marinar los filtros de imagen reales en cualquier salsa secreta que memcpy esté usando!

Información adicional: Todos los datos están alineados con vectores. Estoy haciendo copias filtradas de la imagen, no reemplazando el original. El código se ejecuta en PowerPC G4, G5 y Cell PPU. La versión de Cell SPU ya es increíblemente rápida.

Respuesta

0

Tal vez sea por el almacenamiento en caché de la CPU. Intente ejecutar CacheGrind:

Cachegrind es un generador de perfiles de caché. Es realiza una simulación detallada de las cachés I1, D1 y L2 de en su CPU y , por lo que puede identificar con exactitud las fuentes de fallas de caché en su código. Es identifica el número de omisiones de memoria caché, referencias de memoria e instrucciones ejecutadas para cada línea de código fuente, con resúmenes de programa completo por función, por módulo y . Es útil con programas escritos en cualquier idioma. Cachegrind ejecuta programas sobre 20--100x más lento que lo normal.

+0

CacheGrind absolutamente no funciona en PPC/Darwin. –

+0

@Nick, ¿estás seguro? http://en.wikipedia.org/wiki/Valgrind "A partir de la versión 3.4.0, Valgrind admite Linux en x86, x86-64 y PowerPC" –

+1

@Andreas: Funciona en * linux *, pero definitivamente no es Darwin. El único soportado (y apenas) Darwin es x86. –

2

No sé exactamente lo que estás haciendo, ya que no puedo ver tu código, pero la salsa secreta de Apple es here.

+0

Pude ver el desmontaje en Shark, así que sé lo que están haciendo en el ciclo de copiado. Me pregunto qué hay antes de ese bucle que parece ponerlo en marcha. Ese código debería ayudar, ¡así que gracias por el enlace! –

+0

@Invisible Cow: Sí, esperaba que eso proporcionara un poco más de contexto (y comentarios) que podría ser perspicaz. –

+0

Agregó un código para la pregunta, para el G4 y sus cachelines de 32 bytes. –

7

El análisis de tiburones revela que su bucle interno usa dcbt para captar previamente, con 4 lecturas vectoriales, luego 4 escrituras vectoriales. Después de ajustar lo mejor posible la función de transportar también 64 bytes por iteración

me puede decir lo obvio, pero ya que usted no menciona lo siguiente en absoluto en su pregunta, puede valer la pena señalarlo:

Apostaría que la elección de 4 vectores de Apple seguidos por 4 escrituras vectoriales tiene tanto que ver con el G5's pipeline and its management of out-of-order instruction execution in "dispatch groups" como con un mágico tamaño de línea perfecto de 64 bytes. ¿Notaste que la línea se salta en los archivos enlazados de Nick Bastin? Esto significa que el desarrollador pensó en cómo el flujo de instrucciones sería consumido por el G5. Si desea reproducir el mismo rendimiento, no es suficiente leer datos de 64 bytes a la vez, debe asegurarse de que sus grupos de instrucciones estén bien llenos (básicamente, recuerdo que las instrucciones se pueden agrupar hasta en cinco independientes, con el los primeros cuatro son instrucciones sin salto y el quinto solo se permite saltar. Los detalles son más complicados).

EDIT: También puede estar interesado por el siguiente párrafo en la misma página:

La instrucción DCBZ todavía ceros alineados 32 segmentos de bytes de memoria de acuerdo con el G4 y G3. Sin embargo, dado que no es una línea de caché completa en un G5, no tendrá los beneficios de rendimiento que probablemente esperaba. Hay una instrucción dcbzl recientemente introducida para el G5 que cierra una cacheline completa de 128 bytes.

+0

No había pensado en grupos de despacho Toda la "sopa de instrucciones" del G5 siempre me ha dejado perplejo, y prefiero trabajar con Cell, simplemente porque su modelo de ejecución cabe en mi cabeza. En cuanto a la edición, el código ya difiere para las caché más grandes. –

0

Todavía no es una respuesta, pero ¿has verificado que memcpy está realmente moviendo los datos? Tal vez fue solo un remapeado de copiar y escribir. Todavía vería el bucle memcpy interno en Shark como parte de la primera y la última página se copian realmente.

0

Como se menciona en otra respuesta, "dcbz", tal como lo define Apple en el G5, solo opera en 32 bytes, por lo que perderá rendimiento con esta instrucción en un G5 que tiene cachelines de 128 bytes. Debe usar "dcbzl" para evitar que la caché de destino sea extraída de la memoria (y efectivamente reduciendo a la mitad el ancho de banda de la memoria de lectura útil).

+1

Y no olvide: solo debe usar 1 "dcbzl" por línea de 128 bytes. Parece que su código está haciendo un "dcbz" cada 32 bytes. – JanePhanie

Cuestiones relacionadas