function TimingTest
% TimingTest compares four timers for accuracy and ability to run 
% at high processor priority.
% 
% We test four timers against each other. Typically
% they are based on two independent timebases (UpTime and
% Microseconds), which may run at slightly different rates. You may
% run GetSecsTest.m to bring the two timebases into synch; TimingTest
% will document its success. GetSecs and WaitSecs both use the same
% timebase, usually UpTime. And GetTicks and CPUTIME use the Time
% Manager's Microseconds. GetSecsTest.m scales UpTime's rate to agree
% with that of Microseconds.
% 
% GetSecs and WaitSecs use the VideoToolbox Seconds.c to access the
% best available Mac timebase. Usually this is a counter in the
% PowerPC chip, which is extremely reliable and accurate, accessed
% through Apple's UpTime routine, which is available on nearly all
% PowerPC Macs (the exceptions are old: 6100 and NuBus PowerMacs).
% 
% Most time information on Macs (including time of day, Ticks,
% Microseconds, and Matlab's CPUTIME) is derived from the Mac OS Time
% Manager's Microseconds timebase, which is interrupt-driven. Macs can
% occasionally miss interrupts, so the Time Manager's timebase
% occasionally loses time. (When UpTime is not available, then
% Seconds.c uses the Time Manager's Microseconds routine.)
% 
% Matlab's CPUTIME is unreliable. 'help cputime' says that its internal 
% counter may occasionally overflow. Use GetSecs instead.
% 
% TIMING ADVICE: the first time you access any MEX function or M file,
% Matlab takes several hundred milliseconds to load it from disk.
% Allocating a variable takes time too. Usually you'll want to omit
% those delays from your timing measurements by making sure all the
% functions you use are loaded and that all the variables you use are
% allocated before you start timing. MEX files stay loaded until you
% flush the MEX files (e.g. by changing directory or calling CLEAR
% MEX). M files and variables stay in memory until you clear them.
% 
% HISTORY: In Mac OS 9.0 GetSecs ran about 1% slow. 
% This was because the Apple-supplied conversion factor for
% UpTime was slightly off. The Psychtoolbox provided GetSecsTest to allow
% the user to apply a correction factor to get the time right. However, in
% Mac OS 9.2.2 the problem is gone. We don't know which version of the OS
% instituted the fix.
% 
% See GetSecsTest to calibrate GetSecs.

% 1/29/97  dhb  Added some comments.
% 3/4/97   dhb  Added GetSecs examples too.
% 3/15/97  dgp	Enhanced printout. Preload WaitSecs. 
% 3/16/97  dgp	Synch to ticks when timing ticks. Test Matlab's cputime.
% 3/19/97  dhb  First WaitSecs call needed an argument, inserted.
% 7/19/98  dgp  Removed all mention of obsolete TIMER.
% 2/18/99  dgp  Enhanced to test improved accuracy of GetSecs.
% 4/23/99  dgp  Say more about Mac OS Time Manager.
% 6/18/02  dgp  Merged in the code from PriorityTest.

fprintf('TimingTest\n');
fprintf('\nASSESS ACCURACY OF CLOCKS, ONE AGAINST ANOTHER.\n\n');
fprintf('WaitSecs and GetSecs are based on the VideoToolbox Seconds.c, which uses the \n');
fprintf('UpTime timebase (a counter in your PowerPC chip), if available. WaitTicks and \n');
fprintf('CPUTIME are based on the Mac OS Time Manager.\n\n');

% Specify time interval
intervalSecs=1;

% Measure calling overhead
GetSecs;					% make sure MEX files are loaded, to avoid delay later.
startSecs=0;getsecsOverhead=0;	% make sure variables are allocated, " ".
startSecs=GetSecs;
getsecsOverhead=GetSecs-startSecs;

% Time an interval defined by WaitTicks.
WaitTicks(0);GetSecs;		% make sure MEX files are loaded, to avoid delay later.
startSecs=0;elapsedSecs=0;	% make sure variables are allocated, " ".
ticks=round(intervalSecs*60.15);
WaitTicks(1);				% synch to the ticks
startSecs=GetSecs;
WaitTicks(ticks);
elapsedSecs=GetSecs;
elapsedSecs=elapsedSecs-startSecs;
fprintf('%-18s: %s says it took %.4f of nominal.\n','WaitTicks','GetSecs',elapsedSecs/(ticks/60.15));

% Time an interval defined by WaitSecs.
GetSecs;WaitSecs(0);		% make sure MEX file is loaded, to avoid delay later.
startSecs=GetSecs;
WaitSecs(intervalSecs);
elapsedSecs=GetSecs-startSecs-getsecsOverhead;
fprintf('%-18s: %s says it took %.4f of nominal.\n','WaitSecs','GetSecs',elapsedSecs/intervalSecs);

% Time an interval defined by WaitTicks.
WaitTicks(0);GetSecs;		% make sure MEX files are loaded, to avoid delay later.
startSecs=0;elapsedSecs=0;	% make sure variables are allocated, " ".
ticks=round(intervalSecs*60.15);
WaitTicks(1);				% synch to the ticks
startSecs=cputime;
WaitTicks(ticks);
elapsedSecs=cputime;
elapsedSecs=elapsedSecs-startSecs;
fprintf('%-18s: %s says it took %.4f of nominal.\n','WaitTicks','cputime',elapsedSecs/(ticks/60.15));

% Time an interval defined by WaitSecs.
WaitSecs(0);cputime;		% make sure MEX files are loaded, to avoid delay later.
startSecs=0;elapsedSecs=0;	% make sure variables are allocated, " ".
startSecs=cputime;
WaitSecs(intervalSecs);
elapsedSecs=cputime-startSecs-getsecsOverhead;
fprintf('%-18s: %s says it took %.4f of nominal.\n','WaitSecs','cputime',elapsedSecs/intervalSecs);

%%%%%%%%%%%% PART 2 %%%%%%%

fprintf('\nMEASURE EFFECT OF PRIORITY\n\n');
fprintf('TIme the same interval using several timers at various priority levels. \n');
fprintf('Some timers work only at low priority. \n\n');

fprintf('%12s %12s %12s %12s %12s \n','priority','PeekBlanking','getticks','cputime','getsecs'); 

for p=0:7
	priority(p);

	f=screen(0,'PeekBlanking');
	ticks=getticks;
	time=cputime;
	gs=getsecs;

	for i=1:200000;end

	f=screen(0,'PeekVBL')-f;
	ticks=getticks-ticks;
	time=cputime-time;
	gs=getsecs-gs;

	priority(0);
	fprintf('%12d %12d %12d %12.3f %12.3f\n',p,f,ticks,time,gs); 
end
