Delphi: як виміряти точний час виконання операції?

  1. Спосіб №1 - найпростіший. Використовуємо функцію Now ()
  2. Спосіб №2 - використовуємо Windows API. Функція GetTickCount ().
  3. Спосіб №3 - продовжуємо використовувати Windows API. Функції QueryPerformanceCounter і QueryPerformanceFrequency
  4. Спосіб №4 - використовуємо можливості Delphi. модуль System.Diagnostics
  5. Підведемо підсумок
  6. Книжкова полиця

Точний час вимірювання виконання операції в Delphi може стане в нагоді в багатьох випадках, починаючи від самого простого - показати користувачеві час, витрачений на виконання тривалої операції (тут, до речі, висока точність потрібна рідко) і, закінчуючи, ситуаціями, коли в цілях оптимізації програми нам необхідно виявити в програмі найбільш «вузькі» місця в яких програма «застряє» на тривалий проміжок часу. В основному, остання ситуація характерна при розробці програм, що використовують і обробних великі масиви даних, коли швидкість виконання операцій виходить, якщо не на перше, то на одне з перших місць у вимогах до додатка.
Є кілька способів дізнатися час виконання операцій в Delphi і всі ці способи, в принципі, розглянуті як в Мережі, так і моєму блозі. Тому представлена ​​нижче стаття - це лише об'єднання всіх можливих способів вимірювання часу в Delphi і досвідчений Delphi-програміст тут навряд чи зустріне щось нове для себе.

Спосіб №1 - найпростіший. Використовуємо функцію Now ()

Найпростіший і найменш точний спосіб виміряти час, витрачений на виконання будь-якої операції в Delphi - скористатися функцією Now () з модуля System.SysUtils.

Вихідний код може виглядати, наприклад, так:

uses System. DateUtils; .... var Start, Stop: TDateTime; Elapsed: int64; begin Start: = Now; // засікли початок виконання операції DoSomething; // виконуємо щось Stop: = Now; // засікли закінчення виконання операції Elapsed: = SecondsBetween (Start, Stop); // час в секундах end;

Цілком ймовірно, що у вас може виникнути резонне питання: чому я використовував в прикладі SecondsBetween (), а не, наприклад, MilliSecondsBetween () для більшої точності? Зробив я це, спираючись виключно, на опис функції Now () в офіційній довідці по Delphi, яка говорить наступне: «Не дивлячись на те, що в TDateTime можуть передаватися мілісекунди, Now () має точність до найближчої секунди«. Тобто, якщо використовувати Now (), то визначати інтервал часу з точністю до мілісекунд - не має сенсу.

Спосіб №2 - використовуємо Windows API. Функція GetTickCount ().

Функція GetTickCount () не має параметрів і повертає кількість мілісекунд, що пройшли з моменту запуску системи. судячи за офіційною довідкою Microsoft , Р азрешеніе функції GetTickCount () обмежена дозволом системного таймера, яке зазвичай знаходиться в діапазоні від 10 до 16 мілісекунд. При цьому, лічильник мілісекунд буде обнулений, якщо система запущена більш 49,7 днів.
В принципі, приклад використання цієї функції схожий на попередній:

var Start, Stop: cardinal; Elapsed: cardinal; begin Start: = GetTickCount; // засікли початок виконання операції DoSomething; // виконуємо щось Stop: = GetTickCount; // засікли закінчення виконання операції Elapsed: = Stop -Start; // час в мілісекундах end;

Так, використовуючи функцію GetTickCount () ми можемо засікти час виконання операції в Delphi з точністю до мілісекунди. Якщо і така точність Вам не підходить і необхідно виміряти інтервал часу ще точніше, то наступний спосіб - для вас.

Спосіб №3 - продовжуємо використовувати Windows API. Функції QueryPerformanceCounter і QueryPerformanceFrequency

Про ці функції я розповідав давним-давно , Але, повторюся ще раз.

QueryPerformanceCounter - витягує поточне значення лічильника продуктивності, яке представляє собою мітку часу з високою роздільною здатністю (<1 мкс), яка може використовуватися для вимірювання часових інтервалів.
QueryPerformanceFrequency - витягує частоту лічильника продуктивності. Частота лічильника продуктивності фіксується при завантаженні системи і узгоджена у всіх процесорах, тому значення потрібно запитувати тільки при ініціалізації програми, а результат може бути кешуватися.

Для того, щоб скористатися цими функціями для відліку інтервалу часу, витраченого на виконання будь-якої операції в Delphi нам необхідно оформити вихідний код, наприклад, таким чином:

var iCounterPerSec: TLargeInteger; T1, T2: TLargeInteger; // значення лічильника ДО і ПІСЛЯ операції begin QueryPerformanceFrequency (iCounterPerSec); // визначили частоту лічильника QueryPerformanceCounter (T1); // засікли час початку операції DoSomething; // виконали щось QueryPerformanceCounter (T2); // засікли час закінчення ShowMessage (FormatFloat ( '0.0000', (T2 - T1) / iCounterPerSec) + 'сек.'); // вивели кількість секунд на виконання операції end;

