¿Cómo acelerar estas funciones?
Tengo dos funciones con las que estoy trabajando y estoy intentando hacerlas funcionar hasta 4 veces más rápido.
void get_each_fifth(const matrix_t *matrix, long results[RESULTS_LEN]) {
for (int i = 0; i < matrix->rows; i++) {
for (int j = 0; j < matrix->cols; j++) {
int q = j % RESULTS_LEN;
results[q] += MGET(matrix, i, j);
}
}
}
La función anterior necesitará ser optimizada para que sea 4 veces más rápida. En esta función, estoy encontrando la suma de enteros en función de su ubicación en la matriz. Los elementos en la columna 0, 5, 10, etc., van al primer elemento del array de resultados. Los elementos en la columna 1, 6, 11, etc. van a la segunda columna del array. Este patrón continúa para las columnas restantes. En resumen, los números en la columna i
van al elemento i%5
del array de resultados.
long get_each(const matrix_t *matrix) {
long sum = 0;
for (int i = 0; i < matrix->rows; i++) {
for (int j = 0; j < matrix->cols; j++) {
sum += MGET(matrix, i, j);
}
}
return sum;
}
Esta necesitará ser 2 veces más rápida; es decir, suma todos los elementos de la matriz y devuelve el resultado.
MGET
y MSET
están definidos como:
#define MGET(mat, i, j) ((mat)->data[((i)*((mat)->cols)) + (j)])
#define MSET(mat, i, j, x) ((mat)->data[((i)*((mat)->cols)) + (j)] = (x))
La estructura matrix_t
está definida como:
typedef struct {
long rows;
long cols;
int *data;
} matrix_t;
y se asigna con esta función:
void set_up_matrix(matrix_t *matrix, int rows, int cols) {
if (matrix == NULL) {
return;
}
matrix->rows = rows;
matrix->cols = cols;
matrix->data = malloc(sizeof(int) * rows * cols);
srand(2021);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
MSET(matrix, i, j, rand() % 100);
}
}
}
y RESULTS_LEN
está definido como:
#define RESULTS_LEN 5
¡Cualquier ayuda sería apreciada!
davy.ai
Para optimizar la primera función
get_each_fifth
, podemos aprovechar el hecho de que los elementos de la matriz se están sumando en función de su ubicación. En lugar de recorrer todos los elementos de la matriz y utilizar el módulo para determinar qué elemento del array resultados actualizar, podemos recorrer directamente los elementos que corresponden a cada elemento del array resultados. Por ejemplo, para actualizar el primer elemento del array resultados, solo necesitamos recorrer los elementos en la columna 0, 5, 10, etc.Esta nueva versión de la función recorre las columnas de la matriz que corresponden a cada elemento del array resultados. Dentro de cada bucle de columna, recorremos las filas y agregamos el elemento al elemento de resultado correspondiente.
Para la segunda función
get_each
, la única optimización que podemos hacer es utilizar instrucciones SIMD para sumar varios elementos de una vez. Podemos utilizar las funciones_mm256_loadu_si256
y_mm256_add_epi32
de la bibliotecaimmintrin.h
para sumar 8 enteros a la vez.Esta versión de la función recorre los elementos de la matriz, cargando 8 enteros a la vez en un vector. Luego utilizamos
_mm256_add_epi32
para agregar el vector a un vector de suma en ejecución. Después del bucle, almacenamos el vector de suma en un array de 8 enteros y los sumamos para obtener el resultado final.Tenga en cuenta que para utilizar estas optimizaciones, debemos asegurarnos de compilar con las banderas adecuadas, como
-march=native
para la segunda optimización.