Skip to content

Commit 5fe9fec

Browse files
committed
feat: add IL cache stats section to diff report
- Add ShouldIncludeILCacheStatsInReport (default false) to ConfigSettings - Track _internalMisses in ILCache.TryGetILAsync; add GetReportStats() and ILCacheReportStats sealed record (Hits, Misses, HitRatePct, Stores, Evicted, Expired) - Add REPORT_SECTION_IL_CACHE_STATS constant and WriteILCacheStatsSection to ReportGenerateService; insert between Summary and Warnings when ShouldIncludeILCacheStatsInReport=true and ilCache!=null - Thread optional ILCache parameter through GenerateDiffReport / WriteDiffReport / WriteReportSections - Wire scopedProvider.GetService<ILCache>() in ProgramRunner.GenerateReport - Update ConfigSettingsTests (defaults + explicit-override test) - Add 3 ReportGenerateServiceTests for default-false, null-cache, and section-present-with-correct-ordering scenarios - Update README (EN+JA): config table row, example JSON, diff_report sample - Update CHANGELOG (EN+JA): [Unreleased] Added entries https://claude.ai/code/session_0174R4FzjudFBdynScKbhX6m
1 parent c3b8be8 commit 5fe9fec

8 files changed

Lines changed: 203 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
1111

1212
#### Added
1313

