/usr/share/psychtoolbox-3/PsychTests/GetSecsTest.m is in psychtoolbox-3-common 3.0.11.20131230.dfsg1-1build1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 | function GetSecsTest(n)
% GetSecsTest([n=100000])
%
% This test is meant for Microsoft Windows only!
%
% Performs a reliability test of your systems timing hardware. This script
% tries to find out if your systems clock works correctly, ie., if
% GetSecs(), WaitSecs(), Screen('Flip') and the PsychPortAudio functions
% for timed stimulus onset and clock queries will work correctly.
%
% The optional parameter 'n' specifies how many samples to use for each
% test run. A larger number means longer runtime, but higher accuracy of
% the results. Default is 100000 samples.
%
% The test shows a lot of different data plots, but you should focus on the
% results printed to the Matlab command window. If they sound ok then you
% can probably ignore the plots.
%
% The test exercises your timing hardware: It takes 'n' time samples in a
% loop which repeatedly asks GetSecs for the time. GetSecs is used in a
% special debug-mode which also provides time readings from an alternative
% hardware clock. After sampling, the script compares timestamps from the
% normally used high precision timer against samples taken from the low
% precision reference timer. In an ideal world on a well working system,
% both timers should deliver roughly the same time readings. A fixed offset
% between the two clocks is normal - they both count time from system
% bootup or reset, but they are started with a slight offset at system
% start. A slowly drifting offset is not uncommon on lower quality
% hardware, this is considered ok as long as the drift is small. Important
% is that time is monotonically increasing on both clocks and that the
% ratio of elapsed time in both clocks is nearly the same: Dividing elapsed
% time as reported by the high-res timer by the elapsed time reported by
% the low-res timer should yield a ratio of very close to 1.0. The test
% also checks for regular low-res timer ticks, if pause()'ing Matlabs
% execution for multiple seconds affects the clocks in some worrying
% manner (e.g., time slowing down) or if quick switching between multiple
% cpu cores of a multi-core machine causes time inconsistencies, e.g., time
% going backwards.
%
% The test first runs a block of trials with PTBs timing in "normal mode",
% where PTB applies a couple of fixes for broken hardware.
%
% Then it disables those fixes and retests, to assess how earlier PTB
% versions worked on your system - when no such special workarounds were
% available.
%
% Please note that this test is not 100% water-proof, it could
% theoretically have 'false negatives', as many problems with the clocks
% are associated with the behaviour of system power management, which
% itself is influenced by all kind of factors, e.g., what other
% applications are running in parallel to Matlab, if there is any network
% traffic, what kind of hardware is connected to the system...
%
% We will try to improve the test as we learn more about possible causes of
% trouble.
%
% Starting with PTB releases as of 'beta' from 26th November 2007, PTB also
% performs a couple of runtime checks to spot more timer problems. These
% checks are performed all the time while your scripts are executing, so if
% you see some "CRITICAL-WARNING" messages about timer problems at the
% Matlab prompt while your scripts are executing, better take them serious!
%
% For more (up to date) information about system configurations that might
% suffer from clock problems, background information and troubleshooting
% tips, visit the Psychtoolbox Wiki's FAQ section, specifically:
%
% http://psychtoolbox.org/wikka.php?wakka=FaqGetSecsTestFails
%
% Btw. Currently there are no known problems with timers and clocks on PC
% hardware running recent Linux distributions or on any Apple Macintosh
% computers running MacOS/X ;-) -- That's why first versions of this test
% are only targeted at MS-Windows.
% History:
% 11/26/2007 Written (MK).
if IsWin
hardfail = 0;
softfail = 0;
% Set default number of samples to 100000:
if nargin < 1
n = [];
end
if isempty(n)
n = 100000;
end
% Close all plot figure windows:
close all;
drawnow;
clear mex;
drawnow;
% Read the boot.ini if possible:
fid = fopen('C:\boot.ini');
if fid==-1
fprintf('Failed to read C:\\boot.ini - not present or inaccessible.\n\n\n');
else
bootini = transpose(char(fread(fid)));
fclose(fid);
fprintf('Startup config file C:\\boot.ini looks like this:\n');
disp(bootini);
if ~isempty(findstr(bootini, '/usepmtimer'))
fprintf('Seems that your system vendor applied some proper fixes for timing on your system... - Good! ;-)\n\n\n');
else
fprintf('No special configuration options found in your startup file. Either not neccessary, or your\n');
fprintf('system vendor is a moron. We''ll see...\n\n\n');
end
end
% Perform cold init of GetSecs:
GetSecs;
Priority(MaxPriority(0));
fprintf('The first block of tests tests timing precision with the new timing fixes applied...\n\n');
fprintf('Testing precision and tick rate of the low precision reference timer and high precision timer...\n');
% Take n samples of all timers in a measurement loop:
ticks = zeros(1,n);
raw = zeros(1,n);
cooked = zeros(1,n);
for i=1:n
% The -1 argument tells GetSecs to return unfiltered raw values as
% well:
[cooked(i) ticks(i) raw(i)] = GetSecs(-1);
end
% Compute increment between successive low-res timer ticks:
tickinc = diff(ticks);
plot(tickinc * 1000);
title('Delta of low-res timer (msecs) between consecutive samples:');
figure;
hist(tickinc * 1000, 50);
title('Distribution of low-res timer deltas (msecs):');
% Find average duration of a timer tick: This should be 1 msec...
avgtickdelta = median(tickinc(find(tickinc > 0)));
fprintf('The average duration of a low-res timer tick is %f milliseconds.\n', avgtickdelta * 1000);
if abs(avgtickdelta - 0.001) < 0.0001
fprintf('The low-res timer runs at 1 msec resolution. It is suitable as a fallback-timesource in case\n')
fprintf('of trouble with the high-res timer. Good!\n\n');
else
fprintf('The low-res timer did not switch to 1 msec resolution as requested :( - Not good!\n');
fprintf('* PTB has to use a much more inefficient implementation of WaitSecs for timed operations.\n');
fprintf('* The likelihood of defective power management drivers interfering with timing is higher.\n');
fprintf('* Should PTB need to disable the high res timer, then the low-res timer will only provide inadequate\n')
fprintf(' resolution for timed stimulus presentation and timing.\n\n');
end
overrunticks = length(find(tickinc > avgtickdelta + 0.0001));
fprintf('The low-res timer showed timing spikes a total of %i times.', overrunticks);
if overrunticks > 0
fprintf(' Maximum spike %f msecs.\n\n', max(tickinc)*1000);
fprintf('The low-res timer seems to be a bit shaky. That will only be a problem if it shows large spikes often,\n');
fprintf('because it could cause the online correctness tests to fail (false positive) and trigger an unwanted\n');
fprintf('switch from the high-res timer to the unreliable low-res timer.\n');
fprintf('Small occasional spikes are not uncommon on such a deficient system as Windows. Many spikes could\n');
fprintf('indicate that some of your hardware devices or its drivers don''t operate optimally or the system\n');
fprintf('is severly overloaded in some way.\n\n');
else
fprintf('\n\n');
end
figure;
plot(ticks, raw);
title('Elapsed time (msecs) of low-res (x-axis) vs. high-res (y-axis) timer:');
figure;
plot((raw - ticks)*1000);
title('Lag of high-res timer vs. low-res timer, plotted against sample count:');
avglag = mean(raw-ticks)*1000;
lag1 = (raw(1) - ticks(1)) * 1000;
lagn = (raw(n) - ticks(n)) * 1000;
% Most important: The ratio between low-res and high-res timer:
ratio = (raw(n)-raw(1))/(ticks(n)-ticks(1));
fprintf('lag1 = %15.6f , lag%i = %15.6f - Not too important...\n\n', lag1, n, lagn);
fprintf('Ratio of elapsed time in high-res vs. low-res clock: %15.10f\n', ratio);
if abs(ratio - 1.0) > 0.05
fprintf('\n\nTimers DISAGREE by more than 5 percent! --> This likely indicates an UNRELIABLE high-precision timer!!\n\n');
hardfail = 1;
end
if min(diff(raw)) < 0
fprintf('TIME WAS RUNNING BACKWARDS!!! The TSC timers are not synchronized across cpu cores and\n');
fprintf('PTB''s countermeasures were unable to fix this problem! Your system is highly unreliable!\n\n');
hardfail = 1;
end
% Test 3: Let CPU go to sleep for a few seconds and see if there's drift:
% We use pause() here, because WaitSecs would take counter-measures,
% rendering our little test non-diagnostic.
fprintf('\nGoing to sleep for 10 seconds, then checking if this idle time did something bad...\n');
[cooked1 lowres1 highres1] = GetSecs(-1);
pause(10);
[cooked2 lowres2 highres2] = GetSecs(-1);
fprintf('Elapsed time should be 10 seconds: lowres timer says %f secs, highres timer says %f secs.\n', lowres2-lowres1, highres2-highres1);
deltaratio = abs(((lowres2-lowres1) / (highres2-highres1)) - 1.0);
if deltaratio > 0.05
fprintf('\n\nTimers DISAGREE by more than 5 percent! --> This likely indicates an UNRELIABLE high-precision timer (delta %f %%)!\n\n', deltaratio * 100);
hardfail = 1;
end
% Give a summary of behaviour with new PsychTimeGlue implementation:
if hardfail > 0
fprintf('YOUR SYSTEMS TIMING IS BROKEN AND UNRELIABLE!!!\n');
fprintf('PTB''s built in counter-measures are not an effective fix on your system.\n');
fprintf('Read in the online help of this test script and on the PTB Wiki about measures\n');
fprintf('that may allow to fix your systems timing. Apply them, then retest.\n\n');
else
fprintf('So far your system behaved well. This could mean it is well behaved.\n');
fprintf('it could also mean that it is broken, but PTB''s built in work-arounds provide\n');
fprintf('an effective fix for the brokeness.\n');
fprintf('Unfortunately it could also mean that the test is unable to detect real problems (false negative) :(\n\n');
end
fprintf('\n\nThe second block of tests tries to assess how your system would behave without\n');
fprintf('PTB''s special builtin work-arounds enabled. This is a hint on how the system behaved\n');
fprintf('with Psychtoolbox versions prior to 23rd November 2007, and how it would likely behave\n');
fprintf('with other psychophysics toolkits...\n\n');
% Disable PTB's fixes:
% This will disable thread affinity to core zero and allow scheduling to
% cores zero and one - the first two cores in a multi-core system. It will
% not do anything on single-core systems. If there is no sync between
% different cores, this should facilitate detection of the problem:
GetSecs(1+2);
% This will set the low-res timer and scheduling rate back to "factory
% defaults", ie., around 15-16 msecs intervals instead of 1 msec intervals.
% Given the much lower timer IRQ load, this increases the likelihood of the
% system entering lower power modes (P-States or C-States), thereby
% increasing the effects of possible broken power management drivers:
for j=1:10
GetSecs(-2);
end
pause(1);
% Take n samples of all timers in a measurement loop:
ticks = zeros(1,n);
raw = zeros(1,n);
cooked = zeros(1,n);
for i=1:n
% The -1 argument tells GetSecs to return unfiltered raw values as
% well:
[cooked(i) ticks(i) raw(i)] = GetSecs(-1);
end
% Compute increment between successive low-res timer ticks:
tickinc = diff(ticks);
figure;
plot(tickinc * 1000);
title('Block II: Delta of low-res timer (msecs) between consecutive samples:');
figure;
hist(tickinc * 1000, 50);
title('Block II: Distribution of low-res timer deltas (msecs):');
% Find average duration of a timer tick: This should be 1 msec...
avgtickdelta = median(tickinc(find(tickinc > 0)));
fprintf('The average duration of a low-res timer tick is %f milliseconds.\n', avgtickdelta * 1000);
if abs(avgtickdelta - 0.001) < 0.0001
fprintf('The low-res timer still runs at 1 msec resolution. That means that our test is\n');
fprintf('not diagnostic. Please exit and restart Matlab, then retry. Make sure that any\n');
fprintf('kind of multi-media applications are closed while the test is running\n\n');
error('Test failed, because could not disable 1khZ timer Interrupts.');
end
overrunticks = length(find(tickinc > avgtickdelta + 0.0001));
fprintf('The low-res timer showed timing spikes a total of %i times.', overrunticks);
if overrunticks > 0
fprintf(' Maximum spike %f msecs.\n\n', max(tickinc)*1000);
fprintf('The low-res timer seems to be a bit shaky. That will only be a problem if it shows large spikes often,\n');
fprintf('because it could cause the online correctness tests to fail (false positive) and trigger an unwanted\n');
fprintf('switch from the high-res timer to the unreliable low-res timer.\n');
fprintf('Small occasional spikes are not uncommon on such a deficient system as Windows. Many spikes could\n');
fprintf('indicate that some of your hardware devices or its drivers don''t operate optimally or the system\n');
fprintf('is severly overloaded in some way.\n\n');
else
fprintf('\n\n');
end
figure;
plot(ticks, raw);
title('Block II: Elapsed time (msecs) of low-res (x-axis) vs. high-res (y-axis) timer:');
figure;
plot((raw - ticks)*1000);
title('Block II: Lag of high-res timer vs. low-res timer, plotted against sample count:');
avglag = mean(raw-ticks)*1000;
lag1 = (raw(1) - ticks(1)) * 1000;
lagn = (raw(n) - ticks(n)) * 1000;
% Most important: The ratio between low-res and high-res timer:
ratio = (raw(n)-raw(1))/(ticks(n)-ticks(1));
fprintf('lag1 = %15.6f , lag%i = %15.6f - Not too important...\n\n', lag1, n, lagn);
fprintf('Ratio of elapsed time in high-res vs. low-res clock: %15.10f\n', ratio);
if abs(ratio - 1.0) > 0.05
fprintf('\n\nTimers DISAGREE by more than 5 percent! --> This likely indicates an UNRELIABLE high-precision timer!!\n\n');
softfail = 1;
end
if min(diff(raw)) < 0
fprintf('TIME WAS RUNNING BACKWARDS!!! The TSC timers are not synchronized across cpu cores!\n');
softfail = 1;
end
% Test 3: Let CPU go to sleep for a few seconds and see if there's drift:
% We use pause() here, because WaitSecs would take counter-measures,
% rendering our little test non-diagnostic.
fprintf('\nGoing to sleep for 10 seconds, then checking if this idle time did something bad...\n');
[cooked1 lowres1 highres1] = GetSecs(-1);
pause(10);
[cooked2 lowres2 highres2] = GetSecs(-1);
fprintf('Elapsed time should be 10 seconds: lowres timer says %f secs, highres timer says %f secs.\n', lowres2-lowres1, highres2-highres1);
deltaratio = abs(((lowres2-lowres1) / (highres2-highres1)) - 1.0);
if deltaratio > 0.05
fprintf('\n\nTimers DISAGREE by more than 5 percent! --> This likely indicates an UNRELIABLE high-precision timer (delta %f %%)!\n\n', deltaratio * 100);
softfail = 1;
end
fprintf('\nTesting TSC sync across cpu cores on multi-core machines during enforced cpu hopping.\n');
% Test 4: Multicore hopping stress test:
timewarp = 0;
told = GetSecs;
for i=1:n
tnew = GetSecs(mod(i,2)+1);
if tnew < told
fprintf('Time warps (time going backwards!) detected when switching between CPU cores!!! (delta = %f secs)\n', tnew - told);
timewarp = timewarp + 1;
end
told = tnew;
end
if timewarp > 0
fprintf('TIME WAS RUNNING BACKWARDS %i TIMES! Synchronization across cpus is broken on your setup despite PTB taking counter-measures!\n', timewarp);
softfail = 1;
end
% Give a summary of behaviour without new PsychTimeGlue implementation:
if softfail > 0
fprintf('YOUR SYSTEMS TIMING IS BROKEN AND UNRELIABLE!!!\n');
fprintf('Read in the online help of this test script and on the PTB Wiki about measures\n');
fprintf('that may allow to fix your systems timing. Apply them, then retest.\n\n');
end
% Give a final conclusion:
fprintf('\n\nPRELIMINARY CONCLUSION (Disclaimer: No test is perfect, this one isn''t an exception)\n\n');
if hardfail > 0
fprintf('Your system shows severe timing problems and PTB was unable to fix them\n');
fprintf('with its built-in workarounds. Likely, PTB will detect this problems at runtime\n');
fprintf('and switch to a low resolution backup time source, so it is at least useable for\n');
fprintf('studies with low requirements on timing precision.\n');
fprintf('However, if PTB should fail to detect the problems at runtime, you are in trouble.\n');
fprintf('Read the help text of this script and on our Wiki how to solve this properly.\n\n');
else
fprintf('The test could not find indications of timing problems on your system when running\n');
fprintf('with the current PTB. However, there is some likelihood of the test reporting false\n');
fprintf('negatives.\n\n');
end
if hardfail == 0
if softfail > 0
fprintf('When running the timing tests without PTB''s automatic workarounds,\n');
fprintf('your system showed severe timing problems!\n');
fprintf('Studies run with older versions of PTB or other toolkits may have been\n');
fprintf('affected by false time measurements. You may want to run some of your old\n');
fprintf('scripts with the new PTB to see if you get different results.\n\n');
fprintf('Read the help text of this script and on our Wiki for more background information.\n\n');
else
fprintf('So far your system behaved well, even without PTB''s fixes applied. This could mean it is well behaved.\n');
fprintf('Unfortunately it could also mean that the test is unable to detect real problems (false negative) :(\n\n');
end
end
Priority(0);
fprintf('Test finished.\n');
end
if ~IsWin
error('GetSecsTest is not yet capable of meaningful operation on non-Windows systems.');
end
return;
|