Animesh D
Animesh D

Reputation: 5002

Equivalent of Unix time command in PowerShell?

Earlier I was reading a great answer on SO and I wondered why it has not been emulated yet in PowerShell.

In unix/linux, we can use the time command as a simple benchmark tool.

$ time ./script1.sh  

real    0m1.005s  
user    0m0.000s  
sys     0m0.008s  

In powershell, we can use the measure-command similarly:

$ Measure-Command {java post_incr}

Days              : 0  
Hours             : 0  
Minutes           : 0  
Seconds           : 1  
Milliseconds      : 18  
Ticks             : 10188003  
TotalDays         : 1.17916701388889E-05  
TotalHours        : 0.000283000083333333  
TotalMinutes      : 0.016980005  
TotalSeconds      : 1.0188003  
TotalMilliseconds : 1018.8003  

But this is not the same as the time, which reports the real, user and sys (See the difference between the three in the linked SO Answer.)

This (time) is obviously such a useful little tool. Are there any user written cmdlets for this functionality or is it already in V3 or planned for future releases?

Upvotes: 16

Views: 5418

Answers (4)

Andrei Ghimus
Andrei Ghimus

Reputation: 57

Warning, PowerShell ahead.

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:\>

Upvotes: 4

Greg Bray
Greg Bray

Reputation: 15707

The process you are trying to measure may also be forking and running in the background which causes the Measure-Command measurement to be cut short. You can use Start-Process with the -Wait parameter to get the full time measurement that you expect. Here is an example that shows that it takes stackoverflow.com 34 seconds to close an idle connection:

$program = 'telnet'
$ArgumentList = 'stackoverflow.com 80'
$WorkingDirectory = 'c:\'
Measure-Command {
   $p = Start-Process -FilePath $program -ArgumentList $ArgumentList -Wait -PassThru -WorkingDirectory $WorkingDirectory -NoNewWindow;
   Write-Host $p.ExitCode;
}


#Output:
0


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 34
Milliseconds      : 37
Ticks             : 340370635
TotalDays         : 0.000393947494212963
TotalHours        : 0.00945473986111111
TotalMinutes      : 0.567284391666667
TotalSeconds      : 34.0370635
TotalMilliseconds : 34037.0635

Upvotes: 1

manojlds
manojlds

Reputation: 301157

I used both the times provided by System.Diagnostics.Process and GetProcessTimes to come up with an implementation for time:

$source=@'

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

public class Timer
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool GetProcessTimes(IntPtr handle, out long creation, out long exit, out long kernel,
                                                  out long user);

        public static void Time(string file,string args)
        {
            long user,kernel,exit,creation;
            Process proc = null;
            proc = Process.Start(file,args);
            proc.WaitForExit();
            GetProcessTimes(proc.Handle, out creation, out exit, out kernel, out user);
            long real = exit - creation;
            Console.WriteLine("real {0}\nuser {1}\nsys {2}", real / 10000000.0, user/10000000.0,kernel/10000000.0);
        }
    }
'@

Add-Type -TypeDefinition $source -Language CSharpVersion3

function time ($scriptblock) {

    $file = "powershell";
    $args = $scriptblock;

    $startInfo = new-object Diagnostics.ProcessStartInfo;
    $startInfo.FileName = $file;
    $startInfo.Arguments = $args;
    $startInfo.CreateNoWindow = $true;
    $startInfo.UseShellExecute = $false;
    $startInfo.RedirectStandardOutput = $true;
    $process = [Diagnostics.Process]::Start($startInfo);
    $process.WaitForExit();
    write-host $process.StandardOutput.ReadToEnd();
    write-host real: ($process.ExitTime - $process.StartTime)
    write-host user: $process.UserProcessorTime;
    write-host sys:  $process.PrivilegedProcessorTime;
    write-host using GetProcessTimes
    [Timer]::Time($file,$args)
}

time {sleep 10}

It isn't really perfect as the real time comes out as about 11 seconds ( for sleep 10 ) since I am creating a powershell process and running the command in that. I will see if I can implement a cmdlet or something for this.

Upvotes: 2

mjsr
mjsr

Reputation: 7590

Write a C program using the GetProcessTimes function, you could find its documentation in: http://msdn.microsoft.com/en-us/library/ms683223%28VS.85%29.aspx.

In the examples of the book "Windows System Programming" comes a program that use that function to retrieve exactly what you need(Elapsed, Kernel, User times). The program is call "timep.exe" and it can be found in the runX subdirectories (the X comes from the version of Visual Studio used in the compilation) inside the zipped examples archive. Here is the author page from where you could download that archive http://www.jmhartsoftware.com/, of course the source code is also there so you could see exactly how timep.exe works.

Upvotes: 2

Related Questions