2012-01-25 6 views
8

Tengo el siguiente fragmento de código C++ (la parte C++ es la clase de generador de perfiles que se omite aquí), compilada con VS2010 (máquina Intel de 64 bits). El código simplemente multiplica una serie de flotadores (arr2) con un escalar, y pone el resultado en otra matriz (arr1):Cómo depende el rendimiento de los valores de datos subyacentes

int M = 150, N = 150; 
int niter = 20000; // do many iterations to have a significant run-time 
float *arr1 = (float *)calloc (M*N, sizeof(float)); 
float *arr2 = (float *)calloc (M*N, sizeof(float)); 

// Read data from file into arr2 

float scale = float(6.6e-14); 

// START_PROFILING 
for (int iter = 0; iter < niter; ++iter) { 
    for (int n = 0; n < M*N; ++n) {   
     arr1[n] += scale * arr2[n]; 
    } 
} 
// END_PROFILING 

free(arr1); 
free(arr2); 

La lectura-de-archivo de pieza y perfilado (es decir, la medición en tiempo de ejecución) es omitido aquí por simplicidad. arr2 Cuando arr2 se inicializa en números aleatorios en el rango [0 1], el código se ejecuta aproximadamente 10 veces más rápido que en un caso donde arr2 se inicializa en una matriz dispersa en la que aproximadamente 2/3 de los valores son ceros . He jugado con las opciones del compilador /fp y /O, que cambiaron un poco el tiempo de ejecución, pero se mantuvo aproximadamente la proporción de 1:10.

  • ¿Cómo es que el rendimiento depende de los valores reales? ¿Qué hace la CPU de manera diferente que hace que la ejecución de datos dispersos sea 10 veces más lenta?
  • ¿Hay alguna manera de hacer que la "información lenta" corra más rápido, o cualquier optimización (por ejemplo, vectorizando el cálculo) tendrá el mismo efecto en ambas matrices (es decir, los "datos lentos" seguirán siendo más lentos que los "rápidos" datos")?

EDITAR

de código completo está aquí: https://gist.github.com/1676742, la línea de comandos para la compilación está en un comentario en test.cpp.

Los archivos de datos son aquí:

+2

¿Podrías proporcionar versiones completas y compilables de las dos pruebas para que podamos experimentar con ellas? – NPE

+0

¿Podría ser que cuando pasa '0' a su flotador en su matriz dispersa, la conversión de' int' a 'float' introduce cierta sobrecarga? –

+0

¿Solo actualizas los elementos que no son 0? Entonces, ¿puede ser que los ceros no estén en la memoria caché? – duedl0r

Respuesta

7

Probablemente esto se debe a que sus datos "rápida" consta sólo de números de punto flotante normales, pero su "lento" de datos contiene muchos números desnormalizados

En cuanto a su segunda pregunta, se puede tratar de mejorar la velocidad con esto (y tratar a todos los números no normalizados como ceros exactas):

#include <xmmintrin.h> 
_mm_setcsr(_mm_getcsr() | 0x8040); 
+0

Sí, de hecho, si la 'escala' es alta, los datos lentos se vuelven mucho más rápidos .. – duedl0r

2

puedo pensar en dos razones para esto.

En primer lugar, el predictor de bifurcación puede estar tomando decisiones incorrectas. Esta es una causa potencial de las brechas de rendimiento causadas por cambios de datos sin cambios de código. Sin embargo, en este caso, parece muy poco probable.

La segunda razón posible es que sus datos "principalmente ceros" en realidad no consisten en ceros, sino casi de cero, o que está manteniendo arr1 en el rango de casi cero. Ver this Wikipedia link.

+0

No piense - ejecute pruebas. –

1

No hay nada extraño que los datos de I.bin tarden más en procesarse: tiene muchos números como '1.401e-045 # DEN' o '2.214e-043 # DEN', donde #DEN significa el número no puede ser normalizado a la precisión de flotación estándar. Dado que va a multiplicarlo por 6.6e-14, definitivamente tendrá excepciones de subdesbordamiento, lo que ralentiza significativamente los cálculos.

Cuestiones relacionadas