Неприятное открытие
От: кт  
Дата: 23.04.17 07:38
Оценка:
Похвастался коллеге, что мы в ногу с прогрессом используем 64-разрядный транслятор, а он, небось, по старинке – 32-разрядный.
Ну и он попросил дать ему 64-разрядный компилятор. Задачи у него почти чисто вычислительные. Главный процесс – численное интегрирование. Поэтому производительность важна – чем быстрее считается, тем меньше шаг интегрирования можно задать.
Попробовал. Говорит, перетранслировал – коды стали больше (ну, это ожидаемо). А скорость стала ниже!
Я сначала не поверил. Забрал его тексты проверил. И вот, что получилось.
Процессор Intel Core i5-3210M 2.5 GHz. Стоит Windows-7.
Одна и та же задача. Результаты выдает одинаковые. Компилятор (не скажу с какого языка  ) 64-разряда сделан из 32-х разрядного, поэтому команды очень похожие.
Размер кода увеличился на 9%, а скорость упала на 20.5%. Расчет длинный, ввода-вывода мало.
Попробовал разобраться.
Ну да, там, где индексы, их надо бы перевести в 8 байт, но не хочется трогать исходные тексты. Поэтому для 64 разрядов появляется лишняя пересылка, которая вероятно не дает свернуть адресацию в SIB-байт.
Вот одно и то же место:
A12(i,j)=0.0;       64 разряда
0013CD 48630580000000     movsxq rax,I
0013D4 486BF818           imul q rdi,rax,24
0013D8 48630584000000     movsxq rax,J
0013DF 48C1E003           shl  q rax,3
0013E3 4803F8             add  q rdi,rax
0013E6 488DBFE0FFFFFF     lea    rdi,@A12+0FFFFFFE0h[rdi]
0013ED BE28010000         mov  q rsi,offset @00000128h
0013F2 48A5               movsq

A12(i,j)=0.0;    32 разряда
001393 6B3D8000000018     imul   edi,I,24
00139A A184000000         mov    eax,J
00139F 8DBCC7E0FFFFFF     lea    edi,@A12+0FFFFFFE0h[edi+eax*8]
0013A6 BE28010000         mov    esi,offset @00000128h
0013AB A5                 movs
0013AC A5                 movs

Но это все нечасто встречающийся код. Большая часть состоит из вот таких операторов:
32 разряда:
A02(3,3)=-SPH2*STH2*SPS2+CPH2*CPS2;
001334 BB70020000         mov    ebx,offset SPH2
001339 DD03               fld64  [ebx]
00133B 53                 push   ebx
00133C 53                 push   ebx
00133D D9E0               fchs
00133F BB50020000         mov    ebx,offset STH2
001344 DC0B               fmul64 [ebx]
001346 BB30020000         mov    ebx,offset SPS2
00134B DC0B               fmul64[ebx]
00134D DD1C24             fst64p[esp]
001350 BB28020000         mov    ebx,offset CPS2
001355 BA68020000         mov    edx,offset CPH2
00135A E800000000         call   ?FMS_M
00135F DD1D40000000       fst64p @A02+000000040h

64 разряда
A02(3,3)=-SPH2*STH2*SPS2+CPH2*CPS2;
00136F BB78020000         mov  q rbx,offset SPH2
001374 DD03               fld64[rbx]
001377 53                 push rbx
001378 D9E0               fchs
001379 BB58020000         mov  q rbx,offset STH2
00137E DC0B               fmul64[rbx]
001380 BB38020000         mov  q rbx,offset SPS2
001385 DC0B               fmul64[rbx]
001387 DD1C24             fst64p[rsp]
00138A BB30020000         mov  q rbx,offset CPS2
00138F BA70020000         mov  q rdx,offset CPH2
001394 E800000000         call   ?FMS_M
001399 DD1D40000000       fst64p @A02+000000040h

Практически одни и те же команды и это 95% всего выполняемого расчета. Компилятор даже константы загружает без префикса 48 потому, что код не превышает 4 Гбайт.

Итак, имеем две почти одинаковых последовательности команд в двух режимах, проводящих одни и те же вычисления, главным образом, через FPU.
Исходные тексты одинаковы. Код в 64 разряда ожидаемо увеличивается.
А скорость его работы падает на 20%!

Я читал (и считал), что теперь 64-разряда – это «родной» режим, а 32-разряда оставлен для совместимости. А вот по этому тесту выходит наоборот
Re: Неприятное открытие
От: Stanislaw K СССР  
Дата: 23.04.17 08:26
Оценка:
Здравствуйте, кт, Вы писали:

кт>Попробовал. Говорит, перетранслировал – коды стали больше (ну, это ожидаемо). А скорость стала ниже!

кт>Я сначала не поверил. Забрал его тексты проверил. И вот, что получилось.
кт>Процессор Intel Core i5-3210M 2.5 GHz. Стоит Windows-7.

кт>Я читал (и считал), что теперь 64-разряда – это «родной» режим, а 32-разряда оставлен для совместимости. А вот по этому тесту выходит наоборот


Это смотря с какого момента "теперь".

Processor Number i5-3210M
Status Launched
Launch Date Q2'12


http://ark.intel.com/products/67355/Intel-Core-i5-3210M-Processor-3M-Cache-up-to-3_10-GHz-rPGA
Все проблемы от жадности и глупости
Re: Неприятное открытие
От: denisko http://sdeniskos.blogspot.com/
Дата: 23.04.17 08:57
Оценка: +2
Здравствуйте, кт, Вы писали:

