Способен ли компилятор правильно разматать такой цикл?
От: Аноним  
Дата: 09.11.09 12:39
Оценка:
void f(int a[8])
{
int sum=0;
for(int i=0;i<8;i++)
{
sum+=a[i];
};
};

Способен ли он превратить этот код в:

sum1=a[0]+a[1];
sum2=a[2]+a[3];
sum3=a[4]+a[5];
sum4=a[6]+a[7];

sum6=sum1+sum2;
sum7=sum3+sum4;

sum=sum6+sum7;

Я пробовал, но у меня компиялтор даёт строго последовательный код.
А с интринсиками? А с float point?




09.11.09 17:03: Перенесено модератором из 'Алгоритмы' — Кодт
Re: Способен ли компилятор правильно разматать такой цикл?
От: CreatorCray  
Дата: 09.11.09 13:04
Оценка: +1
Здравствуйте, <Аноним>, Вы писали:

А>void f(int a[8])

А>{
А>int sum=0;
А>for(int i=0;i<8;i++)
А>{
А> sum+=a[i];
А>};
А>};

А>Способен ли он превратить этот код в:


А>sum1=a[0]+a[1];

А>sum2=a[2]+a[3];
А>sum3=a[4]+a[5];
А>sum4=a[6]+a[7];

А>sum6=sum1+sum2;

А>sum7=sum3+sum4;

А>sum=sum6+sum7;


А почему ты считаешь что с точки зрения оптимальности кода твой вариант "размотки" будет лучше чем последовательное суммирование?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[2]: Способен ли компилятор правильно разматать такой цикл
От: Аноним  
Дата: 09.11.09 13:11
Оценка:
Здравствуйте, CreatorCray, Вы писали:

CC>А почему ты считаешь что с точки зрения оптимальности кода твой вариант "размотки" будет лучше чем последовательное суммирование?


Потому что идёт распаралеливание на уровне команд.
Например, p6 может исполнять паралельно две команды сложения за такт.
Re: Способен ли компилятор правильно разматать такой цикл?
От: D14  
Дата: 09.11.09 13:23
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Я пробовал, но у меня компиялтор даёт строго последовательный код.

А>А с интринсиками? А с float point?
Intel c++ может такое делать, но не факт, что будет именно 4 штуки sum1..sum4, а не 2 или 3.
Re[3]: Способен ли компилятор правильно разматать такой цикл
От: Vzhyk  
Дата: 09.11.09 13:24
Оценка:
Аноним 311 пишет:
>
> Потому что идёт распаралеливание на уровне команд.
> Например, p6 может исполнять паралельно две команды сложения за такт.
Самый лучший способ проверить себя написать оное на асме в обоих
вариантах и проверить и на своем компьютере (на другом результаты могут
оказаться другие).
Posted via RSDN NNTP Server 2.1 beta
Re[3]: Способен ли компилятор правильно разматать такой цикл
От: CreatorCray  
Дата: 09.11.09 13:27
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Потому что идёт распаралеливание на уровне команд.

А>Например, p6 может исполнять паралельно две команды сложения за такт.

Компилятору совершенно не кажется правильным ради копеечной экономии вытеснить всё то, что он закешировал в регистрах ради суммирования 8 чисел.
Этот код ведь не в вакууме исполняется.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[2]: Способен ли компилятор правильно разматать такой цикл
От: CreatorCray  
Дата: 09.11.09 13:37
Оценка:
Здравствуйте, D14, Вы писали:

А>>Я пробовал, но у меня компиялтор даёт строго последовательный код.

А>>А с интринсиками? А с float point?
D14>Intel c++ может такое делать, но не факт, что будет именно 4 штуки sum1..sum4, а не 2 или 3.
Распоследний ICC (11.1) выдал вот такой код:

