You can write C++ code using Windows API to create a utility tool for yourself.
Possible reasons to do so:
- You don't want to use PowerShell.
- You want more control of the
time
program. You may consider falling back to cmd /c <COMMAND>
if <COMMAND>
can only be interpreted by cmd.exe
.
- Normally, utility tools (e.g.
ptime
and MSYS2 time
) take the process creation time into account. But Measure-Command
in PowerShell does not. To get a closer estimation, you can record start time after the creating subprocess and before waiting for it. If you do want to include process creation time, just move the line where the start time is recorded.
Code:
#include <iostream>
#include <chrono>
#include <cstdlib>
#include <process.h>
using namespace std::chrono;
int main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "** Error: no command provided\n");
exit(1);
}
printf("Running ");
for (int i = 1; i < argc; ++i)
printf("[%s] ", argv[i]);
printf("\n");
auto handle = _spawnvp(_P_NOWAIT, argv[1], &argv[1]);
if (handle < 0) {
perror("_spawnv failed");
exit(1);
}
auto start_time = high_resolution_clock::now();
int status;
if (_cwait(&status, handle, _WAIT_CHILD) == -1) {
perror("_cwait failed");
exit(1);
}
auto end_time = high_resolution_clock::now();
auto duration = duration_cast<milliseconds>(end_time - start_time);
printf("duration: %lld ms\n", duration.count());
}
Assume the utility is mtime
. Run mtime mtime
in cmd
:
cmd> mtime mtime
Running [mtime]
** Error: no command provided
duration: 5 ms
The first mtime
measures the running time of the second mtime
, which fails fast (and can be considered as a "Hello World" program). Result should be 5 ~ 7 ms, and is so close to Measure-Command
's estimation:
PowerShell> measure-command{.\mtime|Out-Default}
** Error: no command provided
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 6
Ticks : 64007
TotalDays : 7.40821759259259E-08
TotalHours : 1.77797222222222E-06
TotalMinutes : 0.000106678333333333
TotalSeconds : 0.0064007
TotalMilliseconds : 6.4007
If you count process creation time, the result should be about 11 ms. (Process creation is much slower on Windows than on Linux.)
Caveats:
- Do not pass
_P_WAIT
to _spawnvp
. That way, when the subprocess exits with a non-zero code, your measuring program will fail as well (because it cannot tell whether process creation fails or subprocess exits abnormally).
- Use
cl.exe
or clang++.exe
to compile. Do not use g++.exe
, because it cannot optimize Windows API as well as the other two. (My g++
version is g++ (Rev1, Built by MSYS2 project) 11.3.0
, and clang++
version is clang version 14.0.0; Target: x86_64-pc-windows-msvc
)
- In PowerShell,
measure-command{<COMMAND>|Out-Default}
takes longer if <COMMAND>
can only be resolved in PATH
and your PATH
is long (for my laptop it takes 14 ms for a "Hello World" exe at the bottom of PATH
). In cmd, executable files are cached, so consecutive same commands run faster even if full path is not specified.
In my test, the program was compiled with no optimization. If you turn it on, program should be a little bit faster.
Unable to query system performance data (c0000004)
. I googled it and someone else had the exact same problem, but the forum suggests no solution. Thanks for the suggestion anyway. Can someone suggest something for the other part?