Очень странно выглядит если честно. Во-первых, если это оптимизрованный код какого хрена он используется FPU вместо AVX/SSE. Второе, какого хрена он все время в память лезет аргументы загружать. __restrict/__declspec ( restrict нигде не забыл?
<Подпись удалена модератором>
Скорость в 64 битах (Re: Неприятное открытие)
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.04.17 08:59
Оценка: 1 (1) +1
Здравствуйте, кт, Вы писали:

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

кт>Вот одно и то же место:
кт>
кт>A12(i,j)=0.0;       64 разряда
кт>0013CD 48630580000000     movsxq rax,I
кт>0013D4 486BF818           imul q rdi,rax,24
кт>0013D8 48630584000000     movsxq rax,J
кт>0013DF 48C1E003           shl  q rax,3
кт>0013E3 4803F8             add  q rdi,rax
кт>0013E6 488DBFE0FFFFFF     lea    rdi,@A12+0FFFFFFE0h[rdi]
кт>0013ED BE28010000         mov  q rsi,offset @00000128h
кт>0013F2 48A5               movsq

кт>A12(i,j)=0.0;    32 разряда
кт>001393 6B3D8000000018     imul   edi,I,24
кт>00139A A184000000         mov    eax,J
кт>00139F 8DBCC7E0FFFFFF     lea    edi,@A12+0FFFFFFE0h[edi+eax*8]
кт>0013A6 BE28010000         mov    esi,offset @00000128h
кт>0013AB A5                 movs
кт>0013AC A5                 movs
кт>


Хм. Попробую смоделировать у себя. Раз I умножается на 24, а J на 8, значит, размер по I равен 3? Я не буду для C моделировать адресацию массива от 1:

double f01(double A12[][3], int i, int j) {
        return A12[i][j];
}


Результат (тут и далее — x86-64, GCC 5.4.0, AT&T ассемблер; SysV конвенция — аргументы поступают: rdi, rsi, rdx, rcx...):
f01:
.LFB0:
        .cfi_startproc
        movslq  %esi, %rsi
        leaq    (%rsi,%rsi,2), %rax
        leaq    (%rdi,%rax,8), %rax
        movslq  %edx, %rdx
        movsd   (%rax,%rdx,8), %xmm0
        ret


Хорошо видно, что отличается: ваш пример совсем не использует адресацию от двух регистров (базового плюс индексного). Ну и IMUL на 24 разложен в два LEA (не столь существенно). У вас же в примере какой-то кошмарик.

Ну хорошо, возьмём от того же GCC5 — gfortran:

      function f02(a12, i, j)
      double precision f02
      double precision a12(3,3)
      integer i, j
      f02 = a12(i, j)
      end


Результат:

f02_:
.LFB0:
        .cfi_startproc
        movslq  (%rdx), %rax
        movslq  (%rsi), %rdx
        leaq    (%rax,%rax,2), %rax
        leaq    -4(%rdx,%rax), %rax
        movsd        (%rdi,%rax,8), %xmm0
        ret


Первые два movslq — взятие значения аргумента по ссылке, дальше — код взятия по индексу.

Вывод: с процессором, скорее всего, всё в порядке. А вот компилятор для 64-битного режима у вас, мягко говоря, фиговый.
Назовёте марку и версию компилятора?

кт>64 разряда

кт>
кт>A02(3,3)=-SPH2*STH2*SPS2+CPH2*CPS2;
кт>00136F BB78020000         mov  q rbx,offset SPH2
кт>001374 DD03               fld64[rbx]
кт>001377 53                 push rbx
кт>001378 D9E0               fchs
кт>001379 BB58020000         mov  q rbx,offset STH2
кт>00137E DC0B               fmul64[rbx]
кт>001380 BB38020000         mov  q rbx,offset SPS2
кт>001385 DC0B               fmul64[rbx]
кт>001387 DD1C24             fst64p[rsp]
кт>00138A BB30020000         mov  q rbx,offset CPS2
кт>00138F BA70020000         mov  q rdx,offset CPH2
кт>001394 E800000000         call   ?FMS_M
кт>001399 DD1D40000000       fst64p @A02+000000040h
кт>

кт>Практически одни и те же команды и это 95% всего выполняемого расчета. Компилятор даже константы загружает без префикса 48 потому, что код не превышает 4 Гбайт.

Интересно, кто и зачем использует FPU в 64-битном режиме. MS категорически переключилась на SSE для 64-битки. Unix переключаются по умолчанию, но могут включать FPU для усиленного распараллеливания. Повторяю вопрос про компилятор.

кт>Итак, имеем две почти одинаковых последовательности команд в двух режимах, проводящих одни и те же вычисления, главным образом, через FPU.

кт>Исходные тексты одинаковы. Код в 64 разряда ожидаемо увеличивается.
кт>А скорость его работы падает на 20%!

Специфика Intel? Есть AMD для сравнения? Тот более лояльно относится к FPU в 64-битке.

кт>Я читал (и считал), что теперь 64-разряда – это «родной» режим, а 32-разряда оставлен для совместимости. А вот по этому тесту выходит наоборот


Вообще-то для раннего Intel это было, по слухам, вполне верно — они настолько быстро и грязно сделали EM64T, что в первых его версиях (для Pentium 4) 64-битный код вообще не имел никакого out-of-order. Но уже начиная с Core, AFAIK, это не так. И ваш i7 должен вполне нормально это отрабатывать.

И кто такой FMS_M? Это проверка границ массива? А если её отключить, что получится со скоростью?

А почему одни и те же регистры (rbx, rdx) по кругу? Или это только в одном таком куске кода? Я понимаю, что переименование регистров спасает отцов русской демократии в 95% случаев, но компилятор явно без SSA, а постоянные дёргания регистров через стек дороги в любом варианте. А с учётом FPU, непонятно, что это за диковинка такая.

Возьмите GNU Fortran, возьмите интеловский, и сравните. Я подозреваю, что картина выровняется, а, может, 64-битка станет и быстрее (за счёт прямого использования большего количества регистров).
The God is real, unless declared integer.
Отредактировано 23.04.2017 9:01 netch80 . Предыдущая версия . Еще …
Отредактировано 23.04.2017 9:00 netch80 (заголовок) . Предыдущая версия .
Re: Неприятное открытие
От: кт  
Дата: 23.04.17 09:13
Оценка:
так и знал, что все найдут генерируемый код плохим.

А речь о том, что почти ОДИНАКОВЫЕ последовательности команд в 64-разрядном режиме работают на 20% медленнее, чем в они же 32 разрядном режиме.
Хотя по идее должны были бы работать ТАКЖЕ (плохо или хорошо, это уже второй вопрос)

И, кстати, SSE это не совсем то же, что FPU. В FPU реально работа идет с 80 разрядами, поэтому очень хорошее округление и точность. Промежуточные результаты можно запомнить командой FST80. А в SSE2-4 чем?
Все эти 128 и 256 разрядные регистры все (по времени) теряют на загрузках. Тоже, увы, проверено.
Re: Неприятное открытие
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.04.17 09:22
Оценка:
Здравствуйте, кт, Вы писали:

И второе вдогонку — буду приводить по-прежнему примеры для Фортрана — попытался сэмулировать вторую часть с присвоением одного результата умножения.

Входной код

      function f03(a02)
      common /globals/ SPH2, STH2, SPS2, CPH2, CPS2
      double precision f03
      double precision a02(3,3)
      A02(3,3)=-SPH2*STH2*SPS2+CPH2*CPS2
      end


Сгенерированное с принуждением к FPU:

f03_:
        flds    globals_+12(%rip)
        fmuls   globals_+16(%rip)
        flds    globals_(%rip)
        fmuls   globals_+4(%rip)
        fmuls   globals_+8(%rip)
        fsubrp  %st, %st(1)
        fstpl   64(%rdi)
        ret


Или в дизассемблере:

0000000000000000 <f03_>:
   0:   d9 05 00 00 00 00       flds   0x0(%rip)        # 6 <f03_+0x6>
   6:   d8 0d 00 00 00 00       fmuls  0x0(%rip)        # c <f03_+0xc>
   c:   d9 05 00 00 00 00       flds   0x0(%rip)        # 12 <f03_+0x12>
  12:   d8 0d 00 00 00 00       fmuls  0x0(%rip)        # 18 <f03_+0x18>
  18:   d8 0d 00 00 00 00       fmuls  0x0(%rip)        # 1e <f03_+0x1e>
  1e:   de e9                   fsubrp %st,%st(1)
  20:   dd 5f 40                fstpl  0x40(%rdi)
  23:   c3                      retq

(0 в смещениях — потому что отдельный объектник. В готовом бинарнике будут реальные цифры.)

Сравниваем с тем, что у вас:

кт>
кт>A02(3,3)=-SPH2*STH2*SPS2+CPH2*CPS2;
кт>00136F BB78020000         mov  q rbx,offset SPH2
кт>001374 DD03               fld64[rbx]
кт>001377 53                 push rbx
кт>001378 D9E0               fchs
кт>001379 BB58020000         mov  q rbx,offset STH2
кт>00137E DC0B               fmul64[rbx]
кт>001380 BB38020000         mov  q rbx,offset SPS2
кт>001385 DC0B               fmul64[rbx]
кт>001387 DD1C24             fst64p[rsp]
кт>00138A BB30020000         mov  q rbx,offset CPS2
кт>00138F BA70020000         mov  q rdx,offset CPH2
кт>001394 E800000000         call   ?FMS_M
кт>001399 DD1D40000000       fst64p @A02+000000040h
кт>


Учитывая, что "mov q rbx,offset SPH2" грузит 4 байта, и адресация по RIP тоже с 4-байтными смещениями, реально имеем такое же ограничение на помещение статических данных в 2GB (с учётом знаковости). Выше этой границы допускается только динамически распределяемая память. Тогда
1) компилятор совсем не умеет использовать адресацию по RIP;
2) как минимум, команды FSUBR[P] он не знает.