; mark_description "Intel(R) C++ Compiler for applications running on IA-32, Version 11.1    Build 20090903 %s";
; mark_description "-c -O3 -Og -Ob2 -Oi -Ot -GT -GA -D WIN32 -D NDEBUG -D _CONSOLE -D _MBCS -GF -MT -fp:fast -Zc:forScope -FAcs ";
; mark_description "-Fa\\BuildCache/Test/Test/Release// -Fo\\BuildCache/Test/Test/Release// -W3 -nologo -Wp64 -Zi -QxSSE2 -Qstd=";
; mark_description "c++0x -MP -Qvec-report0 -Qvc7.1 -Qlocation,link,D:\\soft\\MSVC7\\Vc7\\bin";

...

  00014 8b 44 24 04      mov eax, DWORD PTR [4+esp]             ;D:\Projects\Test\main2.cpp:17.2
  00018 03 04 24         add eax, DWORD PTR [esp]               ;D:\Projects\Test\main2.cpp:17.2
  0001b 03 44 24 08      add eax, DWORD PTR [8+esp]             ;D:\Projects\Test\main2.cpp:17.2
  0001f 03 44 24 0c      add eax, DWORD PTR [12+esp]            ;D:\Projects\Test\main2.cpp:17.2
  00023 03 44 24 10      add eax, DWORD PTR [16+esp]            ;D:\Projects\Test\main2.cpp:17.2
  00027 03 44 24 14      add eax, DWORD PTR [20+esp]            ;D:\Projects\Test\main2.cpp:17.2
  0002b 03 44 24 18      add eax, DWORD PTR [24+esp]            ;D:\Projects\Test\main2.cpp:17.2
  0002f 03 44 24 1c      add eax, DWORD PTR [28+esp]            ;D:\Projects\Test\main2.cpp:17.2


Походу никто таким заморачиваться не будет. Потому как копеечное улучшение в этом кусочке в результате может вылиться в просадку производительности в целом.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[3]: Способен ли компилятор правильно разматать такой цикл
От: Аноним  
Дата: 09.11.09 13:51
Оценка:
Здравствуйте, CreatorCray, Вы писали:

CC>Здравствуйте, D14, Вы писали:


А>>>Я пробовал, но у меня компиялтор даёт строго последовательный код.

А>>>А с интринсиками? А с float point?
D14>>Intel c++ может такое делать, но не факт, что будет именно 4 штуки sum1..sum4, а не 2 или 3.
CC>Распоследний ICC (11.1) выдал вот такой код:

CC>
CC>; mark_description "Intel(R) C++ Compiler for applications running on IA-32, Version 11.1    Build 20090903 %s";
CC>; mark_description "-c -O3 -Og -Ob2 -Oi -Ot -GT -GA -D WIN32 -D NDEBUG -D _CONSOLE -D _MBCS -GF -MT -fp:fast -Zc:forScope -FAcs ";
CC>; mark_description "-Fa\\BuildCache/Test/Test/Release// -Fo\\BuildCache/Test/Test/Release// -W3 -nologo -Wp64 -Zi -QxSSE2 -Qstd=";
CC>; mark_description "c++0x -MP -Qvec-report0 -Qvc7.1 -Qlocation,link,D:\\soft\\MSVC7\\Vc7\\bin";

CC>...

CC>  00014 8b 44 24 04      mov eax, DWORD PTR [4+esp]             ;D:\Projects\Test\main2.cpp:17.2
CC>  00018 03 04 24         add eax, DWORD PTR [esp]               ;D:\Projects\Test\main2.cpp:17.2
CC>  0001b 03 44 24 08      add eax, DWORD PTR [8+esp]             ;D:\Projects\Test\main2.cpp:17.2
CC>  0001f 03 44 24 0c      add eax, DWORD PTR [12+esp]            ;D:\Projects\Test\main2.cpp:17.2
CC>  00023 03 44 24 10      add eax, DWORD PTR [16+esp]            ;D:\Projects\Test\main2.cpp:17.2
CC>  00027 03 44 24 14      add eax, DWORD PTR [20+esp]            ;D:\Projects\Test\main2.cpp:17.2
CC>  0002b 03 44 24 18      add eax, DWORD PTR [24+esp]            ;D:\Projects\Test\main2.cpp:17.2
CC>  0002f 03 44 24 1c      add eax, DWORD PTR [28+esp]            ;D:\Projects\Test\main2.cpp:17.2
CC>


