低優先度スタートアップ.vbs

スタートアップ時の負荷軽減のためにこんなスクリプトを書いてみた。ディスク I/O 使用率を監視し、2 回平均で 50% 以下になるのを待ってアプリケーションを実行する。
…んで、使ってみてどうだったかというと、意味がなかった。orz

  • まず、ハードウェア監視機能を提供するクラス群の初期化に時間がかかる。
  • そして、Vista では OS 側でいろんな処理がスタートアップ時にロープライオリティ I/O を使って動いている。それらは通常ユーザーのスタートアップ処理が終わった後に動き出すんだけど、監視のためにしばらく待っていると処理が終わったと思ってロープライオリティ I/O を使った処理が動き出す。ここで単純にディスク I/O を監視するだけではそれがロープライオリティ I/O なのかどうか判別できず、結果としてロープライオリティ I/O の処理が終わるのを待ってユーザーのスタートアップ処理を行うという本末転倒な結果になる。

というわけで、結局このスクリプトはお蔵入りになった。将来何かに使いたくなるかもしれないからここに貼り付けておく。

Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\.\root\cimv2")
Set objRefresher = CreateObject("WbemScripting.Swbemrefresher")
Set objProcessor = objRefresher.AddEnum(objWMIService, "Win32_PerfFormattedData_PerfOS_Processor").objectSet
Set colDisks = objRefresher.AddEnum(objWMIService, "win32_perfformatteddata_perfdisk_logicaldisk").objectSet
Set objWshShell = WScript.CreateObject("WScript.Shell")

usagehist = "開始 " & Time & vbCrLf
launch """C:\Program Files\TTBase\TTBase.exe""", 1, false
launch """C:\Program Files\TClock\tclock.exe""", 1, false
WScript.Echo usagehist & "終了 " & Time

Set objWMIService = Nothing
Set objRefresher = Nothing
Set objProcessor = Nothing
Set colDisks = Nothing
Set objWshShell = Nothing

Sub launch(cmdline, style, wait)
    waitForPercentTime "disk", 50
    objWshShell.Run cmdline, style, wait
    usagehist = usagehist & vbCrLf & cmdline & vbCrLf
End Sub

' 指定されたリソースの使用率が 2 回平均で intThreshold % 以下になるのを待つ
Sub waitForPercentTime(strResource, intThreshold)
    intTimeout  = 5000 ' msec
    intInterval =  250 ' msec
    intTimeSpent = 0
    intUsage1 = 100
    intUsage2 = 100
    Do
        Select Case strResource
            Case "cpu"  intUsage1 = percentProcessorTime()
            Case "disk" intUsage1 = percentDiskTime()
        End Select
        usagehist = usagehist & intUsage1 & ", "
        If intUsage1 + intUsage2 <= intThreshold * 2 Then Exit Do
        intUsage2 = intUsage1
        If intTimeSpent > intTimeout Then Exit Do
        intTimeSpent = intTimeSpent + intInterval
        Wscript.Sleep intInterval
    Loop
End Sub

' http://www.microsoft.com/japan/technet/scriptcenter/scripts/hardware/monitor/hwmovb06.mspx
' http://www.microsoft.com/japan/technet/scriptcenter/resources/qanda/apr05/hey0421.mspx
Function percentProcessorTime()
    objRefresher.Refresh
    For each intProcessorUse in objProcessor
        percentProcessorTime = CInt(intProcessorUse.percentProcessorTime)
        ' returns three values for dual core: CPU1, CPU2, Total. Get the last value.
    Next
End Function

' http://www.microsoft.com/japan/technet/scriptcenter/scripts/storage/disks/monitor/stmovb04.mspx
Function percentDiskTime()
    objRefresher.Refresh
    For Each objDisk in colDisks
        If objDisk.Name = "_Total" Then
            percentDiskTime = CInt(objDisk.percentDiskTime)
        End If
    Next
End Function