[UPD: deleted — не досмотрел, что часть операндов берётся из памяти]
The God is real, unless declared integer.
Отредактировано 23.04.2017 12:02 netch80 . Предыдущая версия .
Re[2]: Неприятное открытие
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.04.17 09:28
Оценка:
Здравствуйте, кт, Вы писали:

кт>так и знал, что все найдут генерируемый код плохим.


Да, и это правильно. Потому что пример с загрузкой константы очевидно хуже написан в 64 битах, чем в 32. Сами же сказали, что в 64 битах компилятор чего-то не сумел. А я показываю, что это проблема не режима, а компилятора, что он очевидно слаб.

кт>А речь о том, что почти ОДИНАКОВЫЕ последовательности команд в 64-разрядном режиме работают на 20% медленнее, чем в они же 32 разрядном режиме.


Вы это можете доказать, только избавившись от посторонних влияний типа FMS_M. Неизвестно их качество.
Или проанализируйте чем-то вроде Intel VTune, который умеет (AFAIR) показывать тормоза вплоть до конкретной машинной команды и исходной строчки. Или — повторюсь — проверьте с AMD.

кт>Хотя по идее должны были бы работать ТАКЖЕ (плохо или хорошо, это уже второй вопрос)


По форме: "так же" пишется в данном случае раздельно.

кт>И, кстати, SSE это не совсем то же, что FPU. В FPU реально работа идет с 80 разрядами, поэтому очень хорошее округление и точность. Промежуточные результаты можно запомнить командой FST80. А в SSE2-4 чем?


В FPU "реально" работа идёт с точностью согласно режиму процессора. Вы точно выставили extended? Или хотя бы проверили, что оно такое? В винде в 32 битах по умолчанию там double, так же, как и во FreeBSD (а вот в Linux — extended).

Аргумент, что в FPU можно считать в 80 битах, принимаю. Иногда это даже полезно. Но обычно эту пользу переоценивают.

кт>Все эти 128 и 256 разрядные регистры все (по времени) теряют на загрузках. Тоже, увы, проверено.


Какие именно загрузки? Там несколько разных.
The God is real, unless declared integer.
Re[3]: Неприятное открытие
От: кт  
Дата: 23.04.17 09:50
Оценка:
Здравствуйте, netch80, Вы писали:

N>Да, и это правильно. Потому что пример с загрузкой константы очевидно хуже написан в 64 битах, чем в 32. Сами же сказали, что в 64 битах компилятор чего-то не сумел. А я показываю, что это проблема не режима, а компилятора, что он очевидно слаб.


Ухудшение кода есть, но оно никак не может дать 20% замедление, поскольку в основных циклах встречается очень редко.

N>Вы это можете доказать, только избавившись от посторонних влияний типа FMS_M. Неизвестно их качество.

внутри этой системной подпрограммки команды тоже одинаковые для 32 и 64

N>Или проанализируйте чем-то вроде Intel VTune, который умеет (AFAIR) показывать тормоза вплоть до конкретной машинной команды и исходной строчки. Или — повторюсь — проверьте с AMD.

На AMD обязательно проверю

кт>>Хотя по идее должны были бы работать ТАКЖЕ (плохо или хорошо, это уже второй вопрос)


N>По форме: "так же" пишется в данном случае раздельно.

Спасибо, постараюсь проверять написанное более тщательно

N>В FPU "реально" работа идёт с точностью согласно режиму процессора. Вы точно выставили extended? Или хотя бы проверили, что оно такое? В винде в 32 битах по умолчанию там double, так же, как и во FreeBSD (а вот в Linux — extended).

Внутри FPU все идет в 80 разрядах. "Реально" — я имел ввиду "внутри"

N>Аргумент, что в FPU можно считать в 80 битах, принимаю. Иногда это даже полезно. Но обычно эту пользу переоценивают.

А ошибки IEEE-754 обычно недооценивают.

кт>>Все эти 128 и 256 разрядные регистры все (по времени) теряют на загрузках. Тоже, увы, проверено.


N>Какие именно загрузки? Там несколько разных.

Я уже выкладывал этот плач Ярославны
https://groups.google.com/forum/#!topic/comp.lang.asm.x86/j7wBKVUOmfI

И все-таки еще раз: одинаковые команды в двух режимах и должны были бы выполняться одинаково быстро (медленно)
Re[2]: Неприятное открытие
От: кт  
Дата: 23.04.17 10:33
Оценка:
Здравствуйте, netch80, Вы писали:

N>Учитывая, что "mov q rbx,offset SPH2" грузит 4 байта, и адресация по RIP тоже с 4-байтными смещениями, реально имеем такое же ограничение на помещение статических данных в 2GB (с учётом знаковости). Выше этой границы допускается только динамически распределяемая память. Тогда

И это действительно так, в таких программах (о, ужас) команды и статические данные не могут превысить 4 Гбайт.
Кстати, реальный размер исследуемой программы 500 Кбайт кодов.

N>1) компилятор совсем не умеет использовать адресацию по RIP;

Здесь она ничего не дает в плане объема/скорости, статические данные не "рассыпаны" между кодов.
N>2) как минимум, команды FSUBR[P] он не знает.
А в чем будет выигрыш? Кстати, подпрограмма FMS_M, судя по всему, выполняет сразу и умножение и сложение.

N>И ещё одно (которое уже по счёту) — смысла писать fmul64 нет! fmul одинаков для всех, а точность задаётся режимом процессора. (В отличие от load/store, которое таки имеет размер операнда в памяти.) Это не имеет отношения к скорости, но имеет отношение к интеллекту авторов компилятора.


А вот сейчас стало обидно за авторов, да.
значит, писать безликие flds 0x0(%rip) это интеллект,
а явно и наглядно указывать fld64 [rbx] вместо какого-нибудь громоздкого fld q ptr [rbx] это плохо.
Re[4]: Неприятное открытие
От: Michael7 Россия  
Дата: 23.04.17 11:05
Оценка:
Здравствуйте, кт, Вы писали:

кт>И все-таки еще раз: одинаковые команды в двух режимах и должны были бы выполняться одинаково быстро (медленно)


А этого, по-моему, никогда не было на x86. 8-битные команды (с AH,AL, короткими переходами и прочим) выполнялись быстрее 16-ти битных, а 16-ти битные были быстрее 32-битных. Между прочим, попробуйте ради любопытства запустить аналогичный 16-ти битный код в MS-DOS, не исключено, что код и сейчас будет быстрее 32-битного. Хотя сейчас вспомнил, что вроде как раз начиная с P6 (i686, Pentium Pro и Pentium-II) оптимизатор исполнения в процессоре стал плохо работать с 16-ти битным кодом, так что возможно сейчас он уже сильно устарел и выигрыша не будет. Но он был вплоть до первых пентиумов включительно.
Отредактировано 23.04.2017 11:08 Michael7 . Предыдущая версия .
Re[3]: Неприятное открытие
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.04.17 11:05
Оценка:
Здравствуйте, кт, Вы писали:

