Отладка с вложенным циклом for с матричным алгоритмом и константами.

#c #matrix #sse #nested-loops #matrix-multiplication

#c #матрица #sse #вложенные циклы #умножение матрицы

Вопрос:

Этот набор вложенных циклов for корректно работает для значений M = 64 и N = 64, но не работает, когда я делаю M = 128 и N = 64. У меня есть другая программа, которая проверяет правильность значений для умножения матрицы. Интуитивно кажется, что это все еще должно работать, но дает мне неправильный ответ.

 for(int m=64;m<=M;m =64){
for(int n=64;n<=N;n =64){
    for(int i = m-64; i < m; i =16){

        float *A_column_start, *C_column_start;
        __m128 c_1, c_2, c_3, c_4, a_1, a_2, a_3, a_4, mul_1, 
               mul_2, mul_3, mul_4, b_1;
        int j, k;

        for(j = m-64; j < m; j  ){

            //Load 16 contiguous column aligned elements from matrix C in
            //c_1-c_4 registers

            C_column_start = C i j*M;

            c_1 = _mm_loadu_ps(C_column_start);
            c_2 = _mm_loadu_ps(C_column_start 4);
            c_3 = _mm_loadu_ps(C_column_start 8);
            c_4 = _mm_loadu_ps(C_column_start 12);

            for (k=n-64; k < n; k =2){

                //Load 16 contiguous column aligned elements from matrix A to
                //the a_1-a_4 registers

                A_column_start = A k*M;

                a_1 = _mm_loadu_ps(A_column_start i);
                a_2 = _mm_loadu_ps(A_column_start i 4);
                a_3 = _mm_loadu_ps(A_column_start i 8);
                a_4 = _mm_loadu_ps(A_column_start i 12);

                //Load a value to resgister b_1 to act as a "B" or ("A^T") 
                //element to multiply against the A matrix

                b_1 = _mm_load1_ps(A_column_start j);

                mul_1 = _mm_mul_ps(a_1, b_1);
                mul_2 = _mm_mul_ps(a_2, b_1);
                mul_3 = _mm_mul_ps(a_3, b_1);
                mul_4 = _mm_mul_ps(a_4, b_1);

                //Add together all values of the multiplied A and "B"
                //(or "A^T") matrix elements

                c_4 = _mm_add_ps(c_4, mul_4);
                c_3 = _mm_add_ps(c_3, mul_3);
                c_2 = _mm_add_ps(c_2, mul_2);
                c_1 = _mm_add_ps(c_1, mul_1);

                //Move over one column in A, and load the next 16 contiguous 
                //column aligned elements from matrix A to the a_1-a_4 registers

                A_column_start =M;

                a_1 = _mm_loadu_ps(A_column_start i);
                a_2 = _mm_loadu_ps(A_column_start i 4);
                a_3 = _mm_loadu_ps(A_column_start i 8);
                a_4 = _mm_loadu_ps(A_column_start i 12);

                //Load a value to resgister b_1 to act as a "B" or "A^T"
                //element to multiply against the A matrix

                b_1 = _mm_load1_ps(A_column_start j);

                mul_1 = _mm_mul_ps(a_1, b_1);
                mul_2 = _mm_mul_ps(a_2, b_1);
                mul_3 = _mm_mul_ps(a_3, b_1);
                mul_4 = _mm_mul_ps(a_4, b_1);

                //Add together all values of the multiplied A and "B" or
                //("A^T") matrix elements

                c_4 = _mm_add_ps(c_4, mul_4);
                c_3 = _mm_add_ps(c_3, mul_3);
                c_2 = _mm_add_ps(c_2, mul_2);
                c_1 = _mm_add_ps(c_1, mul_1);

            }
            //Store the added up C values back to memory

            _mm_storeu_ps(C_column_start, c_1);
            _mm_storeu_ps(C_column_start 4, c_2);
            _mm_storeu_ps(C_column_start 8, c_3);
            _mm_storeu_ps(C_column_start 12, c_4);

        }

    }
    }
}}
  

Комментарии:

1. Мне нравится, когда ppl утверждают, что решения просты, когда они не в состоянии найти ответ самостоятельно 😉

2. Вы пробовали пошагово просматривать код в отладчике, чтобы посмотреть, какие циклы выполняются, когда? Ваши внешние два цикла будут выполняться только один раз каждый, если M и N равны 64. Я бы также подумал о #define изменении 64 и уменьшении его до некоторого гораздо меньшего значения, чтобы создать минимальный тестовый пример, который поможет вам понять, что происходит.

Ответ №1:

Я предполагаю, что вы используете M в коде

 C_column_start = C i j*M;
  

вместо этого необходимо использовать m . Возможно, также в других строках, где вы используете M .
Однако я не совсем понимаю ваш код, поскольку вы не объяснили, для чего предназначен код, а я не программист-математик.

Ответ №2:

Это работает корректно для M = 64 и N = 64, потому что в этих случаях вы выполняете только одну итерацию в соответствующем цикле (два самых внешних). Когда у вас будет M = 128, вы теперь выполняете два шага во внешнем цикле, и в этом случае строка

 C_column_start = C i j*M;
  

и строка

 A_column_start = A k*M;
  

Для внутреннего цикла будут получены те же результаты, поэтому, по сути, для двух шагов, которые вы выполняете во внешнем цикле (m = 64 128), вы просто удваиваете результат одного шага с m = 128. Исправление так же просто, как изменение M на m, чтобы вы использовали переменную итерации.

Также вам следует рассмотреть возможность выравнивания ваших данных в A и C, чтобы вы могли выполнять загрузки, выровненные по SSE. Это приведет к гораздо более быстрому кодированию.