FPC 3.0.0 генерит самый медленный код.
Модератор: Модераторы
FPC 3.0.0 генерит самый медленный код.
Сравнил время выполнения одной и той же программы , на D7, D10S, Laz144 (fpc 2.6.4) и Laz1.6RC2 (FPC 3.0.0).
Программа вызов в цикле 100 тыс. преобразований FFT.
Компиляция для Win32 процы по умолчнию.
Результаты:
D7 ~4200 мс
D10Seattle ~3200 мс
Laz144 (fpc 2.6.4) ~3600 мс
Laz1.6RC2 (FPC 3.0.0) ~ 5300 мс
Может кто знает, почему FPC 3.0.0 такой мертвый ?
Программа вызов в цикле 100 тыс. преобразований FFT.
Компиляция для Win32 процы по умолчнию.
Результаты:
D7 ~4200 мс
D10Seattle ~3200 мс
Laz144 (fpc 2.6.4) ~3600 мс
Laz1.6RC2 (FPC 3.0.0) ~ 5300 мс
Может кто знает, почему FPC 3.0.0 такой мертвый ?
ntechmen писал(а):Может кто знает, почему FPC 3.0.0 такой мертвый ?
Потому что при замерах производительности использовать нужно не дефолтные настройки, а включать оптимизацию.
ntechmen, а где код?
kazalex писал(а):Потому что при замерах производительности использовать нужно не дефолтные настройки, а включать оптимизацию.
Скорее всего, дело в строках. Я тоже этот эффект заметил. Меняя тип строк, можно попробовать "выжать" чуть-чуть производительности, но 2.6.4 догнать будет проблематично. Впрочем, определённую роль здесь играет ОС: наибольшее замедление наблюдается на win32, наименьшее - x86_64-linux.
kazalex писал(а):ntechmen писал(а):Может кто знает, почему FPC 3.0.0 такой мертвый ?
Потому что при замерах производительности использовать нужно не дефолтные настройки, а включать оптимизацию.
это цифры при включенной оптимизации, лучшие варианты. В fpc 3 оптимизацию по -О4, не дала ни каких преимуществ, иногда даже ухудшает.
daesher писал(а):Скорее всего, дело в строках.
FFT со строками?
daesher писал(а):Я тоже этот эффект заметил.
Когда мне, с горем пополам, удалось собрать свою библиотеку под FPC и запустить бенчик, я был немало удивлён, что производительность оказалась на уровне дельфей (думал будет сильно хуже), при том, что менеджер памяти в FPC, мягко говоря, не блещет. В бенчике значительная часть, как раз, связана с работой со строками.
ntechmen писал(а):это цифры при включенной оптимизации, лучшие варианты. В fpc 3 оптимизацию по -О4, не дала ни каких преимуществ, иногда даже ухудшает.
Код покажешь?
а как это фурье со строками?
зы
мертвый - это 3200 и 5600. Так пишите на делфи хе 10 или ваще уходите на С, в чем проблема, хз.
зы
мертвый - это 3200 и 5600. Так пишите на делфи хе 10 или ваще уходите на С, в чем проблема, хз.
kazalex писал(а):daesher писал(а):Скорее всего, дело в строках.
FFT со строками?daesher писал(а):Я тоже этот эффект заметил.
Когда мне, с горем пополам, удалось собрать свою библиотеку под FPC и запустить бенчик, я был немало удивлён, что производительность оказалась на уровне дельфей (думал будет сильно хуже), при том, что менеджер памяти в FPC, мягко говоря, не блещет. В бенчике значительная часть, как раз, связана с работой со строками.ntechmen писал(а):это цифры при включенной оптимизации, лучшие варианты. В fpc 3 оптимизацию по -О4, не дала ни каких преимуществ, иногда даже ухудшает.
Код покажешь?
type
TArrayValues = array of double;
const
TwoPi = 6.283185307179586;
var
Form1: TForm1;
implementation
{$R *.lfm}
// AVal - массив анализируемых данных, Nvl - длина массива, должна быть кратна степени 2.
// FTvl - массив полученных значений, Nft - длина массива, должна быть равна Nvl / 2 или меньше.
procedure FFTAnalysis(var AVal, FTvl: TArrayValues; Nvl, Nft: integer);
var
i, j, n, m, Mmax, Istp: integer;
Tmpr, Tmpi, Wtmp, Theta: double;
Wpr, Wpi, Wr, Wi: double;
Tmvl: TArrayValues;
begin
n := Nvl * 2;
SetLength(Tmvl, n);
for i := 0 to Nvl - 1 do
begin
j := i * 2;
Tmvl[j] := 0;
Tmvl[j + 1] := AVal[i];
end;
i := 1;
j := 1;
while i < n do
begin
if j > i then
begin
Tmpr := Tmvl[i];
Tmvl[i] := Tmvl[j];
Tmvl[j] := Tmpr;
Tmpr := Tmvl[i + 1];
Tmvl[i + 1] := Tmvl[j + 1];
Tmvl[j + 1] := Tmpr;
end;
i := i + 2;
m := Nvl;
while (m >= 2) and (j > m) do
begin
j := j - m;
m := m div 2;
end;
j := j + m;
end;
Mmax := 2;
while n > Mmax do
begin
Theta := -TwoPi / Mmax;
Wpi := Sin(Theta);
Wtmp := Sin(Theta / 2);
Wpr := Wtmp * Wtmp * 2;
Istp := Mmax * 2;
Wr := 1;
Wi := 0;
m := 1;
while m < Mmax do
begin
i := m;
m := m + 2;
Tmpr := Wr;
Tmpi := Wi;
Wr := Wr - Tmpr * Wpr - Tmpi * Wpi;
Wi := Wi + Tmpr * Wpi - Tmpi * Wpr;
while i < n do
begin
j := i + Mmax;
Tmpr := Wr * Tmvl[j] - Wi * Tmvl[j - 1];
Tmpi := Wi * Tmvl[j] + Wr * Tmvl[j - 1];
Tmvl[j] := Tmvl[i] - Tmpr;
Tmvl[j - 1] := Tmvl[i - 1] - Tmpi;
Tmvl[i] := Tmvl[i] + Tmpr;
Tmvl[i - 1] := Tmvl[i - 1] + Tmpi;
i := i + Istp;
end;
end;
Mmax := Istp;
end;
for i := 0 to Nft - 1 do
begin
j := i * 2;
FTvl[i] := 2 * Sqrt(Sqr(Tmvl[j]) + Sqr(Tmvl[j + 1])) / Nvl;
end;
SetLength(Tmvl, 0);
end;
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var
i:integer;
BufSig:TArrayValues;
FAmp:TArrayValues;
tStamp1,tStamp2: Cardinal;
begin
Memo1.Clear;
SetLength(BufSig,1048576);
SetLength(FAmp,524288);
Memo1.Lines.Add('Signal array = '+IntToStr(Length(BufSig)));
Memo1.Lines.Add('Analysis array = '+IntToStr(Length(FAmp)));
FillChar(BufSig,sizeof(BufSig),0);
FillChar(FAmp,sizeof(FAmp),0);
//Временая отметка Начало
tStamp1:=GetTickCount;
for i:=1 to 100000000 do begin
FFTAnalysis(BufSig,FAmp,Length(BufSig),Length(fAmp));
end;
tStamp2:=GetTickCount;
//Временая отметка Конец
Memo1.Lines.Add('FFTAnalysis time = '+IntToStr(tStamp2-tStamp1));
SetLength(BufSig,0);
SetLength(FAmp,0);
end;
тестировалось на проце I5-4210M 2.6 GHZ turbo 3.2 GHz, компиляции с оптимизациями для x86_32.
/*интересный момент, при компиляции на FPC 3.0.0 для x86_64 ATHLON64 время было около 2200 мсек.*/
но почем у 32х разрядный код такой медленный у FPC 3.0.0?
ntechmen писал(а):тестировалось на проце I5-4210M 2.6 GHZ turbo 3.2 GHz, компиляции с оптимизациями для x86_32
Всё дело в менеджере памяти FPC. У тебя на каждой итерации выделяется динамический массив. В дельфях, по дефолту, используется FastMM со времён Delphi 2006, в FPC с этим сильно хуже. Но, если избавиться от постоянных обращений к менеджеру, то результат получается совсем другим:
Delphi 10 Seattle (x86, release): 1219
FPC 3.1.1 (x86, O4): 844
Тестировалось на виртуальной машине Windows 10 x64, VirtualBox 5.0.14 под Ubuntu 14.04. CPU Phenom II X4 940BE 3GHz.
Код: Выделить всё
program fft;
uses windows;
{$DEFINE PREALLOCATED_TMVL}
type
TArrayValues = array of double;
const
TwoPi = 6.283185307179586;
// AVal - массив анализируемых данных, Nvl - длина массива, должна быть кратна степени 2.
// FTvl - массив полученных значений, Nft - длина массива, должна быть равна Nvl / 2 или меньше.
procedure FFTAnalysis(var AVal, FTvl{$IF Defined(PREALLOCATED_TMVL)}, Tmvl{$IFEND}: TArrayValues; Nvl, Nft: integer);
var
i, j, n, m, Mmax, Istp: integer;
Tmpr, Tmpi, Wtmp, Theta: double;
Wpr, Wpi, Wr, Wi: double;
{$IF Not Defined(PREALLOCATED_TMVL)}
Tmvl: TArrayValues;
{$IFEND}
begin
n := Nvl * 2;
{$IF Not Defined(PREALLOCATED_TMVL)}
SetLength(Tmvl, n);
{$IFEND}
for i := 0 to Nvl - 1 do
begin
j := i * 2;
Tmvl[j] := 0;
Tmvl[j + 1] := AVal[i];
end;
i := 1;
j := 1;
while i < n do
begin
if j > i then
begin
Tmpr := Tmvl[i];
Tmvl[i] := Tmvl[j];
Tmvl[j] := Tmpr;
Tmpr := Tmvl[i + 1];
Tmvl[i + 1] := Tmvl[j + 1];
Tmvl[j + 1] := Tmpr;
end;
i := i + 2;
m := Nvl;
while (m >= 2) and (j > m) do
begin
j := j - m;
m := m div 2;
end;
j := j + m;
end;
Mmax := 2;
while n > Mmax do
begin
Theta := -TwoPi / Mmax;
Wpi := Sin(Theta);
Wtmp := Sin(Theta / 2);
Wpr := Wtmp * Wtmp * 2;
Istp := Mmax * 2;
Wr := 1;
Wi := 0;
m := 1;
while m < Mmax do
begin
i := m;
m := m + 2;
Tmpr := Wr;
Tmpi := Wi;
Wr := Wr - Tmpr * Wpr - Tmpi * Wpi;
Wi := Wi + Tmpr * Wpi - Tmpi * Wpr;
while i < n do
begin
j := i + Mmax;
Tmpr := Wr * Tmvl[j] - Wi * Tmvl[j - 1];
Tmpi := Wi * Tmvl[j] + Wr * Tmvl[j - 1];
Tmvl[j] := Tmvl[i] - Tmpr;
Tmvl[j - 1] := Tmvl[i - 1] - Tmpi;
Tmvl[i] := Tmvl[i] + Tmpr;
Tmvl[i - 1] := Tmvl[i - 1] + Tmpi;
i := i + Istp;
end;
end;
Mmax := Istp;
end;
for i := 0 to Nft - 1 do
begin
j := i * 2;
FTvl[i] := 2 * Sqrt(Sqr(Tmvl[j]) + Sqr(Tmvl[j + 1])) / Nvl;
end;
{$IF Not Defined(PREALLOCATED_TMVL)}
SetLength(Tmvl, 0);
{$IFEND}
end;
var
i: integer;
BufSig: TArrayValues;
FAmp: TArrayValues;
{$IF Defined(PREALLOCATED_TMVL)}
Tmvl: TArrayValues;
{$IFEND}
tStamp1, tStamp2: Cardinal;
begin
SetLength(BufSig, 1048576);
SetLength(FAmp, 524288);
{$IF Defined(PREALLOCATED_TMVL)}
SetLength(Tmvl, Length(BufSig) * 2);
{$IFEND}
writeln('Signal array = ', Length(BufSig));
writeln('Analysis array = ', Length(FAmp));
FillChar(BufSig, sizeof(BufSig), 0);
FillChar(FAmp, sizeof(FAmp), 0);
tStamp1 := GetTickCount;
for i := 1 to 100000000 do
begin
FFTAnalysis(BufSig, FAmp{$IF Defined(PREALLOCATED_TMVL)}, Tmvl{$IFEND}, Length(BufSig), Length(FAmp));
end;
tStamp2 := GetTickCount;
Writeln('FFTAnalysis time = ', tStamp2 - tStamp1);
SetLength(BufSig, 0);
SetLength(FAmp, 0);
{$IF Defined(PREALLOCATED_TMVL)}
SetLength(Tmvl, 0);
{$IFEND}
readln;
end.Прошу прощенья допустил ошибки.
Все разобрался. В чем дело. (Сколько раз говорил, нельзя писать по ночам).
Ошибка в этих двух строчках:
FillChar(BufSig,sizeof(BufSig),0);
FillChar(FAmp,sizeof(FAmp),0);
а потом
FFTAnalysis(BufSig,FAmp,Length(BufSig),Length(fAmp))
Правильный код:
procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
BufSig: TArrayValues;
FAmp: TArrayValues;
tStamp1, tStamp2: cardinal;
szS, szA: integer;
begin
Memo1.Clear;
SetLength(BufSig, 512);
SetLength(FAmp, 256);
szS := Length(BufSig);
szA := Length(FAmp);
Memo1.Lines.Add('Signal array = ' + IntToStr(szS));
Memo1.Lines.Add('Analysis array = ' + IntToStr(szA));
// FillChar(BufSig,sizeof(BufSig),0);
// FillChar(FAmp,sizeof(FAmp),0);
//Временая отметка Начало
tStamp1 := GetTickCount;
for i := 1 to 100000 do
begin
FFTAnalysis(BufSig, FAmp, szS, szA);
end;
tStamp2 := GetTickCount;
//Временая отметка Конец
Memo1.Lines.Add('FFTAnalysis time = ' + IntToStr(tStamp2 - tStamp1));
SetLength(BufSig, 0);
SetLength(FAmp, 0);
end;
Результаты
Для x86_32
D7 2900-3000 мс
D10 4400-4500 мс
Для
x86_32
-03
Laz16RC2 FPC2.6.4 4000-4100 мс
Laz16RC2 FPC3.0.0 3600-3700 мс
Для
x86_64
-03
Laz16RC2 FPC3.0.0 1900=2000мс
Все разобрался. В чем дело. (Сколько раз говорил, нельзя писать по ночам).
Ошибка в этих двух строчках:
FillChar(BufSig,sizeof(BufSig),0);
FillChar(FAmp,sizeof(FAmp),0);
а потом
FFTAnalysis(BufSig,FAmp,Length(BufSig),Length(fAmp))
Правильный код:
procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
BufSig: TArrayValues;
FAmp: TArrayValues;
tStamp1, tStamp2: cardinal;
szS, szA: integer;
begin
Memo1.Clear;
SetLength(BufSig, 512);
SetLength(FAmp, 256);
szS := Length(BufSig);
szA := Length(FAmp);
Memo1.Lines.Add('Signal array = ' + IntToStr(szS));
Memo1.Lines.Add('Analysis array = ' + IntToStr(szA));
// FillChar(BufSig,sizeof(BufSig),0);
// FillChar(FAmp,sizeof(FAmp),0);
//Временая отметка Начало
tStamp1 := GetTickCount;
for i := 1 to 100000 do
begin
FFTAnalysis(BufSig, FAmp, szS, szA);
end;
tStamp2 := GetTickCount;
//Временая отметка Конец
Memo1.Lines.Add('FFTAnalysis time = ' + IntToStr(tStamp2 - tStamp1));
SetLength(BufSig, 0);
SetLength(FAmp, 0);
end;
Результаты
Для x86_32
D7 2900-3000 мс
D10 4400-4500 мс
Для
x86_32
-03
Laz16RC2 FPC2.6.4 4000-4100 мс
Laz16RC2 FPC3.0.0 3600-3700 мс
Для
x86_64
-03
Laz16RC2 FPC3.0.0 1900=2000мс
ntechmen писал(а):Прошу прощенья допустил ошибки
Ну вот, и я тоже промограл, хотя отмечал про себя, что очищать дин. массивы не нужно
-
Mirage
- энтузиаст
- Сообщения: 881
- Зарегистрирован: 06.05.2005 20:29:07
- Откуда: Russia
- Контактная информация:
Т.е. получается, что FPC стал в полтора раза быстрей D7? Круто.
А D10 почему стал медленнее D7? Из-за очистки лин. массивов? Т.е. D10 как-то быстрее их очищает, или догадался выкинуть вообще этот код?
А D10 почему стал медленнее D7? Из-за очистки лин. массивов? Т.е. D10 как-то быстрее их очищает, или догадался выкинуть вообще этот код?
Mirage писал(а):А D10 почему стал медленнее D7? Из-за очистки лин. массивов
А ты посмотри ЧТО там очищалось
-
Mirage
- энтузиаст
- Сообщения: 881
- Зарегистрирован: 06.05.2005 20:29:07
- Откуда: Russia
- Контактная информация:
А понял, туда nil'ы передавались. И длины соот-но нулевые. На что тогда время шло?
Вообще, в бенчмарках корректность полученных данных принято контролировать. А то ведь в процессе оптимизации можно ошибок навносить.
Вообще, в бенчмарках корректность полученных данных принято контролировать. А то ведь в процессе оптимизации можно ошибок навносить.
Mirage писал(а):На что тогда время шло?
На сто миллионов вызовов процедуры FFTAnalysis + двести миллионов вызовов SetLength.
