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ではできないホスト出力コスト計測もできます。 それには、スイッチやプロパティを指定せずにコマンドを実行します。

なお、Get-Dateの出力がされた後に、計測時間も出力されます。そのため、所要時間は、ホスト出力分も加味されています。

#フル表記
PS> Measure-Stopwatch -Command {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  : 201331212:21:18

#-Commandパラメータは省略可能
PS> Measure-Stopwatch {Get-Date}
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

#好きな計測時間出力スイッチ指定 (-Days / -Hours / -Minutes / -Seconds / -Milliseconds)
PS> Measure-Stopwatch -Command {Get-Date} -Milliseconds
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  : 201331212:24:57

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

逆に、Measure-Commandのようにホスト出力せずにコスト計測できます。 それには、2つの方法があり、いずれもMeasure-Commandと同等の計測時間が得られます。

#プロパティを指定
PS> (Measure-Stopwatch -Command {Get-Date}).TotalMilliseconds
0.2406

#Select-Object -Last 1 で出力結果のみ取得する
PS> (Measure-Stopwatch -Command {Get-Date}).TotalMilliseconds
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の結果です。

PS> (Measure-Command {Get-Date}).TotalMilliseconds
0.2953

PS> 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-Stopwatchを利用することで、Write-Outputのホスト出力も計測可能になります。

PS> Measure-Stopwatch -Command {Write-Output $hoge}
PS> Measure-Stopwatch -Command {Write-Output $hoge} | Select -Last 1