N>>2) как минимум, команды FSUBR[P] он не знает.

кт>А в чем будет выигрыш?

Чуть меньше возни.

кт> Кстати, подпрограмма FMS_M, судя по всему, выполняет сразу и умножение и сложение.


А, это fused multiply and subtract? Понятно. Вряд ли оно выполняет fused с ещё более расширенной точностью, так что вынесение в подпрограмму явно не имеет смысла, но сравнение скорости оно, таки да, не портит.

N>>И ещё одно (которое уже по счёту) — смысла писать fmul64 нет! fmul одинаков для всех, а точность задаётся режимом процессора. (В отличие от load/store, которое таки имеет размер операнда в памяти.) Это не имеет отношения к скорости, но имеет отношение к интеллекту авторов компилятора.


кт>А вот сейчас стало обидно за авторов, да.


Потому что криво читаете.

кт>значит, писать безликие flds 0x0(%rip) это интеллект,

кт>а явно и наглядно указывать fld64 [rbx] вместо какого-нибудь громоздкого fld q ptr [rbx] это плохо.

fld64 — это то же, что fldl в AT&T (fld32 == flds, fld80 == fldt). Тут разницы нет, кроме стиля. Команды разные.

Я говорю про _арифметику_. fmul32, fmul64, fmul80 пишутся одним и тем же кодом, и точность будет выбираться согласно режиму FPU, а не тем, какую точность записали в ассемблере. Поэтому ставить точность после fmul не просто бессмысленно, а и вредно для читающего.
The God is real, unless declared integer.
Re[4]: Неприятное открытие
От: Michael7 Россия  
Дата: 23.04.17 11:15
Оценка:
Здравствуйте, netch80, Вы писали:

N>Я говорю про _арифметику_. fmul32, fmul64, fmul80 пишутся одним и тем же кодом, и точность будет выбираться согласно режиму FPU, а не тем, какую точность записали в ассемблере. Поэтому ставить точность после fmul не просто бессмысленно, а и вредно для читающего.


Может быть указание точности приводит к генерации кода, устанавливающего нужный режим работы FPU (FLDCW)?
Re[4]: Неприятное открытие
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.04.17 11:22
Оценка:
Здравствуйте, кт, Вы писали:

N>>Да, и это правильно. Потому что пример с загрузкой константы очевидно хуже написан в 64 битах, чем в 32. Сами же сказали, что в 64 битах компилятор чего-то не сумел. А я показываю, что это проблема не режима, а компилятора, что он очевидно слаб.

кт>Ухудшение кода есть, но оно никак не может дать 20% замедление, поскольку в основных циклах встречается очень редко.

Ну тогда — не знаю аналога для Windows, но тут я бы напустил на неё perf stat и померял, где основные тормоза (фронтэнд, бэкэнд, кэш, ветвления...)

N>>В FPU "реально" работа идёт с точностью согласно режиму процессора. Вы точно выставили extended? Или хотя бы проверили, что оно такое? В винде в 32 битах по умолчанию там double, так же, как и во FreeBSD (а вот в Linux — extended).

кт>Внутри FPU все идет в 80 разрядах. "Реально" — я имел ввиду "внутри"

И результат каждой операции округляется согласно выбранному режиму.

N>>Аргумент, что в FPU можно считать в 80 битах, принимаю. Иногда это даже полезно. Но обычно эту пользу переоценивают.

кт>А ошибки IEEE-754 обычно недооценивают.

Какие именно ошибки? Погрешности принципа плавучки, ошибки реализации, другое?
В любом случае, как только вы выгружаете из FPU в double, а не long double, точность усекается. И ваш код всё время содержит именно такие усечения (fstp64 и тому подобное).

кт>>>Все эти 128 и 256 разрядные регистры все (по времени) теряют на загрузках. Тоже, увы, проверено.


N>>Какие именно загрузки? Там несколько разных.

кт>Я уже выкладывал этот плач Ярославны
кт>https://groups.google.com/forum/#!topic/comp.lang.asm.x86/j7wBKVUOmfI

Мнэээ... я правильно понял, что вся проблема была в использовании AVX после SSE без vzeroupper? Тогда — удивляюсь, потому что это уровень букваря. Но даже это даёт только начальный тормоз работы с одним конкретным регистром.

кт>И все-таки еще раз: одинаковые команды в двух режимах и должны были бы выполняться одинаково быстро (медленно)


Давайте пока не спешить с выводами. У вас есть возможность прогнать через аппаратные счётчики? i5-3210M это Ivy Bridge, у него этих счётчиков уже есть на все случаи жизни.
The God is real, unless declared integer.
Re[5]: Неприятное открытие
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.04.17 11:24
Оценка:
Здравствуйте, Michael7, Вы писали:

N>>Я говорю про _арифметику_. fmul32, fmul64, fmul80 пишутся одним и тем же кодом, и точность будет выбираться согласно режиму FPU, а не тем, какую точность записали в ассемблере. Поэтому ставить точность после fmul не просто бессмысленно, а и вредно для читающего.

M>Может быть указание точности приводит к генерации кода, устанавливающего нужный режим работы FPU (FLDCW)?

Эээ... это замедлило бы раз в 10 по сравнению с конкурентами. Честно, даже для компилятора с такими тараканами это чересчур.
The God is real, unless declared integer.
Re[4]: Неприятное открытие
От: Michael7 Россия  
Дата: 23.04.17 11:25
Оценка:
Здравствуйте, кт, Вы писали:

кт>Я уже выкладывал этот плач Ярославны

кт>https://groups.google.com/forum/#!topic/comp.lang.asm.x86/j7wBKVUOmfI

Кстати, вас вероятно заинтересует статья "Как я сделал самый быстрый ресайз изображений. Часть 2, SIMD" https://habrahabr.ru/post/326900/ Ее автор описывает как он добился двух-трех кратного ускорения путем использования инструкций SSE2-SSE4. Что интересно, использование AVX такого большого прироста не дало, а в ряде случаев привело даже к падению производительности. Но не из-за проблем с AVX, а из-за того, что процессор Intel Core i5-4258U — ноутбучный (у вас вроде тоже) и он сбрасывает частоту при полной загрузке AVX. Причем это не тротлинг, температура так сильно не вырастала. На процессорах Xeon такого эффекта нет и там использование AVX не приводило к падению производительности.
Re[5]: Неприятное открытие
От: кт  
Дата: 23.04.17 11:29
Оценка:
Здравствуйте, Michael7, Вы писали:

M>Кстати, вас вероятно заинтересует статья "Как я сделал самый быстрый ресайз изображений. Часть 2, SIMD" https://habrahabr.ru/post/326900/ Ее автор описывает как он добился двух-трех кратного ускорения путем использования инструкций SSE2-SSE4. Что интересно, использование AVX такого большого прироста не дало, а в ряде случаев привело даже к падению производительности. Но не из-за проблем с AVX, а из-за того, что процессор Intel Core i5-4258U — ноутбучный (у вас вроде тоже) и он сбрасывает частоту при полной загрузке AVX. Причем это не тротлинг, температура так сильно не вырастала. На процессорах Xeon такого эффекта нет и там использование AVX не приводило к падению производительности.


