FPC 3.0.0 генерит самый медленный код.

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

FPC 3.0.0 генерит самый медленный код.

Сообщение ntechmen » 26.01.2016 00:11:34

Сравнил время выполнения одной и той же программы , на 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 такой мертвый ?
ntechmen
незнакомец
 
Сообщения: 4
Зарегистрирован: 25.01.2016 23:54:58

Re: FPC 3.0.0 генерит самый медленный код.

Сообщение kazalex » 26.01.2016 00:15:59

ntechmen писал(а):Может кто знает, почему FPC 3.0.0 такой мертвый ?

Потому что при замерах производительности использовать нужно не дефолтные настройки, а включать оптимизацию.
kazalex
постоялец
 
Сообщения: 296
Зарегистрирован: 01.06.2012 14:54:10

Re: FPC 3.0.0 генерит самый медленный код.

Сообщение sign » 26.01.2016 06:41:12

ntechmen, а где код?
sign
энтузиаст
 
Сообщения: 1131
Зарегистрирован: 30.08.2009 09:20:53

Re: FPC 3.0.0 генерит самый медленный код.

Сообщение daesher » 26.01.2016 10:17:03

kazalex писал(а):Потому что при замерах производительности использовать нужно не дефолтные настройки, а включать оптимизацию.

Скорее всего, дело в строках. Я тоже этот эффект заметил. Меняя тип строк, можно попробовать "выжать" чуть-чуть производительности, но 2.6.4 догнать будет проблематично. Впрочем, определённую роль здесь играет ОС: наибольшее замедление наблюдается на win32, наименьшее - x86_64-linux.
daesher
постоялец
 
Сообщения: 221
Зарегистрирован: 09.03.2010 22:17:14

Re: FPC 3.0.0 генерит самый медленный код.

Сообщение ntechmen » 26.01.2016 10:22:18

kazalex писал(а):
ntechmen писал(а):Может кто знает, почему FPC 3.0.0 такой мертвый ?

Потому что при замерах производительности использовать нужно не дефолтные настройки, а включать оптимизацию.

это цифры при включенной оптимизации, лучшие варианты. В fpc 3 оптимизацию по -О4, не дала ни каких преимуществ, иногда даже ухудшает.
ntechmen
незнакомец
 
Сообщения: 4
Зарегистрирован: 25.01.2016 23:54:58

Re: FPC 3.0.0 генерит самый медленный код.

Сообщение kazalex » 26.01.2016 11:25:07

daesher писал(а):Скорее всего, дело в строках.

FFT со строками?
daesher писал(а):Я тоже этот эффект заметил.

Когда мне, с горем пополам, удалось собрать свою библиотеку под FPC и запустить бенчик, я был немало удивлён, что производительность оказалась на уровне дельфей (думал будет сильно хуже), при том, что менеджер памяти в FPC, мягко говоря, не блещет. В бенчике значительная часть, как раз, связана с работой со строками.

ntechmen писал(а):это цифры при включенной оптимизации, лучшие варианты. В fpc 3 оптимизацию по -О4, не дала ни каких преимуществ, иногда даже ухудшает.

Код покажешь?
kazalex
постоялец
 
Сообщения: 296
Зарегистрирован: 01.06.2012 14:54:10

Re: FPC 3.0.0 генерит самый медленный код.

Сообщение azsx » 26.01.2016 11:42:11

а как это фурье со строками?
зы
мертвый - это 3200 и 5600. Так пишите на делфи хе 10 или ваще уходите на С, в чем проблема, хз.
azsx
энтузиаст
 
Сообщения: 959
Зарегистрирован: 16.11.2015 06:38:32

Re: FPC 3.0.0 генерит самый медленный код.

Сообщение ntechmen » 26.01.2016 12:37:27

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
незнакомец
 
Сообщения: 4
Зарегистрирован: 25.01.2016 23:54:58

Re: FPC 3.0.0 генерит самый медленный код.

Сообщение kazalex » 26.01.2016 13:48:19

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.
kazalex
постоялец
 
Сообщения: 296
Зарегистрирован: 01.06.2012 14:54:10

Re: FPC 3.0.0 генерит самый медленный код.

Сообщение ntechmen » 26.01.2016 13:56:08

Прошу прощенья допустил ошибки.

Все разобрался. В чем дело. (Сколько раз говорил, нельзя писать по ночам).

Ошибка в этих двух строчках:
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
незнакомец
 
Сообщения: 4
Зарегистрирован: 25.01.2016 23:54:58

Re: FPC 3.0.0 генерит самый медленный код.

Сообщение kazalex » 26.01.2016 14:31:32

ntechmen писал(а):Прошу прощенья допустил ошибки

Ну вот, и я тоже промограл, хотя отмечал про себя, что очищать дин. массивы не нужно :lol:
kazalex
постоялец
 
Сообщения: 296
Зарегистрирован: 01.06.2012 14:54:10

Re: FPC 3.0.0 генерит самый медленный код.

Сообщение Mirage » 26.01.2016 15:46:30

Т.е. получается, что FPC стал в полтора раза быстрей D7? Круто.
А D10 почему стал медленнее D7? Из-за очистки лин. массивов? Т.е. D10 как-то быстрее их очищает, или догадался выкинуть вообще этот код?
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: FPC 3.0.0 генерит самый медленный код.

Сообщение kazalex » 26.01.2016 15:59:32

Mirage писал(а):А D10 почему стал медленнее D7? Из-за очистки лин. массивов

А ты посмотри ЧТО там очищалось :wink:
kazalex
постоялец
 
Сообщения: 296
Зарегистрирован: 01.06.2012 14:54:10

Re: FPC 3.0.0 генерит самый медленный код.

Сообщение Mirage » 26.01.2016 16:25:56

А понял, туда nil'ы передавались. И длины соот-но нулевые. На что тогда время шло?
Вообще, в бенчмарках корректность полученных данных принято контролировать. А то ведь в процессе оптимизации можно ошибок навносить.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: FPC 3.0.0 генерит самый медленный код.

Сообщение kazalex » 26.01.2016 16:40:55

Mirage писал(а):На что тогда время шло?

На сто миллионов вызовов процедуры FFTAnalysis + двести миллионов вызовов SetLength.
kazalex
постоялец
 
Сообщения: 296
Зарегистрирован: 01.06.2012 14:54:10

След.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 235

Рейтинг@Mail.ru