не, его ещё долго не выкинут.. а на таком https://dalthron.com.pe/product/laptop-hp-245-g7-amd-ryzen-3-1tb-8gb-ram-freedos/ ещё и фридос запускается
UbIvItS, sse/mmx блоки ведь не для расчёта тригонометрии. А если выкинуть fpu, то это изменение всей архитектуры - как обрабатывать ошибки, ловушки и прочие вещи(нп осевой планировщик не тупо крутит мат блоки, он их оптимизирует выключая мат блоки на новых квантах). Если отказаться от fpu, то это будет уже не IA. Что все утверждают что новые мат блоки быстрее это всё фигня, где реальные цифры, как всегда где замеры по профайлу ? Кто там выше утверждал что реализовал Тейлор на sse, где примеры тесты профайл ?
Indy_, aida64 prime95 https://www.codeproject.com/Articles/21024/Inner-Product-Experiment-CPU-FPU-vs-SSE тестЬ сколько хОшЪЪЪ. другой Вопрос, что фпу и векторные регистры всё же несколько разные вещи == фпу -- это скалярные вычисления и аж 80бит число, а векторные регистры позволяют проводить пакетные операции, но точность страдает. т.е. лобовое сравнение тут не очень уместно.
UbIvItS, Тут задача в реализации тригонометрии через блоки расширения(sse etc). Тоесть софт реализация вычислений, Тейлор/Маклорен/etc. Конечный результат не обязательно в регистрах хранить, всё равно они выгружаются в память при чтении. По ссылке никакой тригонометрии не обнаружил.
Indy_, Delphi 10.4 (последний): x86 использует FPU, x64 – SSE2. Тестим: Код (Text): {$APPTYPE CONSOLE} uses Winapi.Windows; var C, i: Integer; D, delta: Double; begin D := 0; delta := Pi / 18000000; C := GetTickCount; for i := 1 to 36000000 do begin D := D + delta; Sin(D); end; C := GetTickCount - C; WriteLn(C); end. x86 ≈ 1350 x64 ≈ 875 Заменяем Sin на Exp: 1150 / 750. Ln у обоих 780.
Jin X, Теорию относительности читал, константа не имеет смысла если её не с чем сравнить. Получилось значение для fpu-sin. Теперь нужен тот же цикл для реализации син через Тейлор-sse. А в общем нужно глянуть на саму дельфовую sin() дизом, не известно что там, я дельфи никогда не юзал. Для математики лучший сборщик басик как не удивительно https://www.purebasic.com/ Дельфи тут глупо приводить в пример, это дичь.
тут имеем место быть несколько иная хистория... https://randomascii.wordpress.com/2014/10/09/intel-underestimates-error-bounds-by-1-3-quintillion/ http://notabs.org/fpuaccuracy/
Так, я ж говорю, что x86 – это fpu, а x64 – sse2 (Тейлор). Там не нужен дизасм, там есть исходники этих функций. Я их смотрел (да и под дизасмом тоже), там именно то, что я написал. Не вопрос: Спойлер: FASM Код (ASM): format PE64 Console 5.0 include 'win64axp.inc' ;-- CODE SECTION ------------------------------------------------------------------------------------------------------- .code entry: frame finit fldz invoke GetTickCount mov ebx,eax mov ecx,36000000 @@: fadd [delta] fld st fsin fstp st dec ecx jnz @B fstp st invoke GetTickCount sub eax,ebx cinvoke printf, <'%d',10>, eax invoke ExitProcess, 0 endf ;-- DATA SECTION ------------------------------------------------------------------------------------------------------- .data delta dq 1.745329251994e-7 ;-- IMPORT SECTION ----------------------------------------------------------------------------------------------------- section '.idata' import data readable library kernel32, 'kernel32.dll',\ msvcrt, 'msvcrt.dll' import_kernel32 all_api import msvcrt,\ printf, 'printf' У меня выдаёт ≈ 1150. Если уж "дичь"-sse2/Тейлор работает на 30+% быстрее, чем чистый асм-fpu, то что уж говорить о "нормальной" реализации Тейлора? --- Сообщение объединено, 30 июл 2020 --- А вообще говоря, улучшить её можно как минимум бóльшим "распараллеливанием" вычислений, чем в Delphi. Надо ещё на плюсах попробовать. По любому там будет sse2 под x64 (по крайней мере, под какие-то компиляторы).
ряды и полиномы на большой точности медлительны + имеется нарастающая проблема округления == лучше кордик использовать.
Jin X, > x86 – это fpu, а x64 – sse2 И что межу ними общего. Это не замер, а чушь. Сравнение профайла на разных архитектурах. А есчо покажи где тригон вычисляется через sse, дельфя такое врядле умеет. > Я их смотрел В студию сурки или диз. Что ты видел никого не волнует, может у тебя глюки кто знает
maalchemist, Какой то полином, начало ряда: r6 = ([487] * (r0^2)^2 + [47f]) * (r0^2)^2 + [477] r4 = ((([487] * (r0^2)^2 + [483]) * ((r0^2)^2 + [47b]*2) * r0^2 + r6 + [46B]) * r0^2 Врядле может быть какая то точность. Но уже больше похоже на правду. Это нужно сравнить по таймингу с fsin.
Дельфийский SSE-синус возвращает абсолютно такой же результат, что и FPU:fsin, если аргумент <= 18003. Для косинуса результаты совпадают, если аргумент <= 17908. Только что проверил.
Однако для разных аргументов получаются существенно разные времена. Если сравнивать встроенный SSE-синус вот с такой функцией, Код (Text): function FPU_fsin (a: Double): Double; asm sub rsp, 16 movupd dqword ptr [rsp], xmm0 fld qword ptr [rsp] fsin fstp qword ptr [rsp] movupd xmm0, dqword ptr [rsp] add rsp, 16 end; то для аргумента 0.01 SSE-версия работает в 4.4 раза быстрее. Для других аргументов имеем такие результаты: 0.1 - 4.4 1.0 - 2.8 5.0 - 1.5 10.0 - 1.3 100.0 - 1.3 1000.0 - 1.5 10000.0 - 1.5 100000.0 - 1.04 1000000.0 - 1.3
maalchemist, А длительность замера какая, это важно тк это теже блоки fpu и планировщик их выгружает.
Для оценки я использовал вот такую простенькую функцию: Код (Text): function FPU_SSE_sin_TEST (a: Double): Double; var I : Integer; I1, I2 : Int64; J1, J2 : Int64; ID, JD : Double; Ratio : Double; begin QueryPerformanceCounter (I1); for I := 1 to 1000000 do begin FPU_fsin (a); end; QueryPerformanceCounter (I2); ID := I2 - I1; QueryPerformanceCounter (J1); for I := 1 to 1000000 do begin sin (a); end; QueryPerformanceCounter (J2); JD := J2 - J1; Ratio := ID / JD; Result := Ratio; end;
maalchemist, Если длительность менее кванта профайл будет невалид. Нужно либо очень большое значение dTSC, либо лучше использовать GetTickCount().
Я ж замерил x64 на асме (fpu) и на Delphi (sse), вторая оказалась быстрее, см. выше. К тому же, я переделывал асм-код под x86, скорость была абсолютно той же, как и на x64, так что разница архитектур тут большой роли не играет. Пишем под x86 Sin(1), заходим под отладчиком (IDE-шным), видим: Код (Text): asm FLD tbyte ptr X FSIN FWAIT end; Пишем под x64 то же самое, видим: Код (Text): function Sin(const X: Double): Double; var Q: integer; Y,Z: Double; begin if Abs(x) < Pi/4 then Result := pSinDouble(X, 0) else begin Q := pRemDouble(X, Y, Z); case Q of 0: Result := pSinDouble(Y, Z); 1: Result := pCosDouble(Y, Z); 2: Result := -pSinDouble(Y, Z); 3: Result := -pCosDouble(Y, Z); else Result := 0; // avoid warning W1035 Return value of function '%s' might be undefined end; end; end; далее (pRemDouble неинтересен, идём в pCosDouble): Код (Text): {$IF defined(ARITH_PUREPASCAL_EXT64) or defined(ARITH_X64_SSE)} function pCosDouble(const x, y: Double) : Double; const CCos : ARRAY[0..5] OF UINT64 = ( $BDA8FA6A8A7D84DF, $3E21EE9DC12C88AC, $BE927E4F7F1EE922, $3EFA01A019C8F945, $BF56C16C16C15018, $3FA555555555554B ); var r1, r2, s, t, u, v, L, L1, L2, D2, D4 : Double; begin D2 := x * x; D4 := D2 * D2; L1 := PDouble(@CCos[0])^; L2 := PDouble(@CCos[1])^; L1 := L1 * D4 + PDouble(@CCos[2])^; L2 := L2 * D4 + PDouble(@CCos[3])^; L1 := L1 * D4 + PDouble(@CCos[4])^; L2 := L2 * D4 + PDouble(@CCos[5])^; L := L2 + L1 * D2; L := L * D4; s := 1.0; t := D2 * 0.5; u := s - t; v := u - s; r1 := t + v; r2 := x * y; r2 := L - r2; r2 := r2 - r1; Result := u + r2; end; Смотрим дизасм в этом месте: https://www.screencast.com/t/pTo3pLs7Urz Вот ещё вараинт: Код (Text): {$APPTYPE CONSOLE} uses Winapi.Windows; var C, i: Integer; D, delta: Double; procedure FpuInit; asm FINIT end; function FpuSin: Double; asm FLD qword ptr D FSIN FWAIT FSTP st end; begin D := 0; delta := Pi / 18000000; FpuInit; C := GetTickCount; for i := 1 to 36000000 do begin D := D + delta; FpuSin(); end; C := GetTickCount - C; WriteLn(C); end. Компилим в x64 (чтоб всё по-честному было), получаем: 1125 мсек (против ≈ 850 обычного Sin на sse/Тейлор, тоже x64, исходники выше). --- Сообщение объединено, 1 авг 2020 --- Х/з, что там внутри и почему это медленнее. В исходнике Delphi, по меньшей мере, идёт чередование использования регистров (переменные L1, L2), которые вычисляются параллельно (можно сделать 3 шт вообще, по идее, должно быть ещё быстрее). Может, в харде все вычисления последовательны? Кстати, надо ещё на AMD замерить скорость, кстати... --- Сообщение объединено, 1 авг 2020 --- На AMD разница меньше: 1100 / 800 (вообще говоря, замер sse сильно скачет от 700 до 950 примерно). --- Сообщение объединено, 1 авг 2020 --- *разница НЕ меньше.
Jin X, ~1.3 раза быстрее, это ниочём. Странно конечно почему последовательность инструкций выполняется быстрее чем одна fsin при том же результате. Фишка fpu - там есть стек, на котором идут вычисления, что делает не нужным выгрузку результата в память. Те на последовательности мат функций fpu будет быстрее. Судя по профайлу нет никакого смысла юзать левое(полиномы на sse), тем более для системы это не имеет значения - она выгружает мат блок через xsave. > pCosDouble Так это чебышев походу, нужно искать по коэффициентам. В точности совпадает с fsin ?? --- Сообщение объединено, 1 авг 2020 --- Jin X, > FWAIT Эта инструкция доставляет мат фаулт, если его нет работает как nop. Если зациклить L: fwait/jmp L, то ядро будет использовать мат блок и общий профайл потока просядет. Это сам факт использования математики, mmx отображены на fpu, sse в том же блоке и в общем любо обращение к этим блокам включает механизм выгрузки контекста математики, а это долго ибо он большой. --- Сообщение объединено, 1 авг 2020 --- Jin X, На скрине L1 := CCos[0] А что это ? Какая то константа или может быть перед вычислением синуса вычисляется косинус, откуда ссылки на переменную ?