Some time ago I posted a method that gives precise timing with delay intervals from 15 milliseconds on. This is a copy of the entire post.
I think I achieved a milliseconds delay with precise timing when the delay is small. I used an hybrid Batch-JScript solution with WScript.Sleep method, but in order to avoid the load delay of the JScript section each time it is used, both parts must be active at same time. The JScript process take the delay in milliseconds, do the delay and send a signal to the Batch section. The Batch process send the number of milliseconds to JScript and wait for the signal. The way to achieve this bi-directional communication is via JScript's WshShwll.Exec method that have access to Batch process' Stdin and Stdout streams.
@if (@CodeSection == @Batch) @then
@echo off
setlocal EnableDelayedExpansion
if defined restart goto secondPart
rem First part: execute JScript section, so it re-execute this Batch file
set restart=true
CScript //nologo //E:JScript "%~F0" "%~F0"
goto :EOF
:secondPart
rem To do a delay, use: "echo #millisecs" followed by "set /P ="; use "echo 0" to end
rem To display data in the screen, use: echo data > CON
rem To read data from keyboard, use set /P "data=Prompt: " < CON > CON
set runs=10
For %%t in (5 10 15 20 30 50 100 250 500 1000) do (
set time_idle_ms=%%t
(
set t0=!time!
for /L %%p in (1,1,%runs%) do echo %%t& set /P =
set t1=!time!
)
for /F "tokens=1-8 delims=:.," %%a in ("!t0: =0!:!t1: =0!") do (
set /a "a=(((1%%e-1%%a)*60)+1%%f-1%%b)*6000+1%%g%%h-1%%c%%d, a+=(a>>31) & 8640000"
)
set /a average_time=a*10/runs
echo(Input:!time_idle_ms! ms - Output: Average time !average_time! ms > CON
)
rem Send the signal to end JScript section
echo 0
goto :EOF
@end
// JScript section
// Restart this Batch file with access to its Stdin and Stdout streams
var WshShell = new ActiveXObject("WScript.Shell");
var BatchFile = WshShell.Exec('"'+WScript.Arguments(0)+'"'), delay;
// Get delay, wait and send CR until delay equ 0
while ((delay = BatchFile.Stdout.ReadLine()) != "0" ) {
WScript.Sleep(delay);
BatchFile.Stdin.WriteLine();
}
Output:
Input:5 ms - Output: Average time 15 ms
Input:10 ms - Output: Average time 16 ms
Input:15 ms - Output: Average time 15 ms
Input:20 ms - Output: Average time 32 ms
Input:30 ms - Output: Average time 31 ms
Input:50 ms - Output: Average time 63 ms
Input:100 ms - Output: Average time 109 ms
Input:250 ms - Output: Average time 250 ms
Input:500 ms - Output: Average time 500 ms
Input:1000 ms - Output: Average time 1000 ms
Another test in Windows 8.1 32 bit - 3.2 GHz
Input:5 ms - Output: Average time 14 ms
Input:10 ms - Output: Average time 16 ms
Input:15 ms - Output: Average time 15 ms
Input:20 ms - Output: Average time 31 ms
Input:30 ms - Output: Average time 32 ms
Input:50 ms - Output: Average time 61 ms
Input:100 ms - Output: Average time 110 ms
Input:250 ms - Output: Average time 250 ms
Input:500 ms - Output: Average time 501 ms
Input:1000 ms - Output: Average time 1000 ms
EDIT: pathping
test added
Just to complete this topic, I did a timing test using pathping
and the same code used to test my method. Here it is:
@echo off
setlocal EnableDelayedExpansion
set runs=10
For %%t in (5 10 15 20 30 50 100 250 500 1000) do (
set time_idle_ms=%%t
(
set t0=!time!
for /L %%p in (1,1,%runs%) do pathping 127.0.0.1 -n -q 1 -p %%t >nul
set t1=!time!
)
for /F "tokens=1-8 delims=:.," %%a in ("!t0: =0!:!t1: =0!") do (
set /a "a=(((1%%e-1%%a)*60)+1%%f-1%%b)*6000+1%%g%%h-1%%c%%d, a+=(a>>31) & 8640000"
)
set /a average_time=a*10/runs
echo(Input:!time_idle_ms! ms - Output: Average time !average_time! ms
)
The result show that pathping
is not reliable for small delay times:
Input:5 ms - Output: Average time 48 ms
Input:10 ms - Output: Average time 47 ms
Input:15 ms - Output: Average time 47 ms
Input:20 ms - Output: Average time 62 ms
Input:30 ms - Output: Average time 63 ms
Input:50 ms - Output: Average time 93 ms
Input:100 ms - Output: Average time 141 ms
Input:250 ms - Output: Average time 281 ms
Input:500 ms - Output: Average time 532 ms
Input:1000 ms - Output: Average time 1031 ms