<p><style_prompt:business_automation_expert_v1>
本記事は<strong>Geminiの出力をプロンプト工学で整理した業務ドラフト(未検証)</strong>です。</style_prompt:business_automation_expert_v1></p>
<h1 class="wp-block-heading">VBAで1ミリ秒単位の処理時間を計測!Win32 API(GetTickCount)による精密プロファイリング</h1>
<h3 class="wp-block-heading">【背景と目的】</h3>
<p>VBA標準のTimer関数は精度が秒単位と低く、高速なループ処理のボトルネック特定には不向きです。本稿ではWin32 APIを利用し、ミリ秒単位で正確な実効速度を計測する手法を解説します。</p>
<h3 class="wp-block-heading">【処理フロー図】</h3>
<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">
graph TD
A["計測開始"] --> B["Win32 APIで現在時刻を取得"]
B --> C["画面更新・自動計算の停止"]
C --> D["メイン処理実行/配列処理等"]
D --> E["画面更新・自動計算の再開"]
E --> F["APIで終了時刻を取得"]
F --> G["差分を計算し実行時間を表示"]
</pre></div>
<h3 class="wp-block-heading">【実装:VBAコード】</h3>
<pre data-enlighter-language="generic">Option Explicit
' --- Win32 API 宣言 ---
' 64bit/32bit両対応のため PtrSafe を付与
' GetTickCount はシステム起動からの経過時間をミリ秒単位で返します
#If VBA7 Then
Private Declare PtrSafe Function GetTickCount Lib "kernel32" () As Long
#Else
Private Declare Function GetTickCount Lib "kernel32" () As Long
#End If
''' <summary>
''' 高速化手法を適用した処理時間計測のサンプルコード
''' </summary>
Public Sub MeasurePerformance()
Dim startTime As Long
Dim endTime As Long
Dim diffTime As Double
' 計測開始
startTime = GetTickCount()
' --- 高速化設定 ---
With Application
.ScreenUpdating = False ' 画面更新停止
.Calculation = xlCalculationManual ' 自動計算停止
.EnableEvents = False ' イベント抑止
End With
On Error GoTo ErrorHandler
' --- メイン処理(例:大量データの配列処理) ---
Dim targetRange As Range
Dim dataArray As Variant
Dim i As Long, j As Long
Set targetRange = Sheet1.Range("A1:J10000")
dataArray = targetRange.Value ' セル値を配列に格納(高速化の定石)
For i = LBound(dataArray, 1) To UBound(dataArray, 1)
For j = LBound(dataArray, 2) To UBound(dataArray, 2)
' ここに何らかの加工処理を記述
dataArray(i, j) = dataArray(i, j) * 1.1
Next j
Next i
targetRange.Value = dataArray ' 結果を一括書き戻し
' --------------------------------------------
CleanExit:
' --- 設定の復元 ---
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
.EnableEvents = True
End With
' 計測終了
endTime = GetTickCount()
' 秒単位に変換して表示
diffTime = (endTime - startTime) / 1000
MsgBox "処理が完了しました。" & vbCrLf & _
"実行時間: " & Format(diffTime, "0.000") & " 秒", vbInformation
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました: " & Err.Description, vbCritical
Resume CleanExit
End Sub
</pre>
<h3 class="wp-block-heading">【技術解説】</h3>
<ol class="wp-block-list">
<li><p><strong>GetTickCountの利点</strong>:
VBA標準の<code>Timer</code>関数は午前0時からの秒数(Single型)を返しますが、精度が約1/64秒程度に制限されます。<code>GetTickCount</code>を使用することで、OSレベルの1ミリ秒単位のカウンタにアクセスでき、より厳密なパフォーマンス測定が可能になります。</p></li>
<li><p><strong>64bit環境への対応</strong>:
<code>PtrSafe</code>キーワードを使用することで、Office 64bit版でもエラーなくAPIを呼び出せます。戻り値の<code>Long</code>は32bit整数ですが、経過時間の差分(ミリ秒)を取得する用途では十分実用的です。</p></li>
<li><p><strong>ボトルネックの排除</strong>:
計測対象の処理に<code>ScreenUpdating = False</code>や「配列への一括読み込み」を含めることで、純粋なロジックの計算速度を浮き彫りにします。</p></li>
</ol>
<h3 class="wp-block-heading">【注意点と運用】</h3>
<ul class="wp-block-list">
<li><p><strong>49.7日の壁</strong>:
<code>GetTickCount</code>の戻り値は32bit符号なし整数(をVBAのLongで受ける形)のため、PCを再起動せず約49.7日が経過すると値が0にリセットされます。長時間連続稼働するサーバー等の環境では注意が必要です。</p></li>
<li><p><strong>エラーハンドリングの徹底</strong>:
<code>ScreenUpdating</code>を停止した状態でマクロが異常終了すると、Excelの操作ができなくなったように見えます。必ず<code>On Error GoTo</code>で設定を復元するルートを確保してください。</p></li>
</ul>
<h3 class="wp-block-heading">【まとめ】</h3>
<ul class="wp-block-list">
<li><p><strong>精度を求めるならAPI</strong>: 秒単位のTimer関数ではなく、ミリ秒単位の<code>GetTickCount</code>を採用する。</p></li>
<li><p><strong>環境互換性の確保</strong>: <code>PtrSafe</code>宣言を行い、32bit/64bit双方のExcelで動作するコードを書く。</p></li>
<li><p><strong>純粋な速度計測</strong>: 画面更新停止や配列処理を併用し、VBA特有のオーバーヘッドを最小化して計測する。</p></li>
</ul>
本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。
VBAで1ミリ秒単位の処理時間を計測!Win32 API(GetTickCount)による精密プロファイリング
【背景と目的】
VBA標準のTimer関数は精度が秒単位と低く、高速なループ処理のボトルネック特定には不向きです。本稿ではWin32 APIを利用し、ミリ秒単位で正確な実効速度を計測する手法を解説します。
【処理フロー図】
graph TD
A["計測開始"] --> B["Win32 APIで現在時刻を取得"]
B --> C["画面更新・自動計算の停止"]
C --> D["メイン処理実行/配列処理等"]
D --> E["画面更新・自動計算の再開"]
E --> F["APIで終了時刻を取得"]
F --> G["差分を計算し実行時間を表示"]
【実装:VBAコード】
Option Explicit
' --- Win32 API 宣言 ---
' 64bit/32bit両対応のため PtrSafe を付与
' GetTickCount はシステム起動からの経過時間をミリ秒単位で返します
#If VBA7 Then
Private Declare PtrSafe Function GetTickCount Lib "kernel32" () As Long
#Else
Private Declare Function GetTickCount Lib "kernel32" () As Long
#End If
''' <summary>
''' 高速化手法を適用した処理時間計測のサンプルコード
''' </summary>
Public Sub MeasurePerformance()
Dim startTime As Long
Dim endTime As Long
Dim diffTime As Double
' 計測開始
startTime = GetTickCount()
' --- 高速化設定 ---
With Application
.ScreenUpdating = False ' 画面更新停止
.Calculation = xlCalculationManual ' 自動計算停止
.EnableEvents = False ' イベント抑止
End With
On Error GoTo ErrorHandler
' --- メイン処理(例:大量データの配列処理) ---
Dim targetRange As Range
Dim dataArray As Variant
Dim i As Long, j As Long
Set targetRange = Sheet1.Range("A1:J10000")
dataArray = targetRange.Value ' セル値を配列に格納(高速化の定石)
For i = LBound(dataArray, 1) To UBound(dataArray, 1)
For j = LBound(dataArray, 2) To UBound(dataArray, 2)
' ここに何らかの加工処理を記述
dataArray(i, j) = dataArray(i, j) * 1.1
Next j
Next i
targetRange.Value = dataArray ' 結果を一括書き戻し
' --------------------------------------------
CleanExit:
' --- 設定の復元 ---
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
.EnableEvents = True
End With
' 計測終了
endTime = GetTickCount()
' 秒単位に変換して表示
diffTime = (endTime - startTime) / 1000
MsgBox "処理が完了しました。" & vbCrLf & _
"実行時間: " & Format(diffTime, "0.000") & " 秒", vbInformation
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました: " & Err.Description, vbCritical
Resume CleanExit
End Sub
【技術解説】
GetTickCountの利点:
VBA標準のTimer関数は午前0時からの秒数(Single型)を返しますが、精度が約1/64秒程度に制限されます。GetTickCountを使用することで、OSレベルの1ミリ秒単位のカウンタにアクセスでき、より厳密なパフォーマンス測定が可能になります。
64bit環境への対応:
PtrSafeキーワードを使用することで、Office 64bit版でもエラーなくAPIを呼び出せます。戻り値のLongは32bit整数ですが、経過時間の差分(ミリ秒)を取得する用途では十分実用的です。
ボトルネックの排除:
計測対象の処理にScreenUpdating = Falseや「配列への一括読み込み」を含めることで、純粋なロジックの計算速度を浮き彫りにします。
【注意点と運用】
49.7日の壁:
GetTickCountの戻り値は32bit符号なし整数(をVBAのLongで受ける形)のため、PCを再起動せず約49.7日が経過すると値が0にリセットされます。長時間連続稼働するサーバー等の環境では注意が必要です。
エラーハンドリングの徹底:
ScreenUpdatingを停止した状態でマクロが異常終了すると、Excelの操作ができなくなったように見えます。必ずOn Error GoToで設定を復元するルートを確保してください。
【まとめ】
精度を求めるならAPI: 秒単位のTimer関数ではなく、ミリ秒単位のGetTickCountを採用する。
環境互換性の確保: PtrSafe宣言を行い、32bit/64bit双方のExcelで動作するコードを書く。
純粋な速度計測: 画面更新停止や配列処理を併用し、VBA特有のオーバーヘッドを最小化して計測する。
ライセンス:本記事のテキスト/コードは特記なき限り
CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。
コメント