Спасибо, обязательно учту и проверю
Re[6]: Неприятное открытие
От: Michael7 Россия  
Дата: 23.04.17 11:30
Оценка:
Здравствуйте, netch80, Вы писали:

M>>Может быть указание точности приводит к генерации кода, устанавливающего нужный режим работы FPU (FLDCW)?


N>Эээ... это замедлило бы раз в 10 по сравнению с конкурентами. Честно, даже для компилятора с такими тараканами это чересчур.


Если это делать перед каждой командой, то конечно замедлило бы и как бы не более, чем в 10. Но если один раз перед первым употреблением, а потом отслеживать изменились требования к точности или нет, то лишнего кода не будет. Я это к тому, что в принципе в указании точности некий смысл есть, хотя далеко не факт, что в обсуждаемом компиляторе так сделано.
Re[6]: Неприятное открытие
От: кт  
Дата: 23.04.17 11:37
Оценка:
Здравствуйте, netch80, Вы писали:

N>>>Я говорю про _арифметику_. fmul32, fmul64, fmul80 пишутся одним и тем же кодом, и точность будет выбираться согласно режиму FPU, а не тем, какую точность записали в ассемблере. Поэтому ставить точность после fmul не просто бессмысленно, а и вредно для читающего.

M>>Может быть указание точности приводит к генерации кода, устанавливающего нужный режим работы FPU (FLDCW)?

N>Эээ... это замедлило бы раз в 10 по сравнению с конкурентами. Честно, даже для компилятора с такими тараканами это чересчур.


честно, говоря, я вообще не понимаю, о чем речь. Вот команды загрузки
DD03                fld64 [rbx]     операнд в памяти 8 байт
D903                fld32 [rbx]     операнд в памяти 4 байта
D9C0                fld st          операнд в стеке 10 байт


Причем здесь "точность ассемблера" ? Размер операнда определяет бит в коде операции, что и показывает "неинтеллектуальный" дисассемблер
Re[7]: Неприятное открытие
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.04.17 11:40
Оценка:
Здравствуйте, кт, Вы писали:

N>>>>Я говорю про _арифметику_. fmul32, fmul64, fmul80 пишутся одним и тем же кодом, и точность будет выбираться согласно режиму FPU, а не тем, какую точность записали в ассемблере. Поэтому ставить точность после fmul не просто бессмысленно, а и вредно для читающего.

M>>>Может быть указание точности приводит к генерации кода, устанавливающего нужный режим работы FPU (FLDCW)?
N>>Эээ... это замедлило бы раз в 10 по сравнению с конкурентами. Честно, даже для компилятора с такими тараканами это чересчур.

кт>честно, говоря, я вообще не понимаю, о чем речь. Вот команды загрузки

кт>
кт>DD03                fld64 [rbx]     операнд в памяти 8 байт
кт>D903                fld32 [rbx]     операнд в памяти 4 байта
кт>D9C0                fld st          операнд в стеке 10 байт
кт>


кт>Причем здесь "точность ассемблера" ? Размер операнда определяет бит в коде операции, что и показывает "неинтеллектуальный" дисассемблер


В третий раз повторяю: fmul, а не fld! Повторите для него и убедитесь.
The God is real, unless declared integer.
Re[8]: Неприятное открытие
От: кт  
Дата: 23.04.17 11:50
Оценка:
Здравствуйте, netch80, Вы писали:

N>В третий раз повторяю: fmul, а не fld! Повторите для него и убедитесь.

повторил
 DC0B                fmul64 [rbx]  операнд в памяти 8 байт
 D80B                fmul32 [rbx]  операнд в памяти 4 байта
 DCCA                fmul st2,st0  операнды в стеке 10 байт
Re[9]: Неприятное открытие
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.04.17 12:04
Оценка:
Здравствуйте, кт, Вы писали:

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


N>>В третий раз повторяю: fmul, а не fld! Повторите для него и убедитесь.

кт>повторил
кт>
кт> DC0B                fmul64 [rbx]  операнд в памяти 8 байт
кт> D80B                fmul32 [rbx]  операнд в памяти 4 байта
кт> DCCA                fmul st2,st0  операнды в стеке 10 байт
кт>


Так, понятно. Это я недостаточно чётко объяснил, и тем запутал себя и других.

Третья форма — которую Вы назвали "операнды в стеке 10 байт" — да, работает в любом случае с _представлениями_ в 10 байт. Но в случае режимов single и double мантисса округляется не до полных 64 бит от extended, а до 24 и 53 бит соответственно. (Для порядка это не выполняется, порядок усекается уже при записи в память, поэтому число может неожиданно стать infinity.) Это то, о чём я говорил всё время — точность зависит от режима, даже если формально команда для полных 10-байтных (мантисса 64 бита).

Поэтому, если бы ваш ассемблер позволил, то "fmul32 st2, st0", "fmul64 st2, st0", "fmul80 st2, st0" превращались бы в совершенно одинаковый код инструкции и соответственно выполнялись бы процессором независимо от того, что писал ассемблер.

Первая же и вторая форма работают так: число, извлекая из памяти, расширяется до мантиссы 64 бита; выполняется операция; производится округление согласно режиму FPU (см. выше); результат кладётся в регистр. Поэтому точность исходного представления числа, взятой командой типа fmul из памяти, и точность результата (определяемая режимом FPU) никак между собой не связаны — могут быть комбинации, например, 32-80, а могут и 80-32 (берёте из памяти 10-байтное, умножаете на него, а мантисса округлена до 24 бит).

Это то, что я имел в виду. Вы вывели на этот вопрос своей репликой

кт>> В FPU реально работа идет с 80 разрядами


которая в общем случае неверна, а дальше не заметил, что у этих команд суффикс 64 связан с размером второго операнда в памяти.
The God is real, unless declared integer.
Re[10]: Неприятное открытие
От: кт  
Дата: 23.04.17 12:29
Оценка:
Здравствуйте, netch80, Вы писали:


N>а дальше не заметил, что у этих команд суффикс 64 связан с размером второго операнда в памяти.


Понятно, закрыли эту тему. Остаюсь при своем мнении, что суффиксы 32-64-80 в кодах нагляднее, чем буквы, приклеиваемые к названию команды. Там и так есть уже "p" при очистке стека. Но это дело вкуса.

Обратил внимание, что фортрановский код делает сильную зависимость в цепочке команд FPU.
А в этом трансляторе целочисленные команды (загрузки адресов в регистры) и команды FPU идут вперемежку, что теоретически лучше нагружает каналы. Хотя вряд ли об этом думали
Re[5]: Неприятное открытие
От: Privalov  
Дата: 23.04.17 12:30
Оценка:
Здравствуйте, Michael7, Вы писали:

M>А этого, по-моему, никогда не было на x86. 8-битные команды (с AH,AL, короткими переходами и прочим) выполнялись быстрее 16-ти битных, а 16-ти битные были быстрее 32-битных.


Мы когда-то работали с фортрановским кодом. ЕМНИП, 32-битовый код работал быстрее 16-битового на Pentium-90 в 95-й Винде. Компиляторы — Fortran Power Station 1.0 vs MS Fortran 5.x

