Inline директива нетипично замедляет функцию

Вопросы программирования на Free Pascal, использования компилятора и утилит.

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

Inline директива нетипично замедляет функцию

Сообщение devels » 15.01.2011 22:15:07

Приветствую, сломал уже голову, в Delphi inline деректива для функции убыстряет ее на 30-20%, а в fpc наоборот идет замедление вызова функции на 30-20%.

Код: Выделить всё
function HashTable_Func(key: AnsiString): Cardinal; inline;
begin
    Result := ori_Hash32.BKDRHash(key) and $7FFFFFFF;
end;   

...
for i := 0 to 10000000 do
  begin
      HashTable_Func('x');
      HashTable_Func('y');
      HashTable_Func('z');
      HashTable_Func('a');
      HashTable_Func('b');
      HashTable_Func('c');
  end;


В fpc с дерективой inline - 1000 mlsec
Без нее - 700 mlsec.

Вот собственно и функция. Для меня даже эти 30% очень критичны, т.к. код в функции без вызова работает за 500 mlsec, в делфи с inline директивой, функция вызывается за такую же скорость.

Что за фак вообще? {$MACROS ON} вообще замедляет в 2,5 раза.
devels
постоялец
 
Сообщения: 137
Зарегистрирован: 01.09.2010 12:14:38

Re: Inline директива нетипично замедляет функцию

Сообщение Odyssey » 15.01.2011 23:00:17

Я бы с такими вещами пошёл бы в рассылку FPC. Кроме разработчиков тут вряд ли кто-то сможет помочь.
Odyssey
энтузиаст
 
Сообщения: 580
Зарегистрирован: 29.11.2007 17:32:24

Re: Inline директива нетипично замедляет функцию

Сообщение Иван Шихалев » 15.01.2011 23:15:04

А что с опциями отладки? {$MACRO ON} вообще не должна никак сказываться во время выполнения...
Аватара пользователя
Иван Шихалев
энтузиаст
 
Сообщения: 1138
Зарегистрирован: 15.05.2006 11:26:13
Откуда: Екатеринбург

Re: Inline директива нетипично замедляет функцию

Сообщение devels » 16.01.2011 10:00:43

Вот именно с {$MACRO ON} вообще необъяснимая магия.

Кто нибудь может протестировать у себя код:

Код: Выделить всё
function BKDRHash(const Str : AnsiString) : Cardinal;
const Seed = 31; (* 31 131 1313 13131 131313 etc... *)
var
  i,len: Cardinal;
begin
  Result := 0;
  len := Length(Str);
  for i := 1 to Len do
  begin
    Result := (Result * Seed) + Ord(Str[i]);
  end;
end; 

function HashTable_Func(key: AnsiString): Cardinal; inline; // !!!!
begin
    Result := BKDRHash(key) and $7FFFFFFF;
end; 



...
for i := 0 to 10000000 do
  begin
      HashTable_Func('x');
      HashTable_Func('y');
      HashTable_Func('z');
      HashTable_Func('a');
      HashTable_Func('b');
      HashTable_Func('c');
  end;


Может быть какая-то глючная версия компилятора у меня (fpc 2.4.3 от 5 января).
devels
постоялец
 
Сообщения: 137
Зарегистрирован: 01.09.2010 12:14:38

Re: Inline директива нетипично замедляет функцию

Сообщение Odyssey » 16.01.2011 11:02:26

Проверял с помощью
Код: Выделить всё
$ time -f %E ./project1

Seed = 31, без inline: 0:04.99
Seed = 31, inline: 0:02.77
Seed = 131, без inline: 0:05.24
Seed = 131, inline: 0:02.78
Seed = 13131, без inline: 0:05.28
Seed = 13131, inline: 0:02.77

FPC 2.4.2 [2010/12/27] for i386, Linux.

Версия 2.4.3 -- это сборка из svn, ветки фиксов к 2.4.2.
Возможно стоит проверить на релизной версии (2.4.2) и на последней из trunk (2.5.1).
Odyssey
энтузиаст
 
Сообщения: 580
Зарегистрирован: 29.11.2007 17:32:24

Re: Inline директива нетипично замедляет функцию

Сообщение Maxizar » 16.01.2011 12:41:24

Мой результат тестов:
используем Inline - 1.2 сек.
не используем inline - 2.2 сек.
Тест проводил используя вот этот модуль расчет времени выполнения кода

вот код формы для тестирования:
Код: Выделить всё
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  performancetime;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{$INLINE ON}

function BKDRHash(const Str : AnsiString) : Cardinal;
const Seed = 31; (* 31 131 1313 13131 131313 etc... *)
var
  i,len: Cardinal;
