Производительность 2.0 vs 1.010
Модератор: Модераторы
-
anotherche
anotherche писал(а): Код тестовой программы (просто длинный цикл с вещественными вычислениями), откомпилированный с одинаковыми опциями исполняется на 20%(atlon) - 100%(p4) медленней. Почему?
Это разница между чем и чем?
А ОС какая?
Я правильно понял - один код был собран fpc 2.0.0 и fpc 1.010 и затем оба ипоняемых модуля были запущены на ПК с Atlon и ПК с P4 ?
А можно пример кода?
-
anotherche
Программа была написана давно (видно, что со времен 486-х). Написана, как видно, большим пальцем левой ноги. Но для единообразия тестирования всех последующих конфигураций, она не модифицировалась (разве что длина внешнего цикла увеличивалась так, чтобы общее время счета было порядка секунд).
да, все так.
Это разница между чем и чем?...
Я правильно понял - один код был собран fpc 2.0.0 и fpc 1.010 и затем оба ипоняемых модуля были запущены на ПК с Atlon и ПК с P4 ?
да, все так.
Код: Выделить всё
program Test_PC;
uses crt,dos{,graph};
Var i,j,k, itnum : Longint;
c,dT : double;
{##################################################}
Function Time : double;
Var Ho,Mi,Se,Se1 : word; dH,dM,dS,dS1 : double;
begin
GetTime(Ho,Mi,Se,Se1); dH:=Ho; dM:=Mi; dS:=Se; dS1:=Se1;
Time:=(3600.0*dH +60.0*dM +dS +0.01*dS1); end;
{########################################}
begin
itnum:=30;
WriteLn('############### ',' Test of PC ,DOS',' ###############');
WriteLn('Time for PC 486 133 Mhz, Real = ',16.53:15:9,' Sec');
WriteLn('Time for PC PENTIUM 150 Mhz, Real = ', 5.93:15:9,' Sec');
WriteLn('Time for PC PENTIUM(1) 166 Mhz, Real = ', 5.10:15:9,' Sec');
WriteLn('Time for PC PENTIUM-2 233 Mhz, Real = ', 4.61:15:9,' Sec');
WriteLn('Time for PC Celeron 400 Mhz, Real = ', 2.74:15:9,' Sec');
WriteLn('Time for PC PENTIUM 225 Mhz, Real = ', 2.69:15:9,' Sec');
WriteLn('Time for PC Celeron 333 Mhz, Real = ', 3.24:15:9,' Sec');
WriteLn('Time for PC 486 133 Mhz, Protect= ',21.69:15:9,' Sec');
WriteLn('Time for PC PENTIUM 150 Mhz, Protect= ',12.69:15:9,' Sec');
WriteLn('Time for PC PENTIUM(1) 166 Mhz, Protect= ',11.64:15:9,' Sec');
WriteLn('Time for PC PENTIUM-2 233 Mhz, Protect= ',10.11:15:9,' Sec');
WriteLn('Time for PC Celeron 400 Mhz, Protect= ', 5.66:15:9,' Sec');
WriteLn('Time for PC PENTIUM 225 Mhz, Protect= ', 5.33:15:9,' Sec');
WriteLn('Time for PC Celeron 333 Mhz, Protect= ', 6.81:15:9,' Sec');
WriteLn('Time for PC Athlon XP 1700 Mhz, Protect= ', 0.72:15:9,' Sec');
WriteLn(' Time for FREE PASCAL');
WriteLn('Time for PC Athlon 2000 Mhz, Protect= ', 0.160:15:9,' Sec');
WriteLn('Time for PC Intel 3150 Mhz, Protect= ', 0.118:15:9,' Sec');
WriteLn('Time for PC Intel 3300 Mhz, Protect= ', 0.113:15:9,' Sec');
WriteLn('Time for PC Athlon XP 2800+Mhz, Protect= ', 0.150:15:9,' Sec');
dT:=Time;
c:=0.0;
For k:=1 to itnum do begin
For j:=1 to 33 do begin
For i:=1 to 12345 do begin
c:=c +Ln(0.12*(i+j+k)) +sqrt(0.19*(i+j+k)) +exp(Ln(0.26*(i+j+k))) +sin((i+j+k)*0.34) +cos((i+j+k)*0.77);
end;
end;
end;
dT:=Time-dT;
WriteLn('Time for this PC = ',dT/itnum:15:9,' Sec');
Repeat Until KeyPressed;
end.
ОС FreeBSD
P III, 866Мгц
FPC 1.0.10:
FPC 2.0.0:
Сначала порадовался потом позапускав несколько раз и получив очень(!!!) разные результаты понял, что тест не объективен для многозадачных систем.
P III, 866Мгц
FPC 1.0.10:
Код: Выделить всё
############### Test of PC ,DOS ###############
...
Time for this PC = 0.331333333 SecFPC 2.0.0:
Код: Выделить всё
############### Test of PC ,DOS ###############
...
Time for this PC = 0.318666667 SecСначала порадовался потом позапускав несколько раз и получив очень(!!!) разные результаты понял, что тест не объективен для многозадачных систем.
-
anotherche
Сначала порадовался потом позапускав несколько раз и получив очень(!!!) разные результаты понял, что тест не объективен для многозадачных систем.
Конечно, все это понятно. Но вся эта многозадачность, она же управляема. Выключаешь все, что мешает и вперед. Ошибка конечно будет всегда, но не катастрофичная. У меня она никогда не была хуже чем во втором знаке. Так что разницу в 20%, а тем более в 2 раза видно очень хорошо.
Судя по Вашему результату наблюдается тенденция - чем длиннее конвеер у процессора тем больше падение производительности.
Вы бы asm-код сравнили, что ли... Благо, можно попросить компилятор его сохранить
Сравнил. Я, честно говоря, с ассемблером не на ты, но случай кажется простым. Отличия небольшие. Мне кажется, что основная разница из-за того, что в случае fpc_2.0.0 в конце цикла вставляется команда wait. Как я понял она ждет пока сопроцессор чего-то там доделает (хотя вроде как эта команда означает разное для старых и новых процессоров и у новых это что-то связанное с исключениями).
Ну вот пример (он не для исходного кода, а для кода попроще, для наглядности). Это кусок кода, соответсвующий только циклу
Код: Выделить всё
For j:=1 to 10000 do begin
For i:=1 to 10000 do begin
c:=c +Ln((i+j)*0.001);
end;
end;
ассемблер, выданный fpc_1.0.6 (десятой у меня не было на тот момент)
Код: Выделить всё
;[9] For j:=1 to 10000 do begin
movl $1,_J
.balign 4,144
.L8:
; Register %eax allocated
; [10] For i:=1 to 10000 do begin
movl $1,_I
.balign 4,144
.L13:
; Register %eax allocated
; [11] c:=c +Ln((i+j)*0.001);
movl _I,%eax
addl _J,%eax
pushl %eax
; Register %eax released
fildl (%esp)
; Register %edi allocated
popl %edi
; Register %edi released
fldt .L18 ; это коэффициент 0.001
fmulp %st,%st(1)
fldln2
fxch
fyl2x
faddl _C
fstpl _C
; Register %eax allocated
cmpl $10000,_I
jge .L12
incl _I
jmp .L13
; Register %eax released
.L12:
; Register %eax allocated
cmpl $10000,_J
jge .L7
incl _J
jmp .L8
а вот то, что дал fpc_2.0.0
Код: Выделить всё
; [9] For j:=1 to 10000 do begin
movl $1,U_P$MYTEST_J
decl U_P$MYTEST_J
.balign 4
.L8:
incl U_P$MYTEST_J
; [10] For i:=1 to 10000 do begin
movl $1,U_P$MYTEST_I
decl U_P$MYTEST_I
.balign 4
.L11:
incl U_P$MYTEST_I
; Register %eax allocated
; [11] c:=c +Ln((i+j)*0.001);
movl U_P$MYTEST_I,%eax
addl U_P$MYTEST_J,%eax
; Temp -4,4 allocated
movl %eax,-4(%ebp)
; Register %eax released
fildl -4(%ebp)
; Temp -4,4 released
fldt _$PROGRAM$_L14 ; это коэффициент 0.001
fmulp %st,%st(1)
fldln2
fxch
fyl2x
faddl U_P$MYTEST_C
fstpl U_P$MYTEST_C
fwait ; а вот он wait
cmpl $10000,U_P$MYTEST_I
jl .L11
cmpl $10000,U_P$MYTEST_J
jl .L8
видны и другие отличия (правда мне думается они не принципиальные), и вот почему я грешу на wait. Приведенный код работает с одинаковой скоростью. И если вместо логарифма поставить синус, косинус или корень тоже все работает с одинаковой скоростью. Но вот если взять экспоненту, тут то все и начинается. Скорость падает почти вдвое. Экспонента, в отличие от остальных функций там вызывается не прямо (не как операция процессора), а как подпрограмма (где-то зашитая в freepascal), так что ее пришлось смотреть через IDA. Так вот, там видно, что опять таки отличие кода выдаваемого 106 от 200 заключается в инструкциях wait, их там несколько (кажется три, сейчас не помню точно).
Кто понимает? Действительно ли дело в wait-ах? Зачем fpc2.0.0 добавляет их в код? Может ли fpc компилировать свой asm листинг? (хочется проверить - убрать wait-ы из листинга сделанного в 2.0.0 и скомпилировать результат)
-
Илья Аввакумов
- новенький
- Сообщения: 50
- Зарегистрирован: 04.05.2005 15:06:42
- Откуда: Екатеринбург
-
anotherche
В древности (8088) команда привыполнении инструкции fwait сопроцессор ждал, когда основной процессор будет готов принять данные от сопроцессора (не уверен, так как воспроизвожу по памяти, а было это ой как давно) Я был уверен, что сейчас эта команда не используется.
по уточненным сведениям она теперь используется как запрос на возникновение исключения при вещественных вычислениях . То есть в принципе компилятор прав, он предлагает код который в случае чего вызовет исключение сразу после его возникновения (иначе это происходит при следующем вещественном вычислении, а оно может произойти очень далеко от точки ошибки), но опять же он не прав
-
anotherche
Все, я разобрался в вопросе. Проверил напрямую - собрал из ассемблера два варианта с wait'ами и без них. И оказалось... что wait здесь ни при чем
. А виновата одна инструкция в коде вычисления экспоненты. Впрочем эта инструкция тоже связана с обработкой исключений.
Вот экспонента, которую делает fpc_106
А вот fpc_200
Инструкция fclex очищает флаги исключений в регистре Status Word и очищение это как видно отнимает нимало производительности (на p4 замедление счета в 2 раза). Похоже, что в 2.0.0 просто перестраховываются при расчете экспоненты.
Вот экспонента, которую делает fpc_106
Код: Выделить всё
fn_exp proc
push ebp
mov ebp,esp
fld tbyte ptr [ebp+8]
fldl2e
fmulp st(1),st
fstcw tmpcw1
fstcw tmpcw2
and tmpcw2,0F3FFh
or tmpcw2,400h
fldcw tmpcw2
fld st(0)
frndint
fldcw tmpcw1
fxch st(1)
fsub st,st(1)
f2xm1
fld1
faddp st(1),st
fscale
fstp st(1)
jmp loc_004027A5
loc_004027A5:
leave
ret 0Ch
fn_exp endp
А вот fpc_200
Код: Выделить всё
fn_exp proc
push ebp
mov ebp,esp
sub esp,0Ch
fld tbyte ptr [ebp+8]
fldl2e
fmulp st(1),st
fstcw tmpcw1
fstcw tmpcw2
wait
and tmpcw2,0F3FFh
or tmpcw2,400h
fldcw tmpcw2
fld st(0)
frndint
fldcw tmpcw1
fxch st(1)
fsub st,st(1)
f2xm1
fld1
faddp st(1),st
fscale
fstp st(1)
fclex
jmp loc_004027A5
loc_004027A5:
leave
ret 0Ch
fn_exp endp
Инструкция fclex очищает флаги исключений в регистре Status Word и очищение это как видно отнимает нимало производительности (на p4 замедление счета в 2 раза). Похоже, что в 2.0.0 просто перестраховываются при расчете экспоненты.