CC>Походу никто таким заморачиваться не будет. Потому как копеечное улучшение в этом кусочке в результате может вылиться в просадку производительности в целом.


Поскольку процессоры Intel за такт могут произвести только одно чтение, для них
дествительно это может быть лучший код, но AMD может произвести два чтения за такт, и для него оптимален другой код.
Re[3]: Способен ли компилятор правильно разматать такой цикл
От: D14  
Дата: 09.11.09 13:55
Оценка:
Здравствуйте, CreatorCray, Вы писали:

CC>Походу никто таким заморачиваться не будет. Потому как копеечное улучшение в этом кусочке в результате может вылиться в просадку производительности в целом.


Дык, тут тип int С ним действительно можно не заморачиваться, т.к. большое кол-во чисел типа int редко когда складывают, а с плавающей точкой оптимизирует. Там за счет задействования конвеера приличное ускорение можно поиметь.
Re[4]: Способен ли компилятор правильно разматать такой цикл
От: CreatorCray  
Дата: 09.11.09 14:18
Оценка:
Здравствуйте, D14, Вы писали:

D14>Дык, тут тип int С ним действительно можно не заморачиваться, т.к. большое кол-во чисел типа int редко когда складывают, а с плавающей точкой оптимизирует. Там за счет задействования конвеера приличное ускорение можно поиметь.


Компилятор с вами не согласен.

#define NUM_VALUES    (100)

float f(float* a)
{
    float sum=0;
    for(int i=0;i<NUM_VALUES;i++)
    {
        sum+=a[i];
    };

    return sum;
};

int main ()
{
    float var[NUM_VALUES];

    return f (var);
}


_main    PROC NEAR 
.B1.1:                          ; Preds .B1.0

