Модуль Timer для Паскаля и не только

Часто при программировании в некоторых местах программы необходимо замерять время исполнения кода, в других просто останавливать выполнение не некоторое время. Например, если писать игру, необходимо создавать код, который бы ограничивал скорость игры. Конечно, если игра очень тяжелоя, то некоторое время она может существовать без такого ограничителя. Но со временем вычислительная мощь компютеров растет (к сожелению не сама по себе) и в игры без ограничителя скорости играть становится невозможно. Или вы решили написать бенчмарк для процессора. Тут уже нужны очень точные средства для замера времени исполнения кода. Таких примеров можно привести уйму. Проще сказать, что в любой более - мение серезной программе измерение времени просто необходимо. К сожалению штатные средства в Паскале ограничиваются только процедурой Delay что описана в модуле CRT. Но она очень сильно зависит от производительности системы. Конечно, можно использовать процедуру GetTime, но она довольно громоздка. А стандартных процедур по замеру времени выполнения кода вобще нет.

Ну и не надо! Мы ведь не чайники? Конечно, не чайники! Сами напишем. При написании программ последовательный код стараются обединить в цыклы. Код, повторяющийся в програме выносят в отдельные процедуры и функции. А код, который явно будет использоватся не в одной программе, выносят в модули. Мы так и сделаем. Давайте создадим в Паскале файл TIMER.PAS и начнем. Как известно название модуля и файла должны совпадать, поетому пишем:

Unit Timer;

Далее необходимо создать интерфейсную часть модуля. Тут давайте остановимся и разберемся что нам нужно. Во-первых нам нужны средства для измерения времени исполнения кода. Во-вторых средства по остановке программы на определенное время. Кроме того, при остановке может, понадобится вывод времени, которое прошло.

interface
procedure Start (var T:longint);
procedure Stop (var T:longint);
procedure Pause (T:longint; Show:boolean);

Итак, мы обявили три процедуры. Процедуры Start и Stop будут служить для измерения времени выполнения кода, а Pause станет заменой Delay. Переменная T - будит служить для передачи данных о времени. Show - для разрешения или запрещения вывода времени на екран. Далее следует исполнительная часть. Она служит для обявления локальных констант, переменных и типов. В данном модуле они нам не нужны:

Implementation

Далее следует самое интересное. Вы еще не задумывались каким же способом мы будем производить замер времени? А почему бы не использавать аппаратный таймер? Темболее это очень просто:

SystemTimer:longint absolute $0040:$006C;

Вот и все! Нет, модуль не весь, но мы имеем полный доступ к аапаратному таймеру, расположеному по физическому адресу $0040:$006C. Значение двойного слова по этому адресу увеличивается на единицу 18.2 раза в секунду и независит от производительности системы. Нам осталось только написать примитивные процедуры для оперирования с таймером:

procedure Start (var T:longint);
begin
T:=SystemTimer;
end;
procedure Stop (var T:longint);
begin
T:=SystemTimer-T;
end;

procedure Pause (T:longint; Show:boolean);
var Xn,Xt:longint;
begin
Xt:=0;
Xn:=SystemTimer;
While ((Xt-Xn)/18.2)*1000 < T do
begin
Xt:=SystemTimer;
If Show then
writeln((xt-xn)/18.2:6:4)
end;
end;

Ну, и долгожданный

end.

Все, компилируем. Хочется сразу проверить работу, не так ли?

Program TimerPrimer;
uses timer;
Var i : integer;
a :Real;
Time : LongInt;
begin
Randomize;
Start(Time);
For i:=1 to 30000 do
a:=Sin(sqrt(i))*Cos(sqrt(Random(10000)));
Stop(Time);
Writeln('Время выполнения: ',Time/18.2:6:4);
Readln;
Pause(10000, True);
end.

Данная программа демонстрирует возможности модутя Timer. В начале она исполняет цыкл от 1 до 30000 в котором высчитывает значение а. Время выполнения этого цыкла и замеряют наши процедуры Start и Stop. После чего, дождавшись нажатия на Enter делаем паузу на 10.000 секунд с разрешаем процедуре Pause осуществлять вывод на екран.

Теперь вы сможете использовать точный таймер в своих программах. А почему же я не воспользовался процедурой GetTime? Только из-за ее громоздкости? Конечно нет. Посмотрите на код. Что мы собственно использовали? Только прямой доступ к физическому адресу аппаратного таймера. Так кто мешает использовать его в других языках программирования? Вот тут то и оно.
 
« Предыдущая статья