M>Хотя сейчас вспомнил, что вроде как раз начиная с P6 (i686, Pentium Pro и Pentium-II) оптимизатор исполнения в процессоре стал плохо работать с 16-ти битным кодом, так что возможно сейчас он уже сильно устарел и выигрыша не будет. Но он был вплоть до первых пентиумов включительно.


На Pentium Pro 16-битовый код тормозил адски.
Re[5]: Неприятное открытие
От: кт  
Дата: 23.04.17 12:55
Оценка:
Здравствуйте, Michael7, Вы писали:

M> Между прочим, попробуйте ради любопытства запустить аналогичный 16-ти битный код в MS-DOS, не исключено, что код и сейчас будет быстрее 32-битного. Хотя сейчас вспомнил, что вроде как раз начиная с P6 (i686, Pentium Pro и Pentium-II) оптимизатор исполнения в процессоре стал плохо работать с 16-ти битным кодом, так что возможно сейчас он уже сильно устарел и выигрыша не будет. Но он был вплоть до первых пентиумов включительно.


Да пробовали по-всякому
http://rsdn.org/forum/flame.comp/6439738.flat#6439738
Автор: DOOM
Дата: 10.05.16
Re[11]: Неприятное открытие
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.04.17 14:30
Оценка:
Здравствуйте, кт, Вы писали:

кт>Понятно, закрыли эту тему. Остаюсь при своем мнении, что суффиксы 32-64-80 в кодах нагляднее, чем буквы, приклеиваемые к названию команды. Там и так есть уже "p" при очистке стека. Но это дело вкуса.


Не вы один такой вкус предпочитаете Явные обозначения размеров данных и команд как 32/64 уже есть и в LLVM IR, и в языках более высокого уровня (Rust, Swift — для рекомендованных случаев), и в ассемблерах реальных железяк (Xtensa). Видимо, к этому медленно всё ползёт.

кт>Обратил внимание, что фортрановский код делает сильную зависимость в цепочке команд FPU.

кт>А в этом трансляторе целочисленные команды (загрузки адресов в регистры) и команды FPU идут вперемежку, что теоретически лучше нагружает каналы. Хотя вряд ли об этом думали

О котором примере кода речь?
The God is real, unless declared integer.
Re[12]: Неприятное открытие
От: кт  
Дата: 23.04.17 14:54
Оценка:
Здравствуйте, netch80, Вы писали:

кт>>Обратил внимание, что фортрановский код делает сильную зависимость в цепочке команд FPU.

кт>>А в этом трансляторе целочисленные команды (загрузки адресов в регистры) и команды FPU идут вперемежку, что теоретически лучше нагружает каналы. Хотя вряд ли об этом думали

N>О котором примере кода речь?


Так вот же: следующая команда FPU не может выполниться, пока не кончится предыдущая
f03_:
        flds    globals_+12(%rip)
        fmuls   globals_+16(%rip)
        flds    globals_(%rip)
        fmuls   globals_+4(%rip)
        fmuls   globals_+8(%rip)
        fsubrp  %st, %st(1)
        fstpl   64(%rdi)
Re: Неприятное открытие
От: trop Россия  
Дата: 23.04.17 15:05
Оценка:
Здравствуйте, кт, Вы писали:
кт>Попробовал. Говорит, перетранслировал – коды стали больше (ну, это ожидаемо). А скорость стала ниже!

примерно то же было при переходе 16 на 32, fpu тогда был тормозным,
спасали только mmx операции (64 бит)
-
Re[13]: Неприятное открытие
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.04.17 15:22
Оценка: 1 (1)
Здравствуйте, кт, Вы писали:

кт>>>Обратил внимание, что фортрановский код делает сильную зависимость в цепочке команд FPU.

кт>>>А в этом трансляторе целочисленные команды (загрузки адресов в регистры) и команды FPU идут вперемежку, что теоретически лучше нагружает каналы. Хотя вряд ли об этом думали

N>>О котором примере кода речь?


кт>Так вот же: следующая команда FPU не может выполниться, пока не кончится предыдущая

кт>
кт>f03_:
кт>        flds    globals_+12(%rip)
кт>        fmuls   globals_+16(%rip)
кт>        flds    globals_(%rip)
кт>        fmuls   globals_+4(%rip)
кт>        fmuls   globals_+8(%rip)
кт>        fsubrp  %st, %st(1)
кт>        fstpl   64(%rdi)
кт>


В процессорах есть специальный блок развязываний таких зависимостей на стеках — это включает и обычные push/pop, и FPU. То есть в этой последовательности сначала fld разлагается на пару сдвиг указателя стека + загрузка, а потом загрузки выполняются раздельно для регистров, уже отвязанных от этого идиотского стека, в независимые физические регистры. Поэтому все загрузки могут выполняться параллельно, а между операциями устанавливается своя система зависимостей.
The God is real, unless declared integer.
Re[14]: Неприятное открытие
От: кт  
Дата: 23.04.17 16:06
Оценка:
Здравствуйте, netch80, Вы писали:

N>В процессорах есть специальный блок развязываний таких зависимостей на стеках — это включает и обычные push/pop, и FPU. То есть в этой последовательности сначала fld разлагается на пару сдвиг указателя стека + загрузка, а потом загрузки выполняются раздельно для регистров, уже отвязанных от этого идиотского стека, в независимые физические регистры. Поэтому все загрузки могут выполняться параллельно, а между операциями устанавливается своя система зависимостей.


Не знаю, не знаю. Здесь операции зависят от результата предыдущих. Пока не кончилось умножение нельзя начинать сложение. А в том коде есть физически и логически развязанные операции.
Re: Неприятное открытие
От: fin_81  
Дата: 23.04.17 17:49
Оценка: -1
Здравствуйте, кт, Вы писали:

кт>...

кт>Процессор Intel Core i5-3210M 2.5 GHz. Стоит Windows-7.
кт>... скорость упала на 20.5% ...

Частота процессора может гулять больше чем на 20%, включая отключение вычислительных блоков по желанию левой пятки. Сперва надо добиться, что окружение не зависит от фазы луны. Потом профилировать.
Re[2]: Неприятное открытие
От: кт  
Дата: 23.04.17 18:05
Оценка:
Здравствуйте, fin_81, Вы писали:

_>Частота процессора может гулять больше чем на 20%, включая отключение вычислительных блоков по желанию левой пятки. Сперва надо добиться, что окружение не зависит от фазы луны. Потом профилировать.


проверено на нескольких разных вариантах расчетов, которые считались по несколько минут. Цифры не меняются, всегда около 20%
Re[15]: Неприятное открытие
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.04.17 18:11
Оценка:
Здравствуйте, кт, Вы писали:

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


N>>В процессорах есть специальный блок развязываний таких зависимостей на стеках — это включает и обычные push/pop, и FPU. То есть в этой последовательности сначала fld разлагается на пару сдвиг указателя стека + загрузка, а потом загрузки выполняются раздельно для регистров, уже отвязанных от этого идиотского стека, в независимые физические регистры. Поэтому все загрузки могут выполняться параллельно, а между операциями устанавливается своя система зависимостей.


кт>Не знаю, не знаю. Здесь операции зависят от результата предыдущих. Пока не кончилось умножение нельзя начинать сложение. А в том коде есть физически и логически развязанные операции.


