Как производительность зависит от базовых значений данных - PullRequest
8 голосов
/ 25 января 2012

У меня есть следующий фрагмент кода C ++ (часть C ++ - это класс профилировщика, который здесь опущен), скомпилированный с VS2010 (64-битная машина Intel). Код просто умножает массив с плавающей точкой (arr2) на скаляр и помещает результат в другой массив (arr1):

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); 

Чтение из файла и профилирование (т.е. измерение во время выполнения) здесь для простоты опущено.

Когда arr2 инициализируется случайными числами в диапазоне [0 1], код выполняется примерно в 10 раз быстрее по сравнению со случаем, когда arr2 инициализируется в разреженный массив, в котором около 2/3 из значения нули. Я играл с опциями компилятора /fp и /O, которые немного изменили время выполнения, но соотношение 1:10 было примерно сохранено.

  • Почему производительность зависит от фактических значений? Что делает ЦП иначе, что делает разреженные данные работающими примерно в 10 раз медленнее?
  • Есть ли способ заставить "медленные данные" работать быстрее или любая оптимизация (например, векторизация вычислений) будет одинаково влиять на оба массива (т. Е. "Медленные данные" будут работать медленнее, чем данные ")

EDIT

Полный код здесь: https://gist.github.com/1676742, командная строка для компиляции находится в комментарии в test.cpp.

Файлы данных находятся здесь:

Ответы [ 3 ]

7 голосов
/ 25 января 2012

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

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

#include <xmmintrin.h>
_mm_setcsr(_mm_getcsr() | 0x8040);
2 голосов
/ 25 января 2012

Я могу подумать о двух причинах этого.

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

Вторая возможная причина заключается в том, что ваши «в основном нули» данные на самом деле не состоят из нулей, а скорее из почти нулей, или что вы хранитеarr1 в почти нулевом диапазоне.Смотрите эту ссылку в Википедии .

1 голос
/ 25 января 2012

Нет ничего странного в том, что обработка данных из I.bin занимает больше времени: у вас много чисел, таких как «1.401e-045 # DEN» или «2.214e-043 # DEN», где #DEN означает, что число не может быть нормализованным к стандартной точности плавающего. Учитывая, что вы собираетесь умножить его на 6.6e-14, у вас наверняка будут исключения из-за недостаточного значения, что значительно замедляет вычисления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...