tech.guitarrapc.cóm

Technical updates

PowerShellでStopwatch計測する

前回の記事で、Write-Ouputを計測するときにちょっと困りました。
PowerShellでSubstitute(変数代入)、Host(ホスト出力)、Content(ファイル出力)するコストのベンチマーク
Write-Outputは状況に応じて、「Objectをパイプに渡す」か「Host画面に出力」するか自動的に切り替えます。 その切り替える要素は、ScriptBlockとしてパイプされる、プロパティを指定されるなどなわけですが……Measure-Commandを使うとObjectとして出力/計測されてしまうわけです。 これでは、Measure-Commandで実行時間の計測ができません……。 ということで、今回は、System.Diagnostics.StopWatchを使ったオレオレMeasure-Stopwatchのご紹介です。

ソース全文

サクッとFunction化してあるので利用しやすいかと。
function Measure-Stopwatch{

    [CmdletBinding()]
    param(
    [parameter(Mandatory=$true)]
    [ScriptBlock]$Command,
    [switch]$Days,
    [switch]$Hours,
    [switch]$Minutes,
    [switch]$Seconds,
    [switch]$Milliseconds
    )

    function Start-InputScriptBlock {
        $sw = New-Object System.Diagnostics.StopWatch

        # Start Stopwatch
        $sw.Start()

        #TargetCommand to measure
        $command.Invoke()

        # Stop Stopwatch
        $sw.Stop()

        #Show Result
        switch ($true){
        $Days {$sw.Elapsed.TotalDays}
        $Hours {$sw.Elapsed.TotalHours}
        $Minutes {$sw.Elapsed.TotalMinutes}
        $Seconds {$sw.Elapsed.TotalSeconds}
        $Milliseconds {$sw.Elapsed.TotalMilliseconds}
        default {$sw.Elapsed}
        }

        #Reset Result
        $sw.Reset()
    }

    Start-InputScriptBlock

}

利用例1 : ホスト出力時間も加味する

本コマンドレットは、Measure-Commandではできないホスト出力コスト計測もできます。 それには、スイッチもプロパティも指定せずにコマンドを実行します。
#フル表記
Measure-Stopwatch -Command {Get-Date}

#-Commandパラメータは省略可能
Measure-Stopwatch {Get-Date}

#好きな計測時間出力スイッチ指定 (-Days / -Hours / -Minutes / -Seconds / -Milliseconds)
Measure-Stopwatch -Command {Get-Date} -Milliseconds
Get-Dateの出力がされた後に、計測時間も出力されます。 そのため、所要時間は、ホスト出力分も加味されています。
DisplayHint : DateTime
Date        : 2013/03/12 0:00:00
Day         : 12
DayOfWeek   : Tuesday
DayOfYear   : 71
Hour        : 12
Kind        : Local
Millisecond : 781
Minute      : 21
Month       : 3
Second      : 18
Ticks       : 634986876787816533
TimeOfDay   : 12:21:18.7816533
Year        : 2013
DateTime    : 2013年3月12日 12:21:18

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 6
Ticks             : 68850
TotalDays         : 7.96875E-08
TotalHours        : 1.9125E-06
TotalMinutes      : 0.00011475
TotalSeconds      : 0.006885
TotalMilliseconds : 6.885

#スイッチを指定した場合は次のように指定したスイッチ結果が出力されます。
DisplayHint : DateTime
Date        : 2013/03/12 0:00:00
Day         : 12
DayOfWeek   : Tuesday
DayOfYear   : 71
Hour        : 12
Kind        : Local
Millisecond : 827
Minute      : 24
Month       : 3
Second      : 57
Ticks       : 634986878978273745
TimeOfDay   : 12:24:57.8273745
Year        : 2013
DateTime    : 2013年3月12日 12:24:57

6.2634

利用例2 : ホスト出力しないコストを計測する

逆に、Measure-Commandのようにホスト出力せずにコスト計測をすることもできます。 それには、二つの方法があります。
#プロパティを指定
(Measure-Stopwatch -Command {Get-Date}).TotalMilliseconds

#Select-Object -Last 1 で出力結果のみ取得する
(Measure-Stopwatch -Command {Get-Date}).TotalMilliseconds
いずれも、Measure-Commandと同等の計測時間が得られます。 # プロパティを指定した場合
0.2406
# Select-Object -Last 1の場合 (Measure-Commandと同じ結果です)
Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 0
Ticks             : 3401
TotalDays         : 3.93634259259259E-09
TotalHours        : 9.44722222222222E-08
TotalMinutes      : 5.66833333333333E-06
TotalSeconds      : 0.0003401
TotalMilliseconds : 0.3401

参考 : Measure-Commandの結果

参考までに、Measure-Commandの結果です。
Measure-Command {Get-Date}
出力結果です。
Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 0
Ticks             : 3149
TotalDays         : 3.64467592592593E-09
TotalHours        : 8.74722222222222E-08
TotalMinutes      : 5.24833333333333E-06
TotalSeconds      : 0.0003149
TotalMilliseconds : 0.3149
プロパティ指定の場合です。
(Measure-Command {Get-Date}).TotalMilliseconds
計測結果です。
0.2953

まとめ

このMeasure-Stopwatchを利用することで、Write-Outputのホスト出力も計測可能になります。
Measure-Stopwatch -Command {Write-Output $hoge}
勿論Object出力も可能ですね。
Measure-Stopwatch -Command {Write-Output $hoge} | Select -Last 1
やったね!