Если "тот код" это от вашего странного компилятора, там те же зависимости, плюс вызов подпрограммы, который ещё утяжеляет.
А "разбавление" адресацией, которая не нужна, суммарное время работы блока не сократит.
(Странно, что это приходится объяснять.)
The God is real, unless declared integer.
Re[3]: Неприятное открытие
От: fin_81  
Дата: 23.04.17 18:23
Оценка: -1
Здравствуйте, кт, Вы писали:

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


_>>Частота процессора может гулять больше чем на 20%, включая отключение вычислительных блоков по желанию левой пятки. Сперва надо добиться, что окружение не зависит от фазы луны. Потом профилировать.


кт>проверено на нескольких разных вариантах расчетов, которые считались по несколько минут. Цифры не меняются, всегда около 20%


Эти мобильные процессоры по желанию левой пятки могут отключить турбобуст при 64бит расчетах, при использовании sse, fpu или определенной комбинации, чтобы уложиться в свои 30 ватт и случайно не сжечь какой-нибудь блок. Логику энергосбережения тоже люди писали.
Re[16]: Неприятное открытие
От: кт  
Дата: 23.04.17 18:26
Оценка:
Здравствуйте, netch80, Вы писали:

N>Если "тот код" это от вашего странного компилятора, там те же зависимости, плюс вызов подпрограммы, который ещё утяжеляет.

N>А "разбавление" адресацией, которая не нужна, суммарное время работы блока не сократит.
N>(Странно, что это приходится объяснять.)

Неочевидно. Вызов подпрограммы увеличивает время, но уплотняет код, меньше выборок при декодировании.
И загрузка регистров дает выигрыш, в выражениях часто встречаются одни и те же переменные и тогда регистр загружается один раз и опять последующий код упрощается и декодирование адреса в команде (в том числе и через RIP) уже не требуется.
Re: Скорость в 64 битах (Re: Неприятное открытие)
От: Философ Ад http://vk.com/id10256428
Дата: 23.04.17 22:23
Оценка:
Здравствуйте, netch80, Вы писали:

А что не так с FPU под 64 бита? Где об этом читать?
Когда-то читал Intel Optimization Reference Manual, но что-то не припомню такого.
Всё сказанное выше — личное мнение, если не указано обратное.
Re: Неприятное открытие
От: Философ Ад http://vk.com/id10256428
Дата: 23.04.17 22:33
Оценка:
Здравствуйте, кт, Вы писали:

кт>Я читал (и считал), что теперь 64-разряда – это «родной» режим, а 32-разряда оставлен для совместимости. А вот по этому тесту выходит наоборот



Это не по тесту выходит, это следует из документации:

9.2.1 Use Legacy 32-Bit Instructions When Data Size Is 32 Bits

64-bit mode makes 16 general purpose 64-bit registers available to applications. If application data size
is 32 bits, there is no need to use 64-bit registers or 64-bit arithmetic.
The default operand size for most instructions is 32 bits. The behavior of those instructions is to make
the upper 32 bits all zeros. For example, when zeroing out a register, the following two instruction
streams do the same thing, but the 32-bit version saves one instruction byte:
32-bit version:

xor eax, eax; Performs xor on lower 32bits and zeroes the upper 32 bits.

64-bit version:
xor rax, rax; Performs xor on all 64 bits.

This optimization holds true for the lower 8 general purpose registers: EAX, ECX, EBX, EDX, ESP, EBP,
ESI, EDI. To access the data in registers R9-R15, the REX prefix is required. Using the 32-bit form there
does not reduce code size.


У тебя вряд ли менялся размер данных при переходе на 64 бита, но в твоих листингах почему-то фигурируют 64-е регисты, а не 32. В чём дело?
Всё сказанное выше — личное мнение, если не указано обратное.
Re[2]: Неприятное открытие
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 24.04.17 03:58
Оценка:
Здравствуйте, Философ, Вы писали:

кт>>Я читал (и считал), что теперь 64-разряда – это «родной» режим, а 32-разряда оставлен для совместимости. А вот по этому тесту выходит наоборот

Ф>Это не по тесту выходит, это следует из документации:

Это таки вопрос спорный. Что для 64 бит надо ставить префиксы — в принципе ни на что, кроме размера кода, влиять не должно. Но само построение документации Intel, где с одной стороны 32 бита это legacy mode, а с другой — у большинства команд описание сначала для 32, а потом корректировки для 64, смущает.

Ф>У тебя вряд ли менялся размер данных при переходе на 64 бита, но в твоих листингах почему-то фигурируют 64-е регисты, а не 32. В чём дело?


Кстати да.
В записи типа

001379 BB58020000         mov  q rbx,offset STH2
00137E DC0B               fmul64[rbx]


видно, что команда занимает 5 байт; по opcode table это "mov r32, imm32" для ebx, и тут один байт кода и 4 байта константы; любой нормальный ассемблер записал бы это как загрузку ebx. А этот не просто говорит про rbx, но ещё и "mov q". Хотя для такого "mov q rbx" есть последовательность 48 BB и последующих 8 байтов.
Ещё один камешек в копилку странностей.

Я всё-таки бы на месте ТС без профилирования этого кода сюда всерьёз не приходил. Мало ли где реальные тормоза окажутся, очень часто они не там, где кажется на первый взгляд, даже после оценки "вот таких блоков больше всего"...
The God is real, unless declared integer.
Re[17]: Неприятное открытие
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 24.04.17 04:34
Оценка:
Здравствуйте, кт, Вы писали:

N>>Если "тот код" это от вашего странного компилятора, там те же зависимости, плюс вызов подпрограммы, который ещё утяжеляет.

N>>А "разбавление" адресацией, которая не нужна, суммарное время работы блока не сократит.
N>>(Странно, что это приходится объяснять.)

кт>Неочевидно. Вызов подпрограммы увеличивает время, но уплотняет код, меньше выборок при декодировании.


Это если объём исполняемого в подпрограмме кода большой. Что такого хитрого в этой fused multiply and subtract у вашего компилятора, что не укладывается в пару fmul + fsub? Он что, софтово выполняет её с большей точностью? Заранее не верю. А если там такие две команды FPU плюс обвязка, то для всех было бы дешевле записать их напрямую.

кт>И загрузка регистров дает выигрыш, в выражениях часто встречаются одни и те же переменные и тогда регистр загружается один раз и опять последующий код упрощается и декодирование адреса в команде (в том числе и через RIP) уже не требуется.


О какой загрузке "один раз" речь? Если про все эти "offset SPS2", то сильно непохоже, чтобы компилятор это использовал — он тупо хватает первый свободный регистр из rbx и rdx, не заботясь о том, что было за предыдущее значение. И это я не вспоминаю, что по сравнению с ценой плавучей арифметической операции (которая минимум 4 такта в любой реализации) цена подсчёта RIP+смещение ничтожна, на скорость потока не повлияет.
The God is real, unless declared integer.
Re[2]: Неприятное открытие
От: alexzzzz  
Дата: 24.04.17 14:39
Оценка: +2
Здравствуйте, кт, Вы писали:

кт>А речь о том, что почти ОДИНАКОВЫЕ последовательности команд в 64-разрядном режиме работают на 20% медленнее, чем в они же 32 разрядном режиме.

кт>Хотя по идее должны были бы работать ТАК ЖЕ (плохо или хорошо, это уже второй вопрос)

