94

So, Unix has a time command that lets users time their code/other things. I was wondering if the Windows command line has anything similar.

Also, I asked a previous question regarding the Linux command line here. Can we do the same for Windows? If so, how?

efficiencyIsBliss
  • 2,289
  • 4
  • 20
  • 14
  • 2
    Windows has the standard cmd.exe but if you want something closer to the linux version get the powershell, its way better. – Guillermo Jan 01 '11 at 22:53
  • I searched for "command time for windows" on google on the first result gives: [http://stackoverflow.com/questions/673523/how-to-measure-execution-time-of-command-in-windows-command-line](http://stackoverflow.com/questions/673523/how-to-measure-execution-time-of-command-in-windows-command-line) – David Michel Jan 01 '11 at 22:55
  • I'm on Windows 7 and I just tried the solution posted above. I get the following error: `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? – efficiencyIsBliss Jan 01 '11 at 23:10
  • @eff, timeit.exe is for server 2003 and XP AFAIK, I don't think its compatible with 7. – John T Jan 01 '11 at 23:39

12 Answers12

68

Use Powershell

Measure-Command {start-process whateveryouwantexecute -Wait}

Edited to your need @efficiencylsBliss:

Measure-Command {start-process java -argumentlist "whateverargumentisneeded" -wait}
mjsr
  • 6,438
  • 4
  • 29
  • 37
  • Here's what I tried: `Measure-Command {java test -Wait}`. I got a list of time-related statistics, but not the output from the code. Am I doing something wrong? – efficiencyIsBliss Jan 02 '11 at 00:50
  • @efficiency: You forgot the `start-process` command. – Sasha Chedygov Jan 02 '11 at 01:40
  • Start-Process : A positional parameter cannot be found that accepts argument '.\6-8.txt'. At line:1 char:31 + Measure-Command {start-process <<<< java .\dancebattle .\6-8.txt -wait} + CategoryInfo : InvalidArgument: (:) [Start-Process], ParameterBindingException + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.StartProcessCommand` – efficiencyIsBliss Jan 02 '11 at 15:01
  • The above is what I got when I tried the command on a file named dancebattle that took the file 6-8.txt as input. – efficiencyIsBliss Jan 02 '11 at 15:03
  • @efficiencylsBliss i add an example suited to your need, don't forget that you can read about any cmdlet trough the command "man" (which in fact is an alias to get-help) – mjsr Jan 02 '11 at 19:53
  • 1
    I'm trying to measure the time it takes to run a Python script using `Measure-Command {start-process \Python27\python test.py -Wait}`. This opens up a new cmd window to run the process, but then closes the window when it's done running. I'd like to see the output of the script as well, so how can I keep the window open? – John Thompson Apr 10 '13 at 15:34
  • 2
    @JohnPeterThompsonGarcés use the -NoNewWindow parameter of the start-process cmdlet – mjsr Apr 10 '13 at 16:29
  • Not ideal for short processes (<0.1s), there's overhead to start-process – ACyclic Oct 05 '13 at 17:52
  • How do I redirect the output while using this method? ie `Measure-Command {start-process -NoNewWindow python myscript.py > out.txt -Wait}` isn't working correctly. It outputs everything to the console – SwimBikeRun Nov 11 '14 at 19:45
  • `Measure-Command` is mostly unusable for performance tracking. It displays time with millisecond resolution, but actually rounds it to seconds. This is BS. – kirilloid Jan 31 '16 at 10:13
  • @kirilloid - what would be the way to do this now? – Alex S Sep 05 '19 at 12:19
  • Using `Measure-Command { Start-Process -NoNewWindow -Wait oc version }` (I'm measuring a command 'oc version') will show the output in the same powershell window, and one of the returned measures will be TotalSeconds, which includes 'tick'-level resolution (so in effect much more granular than milliseconds). This is on Windows 10 – Cameron Kerr Apr 06 '21 at 05:07
  • This command omits the sub command output, pipe the sub command to out-default to fix the issue https://stackoverflow.com/questions/3513650/timing-a-commands-execution-in-powershell – Shayan Mar 24 '23 at 00:58
25

I'm using Win XP, for some reason, timeit.exe is not working for me. I found another alternative: ptime:

ptime 1.0 - Accurately measure program execution time

ptime will run any specified command and parameters, and measure the execution time (run time) in seconds, accurate to 5 millisecond or better. It is an automatic process timer, or program timer used for benchmark purposes.

Murali Krishnan
  • 251
  • 3
  • 2
22

You can cheat a little with a batch script...

@echo off
echo %time% < nul
cmd /c %1
echo %time% < nul

Then run your program as an argument to this script...

timer myprogram.exe

and for arguments...

timer "myprogram.exe -sw1 -sw2"

example output:

17:59:20.02
some text
17:59:20.03

place the batch script somewhere in your PATH variable, e.g. C:\Windows\System32 and name it timer.cmd. Of course there is a small performance hit of forking a second cmd instance, although very minimal.

John T
  • 163,373
  • 27
  • 341
  • 348
  • that prompt wouldn't work, `@echo off echo %time% < nul cmd /c %1 echo %time% < nul ` you left out the closing % on the environment variable(?) –  Jan 07 '11 at 18:07
  • There is no closing % for command line parameters like %1. Is that what you meant? – Andrew J. Brehm Apr 30 '11 at 11:42
  • 5
    Why would you redirect `nul` *into* `echo`? `echo` doesn't ever read input. – Joey Jan 04 '14 at 11:28
  • 2
    You can change `cmd /c %1` to `cmd /c %*`, so that you can save quotation mark for command arguments – stanleyxu2005 Dec 03 '17 at 09:23
9

For ease of use, here is the chocolatey package: https://chocolatey.org/packages/ptime C:/> choco install ptime

The advantage if ptime is that it acts like the unix version and yields the console output, which Measure-Command { XXX } does not (or at least I don't know how to do that).

Guy Langston
  • 191
  • 1
  • 3
6

Some coffee helped me come up with this:

function time { $Command = "$args"; Measure-Command { Invoke-Expression $Command 2>&1 | out-default} }

And if you want it to output nothing, just replace with out-null:

function timequiet { $Command = "$args"; Measure-Command { Invoke-Expression $Command 2>&1 | out-null} }

You use it like this:

PS C:\> time sleep 5


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 4
Milliseconds      : 990
Ticks             : 49906722
TotalDays         : 5,77624097222222E-05
TotalHours        : 0,00138629783333333
TotalMinutes      : 0,08317787
TotalSeconds      : 4,9906722
TotalMilliseconds : 4990,6722



PS C:\>
Andrei Ghimus
  • 61
  • 1
  • 1
6

There is no direct equivalent to Unix time on Windows.

The University of Georgia have a brief list of Windows commands for Unix users

I find the older Windows command prompt and .bat scripting is rather limited compared to Unix shells but there are some facilities for looping over files etc. CommandWindows.com has some tips

You could either install bash on Windows (e.g. by installing CygWin) or learn Windows Powershell (which I am assuming has a means of doing something equivalent).

RedGrittyBrick
  • 81,981
  • 20
  • 135
  • 205
3

gnomon is a nice solution if you don't only need the total run time of a command, but also line for line measurements:

A command line utility to prepend timestamp information to the standard output of another command. Useful for long-running processes where you'd like a historical record of what's taking so long.

Installed by running npm install -g gnomon, then just use it via command | gnomon.

janpio
  • 2,396
  • 8
  • 25
  • 34
2

The output for your code can be piped to a file: java test <inputfile> | Out-File d:\a.txt

For measuring how long it takes you have to encapsulate it in Measure-Commmand:

Measure-Commmand {java test <inputfile> | Out-File d:\a.txt}

Abbas
  • 289
  • 2
  • 8
2

If you try to use PowerShell with Measure-Command be aware that there may be some unexpected gotchas. My command writes binary data to a file using > redirection but PowerShell added a BOM to the beginning of the file and a CRLF line break after every write!

hippietrail
  • 4,505
  • 15
  • 53
  • 86
1

An improvement on Andrei Ghimus's answer.

function time {
    $Command = $MyInvocation.Line -Replace ("^$($MyInvocation.MyCommand) ", "")
    Measure-Command { Invoke-Expression $Command | Out-Default }
}

The use of MyInvocation allows obtaining the actual arguments which is important when the command contains double quotes.

I found the 2>&1 just hid stderr which isn't what I wanted.

studog
  • 333
  • 2
  • 10
1

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.

Simon Smith
  • 151
  • 3
0

There are a couple different options to get a 'time' command. My preference is to just install Cygwin (which comes with a UNIX-like time command).

Alternatively, you can write a script and add it to your path (so that you can execute it without specifying the entire path).

If you have Powershell available, try this script (works when calling files--'.exe',etc.):

$start = get-date
if ($args.length -gt 1) {
start-process $args[0] $args[1..$args.length] -workingdirectory $pwd -nonewwindow -wait
} else {
start-process $args[0] -workingdirectory $pwd -nonewwindow -wait
}
$end = get-date
$elapsed = $end - $start
write-host $end-$start
# datetime format
write-host $elapsed
# easy-to-read format
echo $elapsed

Run the code with (for instance):

time.ps1 python program.py

Using Batch, I'd suggest either of the top answers from here (on Stackoverflow.com). Both just need to be copy-pasted. Note that if you use paxdiablo's solution, you should replace

ping -n 11 127.0.0.1 >nul: 2>nul: 

with

%*
David C
  • 250
  • 3
  • 9