14+
- Added `ShouldIncludeILCacheStatsInReport` (default `false`) to [`ConfigSettings`](Models/ConfigSettings.cs). When `true` and the IL cache is active, [`ReportGenerateService`](Services/ReportGenerateService.cs) appends an `IL Cache Stats` section between `Summary` and `Warnings` in `diff_report.md`, showing hits, misses, hit-rate, stores, evicted, and expired counts. Also added `_internalMisses` tracking to [`ILCache`](Services/Caching/ILCache.cs) (miss counter now incremented on full cache miss), a `GetReportStats()` method, and the `ILCacheReportStats` sealed record. Added 3 unit tests to [`ReportGenerateServiceTests`](FolderDiffIL4DotNet.Tests/Services/ReportGenerateServiceTests.cs) and updated [`ConfigSettingsTests`](FolderDiffIL4DotNet.Tests/Models/ConfigSettingsTests.cs), [README.md](README.md), and [CHANGELOG.md](CHANGELOG.md).
1415
- Expanded CLI options: `--help`/`-h` prints usage and exits with code `0` before any logger initialization; `--version` prints the application version and exits with code `0`; `--config <path>` loads a config file from an arbitrary path instead of the default `<exe>/config.json`; `--threads <N>` overrides `MaxParallelism` in [`ConfigSettings`](Models/ConfigSettings.cs) for the current run; `--no-il-cache` forces `EnableILCache = false` for the current run; `--skip-il` skips IL decompilation and IL diff entirely for .NET assemblies (new `SkipIL` property in [`ConfigSettings`](Models/ConfigSettings.cs), also respected by [`FileDiffService`](Services/FileDiffService.cs)); `--no-timestamp-warnings` suppresses timestamp-regression warnings. Unknown flags now produce exit code `2` with a descriptive message instead of silently being ignored. [`ConfigService.LoadConfigAsync()`](Services/ConfigService.cs) now accepts an optional `configFilePath` parameter. Added [`CliOptionsTests`](FolderDiffIL4DotNet.Tests/CliOptionsTests.cs) with 21 parser unit-test cases, and new integration tests in [`ProgramRunnerTests`](FolderDiffIL4DotNet.Tests/ProgramRunnerTests.cs) and [`ConfigServiceTests`](FolderDiffIL4DotNet.Tests/Services/ConfigServiceTests.cs).
1516
- Added [`ConfigSettings.Validate()`](Models/ConfigSettings.cs) and the companion `ConfigValidationResult` class; [`ConfigService.LoadConfigAsync()`](Services/ConfigService.cs) now calls `Validate()` immediately after deserialization and throws [`InvalidDataException`](https://learn.microsoft.com/en-us/dotnet/api/system.io.invaliddataexception?view=net-8.0) listing all invalid settings when validation fails, so misconfigured runs are caught at startup with a clear error message instead of failing silently or causing undefined behavior later. Validated constraints: `MaxLogGenerations >= 1`; `TextDiffParallelThresholdKilobytes >= 1`; `TextDiffChunkSizeKilobytes >= 1`; and `TextDiffChunkSizeKilobytes < TextDiffParallelThresholdKilobytes`. Added validation unit tests to [`ConfigSettingsTests`](FolderDiffIL4DotNet.Tests/Models/ConfigSettingsTests.cs) (7 cases) and validation integration tests to [`ConfigServiceTests`](FolderDiffIL4DotNet.Tests/Services/ConfigServiceTests.cs) (5 cases).
1617

@@ -250,6 +251,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
250251

251252
#### 追加
252253

254+
- [`ConfigSettings`](Models/ConfigSettings.cs) に `ShouldIncludeILCacheStatsInReport`(既定値 `false`)を追加しました。`true` に設定し IL キャッシュが有効な場合、[`ReportGenerateService`](Services/ReportGenerateService.cs) は `diff_report.md` の `Summary` と `Warnings` の間に `IL Cache Stats` セクションを追記します(ヒット数・ミス数・ヒット率・保存数・退避数・期限切れ数)。あわせて [`ILCache`](Services/Caching/ILCache.cs) にミス数追跡フィールド `_internalMisses`(完全なキャッシュミスの際にインクリメント)と `GetReportStats()` メソッド、`ILCacheReportStats` レコードを追加しました。[`ReportGenerateServiceTests`](FolderDiffIL4DotNet.Tests/Services/ReportGenerateServiceTests.cs) に 3 件のユニットテストを追加し、[`ConfigSettingsTests`](FolderDiffIL4DotNet.Tests/Models/ConfigSettingsTests.cs)、[README.md](README.md)、[CHANGELOG.md](CHANGELOG.md) を更新しました。
253255
- CLI オプションを拡充しました。`--help`/`-h` は使い方を表示してロガー初期化前にコード `0` で終了します。`--version` はアプリバージョンを表示してコード `0` で終了します。`--config <path>` はデフォルトの `<exe>/config.json` に代わり任意のパスから設定ファイルを読み込みます。`--threads <N>` は今回の実行に限り [`ConfigSettings`](Models/ConfigSettings.cs) の `MaxParallelism` を上書きします。`--no-il-cache` は今回の実行に限り `EnableILCache = false` に設定します。`--skip-il` は .NET アセンブリの IL 逆アセンブルと IL 差分比較をまるごとスキップします([`ConfigSettings`](Models/ConfigSettings.cs) に新設した `SkipIL` プロパティとして保持され、[`FileDiffService`](Services/FileDiffService.cs) でも参照します)。`--no-timestamp-warnings` はタイムスタンプ逆転の警告を抑制します。未知のフラグを指定した場合は、これまで黙ってスルーされていた挙動を改め、説明付きで終了コード `2` を返します。[`ConfigService.LoadConfigAsync()`](Services/ConfigService.cs) にオプショナルな `configFilePath` パラメータを追加しました。[`CliOptionsTests`](FolderDiffIL4DotNet.Tests/CliOptionsTests.cs) にパーサー単体テスト 21 件を追加し、[`ProgramRunnerTests`](FolderDiffIL4DotNet.Tests/ProgramRunnerTests.cs) と [`ConfigServiceTests`](FolderDiffIL4DotNet.Tests/Services/ConfigServiceTests.cs) にも統合テストを追加しました。
254256
- [`ConfigSettings.Validate()`](Models/ConfigSettings.cs) と `ConfigValidationResult` クラスを追加しました。[`ConfigService.LoadConfigAsync()`](Services/ConfigService.cs) はデシリアライズ直後に `Validate()` を呼び出し、バリデーションが失敗した場合は全エラーを列挙した [`InvalidDataException`](https://learn.microsoft.com/ja-jp/dotnet/api/system.io.invaliddataexception?view=net-8.0) をスローします。これにより、設定不正な実行は後から無言で失敗したり未定義の振る舞いを引き起こしたりする代わりに、起動時に分かりやすいエラーメッセージとして検出されます。検証対象の制約: `MaxLogGenerations >= 1`、`TextDiffParallelThresholdKilobytes >= 1`、`TextDiffChunkSizeKilobytes >= 1`、`TextDiffChunkSizeKilobytes < TextDiffParallelThresholdKilobytes`。あわせて [`ConfigSettingsTests`](FolderDiffIL4DotNet.Tests/Models/ConfigSettingsTests.cs) にバリデーション単体テスト(7 件)、[`ConfigServiceTests`](FolderDiffIL4DotNet.Tests/Services/ConfigServiceTests.cs) にバリデーション統合テスト(5 件)を追加しました。
255257

FolderDiffIL4DotNet.Tests/Models/ConfigSettingsTests.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ public void JsonDeserialize_ExplicitOverrides_AreApplied()
6868
"ILPrecomputeBatchSize": 512,
6969
"OptimizeForNetworkShares": true,
7070
"AutoDetectNetworkShares": false,
71-
"SkipIL": true
71+
"SkipIL": true,
72+
"ShouldIncludeILCacheStatsInReport": true
7273
}
7374
""";
7475

@@ -98,6 +99,7 @@ public void JsonDeserialize_ExplicitOverrides_AreApplied()
9899
Assert.True(config.OptimizeForNetworkShares);
99100
Assert.False(config.AutoDetectNetworkShares);
100101
Assert.True(config.SkipIL);
102+
Assert.True(config.ShouldIncludeILCacheStatsInReport);
101103
}
102104

103105
[Fact]
@@ -252,6 +254,7 @@ private static void AssertMatchesDefaults(ConfigSettings config)
252254
Assert.False(config.OptimizeForNetworkShares);
253255
Assert.True(config.AutoDetectNetworkShares);
254256
Assert.False(config.SkipIL);
257+
Assert.False(config.ShouldIncludeILCacheStatsInReport);
255258
}
256259
}
257260
}

FolderDiffIL4DotNet.Tests/Services/ReportGenerateServiceTests.cs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using FolderDiffIL4DotNet.Common;
55
using FolderDiffIL4DotNet.Models;
66
using FolderDiffIL4DotNet.Services;
7+
using FolderDiffIL4DotNet.Services.Caching;
78
using Xunit;
89

910
namespace FolderDiffIL4DotNet.Tests.Services
@@ -410,6 +411,83 @@ public void GenerateDiffReport_WritesWarningsInSeverityOrder_WhenMd5MismatchAndT
410411
reportText.IndexOf("files in `new` have older last-modified timestamps", StringComparison.Ordinal));
411412
}
412413

414+
[Fact]
415+
public void GenerateDiffReport_ILCacheStats_NotIncludedByDefault()
416+
{
417+
var oldDir = Path.Combine(_rootDir, "old-ilcs-default");
418+
var newDir = Path.Combine(_rootDir, "new-ilcs-default");
419+
var reportDir = Path.Combine(_rootDir, "report-ilcs-default");
420+
Directory.CreateDirectory(oldDir);
421+
Directory.CreateDirectory(newDir);
422+
Directory.CreateDirectory(reportDir);
423+
424+
var config = CreateConfig();
425+
_service.GenerateDiffReport(
426+
oldDir, newDir, reportDir,
427+
appVersion: "test", elapsedTimeString: null, computerName: "test-host",
428+
config);
429+
430+
var reportText = File.ReadAllText(Path.Combine(reportDir, "diff_report.md"));
431+
Assert.DoesNotContain("## IL Cache Stats", reportText);
432+
}
433+
434+
[Fact]
435+
public void GenerateDiffReport_ILCacheStats_NotOutputWhenEnabled_ButCacheIsNull()
436+
{
437+
var oldDir = Path.Combine(_rootDir, "old-ilcs-null");
438+
var newDir = Path.Combine(_rootDir, "new-ilcs-null");
439+
var reportDir = Path.Combine(_rootDir, "report-ilcs-null");
440+
Directory.CreateDirectory(oldDir);
441+
Directory.CreateDirectory(newDir);
442+
Directory.CreateDirectory(reportDir);
443+
444+
var config = CreateConfig();
445+
config.ShouldIncludeILCacheStatsInReport = true;
446+
_service.GenerateDiffReport(
447+
oldDir, newDir, reportDir,
448+
appVersion: "test", elapsedTimeString: null, computerName: "test-host",
449+
config, ilCache: null);
450+
451+
var reportText = File.ReadAllText(Path.Combine(reportDir, "diff_report.md"));
452+
Assert.DoesNotContain("## IL Cache Stats", reportText);
453+
}
454+
455+
[Fact]
456+
public void GenerateDiffReport_ILCacheStats_OutputBetweenSummaryAndWarnings_WhenEnabledWithCache()
457+
{
458+
var oldDir = Path.Combine(_rootDir, "old-ilcs-full");
459+
var newDir = Path.Combine(_rootDir, "new-ilcs-full");
460+
var reportDir = Path.Combine(_rootDir, "report-ilcs-full");
461+
Directory.CreateDirectory(oldDir);
462+
Directory.CreateDirectory(newDir);
463+
Directory.CreateDirectory(reportDir);
464+
465+
var config = CreateConfig();
466+
config.ShouldIncludeILCacheStatsInReport = true;
467+
var ilCache = new ILCache(ilCacheDirectoryAbsolutePath: string.Empty);
468+
469+
_resultLists.RecordDiffDetail("some.dll", FileDiffResultLists.DiffDetailResult.MD5Mismatch);
470+
_service.GenerateDiffReport(
471+
oldDir, newDir, reportDir,
472+
appVersion: "test", elapsedTimeString: null, computerName: "test-host",
473+
config, ilCache);
474+
475+
var reportText = File.ReadAllText(Path.Combine(reportDir, "diff_report.md"));
476+
Assert.Contains("## IL Cache Stats", reportText);
477+
Assert.Contains("- Hits :", reportText);
478+
Assert.Contains("- Misses :", reportText);
479+
Assert.Contains("- Hit Rate:", reportText);
480+
Assert.Contains("- Stores :", reportText);
481+
Assert.Contains("- Evicted :", reportText);
482+
Assert.Contains("- Expired :", reportText);
483+
// IL Cache Stats section must appear between Summary and Warnings
484+
int summaryIdx = reportText.IndexOf("## Summary", StringComparison.Ordinal);
485+
int ilCacheIdx = reportText.IndexOf("## IL Cache Stats", StringComparison.Ordinal);
486+
int warningsIdx = reportText.IndexOf("## Warnings", StringComparison.Ordinal);
487+
Assert.True(summaryIdx < ilCacheIdx);
488+
Assert.True(ilCacheIdx < warningsIdx);
489+
}
490+
413491
private static ConfigSettings CreateConfig() => new()
414492
{
415493
IgnoredExtensions = new List<string>(),

Models/ConfigSettings.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ public List<string> TextFileExtensions
8888
/// </summary>
8989
public bool ShouldIncludeIgnoredFiles { get; set; } = true;
9090

91+
/// <summary>
92+
/// IL キャッシュの統計情報(ヒット数・ミス数・ヒット率など)を差分レポートに出力するかどうか。
93+
/// true の場合、Summary セクションと Warnings セクションの間に IL Cache Stats セクションを追加します。
94+
/// なお、IL キャッシュが無効(EnableILCache = false)の場合は本設定が true でもセクションは出力されません。
95+
/// </summary>
96+
public bool ShouldIncludeILCacheStatsInReport { get; set; } = false;
97+
9198
/// <summary>
9299
/// IL全文を出力するか否か
93100
/// </summary>

ProgramRunner.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,14 +510,16 @@ private static void GenerateReport(
510510
string computerName,
511511
ConfigSettings config)
512512
{
513+
var ilCache = scopedProvider.GetService<ILCache>();
513514
scopedProvider.GetRequiredService<ReportGenerateService>().GenerateDiffReport(
514515
executionContext.OldFolderAbsolutePath,
515516
executionContext.NewFolderAbsolutePath,
516517
executionContext.ReportsFolderAbsolutePath,
517518
appVersion,
518519
elapsedTimeString,
519520
computerName,
520-
config);
521+
config,
522+
ilCache);
521523
}
522524

523525
private void PromptForExitKeyIfNeeded(CliOptions opts)

README.md

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,14 @@ Example `diff_report.md` (trimmed):
150150
- Modified : 2
151151
- Compared : 5 (Old) vs 5 (New)
152152

153+
## IL Cache Stats
154+
- Hits : 42
155+
- Misses : 8
156+
- Hit Rate: 84.0%
157+
- Stores : 8
158+
- Evicted : 0
159+
- Expired : 0
160+
153161
## Warnings
154162
- **WARNING:** One or more files were classified as `MD5Mismatch`. Manual review is recommended because only an MD5 hash comparison was possible.
155163
- **WARNING:** One or more files in `new` have older last-modified timestamps than the corresponding files in `old`.
@@ -203,7 +211,8 @@ Override only the settings you want to change. For example:
203211
"ILIgnoreLineContainingStrings": ["buildserver1_", "buildserver2_"],
204212
"ShouldOutputFileTimestamps": false,
205213
"ShouldOutputILText": false,
206-
"ShouldIncludeIgnoredFiles": false
214+
"ShouldIncludeIgnoredFiles": false,
215+
"ShouldIncludeILCacheStatsInReport": true
207216
}
208217
```
209218

@@ -243,6 +252,11 @@ Override only the settings you want to change. For example:
243252
<td><code>true</code></td>
244253
<td>Includes <code>Ignored Files</code> section before <code>Unchanged</code>.</td>
245254
</tr>
255+
<tr id="config-en-shouldincludeilcachestatsInreport">
256+
<td><code>ShouldIncludeILCacheStatsInReport</code></td>
257+
<td><code>false</code></td>
258+
<td>When <code>true</code>, appends an <code>IL Cache Stats</code> section (hits, misses, hit-rate, stores, evicted, expired) between <code>Summary</code> and <code>Warnings</code>. Has no effect when <code>EnableILCache</code> is <code>false</code>.</td>
259+
</tr>
246260
<tr id="config-en-shouldoutputiltext">
247261
<td><code>ShouldOutputILText</code></td>
248262
<td><code>true</code></td>
@@ -545,6 +559,14 @@ dotnet run "/path/old" "/path/new" "label" --config /etc/my-config.json --no-pau
545559
- Modified : 2
546560
- Compared : 5 (Old) vs 5 (New)
547561

562+
## IL Cache Stats
563+
- Hits : 42
564+
- Misses : 8
565+
- Hit Rate: 84.0%
566+
- Stores : 8
567+
- Evicted : 0
568+
- Expired : 0
569+
548570
## Warnings
549571
- **WARNING:** One or more files were classified as `MD5Mismatch`. Manual review is recommended because only an MD5 hash comparison was possible.
550572
- **WARNING:** One or more files in `new` have older last-modified timestamps than the corresponding files in `old`.
@@ -597,7 +619,8 @@ flowchart TD
597619
"ILIgnoreLineContainingStrings": ["buildserver1_", "buildserver2_"],
598620
"ShouldOutputFileTimestamps": false,
599621
"ShouldOutputILText": false,
600-
"ShouldIncludeIgnoredFiles": false
622+
"ShouldIncludeIgnoredFiles": false,
623+
"ShouldIncludeILCacheStatsInReport": true
601624
}
602625
```
603626

@@ -637,6 +660,11 @@ flowchart TD
637660
<td><code>true</code></td>
638661
<td>レポートに <code>Ignored Files</code> セクションを出力するか。</td>
639662
</tr>
663+
<tr id="config-ja-shouldincludeilcachestatsInreport">
664+
<td><code>ShouldIncludeILCacheStatsInReport</code></td>
665+
<td><code>false</code></td>
666+
<td><code>true</code> の場合、<code>Summary</code> と <code>Warnings</code> の間に <code>IL Cache Stats</code> セクション(ヒット数・ミス数・ヒット率・保存数・退避数・期限切れ数)を出力します。<code>EnableILCache</code> が <code>false</code> の場合は本設定が <code>true</code> でも出力されません。</td>
667+
</tr>
640668
<tr id="config-ja-shouldoutputiltext">
641669
<td><code>ShouldOutputILText</code></td>
642670
<td><code>true</code></td>

0 commit comments

Comments
 (0)