;;; {

$LN1:
  00000 55               push ebp
  00001 8b ec            mov ebp, esp
  00003 83 e4 80         and esp, -128
  00006 81 ec 00 02 00 
        00               sub esp, 512
  0000c 6a 03            push 3
  0000e e8 fc ff ff ff   call ___intel_new_proc_init_N
                                ; LOE ebx esi edi
.B1.6:                          ; Preds .B1.1
  00013 59               pop ecx
  00014 0f ae 1c 24      stmxcsr DWORD PTR [esp]
  00018 33 c0            xor eax, eax
  0001a 66 0f ef c0      pxor xmm0, xmm0
  0001e 81 0c 24 00 80 
        00 00            or DWORD PTR [esp], 32768
  00025 0f ae 14 24      ldmxcsr DWORD PTR [esp]
                                ; LOE eax ebx esi edi xmm0
.B1.2:                          ; Preds .B1.2 .B1.6
$LN3:

;;;     float var[NUM_VALUES];
;;; 
;;;     return f (var);

  00029 0f 58 04 84      addps xmm0, XMMWORD PTR [esp+eax*4]
  0002d 83 c0 04         add eax, 4
  00030 83 f8 64         cmp eax, 100
  00033 72 f4            jb .B1.2 ; Prob 99%
                                ; LOE eax ebx esi edi xmm0
.B1.3:                          ; Preds .B1.2
  00035 0f 28 c8         movaps xmm1, xmm0
  00038 0f 12 c8         movhlps xmm1, xmm0
  0003b 0f 58 c1         addps xmm0, xmm1
  0003e 0f 28 d0         movaps xmm2, xmm0
  00041 0f c6 d0 f5      shufps xmm2, xmm0, 245
  00045 f3 0f 58 c2      addss xmm0, xmm2
  00049 f3 0f 2c c0      cvttss2si eax, xmm0
  0004d 8b e5            mov esp, ebp
  0004f 5d               pop ebp
  00050 c3               ret
  00051 0f 1f 84 00 00 
        00 00 00 0f 1f 
        80 00 00 00 00   ALIGN     16
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[5]: Способен ли компилятор правильно разматать такой цикл
От: D14  
Дата: 09.11.09 14:53
Оценка:
Здравствуйте, CreatorCray, Вы писали:

CC>Здравствуйте, D14, Вы писали:


D14>>Дык, тут тип int С ним действительно можно не заморачиваться, т.к. большое кол-во чисел типа int редко когда складывают, а с плавающей точкой оптимизирует. Там за счет задействования конвеера приличное ускорение можно поиметь.


CC>Компилятор с вами не согласен.


Здорово. А теперь тоже самое, но с double.
Re: Способен ли компилятор правильно разматать такой цикл?
От: zaufi Земля  
Дата: 09.11.09 15:08
Оценка: 1 (1)
вот что сделал gcc с такой програмкой:
#include <iostream>
using namespace std;

int f(int a[8])
{
    int sum=0;
    for(int i=0;i<8;i++)
        sum+=a[i];
    return sum;
};

int main()
{
    int a[8];
    int sum = f(a);
    cout << sum << endl;
    return 0;
}


на -O0 понятное дело все осталость как есть. на -O2 заинлайнил функцию f внутрь main'a. а вот на -O3...
zaufi /work/tests $ g++ --help=optimizers -O3 -Q | grep ftree-vect
  -ftree-vect-loop-version              [enabled]
  -ftree-vectorize                      [enabled]

включается автовекторизация... и получаем:
0000000000400990 <main>:
  400990:       55                      push   %rbp
  400991:       bf 60 10 60 00          mov    $0x601060,%edi
  400996:       53                      push   %rbx
  400997:       48 83 ec 28             sub    $0x28,%rsp
  40099b:       66 0f 6f 04 24          movdqa (%rsp),%xmm0
  4009a0:       66 0f fe 44 24 10       paddd  0x10(%rsp),%xmm0
  4009a6:       66 0f 6f c8             movdqa %xmm0,%xmm1
  4009aa:       66 0f 73 d9 08          psrldq $0x8,%xmm1
  4009af:       66 0f fe c1             paddd  %xmm1,%xmm0
  4009b3:       66 0f 6f c8             movdqa %xmm0,%xmm1
  4009b7:       66 0f 73 d9 04          psrldq $0x4,%xmm1
  4009bc:       66 0f fe c1             paddd  %xmm1,%xmm0
  4009c0:       66 0f 7e c6             movd   %xmm0,%esi
  4009c4:       e8 cf fd ff ff          callq  400798 <std::ostream::operator<<(int)@plt>
// дальше не интересно...


можно посмотреть на вывод компилятора при компиляции (чем больше номер тем больше спама %)
zaufi /work/tests $ g++ -g -march=native -O3 -ftree-vectorizer-verbose=3 -o sum sum.cc                                        

sum.cc:7: note: vect_model_load_cost: unaligned supported by hardware.                                                                                         
sum.cc:7: note: vect_model_load_cost: inside_cost = 2, outside_cost = 0 .                                                                                      
sum.cc:7: note: vect_model_reduction_cost: inside_cost = 1, outside_cost = 6 .                                                                                 
sum.cc:7: note: Cost model analysis:
  Vector inside of loop cost: 3
  Vector outside of loop cost: 6
  Scalar iteration cost: 2
  Scalar outside cost: 0
  prologue iterations: 0
  epilogue iterations: 0
  Calculated minimum iters for profitability: 5

sum.cc:7: note:   Profitability threshold = 4

sum.cc:7: note: LOOP VECTORIZED.
sum.cc:4: note: vectorized 1 loops in function.

sum.cc:7: note: vect_model_load_cost: aligned.
sum.cc:7: note: vect_model_load_cost: inside_cost = 1, outside_cost = 0 .
sum.cc:7: note: vect_model_reduction_cost: inside_cost = 1, outside_cost = 6 .
sum.cc:7: note: Cost model analysis:
  Vector inside of loop cost: 2
  Vector outside of loop cost: 6
  Scalar iteration cost: 2
  Scalar outside cost: 0
  prologue iterations: 0
  epilogue iterations: 0
  Calculated minimum iters for profitability: 5

sum.cc:7: note:   Profitability threshold = 4

sum.cc:7: note: LOOP VECTORIZED.
sum.cc:12: note: vectorized 1 loops in function.


это был
zaufi /work/tests $ g++ --version
g++ (Gentoo 4.4.2 p1.0) 4.4.2
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Re[6]: Способен ли компилятор правильно разматать такой цикл
От: Antikrot  
Дата: 09.11.09 15:47
Оценка:
Здравствуйте, D14, Вы писали:

D14>>>Дык, тут тип int С ним действительно можно не заморачиваться, т.к. большое кол-во чисел типа int редко когда складывают, а с плавающей точкой оптимизирует. Там за счет задействования конвеера приличное ускорение можно поиметь.

CC>>Компилятор с вами не согласен.
D14>Здорово. А теперь тоже самое, но с double.

можно и с int, и с float, и с double. просто в данном конкретном случае ICC решает что векторизовать работу со столь маленьким массивом невыгодно (о чем и говорит в vec-report). нет, его конечно можно явно прагмой пнуть, но смысл? увеличь размер массива (можно обернуть еще в цикл), и получишь векторизацию.
например так (для double):

.B1.2:                          ; Preds .B1.2 .B1.8
$LN3:

;;;     T a[SIZE];
;;;     T sum = f(a);

        addpd     xmm0, XMMWORD PTR [esp+eax*8]                 ;20.13
        addpd     xmm1, XMMWORD PTR [16+esp+eax*8]              ;20.13
        addpd     xmm0, XMMWORD PTR [32+esp+eax*8]              ;20.13
        addpd     xmm1, XMMWORD PTR [48+esp+eax*8]              ;20.13
        add       eax, 8                                        ;20.13
        cmp       eax, 10000                                    ;20.13
        jb        .B1.2         ; Prob 99%                      ;20.13


вот тебе и по два чтения, например
Re[7]: Способен ли компилятор правильно разматать такой цикл
От: D14  
Дата: 09.11.09 15:58
Оценка:
Здравствуйте, Antikrot, Вы писали:


A>можно и с int, и с float, и с double. просто в данном конкретном случае ICC решает что векторизовать работу со столь маленьким массивом невыгодно (о чем и говорит в vec-report). нет, его конечно можно явно прагмой пнуть, но смысл? увеличь размер массива (можно обернуть еще в цикл), и получишь векторизацию.

A>например так (для double):

А я и не утверждал, что обязан всегда. Я писал, что может использовать количество аккумуляторов по своему усмотрению.
Re[3]: Способен ли компилятор правильно разматать такой цикл
От: minorlogic Украина  
Дата: 09.11.09 16:53
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Здравствуйте, CreatorCray, Вы писали:


CC>>А почему ты считаешь что с точки зрения оптимальности кода твой вариант "размотки" будет лучше чем последовательное суммирование?


А>Потому что идёт распаралеливание на уровне команд.

А>Например, p6 может исполнять паралельно две команды сложения за такт.

Нескромный вопрос, вы производительность меряли ?
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[4]: Способен ли компилятор правильно разматать такой цикл
От: superlexx  
Дата: 09.11.09 19:31
Оценка: 30 (3)
Небольшое сравнение оптимизаторов, в том числе и loop unrolling:

http://www.linux-kongress.org/2009/slides/compiler_survey_felix_von_leitner.pdf
Re[5]: Способен ли компилятор правильно разматать такой цикл
От: minorlogic Украина  
Дата: 10.11.09 05:33
Оценка:
Здравствуйте, superlexx, Вы писали:

S>Небольшое сравнение оптимизаторов, в том числе и loop unrolling:


S>http://www.linux-kongress.org/2009/slides/compiler_survey_felix_von_leitner.pdf


За ссылку спасибо , но на вопрос мой никак не отвечает.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Ищу работу, 3D, SLAM, computer graphics/vision.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.