Содержание материала

 

 

Теперь функция получила 45393 пункта, и производительность изменилась на 3%. FXCH действительно ни причем, поскольку производительность опять ушла вниз. В чем же дело?

Инструкция WAIT была рассмотрена в более раннем уроке, и в данный момент мы просто удалим ее.

Code:

function ArcSinApprox1j(X, A, B, C, D : Double) : Double;

asm

//Result := A*X*X*X + B*X*X + C*X + D;

fld   qword ptr [esp+$28]

fld   qword ptr [esp+$20]

fmul  st(0),st(1)

fmul  st(0),st(1)

fmul  st(0),st(1)

fld   qword ptr [esp+$18]

fmul  st(0),st(2)

fmul  st(0),st(2)

faddp

fld   qword ptr [esp+$10]

fmul  st(0),st(2)

ffree st(2)

faddp

fadd  qword ptr [esp+$08]

//wait

end;

 

Производительно упала до 44140.

Посмотрим эти удивляющие нас результаты на процессоре P3.

ArcSinApprox1a         63613

ArcSinApprox1b         64412

ArcSinApprox1c         64433

ArcSinApprox1d         65062

ArcSinApprox1e         64830

ArcSinApprox1f         62598

ArcSinApprox1g         79586

ArcSinApprox1h         85361

ArcSinApprox1i         80515

ArcSinApprox1j         80192

Во-первых, видим, что вариант ArcSinApprox1h самый быстрый на P3. Поэтому видно, что загрузка данных из кэш памяти L1 более ощутима на P3, чем на P4, поскольку изменение кода, такое как одноразовая загрузка X дало существенное улучшение производительности на P3, и почти нет на P4. С другой стороны мы можем также сказать, что получение данных из кэш памяти всегда медленнее, чем получение из внутренних регистров. P4 имеет быструю кэш память уровня L1, которая читается только за 2 такта, но внутренние регистры еще быстрее, только один такт. Мы также видим, что P3 на частоте 1400 примерно на 80% быстрее, чем P4 на частоте 1920 в данном коде. Мы знаем, что латентность на P3 короче, но этого недостаточно для объяснения такой большой разницы.

Латентность и ускорение (throughput) по использованным регистрам на P3

FADD latency is 3 clock cycles and throughput is 1

FMUL latency is 5 clock cycles and throughput is 1

На P4

FADD latency is 5 clock cycles and throughput is 1

FMUL latency is 7 clock cycles and throughput is 2

Я не смог найти данных для FLD

Объяснение плохой производительности P4 в данном коде состоит в 2-тактном сквозном проходе по конвейеру (throughput) для FMUL, совместно с медленным доступом до FP регистров процессора. Конвейер FMUL получает доступ до следующей инструкции только за два такта, тогда как P3 за один такт.

Нормализованный к частоте результат

47939 / 1920 = 25

85361 / 1400 = 61

разоблачает, что при приведении частот процессор P3 примерно в 2.5 раза быстрее P4. Это вызывает подлинное удивление. Чтобы P4 имел некоторые шансы, по отношению к P 3, нам мы должны убрать некоторые умножения. Это получается в функции по версии Хорнера.

Code:

function ArcSinApprox3a(X, A, B, C, D : Double) : Double;

begin

Result := ((A*X + B)*X + C)*X + D;

end;

 

 

Это компилируется в

Code:

function ArcSinApprox3b(X, A, B, C, D : Double) : Double;

begin

{

push ebp

mov  ebp,esp

add  esp,-$08

}

Result := ((A*X + B)*X + C)*X + D;

{

fld  qword ptr [ebp+$20]

fmul qword ptr [ebp+$28]

fadd qword ptr [ebp+$18]

fmul qword ptr [ebp+$28]

fadd qword ptr [ebp+$10]

fmul qword ptr [ebp+$28]

fadd qword ptr [ebp+$08]

fstp qword ptr [ebp-$08]

wait

fld  qword ptr [ebp-$08]

}

{

pop  ecx

pop  ecx

pop  ebp

}

end;

 

 

Первые три версии этой функции идентичны и они получают свои очки без сюрпризов. Наша методика измерения не совсем хороша, но дает достаточную точность в текущий момент ;-)

ArcSinApprox3a        45076

ArcSinApprox3b        45076

ArcSinApprox3c        45076

Оптимизация следует по тому же шаблону, как и в первой функции. Вот первая BASM версия без оптимизации. Закомментирован код добавленный компилятором.

Code:

function ArcSinApprox3c(X, A, B, C, D : Double) : Double;

asm

//push ebp

//mov ebp,esp

add  esp,-$08

//Result := ((A*X + B)*X + C)*X + D;

fld  qword ptr [ebp+$20]

fmul qword ptr [ebp+$28]

fadd qword ptr [ebp+$18]

fmul qword ptr [ebp+$28]

fadd qword ptr [ebp+$10]

fmul qword ptr [ebp+$28]

fadd qword ptr [ebp+$08]

fstp qword ptr [ebp-$08]

wait

fld  qword ptr [ebp-$08]

pop  ecx

pop  ecx

//pop ebp

end;

 

Первым делом удаляем строку ADD ESP, -$08 и две строки POP ECX. Они устанавливают фрейм стека, но ничего не делают кроме манипулирования указателем стека, который нигде не используется.

Code:

function ArcSinApprox3d(X, A, B, C, D : Double) : Double;

asm

//add  esp,-$08

//Result := ((A*X + B)*X + C)*X + D;

fld  qword ptr [ebp+$20]

fmul qword ptr [ebp+$28]

fadd qword ptr [ebp+$18]

fmul qword ptr [ebp+$28]

fadd qword ptr [ebp+$10]

fmul qword ptr [ebp+$28]

fadd qword ptr [ebp+$08]

fstp qword ptr [ebp-$08]

wait

fld  qword ptr [ebp-$08]

//pop  ecx

//pop  ecx

end;

 

Данная функция получила 43535 пункта.

Обе лишние строки, копирующие результат на стек и обратно, удалены одновременно.

Code:

function ArcSinApprox3e(X, A, B, C, D : Double) : Double;

asm

//Result := ((A*X + B)*X + C)*X + D;

fld  qword ptr [ebp+$20]

fmul qword ptr [ebp+$28]

fadd qword ptr [ebp+$18]

fmul qword ptr [ebp+$28]

fadd qword ptr [ebp+$10]

fmul qword ptr [ebp+$28]

fadd qword ptr [ebp+$08]

//fstp qword ptr [ebp-$08]

wait

//fld  qword ptr [ebp-$08]

end;

Этот вариант получил 47237 пункта, и улучшение составило 8.5%

 

Добавить комментарий

Не использовать не нормативную лексику.

Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.

ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!


Защитный код
Обновить