LINUX.ORG.RU
решено ФорумTalks

Давайте померяемся (benchmark для умножения матриц)


0

0

Написал когда-то давно benchmark для умножения матриц.
Интересно, как результаты зависят от машины.
Попробуйте на самых разных машинах, скажите, что выдала программа, версию компилятора, и скажите на какой машине это вычислено.

%--- This software is Public Domain, author: pacify
%--- solid-linux.org.ru.c
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <stdlib.h>

#define M 500
#define N 500
#define FXX double

#define DEFM1(A) FXX A[M*N]
#define ADDR1(A,i,j) A[i*N+j]
#define KILL1(A,B,C)
#define INIT1(A,B,C) \
    for (i=M-1;i>0;i--) for (j=N-1;j>0;j--) ADDR1(C,i,j) = 0; \
    for (i=M-1;i>0;i--) for (j=N-1;j>0;j--) ADDR1(A,i,j) = ADDR1(B,i,j) = (i*j)/(FXX)(M*N);
#define CALC1 for (i=M-1;i>0;i--) for (j=N-1;j>0;j--) { TMP1=0; for (k=N-1;k>0;k--) TMP1 += ADDR1(A1,i,k) * ADDR1(B1,k,j); ADDR1(C1,i,j) = TMP1;}
#define SUMM1 SUM1=0; for (i=M-1;i>0;i--) for (j=N-1;j>0;j--) SUM1+=ADDR1(C1,i,j);

#define DEFM2(A) FXX A[M][N]
#define ADDR2(A,i,j) A[i][j]
#define KILL2(A,B,C)
#define INIT2(A,B,C) \
    for (i=M-1;i>0;i--) for (j=N-1;j>0;j--) ADDR2(C,i,j) = 0; \
    for (i=M-1;i>0;i--) for (j=N-1;j>0;j--) ADDR2(A,i,j) = ADDR2(B,i,j) = (i*j)/(FXX)(M*N);
#define CALC2 for (i=M-1;i>0;i--) for (j=N-1;j>0;j--) { TMP2=0; for (k=N-1;k>0;k--) TMP2 += ADDR2(A2,i,k) * ADDR2(B2,k,j); ADDR2(C2,i,j) = TMP2;}
#define SUMM2 SUM2=0; for (i=M-1;i>0;i--) for (j=N-1;j>0;j--) SUM2+=ADDR2(C2,i,j);

int main (int argc, char **argv) {
    DEFM1(A1); DEFM1(B1); DEFM1(C1);
    DEFM2(A2); DEFM2(B2); DEFM2(C2);
    unsigned int i;
    register unsigned int j,k;
    register FXX TMP1,TMP2;
    FXX SUM1,SUM2;
    clock_t T1,T2,T3,T4;
    double delta,d1,d2,d3,d4;
    INIT1(A1,B1,C1) T1=clock(); CALC1 T2=clock(); SUMM1
    INIT2(A2,B2,C2) T3=clock(); CALC2 T4=clock(); SUMM2
    KILL1(A1,B1,C1) KILL2(A2,B2,C2)
    delta=((double)((T4-T3)-(T2-T1)))/CLOCKS_PER_SEC;
    d1=((double)((T2-T1)))/CLOCKS_PER_SEC;
    d2=((double)((T4-T3)))/CLOCKS_PER_SEC;
    printf("%7d%7d%7d",M,N,(M*N));
    printf("%12.5lf%12.5lf%12.5lf",d1,d2,delta);
    printf("%15.7E%15.7E",SUM1/(M*N),SUM2/(M*N));
    printf("\n");
    return 0;
}

%--- Makefile-linux.org.ru

NAME = solid-linux.org.ru
OPTS = -O7 -fforce-mem -ffast-math -fstrength-reduce
GCC  = gcc

result : ${NAME}.c
        ${GCC} -S ${OPTS} -o ${NAME}.S ${NAME}.c
        ${GCC} ${OPTS} -o ${NAME} ${NAME}.c
        strip --strip-all ${NAME}

%--- что набрать в командной строке

% make -f Makefile-linux.org.ru
% ulimit -s 65536
% ./solid-linux.org.ru

%--- END
★★★★★
Ответ на: комментарий от anonymous

    500    500 250000     0.65000     0.70000     0.05000  4.1375749E+01  4.1375749E+01
    500    500 250000     0.64000     0.70000     0.06000  4.1375749E+01  4.1375749E+01
    500    500 250000     0.65000     0.70000     0.05000  4.1375749E+01  4.1375749E+01
    500    500 250000     0.65000     0.69000     0.04000  4.1375749E+01  4.1375749E+01

birdie ★★★★★
()
Ответ на: комментарий от birdie

> 500 500 250000 0.65000 0.70000 0.05000 4.1375749E+01 4.1375749E+01

Чем меньше числа "0.65000 0.70000" (время прохода в секундах), тем больше пиписька (в метрах), "0.05000" - это дельта по времени.
Первое - это время умножения матриц 500x500 при адресации типа A[i*N+j],
второе - при адресации A[i][j].
Обычно первое меньше второго, т.е. адресация A[i*N+j] немного выгоднее (заметно на старых машинах).
Но вот у товарища owlfog выдался противоположный результат.

pacify ★★★★★
() автор топика
Ответ на: комментарий от pacify

Когда ты создаешь массив как A[500][500] никакой двойной адресации нет, так как элементы лежат последовательно. С таким массивом можно работать и так (&A[0][0])[i * M + j]

Reset ★★★★★
()
Ответ на: комментарий от pacify

А вообще ты бы лучше не позорился такой код сюда постить. Страшно смотреть на это убожество. И матрицы ты умножаешь неправильно - забыл про нулевой элемент.

Reset ★★★★★
()
Ответ на: комментарий от pacify

и то о чем ты говоришь должно быть как раз заметно на новых машиных, так как раньше разрыв между скоростью памяти и проца был не таким большим :)

Reset ★★★★★
()
Ответ на: комментарий от Reset

> А вообще ты бы лучше не позорился такой код сюда постить. Страшно смотреть на это убожество.

Мне такой код нравится. А ты, если можешь, приведи пример кода как надо писать, а ?

> И матрицы ты умножаешь неправильно - забыл про нулевой элемент.

Точно.

pacify ★★★★★
() автор топика
Ответ на: комментарий от pacify

>> И матрицы ты умножаешь неправильно - забыл про нулевой элемент.
> Точно.

Хотя, вспомнил. Нулевые элементы выброшены, так как:
ADDR2(A,i,j) = ADDR2(B,i,j) = (i*j)/(FXX)(M*N);
и их можно не учитывать в при суммировании.

pacify ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.