В общем случае код под х64 длиннее, данные длиннее (как минимум указатели), а объём кэша какой был, такой остался. Если вариант х64 не использует в вычислениях дополнительно доступные регистры, то быстрее он не будет, а медленнее — легко.
Re: Разобрался. Вопрос закрыт.
От: кт  
Дата: 01.05.17 05:54
Оценка: 1 (1) +1
Все-таки разобрался с работой программы в 32 и 64 разрядах.
Нет никакого замедления. В системной подпрограмме для 64 разрядов оказались дополнительные действия, они-то и вызывали замедление, причем никак не связанные с FPU и вычислениями.

В 64-разрядной NTDLL при вызове обработчика исключений пользователя стоит проверка, что RSP должен быть кратен 8. Следствием этой проверки является, что если в программе произошло исключение, а в этот момент указатель стека в допустимых границах, но не кратен 8, то такое исключение не перехватывается в программе, а она принудительно оканчивается с системным сообщением.
Чтобы не было таких участков кода, когда нельзя перехватить исключение, в программе выполняется ряд действий, чтобы объекты с длиной не кратной 8 размещались в стеке всегда по адресу кратному 8. Хотя вообще-то самому процессору наплевать на кратность стека, да и стек обычно тут же возвращается в исходное.

В данной программе результаты вычислений пишутся и в виде текстовых строк, передаваемых через стек. Требуется выбросить один байт из строки в стеке слева. Когда в NTDLL не было дурацкой проверки, это можно было сделать в подпрограмме как-то так:
pop rbx ; достали адрес возврата
add rsp,1; обрезали строку в стеке слева на байт
jmp rbx ; вернулись с обрезанной строкой в стеке

Далее где-то из стека извлекается побайтно эта строка известной (уменьшенной) длины и стек возвращается в исходной состояние.
В 32-х разрядном режиме примерно так и работало. Теперь же требуется еще подвинуть в стеке в данном случае на байт всю строку влево, чтобы справа оказался «пустой» байт и указатель стека остался кратным 8.

Сделал результирующую строку кратной 8, дополнительные пересылки исчезли, и скорость выполнения в 32 и 64 разрядах стала практически одинаковая. Ну и слава богу.
Re[2]: Разобрался. Вопрос закрыт.
От: Michael7 Россия  
Дата: 01.05.17 10:36
Оценка:
Здравствуйте, кт, Вы писали:

кт>Сделал результирующую строку кратной 8, дополнительные пересылки исчезли, и скорость выполнения в 32 и 64 разрядах стала практически одинаковая. Ну и слава богу.


Глубоко копнул. Приятно читать такое.
Правда непонятно, зачем такое выравнивание нужно ntdll, если процессору все-равно. Неужто вот так просто остался код для архитектур, где это требовалось.
Re[3]: Разобрался. Вопрос закрыт.
От: кт  
Дата: 01.05.17 11:33
Оценка:
Здравствуйте, Michael7, Вы писали:

M>Правда непонятно, зачем такое выравнивание нужно ntdll, если процессору все-равно. Неужто вот так просто остался код для архитектур, где это требовалось.


Хрен его знает зачем так. Вот было расследование.
http://files.rsdn.org/122727/pl1ex21.doc
Re[3]: Разобрался. Вопрос закрыт.
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 01.05.17 13:27
Оценка:
Здравствуйте, Michael7, Вы писали:

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


кт>>Сделал результирующую строку кратной 8, дополнительные пересылки исчезли, и скорость выполнения в 32 и 64 разрядах стала практически одинаковая. Ну и слава богу.


M>Глубоко копнул. Приятно читать такое.

M>Правда непонятно, зачем такое выравнивание нужно ntdll, если процессору все-равно. Неужто вот так просто остался код для архитектур, где это требовалось.

Ну SysV ABI требует выравнивания даже не на 8, а на 16 байт, и где-то даже это проверяется. Выравнивание важно потому, что могут использоваться команды типа movdqa, да и просто быстрее с ним.
The God is real, unless declared integer.
Re[4]: Разобрался. Вопрос закрыт.
От: ononim  
Дата: 01.05.17 13:32
Оценка:
M>>Глубоко копнул. Приятно читать такое.
M>>Правда непонятно, зачем такое выравнивание нужно ntdll, если процессору все-равно. Неужто вот так просто остался код для архитектур, где это требовалось.
N>Ну SysV ABI требует выравнивания даже не на 8, а на 16 байт, и где-то даже это проверяется. Выравнивание важно потому, что могут использоваться команды типа movdqa, да и просто быстрее с ним.
В x64 calling convention выравнивание стека так же 16 байт. Выравнивание 8 байт — это неявное требование к каждой инструкции _внутри_ функции. То есть нельзя делать sub/add rsp, _non-8-byte-aligned_. То есть сделать то так можно, но если при этом случится исключение — ось выплюнет вашу программу
Как много веселых ребят, и все делают велосипед...
Отредактировано 01.05.2017 13:33 ononim . Предыдущая версия .
Re[5]: stack align
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 01.05.17 13:41
Оценка:
Здравствуйте, ononim, Вы писали:

M>>>Глубоко копнул. Приятно читать такое.

M>>>Правда непонятно, зачем такое выравнивание нужно ntdll, если процессору все-равно. Неужто вот так просто остался код для архитектур, где это требовалось.
N>>Ну SysV ABI требует выравнивания даже не на 8, а на 16 байт, и где-то даже это проверяется. Выравнивание важно потому, что могут использоваться команды типа movdqa, да и просто быстрее с ним.
O>В x64 calling convention выравнивание стека так же 16 байт.

Лучше говорить "Microsoft x86-64 calling convention", а то в наших краях x64 это "любое 64-битное", вплоть до ARM
И да, я имел в виду SysV x86-64 ABI (которое приняли все известные юниксы) и на границах вызова функций (внутри функции ослабляется — требуется только кратность 8).

O> Выравнивание 8 байт — это неявное требование к каждой инструкции _внутри_ функции. То есть нельзя делать sub/add rsp, _non-8-byte-aligned_.


Точно так же.

Но: тут говорят про обязательность поддержки 16-байтной границы — вот этого я не понял. Зато тут ни слова про 16-байтную границу даже при вызове функции. Кому верить?
The God is real, unless declared integer.
Re[6]: stack align
От: ononim  
Дата: 01.05.17 14:01
Оценка:
N>Но: тут говорят про обязательность поддержки 16-байтной границы — вот этого я не понял. Зато тут ни слова про 16-байтную границу даже при вызове функции. Кому верить?
Ну 16-байтовая в пределах функции — бред, а при вызове — суровая необходимость, которую я в свое время обнаружил на практике, когда после обхучивания функций стал получать рандомные краши в тех самых movdqa.
Как много веселых ребят, и все делают велосипед...
Re[3]: Разобрался. Вопрос закрыт.
От: ononim  
Дата: 01.05.17 14:18
Оценка:
M>Глубоко копнул. Приятно читать такое.
M>Правда непонятно, зачем такое выравнивание нужно ntdll, если процессору все-равно. Неужто вот так просто остался код для архитектур, где это требовалось.
Процессору не все равно, он быстрее работает с выровненными данными. Для арма (когда разрешены обращения по неровным адресам) это прямо по тактам документировано, а с интелом все запутанно. Но вот давече Чен схожую тему описал.
Как много веселых ребят, и все делают велосипед...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.