Why is pause function so inaccurate on Windows?

tic;
for k =1:2000, pause(0.0014);
end
toc
This code takes about 2.89 seconds on Linux machine but 30 seconds on windows. Tested on different machines. Is there a bug in the pause function?

 Risposta accettata

dpb
dpb il 2 Gen 2023
pause uses the Windows default system timer which is 15 msec unless a high resolution timer has been user-created/set. So, your 2000 iterations * 15 msec/iteration --> 30 sec as you observed.
See <MS High-resolution timers> for the poop from MS on the Win API.
I've not looked to see if TMW has implemented any hooks into the higher-resolution timer or not...although I think maybe tic...toc might use one, but they don't reset the OS system clock.

15 Commenti

Walter Roberson
Walter Roberson il 2 Gen 2023
Modificato: Walter Roberson il 30 Gen 2023
Historically, Mathworks on Windows never promised better than 0.01 resolution for pause() so historically the shortest pause would be between 0.005 and 0.015 seconds.
I thought they had switched to 0.001 resolution a while back.
I don't recall the doc ever being precise enough to say anything about such resolution; athough I see going past the top level doc that uses pause(n) where n is an integer there is an example in the input variables description that claims that pause(5/1000) will wait 5 msec.
Let's see what happens here, I didn't actually try I just used what I thought I recalled from days of yore...
>> tic;for i=1:1000,pause(0.001);end,toc
Elapsed time is 1.008547 seconds.
>>
So, indeed, w/ R2020b and on a Win10 system it appears MATLAB is using a high-resolution timer. I couldn't say when that might have changed...
Maybe OP is using older version...
Thanks for your responses. I am using MATLAB 2022b on an intel-i9 10th generation machine running WIn 10. I ran your code on my computer and it takes 1.008 seconds but if I make the pause time 0.0014, surprisingly it becomes 15 seconds.
>> tic;for i=1:1000,pause(0.0014);end,toc
Elapsed time is 14.970255 seconds.
>> tic;for i=1:1000,pause(0.001);end,toc
Elapsed time is 1.007962 seconds.
Indeed, I can reproduce similar effect on R2020b -- and I suppose it probably goes back beyond as well.
Something is clearly amiss when try to set anything finer than the msec resolution; it appears anything that rounds to the next digit after the msec position causes a drastic shift in behavior; appearing to cause the reversion to the system resolution.
I tried the code snippet with a range of pause values starting with 0.001 + Delta where
Delta went from 10.^[-8:0] and observed the results. Was essentially linear with the expected value until Delta got down to 10^-4 at which point the elapsed time jumped by 3X the expected.
I'd reclassify this as a bug in MATLAB; it may well be a "feature" of the behavior of the Win API high-resolution timer if try to push it beyond its limits, but if it is somehow inherent in the implementation, I think the function should error or at least warn the use.
Older iMac:
>> tic;for i=1:1000,pause(0.001);end,toc
Elapsed time is 1.027860 seconds.
>> tic;for i=1:1000,pause(0.0014);end,toc
Elapsed time is 1.444137 seconds.
In a number of other runs, the time per cycle for the 0.0014 case was closer to 0.0149 -- too often to be an accident.
It seems Windows scheduller granularity jumps from 1 ms to 15 ms suddendly
t0=tic;
n = 10000;
t = zeros(1,n);
dtin = 0.0011;
for i=1:n
pause(dtin);
t(i) = toc(t0);
end
os = 'windows11-22H2';
histogram(diff(t))
xline(dtin, '-', sprintf('dtin=%g', dtin));
title(['R' version('-release') ' - ' os])
pt = linspace(0, 0.002, 101);
nt = numel(pt);
t = zeros(1,nt);
N = 20;
for idx = 1 : nt; dtin = pt(idx); start = tic; for K = 1 : N; pause(dtin); end; stop = toc(start); t(idx) = stop/N; end
subplot(2,1,1);
plot(pt, t); xlabel('nominal pause time'); ylabel('actual pause time');
subplot(2,1,2);
plot(pt, t-pt); xlabel('nominal pause time'); ylabel('average time error');
Results on my iMac are not consistent, but the below is typical:
Some of the othe runs showed distinct peaks 1 or 1.2. A peak error right near the beginning was also common.
Clever, @Bruno Luong! :)
But, while pause reverts to a 15 msec system timer for certain values of the input delay time, tic and toc are still using the high resolution timer.
There's something broke inside pause it appears; who wants to submit the bug report?
I would be interested in seeing the Windows result for my code from https://www.mathworks.com/matlabcentral/answers/1887467-why-is-pause-function-so-inaccurate-on-windows#comment_2545602 that tests a range of pause times systematically.
@Walter Roberson here we go on Windows11
@Bruno Luong Thanks! That is very different than Mac !!
It is interesting that between 0.001 and 0.00117-ish that the change is not smooth.
It's bizzarro that the Mac also has an issue right at the 1 msec point...
I have no idea about internal Mac system timer, but clearly something is amiss on both platforms albeit symptoms are somewhat different.
System timer main goal is to schedule various process/task a fair priority, not to do a precise timer.
pause() as I understand call Sleep() in Windows API, and as in this MS page states:
"After the sleep interval has passed, the thread is ready to run. If you specify 0 milliseconds, the thread will relinquish the remainder of its time slice but remain ready. Note that a ready thread is not guaranteed to run immediately. Consequently, the thread may not run until some time after the sleep interval elapses. For more information, see Scheduling Priorities."
The system time, yes; but one can set a high resolution timer as noted earlier; note also that tic;toc don't suffer the same problem...
tic/toc merely inquires time, it is a passive command, in Windows if it it use CPU counter it is very accurate. Of course the current (MATLAB= thread can be suspend by the OS in between tic and toc to run something else in higher priroty.
pause on the other hand suspends the current thread at certain time, (in some sense an active command that performs a passive task) s and this must goes through system scheduler to handle hundred other processes on the computer.
If the purpose is to wait certain time I might propose this as alternative, but it is NOT suspense the tasks and CPU is still eating CPU unlike pause:
t0=tic;
n = 1000;
t = zeros(1,n);
dtin = 0.0014;
for i=1:n
mypause(dtin);
t(i) = toc(t0);
end
os = 'windows11-22H2';
histogram(diff(t))
xline(dtin, '-', sprintf('dtin=%g', dtin));
title(['R' version('-release') ' - ' os])
function mypause(t)
% Like pause(t) but overcome the resolution of 15 ms on certain Windows OS
% NOTE: current thread is not really suspended
tms = floor(t*1000);
if tms == 0
pause(t);
else
t0=tic;
for i=1:tms
pause(0.001);
telapse = toc(t0);
if telapse > t
break
end
end
tremain = t-telapse;
if tremain > 0
pause(min(tremain,0.001)); % pause only accurate less than 1ms
end
end
end

Accedi per commentare.

Più risposte (1)

Bruno Luong
Bruno Luong il 6 Gen 2023
Modificato: Bruno Luong il 6 Gen 2023
The reason is that Windows task scheduler resolution is the order of 15 ms in some recent versions.
I create some C mex and call Windows API
Sleep(tms);
and
MsgWaitForMultipleObjects(0, NULL, FALSE, tms, 0x0010);
Both exibit the 15 ms resolutions observed by pause() discussed above.
I find this article also observe the 15 ms behavioir on Windows https://randomascii.wordpress.com/2020/10/04/windows-timer-resolution-the-great-rule-change/

Categorie

Scopri di più su Loops and Conditional Statements in Centro assistenza e File Exchange

Prodotti

Release

R2022b

Tag

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by