2009-03-20 14 views

Respuesta

13
for (i = 10 ; i-- > 0 ;) 
    result_array[i] = byte_array[i] & byte_mask[i]; 
  • Yendo hacia atrás precarga del procesador de caché líneas.
  • Incluir la disminución en la comparación puede guardar algunas instrucciones.

Esto funcionará para todas las matrices y procesadores. Sin embargo, si sabe que sus matrices están alineadas con palabras, un método más rápido es convertir a un tipo más grande y hacer el mismo cálculo. Por ejemplo, digamos n=16 en lugar de n=10. Entonces esto sería mucho más rápido:

uint32_t* input32 = (uint32_t*)byte_array; 
uint32_t* mask32 = (uint32_t*)byte_mask; 
uint32_t* result32 = (uint32_t*)result_array; 
for (i = 4 ; i-- > 0 ;) 
    result32[i] = input32[i] & mask32[i]; 

(Por supuesto que necesitan un tipo adecuado para uint32_t, y si n no es una potencia de 2 que necesita para limpiar el inicio y/o fin para que el 32- bit cosas está alineado.)

Variación: La pregunta específicamente requiere que los resultados se coloquen en una matriz separada, sin embargo, sería casi seguro que sería más rápido modificar la matriz de entrada en contexto.

+0

Espera, ¿el precaptor de caché funciona mejor a la inversa? Pensé que solo se anticipaba yendo hacia adelante. – Crashworks

+2

Preocuparse por la precarga de las líneas de caché del procesador parece una optimización prematura severa. – Trent

+5

@Trent - el * punto * de la pregunta es optimización. También ir hacia atrás no es más lento, por lo que también podría. @Crashworks: recuerde que las líneas de caché están alineadas, por lo general en límites masivos, por lo que normalmente tiene que extraer bytes antes de los que está solicitando. –

5

Si desea hacerlo más rápido, asegúrese de que byte_array tiene una longitud que es múltiplo de 4 (8 en equipos de 64 bits), y luego:

char byte_array[12]; 
char byte_mask[12]; 
/* Checks for proper alignment */ 
assert(((unsigned int)(void *)byte_array) & 3 == 0); 
assert(((unsigned int)(void *)byte_mask) & 3 == 0); 
for (i = 0; i < (10+3)/4; i++) { 
    ((unsigned int *)(byte_array))[i] &= ((unsigned int *)(byte_mask))[i]; 
} 

Esto es mucho más rápido que hacerlo bytes por byte.

(Tenga en cuenta que se trata de una mutación en el lugar;. Si desea mantener el byte_array original también, entonces, obviamente, necesita almacenar los resultados en otra matriz en lugar)

+0

10/4 == 2, por lo que solo procesa 8 caracteres. Además, en algunas arquitecturas que no sean x86, esto puede generar un error de bus debido a accesos de memoria no alineados. – bk1e

+0

bk1e: tienes razón, i <10/4 está mal. El comentario sobre el error del autobús también es correcto. Editaré la respuesta. –

+0

Si no es un múltiplo de 4/8, use el dispositivo de duff :) – Brian

1
\#define CHAR_ARRAY_SIZE (10) 
\#define INT_ARRAY_SIZE  ((CHAR_ARRAY_SIZE/ (sizeof (unsigned int)) + 1) 

typedef union _arr_tag_ { 

    char   byte_array [CHAR_ARRAY_SIZE]; 
    unsigned int int_array [INT_ARRAY_SIZE]; 

} arr_tag; 

Ahora INT_array para el enmascaramiento. Esto podría funcionar tanto para procesadores de 32 bits como de 64 bits.

arr_tag arr_src, arr_result, arr_mask; 

for (int i = 0; i < INT_ARRAY_SIZE; i ++) { 
    arr_result.int_array [i] = arr_src.int_array[i] & arr_mask.int_array [i]; 
} 

probar esto, código también puede tener un aspecto limpio.

+0

Gracias por escribir el código de ejemplo :) – alvatar

Cuestiones relacionadas