уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Несколько лет назад я описывал четыре способа измерения точного времени выполнения операции в Delphi. Сегодня рассмотрим этот же вопрос, но уже применительно к Lazarus и Free Pascal. Учитывая, что Lazarus можно использовать как в Windows, так и в Linux, способы того, как измерить точное время выполнения операции в Lazarus и Delphi будут немного различаться. Для начала, определимся с тем, время выполнения какой операции мы будем измерять. Путь это будет вот такая простенькая процедура:

procedure DoSomething;
var i,k: QWord;
begin
  k:=0;
  for i:=0 to 999999999 do
    inc(k);
end;

Учитывая то, что на данный момент я могу проверить работоспособность того или иного способа только на двух платформах: Windows и Linux, ниже я буду давать описание применимости различных способов точного измерения времени, исходя из проверок именно на этих платформах.

Способ №1 — использование функции Now()

Платформы: Windows, Linux.

Как и в случае с Delphi этот способ вполне подойдет для измерения времени, например, следующим образом:

procedure TForm1.Button2Click(Sender: TObject);
var start, stop: TDateTime;
begin
  start:=Now;//засекаем начальное время
  DoSomething;
  stop:=Now;//засекаем конечное время
  {выводим время выполнения операции с точностью до секунды}
  Memo1.Lines.Add(SecondsBetween(start, stop).ToString);
end;

И, хотя в справке Free Pascal ничего не сказано про точность функции Now() (в справке Delphi написано, что точность составляет порядка секунды), я не стал рисковать и все также использовал функцию SecondsBetween() из модуля DateUtils для расчёта количества секунд, пошедших на выполнение операции.

Способ №2 — использование функции GetTickCount

Платформы: Windows, Linux

В настоящее время, в модуле sysutils Free Pascal содержатся две функции, одна из которых помечена как deprecated:

function GetTickCount: LongWord; deprecated 'Use GetTickCount64 instead';
function GetTickCount64: QWord;

Как и в случае с Delphi, используя GetTickCount можно получить время в миллисекундах, затраченное на выполнение операции. Однако, в справке Free Pascal про эту функцию сказано следующее: функция полезна для измерения времени, но не следует делать никаких предположений относительно интервала между тиками. В принципе, примерно тоже сказано и в справке Windows относительно их функций GetTickCount.

Использование функций:

procedure TForm1.Button1Click(Sender: TObject);
var Start, Stop: QWord;
begin
  Start:=GetTickCount64;
  DoSomething;
  Stop:=GetTickCount64;
  Memo1.Lines.Add((stop-start).ToString);
end;

Стоит отметить, что в зависимости от платформы на которой собирается приложение, GetTickCount64 имеет различные реализации. Так, например, если мы собираем приложение под Windows, то GetTickCount64 будет использовать одноименную функцию из модуля Windows:

function GetTickCount64: QWord;
{$IFNDEF WINCE}
var
  lib: THandle;
{$ENDIF}
begin
{$IFNDEF WINCE}
  { on Vista and newer there is a GetTickCount64 implementation }
  if Win32MajorVersion >= 6 then begin
    if not Assigned(WinGetTickCount64) then begin
      lib := LoadLibrary('kernel32.dll');
      WinGetTickCount64 := TGetTickCount64(
                             GetProcAddress(lib, 'GetTickCount64'));
    end;
    Result := WinGetTickCount64();
  end else
{$ENDIF}
    Result := Windows.GetTickCount;
end;

Если же мы используем Linux, то реализация GetTickCount64 основывается на использовании clock_gettime() — функции из языка Си:

function GetTickCount64: QWord;
var
  tp: TTimeVal;
  {$IFDEF HAVECLOCKGETTIME}
  ts: TTimeSpec;
  {$ENDIF}
 
begin
 {$IFDEF HAVECLOCKGETTIME}
   if clock_gettime(CLOCK_MONOTONIC, @ts)=0 then
     begin
     Result := (Int64(ts.tv_sec) * 1000) + (ts.tv_nsec div 1000000);
     exit;
     end;
 {$ENDIF}
  fpgettimeofday(@tp, nil);
  Result := (Int64(tp.tv_sec) * 1000) + (tp.tv_usec div 1000);
end;

Способ №3 — использование функций QueryPerformanceCounter и QueryPerformanceFrequency

Платформы: Windows

Использовать функции можно, подключив в uses модуль windows. Соответственно, под Linux метод использовать невозможно, а посмотреть реализацию способа в Windows можно в предыдущей статье про точное измерение времени выполнения операций.

Способ №4 — когда разбираться с функциями лень. Используем компонент TEpikTimer

По аналогии с классом TStopwatch из Delphi, компонент TEpikTimer дает нам широкие возможности по определению времени, затраченного на выполнение какой-либо операции. В принципе, этим компонентом я обычно и пользуюсь.

Чтобы установить компонент, заходим в меню «Пакет — Установить/удалить пакеты»

 

В списке «Доступные для установки» ищем пакет под названием etpackage_dsgn

Жмем кнопку «Установить выбранное» под списком и, потом, «Сохранить и перезапустить IDE». В новом окне жмем «Продолжить», Lazarus пересоберется и на вкладке System появится новый компонент TEpikTimer:

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

procedure TForm1.Button3Click(Sender: TObject);
begin
  EpikTimer1.Clear; //сбрасываем таймер
  EpikTimer1.Start; //засекаем время
  DoSomething;
  EpikTimer1.Stop;  //останавливаем таймер
  {выводим время выполнения операции в секундах}
  Memo1.Lines.Add(EpikTimer1.Elapsed.ToString);
end;

Здесь я вывел время выполнения операции в секундах. Также EpikTimer умеет выводить время в различных форматах.

Помимо представленных выше способов, вы можете также воспользоваться и другими способами измерения точного времени выполнения операции в Lazarus и Free Pascal, например компонентом TJclCounter от JEDI, однако, в любом случае, эти компоненты будут использовать один из способов, рассмотренных выше, как это делает EpikTimer. 

уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
4 2 голоса
Рейтинг статьи
Подписаться
Уведомить о
0 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии