почему поэлементно добавки намного быстрее, в отдельных петель, чем в комбинированном цикле?

a1b1c1d1

предположим , , , и точки в памяти "кучи", и мой числовой код имеет следующие основные петли.

const int n = 100000;for (int j = 0; j < n; j++) {    a1[j] += b1[j];    c1[j] += d1[j];}
for

этот цикл выполняется 10000 раз через другой внешний цикл. чтобы его ускорить, я изменил код на:

for (int j = 0; j < n; j++) {    a1[j] += b1[j];}for (int j = 0; j < n; j++) {    c1[j] += d1[j];}
visual c++ 10.0sse2intel core 2

скомпилирован на ms с полной оптимизацией и поддержкой для 32-разрядной дуэт (х64), в первом примере занимает 5,5 секунд, а двухконтурная пример занимает всего 1,9 секунды. мой вопрос: (пожалуйста, обратитесь к моей перефразировать вопрос внизу)

ps: я не уверен, если это помогает:

разборки на первом круге в основном выглядит так (этот блок повторяется около пяти раз в полной программе):

movsd       xmm0,mmword ptr [edx+18h]addsd       xmm0,mmword ptr [ecx+20h]movsd       mmword ptr [ecx+20h],xmm0movsd       xmm0,mmword ptr [esi+10h]addsd       xmm0,mmword ptr [eax+30h]movsd       mmword ptr [eax+30h],xmm0movsd       xmm0,mmword ptr [edx+20h]addsd       xmm0,mmword ptr [ecx+28h]movsd       mmword ptr [ecx+28h],xmm0movsd       xmm0,mmword ptr [esi+18h]addsd       xmm0,mmword ptr [eax+38h]

каждый цикл двойного примере цикла создает этот код (следующий блок повторяется три раза):

addsd       xmm0,mmword ptr [eax+28h]movsd       mmword ptr [eax+28h],xmm0movsd       xmm0,mmword ptr [ecx+20h]addsd       xmm0,mmword ptr [eax+30h]movsd       mmword ptr [eax+30h],xmm0movsd       xmm0,mmword ptr [ecx+28h]addsd       xmm0,mmword ptr [eax+38h]movsd       mmword ptr [eax+38h],xmm0movsd       xmm0,mmword ptr [ecx+30h]addsd       xmm0,mmword ptr [eax+40h]movsd       mmword ptr [eax+40h],xmm0

вопрос оказался не актуальным, так как поведение сильно зависит от размеров массивов (n) и кэш процессора. так что если есть дальнейший интерес, я перефразирую вопрос:

<сильная>не могли бы вы предоставить некоторые твердые вникнуть в детали, которые приводят к различным кэша, как показано в пяти регионах на следующем графике?</сильный>

<сильный>было бы также интересно отметить различия между архитектурами процессора/кэш, обеспечивая подобный график для этих процессоров.</сильный>

tbbtick_counttbb_timing

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

#include <iostream>#include <iomanip>#include <cmath>#include <string>//#define tbb_timing#ifdef tbb_timing   #include <tbb/tick_count.h>using tbb::tick_count;#else#include <time.h>#endifusing namespace std;//#define preallocate_memory new_contenum { new_cont, new_sep };double *a1, *b1, *c1, *d1;void allo(int cont, int n){    switch(cont) {      case new_cont:        a1 = new double[n*4];        b1 = a1 + n;        c1 = b1 + n;        d1 = c1 + n;        break;      case new_sep:        a1 = new double[n];        b1 = new double[n];        c1 = new double[n];        d1 = new double[n];        break;    }    for (int i = 0; i < n; i++) {        a1[i] = 1.0;        d1[i] = 1.0;        c1[i] = 1.0;        b1[i] = 1.0;    }}void ff(int cont){    switch(cont){      case new_sep:        delete[] b1;        delete[] c1;        delete[] d1;      case new_cont:        delete[] a1;    }}double plain(int n, int m, int cont, int loops){#ifndef preallocate_memory    allo(cont,n);#endif#ifdef tbb_timing       tick_count t0 = tick_count::now();#else    clock_t start = clock();#endif    if (loops == 1) {        for (int i = 0; i < m; i++) {            for (int j = 0; j < n; j++){                a1[j] += b1[j];                c1[j] += d1[j];            }        }    } else {        for (int i = 0; i < m; i++) {            for (int j = 0; j < n; j++) {                a1[j] += b1[j];            }            for (int j = 0; j < n; j++) {                c1[j] += d1[j];            }        }    }    double ret;#ifdef tbb_timing       tick_count t1 = tick_count::now();    ret = 2.0*double(n)*double(m)/(t1-t0).seconds();#else    clock_t end = clock();    ret = 2.0*double(n)*double(m)/(double)(end - start) *double(clocks_per_sec);#endif#ifndef preallocate_memory    ff(cont);#endif    return ret;}void main(){       freopen("c:\\test.csv", "w", stdout);    char *s = " ";    string na[2] ={"new_cont", "new_sep"};    cout << "n";    for (int j = 0; j < 2; j++)        for (int i = 1; i <= 2; i++)#ifdef preallocate_memory            cout << s << i << "_loops_" << na[preallocate_memory];#else            cout << s << i << "_loops_" << na[j];#endif    cout << endl;    long long nmax = 1000000;#ifdef preallocate_memory    allo(preallocate_memory, nmax);#endif    for (long long n = 1l; n < nmax; n = max(n+1, long long(n*1.2)))    {        const long long m = 10000000/n;        cout << n;        for (int j = 0; j < 2; j++)            for (int i = 1; i <= 2; i++)                cout << s << plain(n, m, j, i);        cout << endl;    }}
n

(он показывает флоп/с для различных значений .)

enter image description here