I want to offer a solution for the problem of measuring the execution time of code, especially when it needs to read data from standard input.
MacOS, Unix, Linux, Ubuntu
If you happen to be on MacOS or another Unix-like operating system, you are probably smiling right now. This is because you have available to you a handy little utility called time
. Problem solved! time
does exactly what we want. And is easy to use, if you do not mind redirecting standard input:
time mytask < in.txt
Windows
Windows 2003, released two years before I was born, apparently featured a similar utility called timeit
. But Microsoft removed it from the next versions of Windows. This simple tool was replaced by a convoluted and largely unusable Measure-Command
inside PowerShell.
Goal
I want to re-create timeit
on Windows which will allow easily sending input data to my compiled program .exe
, measure execution time with precision, show output, and report the exit code of my program.
For example, if I have a program add.cpp
which takes three numbers from standard input and adds them up (see below), I want to be able to time its execution like this:
timeit add.exe 2 4 5
Solution
Of course, my first and natural impulse was to count Mississippily — something like https://youtu.be/_RP3DZNKJ28?t=142
But with time this evolved slightly into the following bat
file
Windows Batch file
@echo off
REM By erekle https://mirror.codeforces.com/profile/erekle
REM ------------------------------------------
REM ------------------------------------------
REM This utility times execution of programmes
REM ------------------------------------------
REM ------------------------------------------
REM For usage and help, run this bat file without any arguments
REM -------- BEGIN: Read main parameters --------
set self=%~n0
set executable=%1
set flag=%2
set infile=%3
REM -------- BEGIN: Read main parameters --------
REM -------- BEGIN: Read command input --------
set params=%2
shift
shift
:loop1
if "%1"=="" goto after_loop
set params=%params% %1
shift
goto loop1
:after_loop
REM -------- E N D: Read command input --------
IF [%executable%]==[] (
echo.
echo %self%: Times execution of a program or a command
echo.
echo Usage:
echo. [97m%self% [96mprog.exe
echo. [97m%self% [96mprog.exe [92mparam1 param2 param3 [90m...
echo. [97m%self% [96mprog.exe [95m-f [93minput.txt[0m
exit /b
)
IF NOT EXIST %executable% (
echo [91mProgram not found: [95m%executable%[0m
exit /b
)
IF [%flag%]==[] (
powershell -Command "$duration = Measure-Command { .\%executable% | Out-Default }; $seconds = $duration.TotalSeconds; Write-Host "`n____________________________________________" -ForegroundColor Cyan; Write-Host 'Execution time (seconds):' -NoNewline; Write-Host "`t$seconds" -ForegroundColor Cyan; exit $LastExitCode"
GOTO checkerrors
exit /b
)
IF [%flag%]==[-f] (
IF [%infile%]==[] (
echo [91mOption -f should be followed by input file name[0m, for example:
echo. [96m%self% %executable% [95m-f [93minput.txt[0m
exit /b
)
) ELSE (
powershell -Command "$duration = Measure-Command { echo %params% | .\%executable% | Out-Default }; $seconds = $duration.TotalSeconds; Write-Host "`n____________________________________________" -ForegroundColor Cyan; Write-Host 'Execution time (seconds):' -NoNewline; Write-Host "`t$seconds" -ForegroundColor Cyan; exit $LastExitCode"
GOTO checkerrors
exit /b
)
REM Consider last option: %flag% is -f and %infile% was supplied
IF NOT EXIST %infile% (
echo [91mInput file not found: [95m%infile%[0m
exit /b
)
powershell -Command "$duration = Measure-Command { .\%executable% | Out-Default }" < %infile%; $seconds = $duration.TotalSeconds; Write-Host "`n____________________________________________" -ForegroundColor Cyan; Write-Host 'Execution time (seconds):' -NoNewline; Write-Host "`t$seconds" -ForegroundColor Cyan; exit $LastExitCode
:checkerrors
IF NOT %errorlevel%==0 (
echo [91mWarning: [0mExit code: [91m%errorlevel%[0m
) ELSE (
echo [0mExit code: [92m%errorlevel%[0m
)
Usage
- You can save this code in a text file with extension
.bat
(for exampletimeit.bat
) - Do not use
time.bat
though, astime
is an existing Windows command with different functionality - Place
timeit.bat
somewhere on Windows %PATH% so that it can be found from any directory - Now you can run
timeit
and it will report three different ways to use it
One option allows you to just put your input data right in the command line and your code will receive it on its standard input!
For example, if you execute the following command, add.exe
will receive 2 4 5
on standard input:
timeit add.exe 2 4 5
This might even work if you manually enter 200,000 positive integers from the keyboard ;)
Here is the full example:
Final Standings
With this code, your situation on Windows might be even slightly better than the situation on a Mac or Linux.
I hope this brings some hope back to Windows users — at least until we save money for a Mac ;)