Timing a command's execution in PowerShell

前端 未结 7 805
没有蜡笔的小新
没有蜡笔的小新 2020-11-28 01:13

Is there a simple way to time the execution of a command in PowerShell, like the \'time\' command in Linux?
I came up with this:

$s=Get-Date; .\\do_somet         


        
相关标签:
7条回答
  • 2020-11-28 01:38

    Simples

    function time($block) {
        $sw = [Diagnostics.Stopwatch]::StartNew()
        &$block
        $sw.Stop()
        $sw.Elapsed
    }
    

    then can use as

    time { .\some_command }
    

    You may want to tweak the output

    0 讨论(0)
  • 2020-11-28 01:49

    You can also get the last command from history and subtract its EndExecutionTime from its StartExecutionTime.

    .\do_something.ps1  
    $command = Get-History -Count 1  
    $command.EndExecutionTime - $command.StartExecutionTime
    
    0 讨论(0)
  • 2020-11-28 01:49

    Just a word on drawing (incorrect) conclusions from any of the performance measurement commands referred to in the answers. There are a number of pitfalls that should taken in consideration aside from looking to the bare invocation time of a (custom) function or command.

    Sjoemelsoftware

    'Sjoemelsoftware' voted Dutch word of the year 2015
    Sjoemelen means cheating, and the word sjoemelsoftware came into being due to the Volkswagen emissions scandal. The official definition is "software used to influence test results".

    Personally, I think that "Sjoemelsoftware" is not always deliberately created to cheat test results but might originate from accommodating practical situation that are similar to test cases as shown below.

    As an example, using the listed performance measurement commands, Language Integrated Query (LINQ)(1), is often qualified as the fasted way to get something done and it often is, but certainly not always! Anybody who measures a speed increase of a factor 40 or more in comparison with native PowerShell commands, is probably incorrectly measuring or drawing an incorrect conclusion.

    The point is that some .Net classes (like LINQ) using a lazy evaluation (also referred to as deferred execution(2)). Meaning that when assign an expression to a variable, it almost immediately appears to be done but in fact it didn't process anything yet!

    Let presume that you dot-source your . .\Dosomething.ps1 command which has either a PowerShell or a more sophisticated Linq expression (for the ease of explanation, I have directly embedded the expressions directly into the Measure-Command):

    $Data = @(1..100000).ForEach{[PSCustomObject]@{Index=$_;Property=(Get-Random)}}
    
    (Measure-Command {
        $PowerShell = $Data.Where{$_.Index -eq 12345}
    }).totalmilliseconds
    864.5237
    
    (Measure-Command {
        $Linq = [Linq.Enumerable]::Where($Data, [Func[object,bool]] { param($Item); Return $Item.Index -eq 12345})
    }).totalmilliseconds
    24.5949
    

    The result appears obvious, the later Linq command is a about 40 times faster than the first PowerShell command. Unfortunately, it is not that simple...

    Let's display the results:

    PS C:\> $PowerShell
    
    Index  Property
    -----  --------
    12345 104123841
    
    PS C:\> $Linq
    
    Index  Property
    -----  --------
    12345 104123841
    

    As expected, the results are the same but if you have paid close attention, you will have noticed that it took a lot longer to display the $Linq results then the $PowerShell results.
    Let's specifically measure that by just retrieving a property of the resulted object:

    PS C:\> (Measure-Command {$PowerShell.Property}).totalmilliseconds
    14.8798
    PS C:\> (Measure-Command {$Linq.Property}).totalmilliseconds
    1360.9435
    

    It took about a factor 90 longer to retrieve a property of the $Linq object then the $PowerShell object and that was just a single object!

    Also notice an other pitfall that if you do it again, certain steps might appear a lot faster then before, this is because some of the expressions have been cached.

    Bottom line, if you want to compare the performance between two functions, you will need to implement them in your used case, start with a fresh PowerShell session and base your conclusion on the actual performance of the complete solution.

    (1) For more background and examples on PowerShell and LINQ, I recommend tihis site: High Performance PowerShell with LINQ
    (2) I think there is a minor difference between the two concepts as with lazy evaluation the result is calculated when needed as apposed to deferred execution were the result is calculated when the system is idle

    0 讨论(0)
  • 2020-11-28 01:56

    Here's a function I wrote which works similarly to the Unix time command:

    function time {
        Param(
            [Parameter(Mandatory=$true)]
            [string]$command,
            [switch]$quiet = $false
        )
        $start = Get-Date
        try {
            if ( -not $quiet ) {
                iex $command | Write-Host
            } else {
                iex $command > $null
            }
        } finally {
            $(Get-Date) - $start
        }
    }
    

    Source: https://gist.github.com/bender-the-greatest/741f696d965ed9728dc6287bdd336874

    0 讨论(0)
  • 2020-11-28 01:59

    Yup.

    Measure-Command { .\do_something.ps1 }
    

    Note that one minor downside of Measure-Command is that you see no stdout output.

    [Update, thanks to @JasonMArcher] You can fix that by piping the command output to some commandlet that writes to the host, e.g. Out-Default so it becomes:

    Measure-Command { .\do_something.ps1 | Out-Default }
    

    Another way to see the output would be to use the .NET Stopwatch class like this:

    $sw = [Diagnostics.Stopwatch]::StartNew()
    .\do_something.ps1
    $sw.Stop()
    $sw.Elapsed
    
    0 讨论(0)
  • 2020-11-28 02:00

    Use Measure-Command

    Example

    Measure-Command { <your command here> | Out-Host }
    

    The pipe to Out-Host allows you to see the output of the command, which is otherwise consumed by Measure-Command.

    0 讨论(0)
提交回复
热议问题