З отриманими значеннями T1 і T2 можна «гратися» як завгодно, наприклад, виводити окремо хвилини / секунди / мілісекунди і т.д. тут все залежить від ваших потреб і бажань, я ж показав найбільш простий приклад використання лічильника з високою роздільною здатністю в Delphi.

Спосіб №4 - використовуємо можливості Delphi. модуль System.Diagnostics

Про це модулі я також згадував побіжно в деяких статтях блогу, наприклад, тут . Модуль цей з'явився в Delphi вже досить давно (можу помилятися, але, по-моєму з Delphi XE-XE2). У модулі представлена всього один запис (record) - TStopwatch, яка є ні чим іншим, як зручною «обгорткою» для використання таймерів з високою роздільною здатністю з прикладу вище. Судячи з досить скромною довідці , TStopwatch використовує функціональні можливості, які залежать від операційної системи, для отримання доступу до таймерів з високою роздільною здатністю, якщо вони доступні. Якщо таймери з високою роздільною здатністю в ОС недоступні, то використовуються звичайні таймери.

Незважаючи на те, що TStopwatch - це запис, для коректного використання все ж необхідно викликати метод Create або StartNew.

Опис TStopwatch наступне:

TStopwatch = record strict private class var FFrequency: Int64; class var FIsHighResolution: Boolean; class var TickFrequency: Double; strict private FElapsed: Int64; FRunning: Boolean; FStartTimeStamp: Int64; function GetElapsed: TTimeSpan; function GetElapsedDateTimeTicks: Int64; function GetElapsedMilliseconds: Int64; function GetElapsedTicks: Int64; class procedure InitStopwatchType; static; public class function Create: TStopwatch; static; class function GetTimeStamp: Int64; static; procedure Reset; procedure Start; class function StartNew: TStopwatch; static; procedure Stop; property Elapsed: TTimeSpan read GetElapsed; property ElapsedMilliseconds: Int64 read GetElapsedMilliseconds; property ElapsedTicks: Int64 read GetElapsedTicks; class property Frequency: Int64 read FFrequency; class property IsHighResolution: Boolean read FIsHighResolution; property IsRunning: Boolean read FRunning; end;

  • Властивість IsHighResolution вказує, заснований чи таймер на лічильнику продуктивності з високою роздільною здатністю.
  • Метод Start () починає вимірювати минулий час.
  • Метод Stop () зупиняє вимір минулого часу.
  • Властивість ElapsedMilliseconds отримує загальне минулий час в мілісекундах.
  • Властивість Elapsed отримує минулий час в вигляді TTimeSpan.

Скористатися можливостями TStopwatch також досить просто, наприклад, так:

uses System. Diagnostics; ... var SW: TStopwatch; begin SW: = TStopwatch. StartNew; SW. Start; DoSomething; SW. Stop; ShowMessage (SW. Elapsed. TotalMinutes. ToString); end;

У представленому вище прикладі ми скористалися TStopwatch і вивели кількість хвилин (з дробовою частиною), що пішли на виконання якоїсь операції. В цілому ж, використовуючи можливість TStopwatch.Elapsed можна виводити будь-які значення, обмежені лише можливостями TTimeSpan ( см. довідку ).

Підведемо підсумок

Отже, щоб виміряти точний час виконання операції в Delphi, необхідно, перш за все визначитися з тим яка точність Вас влаштує? Якщо досить, щоб інтервал часу визначався з точністю до секунди, то достатньо скористатися звичайною, давно відомою функцією Now () . Так, точність найнижча, але, зате - просто.

Якщо ваше вимога до точності вимірювання часу обмежується мілісекунд - використовуйте GetTickCount () : Просто, достатньо надійно (тільки, якщо ви не плануєте вимірювати інтервал часу більше 49,7 днів).

Якщо ж потрібно використовувати найточніші методи вимірювання часу на виконання операції, то тут або зв'язка функцій QueryPerformanceCounter () і QueryPerformanceFrequency (), або більш зручний спосіб - використовувати TStopwatch з модуля System.Diagnostics.

Книжкова полиця

Точний час вимірювання виконання операції в Delphi може стане в нагоді в багатьох випадках, починаючи від самого простого - показати користувачеві час, витрачений на виконання тривалої операції (тут, до речі, висока точність потрібна рідко) і, закінчуючи, ситуаціями, коли в цілях оптимізації програми нам необхідно виявити в програмі найбільш «вузькі» місця в яких програма «застряє» на тривалий проміжок часу

Автор: Антон Григор'єв

Назва: Про що не пишуть в книгах по Delphi

Опис Розглянуто малоосвітлених питання програмування в Delphi. Описано методи інтеграції VCL і API.

Купити на ЛітРес Купити на ЛітРес Автор:Автор:

Володимир Шапорев, Дмитро Кузан
Назва: Програмування Win32 API в Delphi
Опис: Розглянуто застосування різних інтерфейсів прикладного програмування Windows (Win32 API) при розробці додатків з використанням Delphi. Описано основи роботи з API Купити на ЛітРес