begin
  Result := 0;
  len := Length(Str);
  for i := 1 to Len do
  begin
    Result := (Result * Seed) + Ord(Str[i]);
  end;
end;

function HashTable_Func(key: AnsiString): Cardinal; inline; // !!!!
begin
    Result := BKDRHash(key) and $7FFFFFFF;
end;

function HashTable_Func1(key: AnsiString): Cardinal; //inline; // !!!!
begin
    Result := BKDRHash(key) and $7FFFFFFF;
end;

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
var
   T:TPerformanceTime;
   i:Integer;
begin

  T:=TPerformanceTime.Create(false);
  T.Start;

  for i := 0 to 10000000 do
    begin
      HashTable_Func('x');
      HashTable_Func('y');
      HashTable_Func('z');
      HashTable_Func('a');
      HashTable_Func('b');
      HashTable_Func('c');
    end;

  T.Stop;
  Caption:=FloatToStr(T.Delay);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
   T:TPerformanceTime;
   i:Integer;
begin

  T:=TPerformanceTime.Create(false);
  T.Start;

  for i := 0 to 10000000 do
    begin
      HashTable_Func1('x');
      HashTable_Func1('y');
      HashTable_Func1('z');
      HashTable_Func1('a');
      HashTable_Func1('b');
      HashTable_Func1('c');
    end;

  T.Stop;
  Caption:=FloatToStr(T.Delay);

end;
end.


ОС: Windows XP SP3 rus
Lazarus SVN 28824
FPC 2.4.2

И в догонку:
Odyssey писал(а):Проверял с помощью
Код: Выделить всё
$ time -f %E ./project1


Что это за проверка такая? как ее сделать на Windows.
Maxizar
постоялец
 
Сообщения: 385
Зарегистрирован: 20.03.2010 19:48:14

Re: Inline директива нетипично замедляет функцию

Сообщение Odyssey » 16.01.2011 15:25:25

Maxizar писал(а):Что это за проверка такая?
time - это posix-команда для замера времени выполнения процесса.
Maxizar писал(а): как ее сделать на Windows.
Не знаю, разве что через cygwin.
Odyssey
энтузиаст
 
Сообщения: 580
Зарегистрирован: 29.11.2007 17:32:24

Re: Inline директива нетипично замедляет функцию

Сообщение Max Rusov » 17.01.2011 11:46:22

Если в функции HashTable_Func поставить const то результат (у меня) такой:

Без inline - 1513 ms
С inline - 3167 ms

Если смотреть код, то цикл _без_ inline:

Код: Выделить всё
@@j86:
      inc   esi
      mov   eax,offset _$TEST$_Ld1
      call   P$TEST_HASHTABLE_FUNC1$ANSISTRING$$LONGWORD
      mov   eax,offset _$TEST$_Ld3
      call   P$TEST_HASHTABLE_FUNC1$ANSISTRING$$LONGWORD
      mov   eax,offset _$TEST$_Ld5
      call   P$TEST_HASHTABLE_FUNC1$ANSISTRING$$LONGWORD
      mov   eax,offset _$TEST$_Ld7
      call   P$TEST_HASHTABLE_FUNC1$ANSISTRING$$LONGWORD
      mov   eax,offset _$TEST$_Ld9
      call   P$TEST_HASHTABLE_FUNC1$ANSISTRING$$LONGWORD
      mov   eax,offset _$TEST$_Ld11
      call   P$TEST_HASHTABLE_FUNC1$ANSISTRING$$LONGWORD
      cmp   esi,50000000
      jl   @@j86

где:

P$TEST_HASHTABLE_FUNC1$ANSISTRING$$LONGWORD:
      sub   esp,4
      mov   dword ptr [esp],eax
      mov   eax,dword ptr [esp]
      call   P$TEST_BKDRHASH$ANSISTRING$$LONGWORD
      and   eax,2147483647
      add   esp,4
      ret


Цикл с inline:

Код: Выделить всё
@@j33:
      inc   esi

      lea   eax,dword ptr [ebp-8]
      call   FPC_ANSISTR_DECR_REF
      mov   dword ptr [ebp-8],0
      mov   edi,offset _$TEST$_Ld1
      lea   eax,dword ptr [ebp-8]
      call   FPC_ANSISTR_DECR_REF
      mov   dword ptr [ebp-8],edi
      mov   eax,dword ptr [ebp-8]
      call   P$TEST_BKDRHASH$ANSISTRING$$LONGWORD
      and   eax,2147483647
      mov   dword ptr [ebp-4],eax

      lea   eax,dword ptr [ebp-8]
      call   FPC_ANSISTR_DECR_REF
      mov   dword ptr [ebp-8],0
      mov   edi,offset _$TEST$_Ld3
      lea   eax,dword ptr [ebp-8]
      call   FPC_ANSISTR_DECR_REF
      mov   dword ptr [ebp-8],edi
      mov   eax,dword ptr [ebp-8]
      call   P$TEST_BKDRHASH$ANSISTRING$$LONGWORD
      and   eax,2147483647

;; И так 6 раз

      mov   dword ptr [ebp-4],eax
      cmp   esi,50000000
      jl   @@j33


Т.е. у компилятора едет крыша и он начинает зачем-то генерить по 2 DecRef'а на каждую итерацию цикла. А DecRef - очень медленная операция.

Вообще хочу сказать, что, IMHO, string'и и inline - вещи несовместимые. Вы должны очень хорошо понимать, как работа со строками влияет на кодогенерацию, прежде чем пытаться начать что-то оптимизировать.
Max Rusov
постоялец
 
Сообщения: 191
Зарегистрирован: 25.04.2009 15:46:03

Re: Inline директива нетипично замедляет функцию

Сообщение Sergei I. Gorelkin » 17.01.2011 14:55:07

Примерное понимание, отчего так происходит, есть. Сложнее с пониманием того, как это исправить, не переписывая пол-компилятора...
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Inline директива нетипично замедляет функцию

Сообщение devels » 17.01.2011 19:12:31

У меня что const, что нет, все равно замедление происходит.
devels
постоялец
 
Сообщения: 137
Зарегистрирован: 01.09.2010 12:14:38

Re: Inline директива нетипично замедляет функцию

Сообщение *vmr » 17.01.2011 23:36:32

devels писал(а):У меня что const, что нет, все равно замедление происходит.

Ну const по идее должен сильно преобразить генерируемый код. Странно что не происходит никаких изменений в производительности.
Мы же о HashTable_Func говорим?
Аватара пользователя
*vmr
постоялец
 
Сообщения: 168
Зарегистрирован: 08.01.2007 01:46:07
Откуда: Киев

Re: Inline директива нетипично замедляет функцию

Сообщение alexrayne » 17.01.2011 23:41:41

Max Rusov писал(а):Если смотреть код, то цикл _без_ inline:

Вообчето етот код выглядит наиболее оптимальным с.т. зрения объема кода. если инлайны развернуть то он полюбому станет длинее а значит медленнее загрузицо в проц. лишние переходы и пересылки будут значимы не на платформе х86.
имхо, стоит поискать другое направление ускорения кода.

Добавлено спустя 3 минуты 7 секунд:
скажем если ансистринг так напрягает подсчетом ссылок, почемубы не сделать хеш для PCHar?
alexrayne
постоялец
 
Сообщения: 125
Зарегистрирован: 03.12.2008 16:56:26

Re: Inline директива нетипично замедляет функцию

Сообщение Max Rusov » 17.01.2011 23:52:20

Переходы, пересылки :). Там по два лишних Lock'а на каждый вызов, а Вы о мелочах беспокоитесь.
Max Rusov
постоялец
 
Сообщения: 191
Зарегистрирован: 25.04.2009 15:46:03

Re: Inline директива нетипично замедляет функцию

Сообщение alexrayne » 18.01.2011 01:35:03

Век жыви век учись. такой засады я от ансистроки неожидал, хотя оно и вытекает логично....
alexrayne
постоялец
 
Сообщения: 125
Зарегистрирован: 03.12.2008 16:56:26

Re: Inline директива нетипично замедляет функцию

Сообщение devels » 18.01.2011 09:06:51

Логично оно вытекает только в fpc, в delphi все нелогично =), на досуге гляну что за код там генерится. Я воспринимаю inline как кусок кода, который должен вставится на место вызова функции и не более. Т.к. в делфи и фпц отсутствуют макросы, единственное спасение inline, в некоторых местах, где функция вставляется 2-3 раза и функция имеет 2-3 строчки (ради красоты кода) я вставляю inline, особенно там где мне нужна колоссальная скорость, потому что, в данном случае, HashTable_Func вызывается очень часто, это влияет на скорость.

Добавлено спустя 9 минут 3 секунды:
Ну вот скажите, что я должен везде писать в fpc:

Код: Выделить всё
ori_Hash32.BKDRHash(key) and $7FFFFFFF;


Вместо вызова функции HashTable_Func ? Если нет, то реализация фпц работает на 20-10% медленнее. Ну разве не уродство писать везде это, в общем переместил весь алгоритм в одну функцию HashTable_Func из-за глючности string.

P.S. PAnsiChar надо попробовать, это хорошая идея.
devels
постоялец
 
Сообщения: 137
Зарегистрирован: 01.09.2010 12:14:38

След.

Вернуться в Free Pascal Compiler

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

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

Рейтинг@Mail.ru