Затем изменим код, таким образом, чтобы X загружался только один раз.
Code: |
function ArcSinApprox3f(X, A, B, C, D : Double) : Double; asm //Result := ((A*X + B)*X + C)*X + D; fld qword ptr [ebp+$20] fld qword ptr [ebp+$28] fxch //fmul qword ptr [ebp+$28] fmul st(0),st(1) fadd qword ptr [ebp+$18] //fmul qword ptr [ebp+$28] fmul st(0),st(1) fadd qword ptr [ebp+$10] //fmul qword ptr [ebp+$28] fmul st(0),st(1) ffree st(1) fadd qword ptr [ebp+$08] wait end; |
Данная функция получила 47226 пункта и без изменения производительности.
Инструкция FFREE может быть удалена, за счет использования инструкции FMULP вместо FMUL, но для этого мы должны сменить два используемых регистра. Только эти два регистра используются и A*B = B*A, так что нет проблем сделать это. Этим мы не удаляем некоторую избыточность, и оба пути дают одинаковый результат.
Code: |
function ArcSinApprox3g(X, A, B, C, D : Double) : Double; asm //Result := ((A*X + B)*X + C)*X + D; fld qword ptr [ebp+$20] fld qword ptr [ebp+$28] fxch st(1) fmul st(0),st(1) fadd qword ptr [ebp+$18] fmul st(0),st(1) fadd qword ptr [ebp+$10] //fmul st(0),st(1) fmulp st(1),st(0) //ffree st(1) fadd qword ptr [ebp+$08] wait end; |
Данная реализация получила 47416 пункта.
Затем мы удалим инструкцию WAIT.
Code: |
function ArcSinApprox3h(X, A, B, C, D : Double) : Double; asm //Result := ((A*X + B)*X + C)*X + D; fld qword ptr [ebp+$20] fld qword ptr [ebp+$28] fxch st(1) fmul st(0),st(1) fadd qword ptr [ebp+$18] fmul st(0),st(1) fadd qword ptr [ebp+$10] fmulp st(1),st(0) fadd qword ptr [ebp+$08] //wait end; |
Теперь функция получила 47059 пункта.
Последняя вещь, которую мы сделаем, это строки, производящие загрузку X и A, и удалим инструкцию FXCH.
Code: |
function ArcSinApprox3i(X, A, B, C, D : Double) : Double; asm //Result := ((A*X + B)*X + C)*X + D; fld qword ptr [ebp+$28] fld qword ptr [ebp+$20] //fld qword ptr [ebp+$28] //fxch st(1) fmul st(0),st(1) fadd qword ptr [ebp+$18] fmul st(0),st(1) fadd qword ptr [ebp+$10] fmulp st(1),st(0) fadd qword ptr [ebp+$08] end; |
Эта реализация функции получила 46544 и производительность упала!
Теперь сравним производительность по версии Хорнера с функцией, получившей наибольшую производительность на P4.
ArcSinApprox1g 47939
ArcSinApprox3g 47416
На P3
ArcSinApprox1h 85361
ArcSinApprox3h 87604
Различие не большое, но обычная функция немного быстрее на P4 и медленнее на P3. Обычная функция имеет больше вычисление, но параллелизм это сгладил. Вариант Хорнера имеющий маленький параллелизм и латентность проявляется в полной мере. Это особо плохо на P4.
Держим это в уме и продолжаем с третьим решением, которое выглядит так.
Code: |
function ArcSinApprox4b(X, A, B, C, D : Double) : Double; begin { push ebp mov ebp,esp add esp,-$08 } Result := (A*X + B)*(X*X)+(C*X + D); { fld qword ptr [ebp+$20] fmul qword ptr [ebp+$28] fadd qword ptr [ebp+$18] fld qword ptr [ebp+$28] fmul qword ptr [ebp+$28] fmulp st(1) fld qword ptr [ebp+$10] fmul qword ptr [ebp+$28] fadd qword ptr [ebp+$08] faddp st(1) fstp qword ptr [ebp-$08] wait fld qword ptr [ebp-$08] } { pop ecx pop ecx pop ebp } end; |
Опыт уже позволяет нам сделать это просто и быстро ;-)
Данная версия сделана так, как это сделала Delphi
Code: |
function ArcSinApprox4c(X, A, B, C, D : Double) : Double; asm //push ebp //mov ebp,esp add esp,-$08 //Result := (A*X + B)*(X*X)+(C*X + D); fld qword ptr [ebp+$20] fmul qword ptr [ebp+$28] fadd qword ptr [ebp+$18] fld qword ptr [ebp+$28] fmul qword ptr [ebp+$28] fmulp //st(1) fld qword ptr [ebp+$10] fmul qword ptr [ebp+$28] fadd qword ptr [ebp+$08] faddp //st(1) fstp qword ptr [ebp-$08] wait fld qword ptr [ebp-$08] pop ecx pop ecx //pop ebp end; |
Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.
ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!