{ -= MEASURE =-  (c) Куранов Антон 19.04.1996  }
{ Модуль для измерения времени выполнения частей программ }

unit Measure;

INTERFACE

const
	Frequency	= 1193180;		{ Собственная частота таймера 8253 }
	DefaultDiv	= 1193;			{ Делитель частоты по умолчанию }

{ Запуск счетчика времени. Вызов	данной процедуры должен стоять
	перед тестируемым фрагментом программы. }
procedure	StartTimer;

{ Завершение работы счетчика и вычисление результатов измерений. }
procedure	StopTimer;

{ После выполнения измерения функции GetTicks и GetTime выдают время
	выполнения измеряемого фрагмента программы. Функция GetTicks возвращает
	время выполнения в "тиках", а функция GetTime - в секундах. }
function		GetTicks	: LongInt;
function		GetTime	: Real;

{ Установить новый делитель частоты. Количество "тиков" в одной секунде
	определяется, как Frequency/Divider. По умолчанию делитель частоты Divider
	равен 1193, что соответствует 1000 "тикам" в секунду. Таким образом,
	уменьшая делитель можно повысить точность измерений, однако установка
	слишком большой частоты (маленького делителя) может привести к сбою
	системы. Следует учесть еще и то, что на каждый "тик" тратится дополни-
	тельное время, так как каждый раз происходит вызов прерывания таймера,
	причем разное в зависимости от скорости процессора. }
procedure	SetDivider( D : Word );


IMPLEMENTATION

uses Dos;

var
	Timer			: LongInt;
	StartTime	: LongInt;
	FinishTime	: LongInt;
	WasStarted	: Boolean;
	Divider		: Word;
	OldIntPtr	: Pointer;
	OldExitProc	: Pointer;

{$F+}
procedure TimerInt; interrupt;
begin
	Inc( Timer );
end;

procedure ExitProcedure; far;
begin
	ExitProc := OldExitProc;
	if WasStarted then StopTimer;
end;
{$F-}

procedure StartTimer;
begin
	WasStarted := True;
	Timer := 0;
	StartTime := 0;
	FinishTime := 0;
	GetIntVec( $1C, OldIntPtr );
	SetIntVec( $1C, Addr( TimerInt ) );
	Port[ $43 ] := $3C;
	Port[ $40 ] := Lo( Divider );
	Port[ $40 ] := Hi( Divider );
	StartTime := Timer;
end;

procedure StopTimer;
begin
	if WasStarted then begin
		FinishTime := Timer;
		Port[ $43 ] := $3C;
		Port[ $40 ] := $FF;
		Port[ $40 ] := $FF;
		SetIntVec( $1C, OldIntPtr );
		WasStarted := False;
	end;
end;

procedure SetDivider;
begin
	StartTime := 0;
	FinishTime := 0;
	Timer := 0;
	if D = 0 then Divider := $FFFF
	else Divider := D;
end;

function GetTicks;
begin
	if FinishTime <> 0 then
		GetTicks := ( FinishTime - StartTime )
	else GetTicks := 0;
end;

function GetTime;
begin
	GetTime := ( Divider/Frequency )*GetTicks;
end;

begin
	WasStarted := False;
	OldExitProc := ExitProc;
	ExitProc := Addr( ExitProcedure );
	SetDivider( DefaultDiv );
end.
