rufio 0.32.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,759 @@
1
+ # FilePreview パフォーマンス最適化分析レポート
2
+
3
+ ## エグゼクティブサマリー
4
+
5
+ Rufio ファイルマネージャーのテキストビューワ(FilePreviewクラス)のパフォーマンス分析を実施し、複数の改善方式を検討しました。
6
+
7
+ **主要な発見:**
8
+ - 現在の実装は既に高速(50行: 0.056ms、1000行: 0.193ms)
9
+ - ボトルネックはテキストファイル読み込み(全体の79.3%)
10
+ - 最も効果的な改善方式: **Zig ネイティブ実装**(2-3倍高速化の見込み)
11
+
12
+ ---
13
+
14
+ ## 目次
15
+
16
+ 1. [現在の実装分析](#現在の実装分析)
17
+ 2. [パフォーマンスベンチマーク結果](#パフォーマンスベンチマーク結果)
18
+ 3. [ボトルネック特定](#ボトルネック特定)
19
+ 4. [改善方式の比較](#改善方式の比較)
20
+ 5. [推奨事項](#推奨事項)
21
+ 6. [実装ロードマップ](#実装ロードマップ)
22
+
23
+ ---
24
+
25
+ ## 現在の実装分析
26
+
27
+ ### ファイル構成
28
+
29
+ - **実装ファイル**: `lib/rufio/file_preview.rb`
30
+ - **主要クラス**: `Rufio::FilePreview`
31
+ - **コード行数**: 約200行
32
+
33
+ ### 処理フロー
34
+
35
+ ```
36
+ 1. ファイル存在・読み取り権限チェック
37
+ 2. バイナリファイル検出(先頭512バイトをサンプリング)
38
+ 3. テキストファイル読み込み
39
+ - UTF-8でオープン
40
+ - 行ごとに読み込み(max_lines制限付き)
41
+ - 長い行の切り詰め(500文字超)
42
+ - chomp処理
43
+ 4. ファイルタイプ判定(拡張子ベース)
44
+ 5. メタデータ収集(サイズ、更新日時)
45
+ ```
46
+
47
+ ### 現在のコードの特徴
48
+
49
+ **長所:**
50
+ - ✓ シンプルで保守しやすい
51
+ - ✓ エンコーディング処理が堅牢(UTF-8 → Shift_JIS フォールバック)
52
+ - ✓ 長い行の安全な処理
53
+ - ✓ バイナリファイルの適切な検出
54
+
55
+ **短所:**
56
+ - ✗ 行ごとの処理でオーバーヘッド
57
+ - ✗ chomp の繰り返し呼び出し
58
+ - ✗ エンコーディングエラー時の2回読み込み
59
+ - ✗ バイナリ検出のバイト配列走査
60
+
61
+ ---
62
+
63
+ ## パフォーマンスベンチマーク結果
64
+
65
+ ### テスト環境
66
+
67
+ - **プラットフォーム**: macOS (Apple Silicon)
68
+ - **Ruby バージョン**: 3.4.2
69
+ - **テスト日時**: 2026-01-03
70
+
71
+ ### ベンチマーク1: max_lines パラメータの影響
72
+
73
+ | max_lines | 処理時間 (ms) | 1行あたり (µs) | ベースライン比 |
74
+ |-----------|---------------|----------------|----------------|
75
+ | 50 | 0.056 | 1.12 | 1.0x |
76
+ | 100 | 0.080 | 0.80 | 1.4x |
77
+ | 500 | 0.123 | 0.25 | 2.2x |
78
+ | 1,000 | 0.193 | 0.19 | 3.4x |
79
+ | 5,000 | 0.720 | 0.14 | 12.9x |
80
+ | 10,000 | 1.378 | 0.14 | 24.6x |
81
+
82
+ **観察:**
83
+ - 行数増加に対して**ほぼ線形**にスケール
84
+ - 1行あたりの処理時間は行数が増えると改善(キャッシング効果)
85
+ - 10,000行でも**予想より87%高速**(優れたスケーラビリティ)
86
+
87
+ ### ベンチマーク2: ファイルタイプ別の性能
88
+
89
+ | ファイルタイプ | サイズ | 処理時間 (ms) | 備考 |
90
+ |----------------|-----------|---------------|-------------------------|
91
+ | Gemfile | 0.2 KB | 0.035 | 最速(小さいファイル) |
92
+ | Plain text | 4,882.8 KB| 0.049 | 大規模でも高速 |
93
+ | Ruby code | 108.4 KB | 0.060 | 通常のコードファイル |
94
+ | Markdown | 26.5 KB | 0.063 | ドキュメント |
95
+ | Real Ruby file | 1.6 KB | 0.064 | 実際のプロジェクトファイル|
96
+
97
+ **観察:**
98
+ - ファイルサイズより**ファイル構造**が影響
99
+ - すべてのファイルタイプで**0.06ms前後**と高速
100
+ - max_lines=50制限により、大規模ファイルでも高速
101
+
102
+ ### ベンチマーク3: 処理内訳(max_lines=1000)
103
+
104
+ | 処理ステップ | 時間 (ms) | 割合 |
105
+ |----------------------|-----------|--------|
106
+ | テキストファイル読込 | 0.153 | 79.3% |
107
+ | バイナリ検出 | 0.015 | 7.8% |
108
+ | その他 | 0.025 | 12.7% |
109
+ | ファイルタイプ判定 | 0.000 | 0.2% |
110
+ | **合計** | **0.193** | 100% |
111
+
112
+ ---
113
+
114
+ ## ボトルネック特定
115
+
116
+ ### 主要ボトルネック
117
+
118
+ #### 1. テキストファイル読み込み(79.3%)
119
+
120
+ **現在の実装:**
121
+ ```ruby
122
+ File.open(file_path, "r:UTF-8") do |file|
123
+ file.each_line.with_index do |line, index|
124
+ break if index >= max_lines
125
+
126
+ if line.length > MAX_LINE_LENGTH
127
+ line = line[0...MAX_LINE_LENGTH] + "..."
128
+ end
129
+
130
+ lines << line.chomp
131
+ end
132
+ end
133
+ ```
134
+
135
+ **問題点:**
136
+ - `each_line` - 行ごとのイテレーション(Ruby VM オーバーヘッド)
137
+ - `chomp` - 毎回の文字列操作
138
+ - `length` チェック - 毎行で実行
139
+ - 文字列スライシング - メモリアロケーション
140
+
141
+ **改善の余地:** ⭐⭐⭐⭐⭐ (最大)
142
+
143
+ #### 2. バイナリ検出(7.8%)
144
+
145
+ **現在の実装:**
146
+ ```ruby
147
+ binary_chars = sample.bytes.count { |byte|
148
+ byte < PRINTABLE_CHAR_THRESHOLD &&
149
+ !allowed_control_chars.include?(byte)
150
+ }
151
+ (binary_chars.to_f / sample.bytes.length) > BINARY_THRESHOLD
152
+ ```
153
+
154
+ **問題点:**
155
+ - `bytes.count` - バイト配列全体を走査
156
+ - ブロック評価 - 各バイトでlambda評価
157
+ - `include?` - 配列検索(3要素)
158
+
159
+ **改善の余地:** ⭐⭐⭐ (中程度)
160
+
161
+ #### 3. その他のオーバーヘッド(12.7%)
162
+
163
+ - ファイルオープン/クローズ
164
+ - Hash構築
165
+ - メタデータ取得
166
+
167
+ **改善の余地:** ⭐⭐ (小)
168
+
169
+ ---
170
+
171
+ ## 改善方式の比較
172
+
173
+ ### 方式1: Zig ネイティブ実装
174
+
175
+ #### 概要
176
+ Zigでネイティブ拡張を実装し、ファイルI/Oとバイト処理を最適化。
177
+
178
+ #### 実装アプローチ
179
+ ```zig
180
+ // 擬似コード
181
+ fn previewFile(path: []const u8, max_lines: usize) callconv(.c) c.VALUE {
182
+ // 1. mmap または buffered read でファイル読み込み
183
+ const file_content = readFileBuffered(path);
184
+
185
+ // 2. バイナリ検出(SIMD最適化可能)
186
+ if (isBinaryFast(file_content)) {
187
+ return createBinaryResponse();
188
+ }
189
+
190
+ // 3. 行分割(memchrを使用)
191
+ var lines = ArrayList([]const u8).init(allocator);
192
+ var line_count: usize = 0;
193
+ var iter = std.mem.split(u8, file_content, "\n");
194
+
195
+ while (iter.next()) |line| {
196
+ if (line_count >= max_lines) break;
197
+
198
+ // 長い行の処理
199
+ const truncated = if (line.len > MAX_LINE_LENGTH)
200
+ line[0..MAX_LINE_LENGTH]
201
+ else
202
+ line;
203
+
204
+ lines.append(truncated);
205
+ line_count += 1;
206
+ }
207
+
208
+ // 4. Ruby配列を構築
209
+ return createRubyArray(lines);
210
+ }
211
+ ```
212
+
213
+ #### 予想性能改善
214
+
215
+ | max_lines | 現在 (ms) | Zig予想 (ms) | 改善率 |
216
+ |-----------|-----------|--------------|--------|
217
+ | 50 | 0.056 | 0.025 | 2.2x |
218
+ | 1,000 | 0.193 | 0.070 | 2.8x |
219
+ | 10,000 | 1.378 | 0.500 | 2.8x |
220
+
221
+ **根拠:**
222
+ - NativeScanner での実績(Zigは他の実装と同等)
223
+ - ファイルI/O最適化(buffered read, mmap)
224
+ - メモリアロケーション削減
225
+ - chomp/文字列操作の最適化
226
+
227
+ #### メリット
228
+
229
+ ✓ **2-3倍の高速化**が期待できる
230
+ ✓ **バイナリサイズ小** (52.6 KB - NativeScannerの実績)
231
+ ✓ **FFI不要** - Ruby C API直接使用
232
+ ✓ メモリ効率が良い
233
+ ✓ C言語エコシステムと互換性
234
+
235
+ #### デメリット
236
+
237
+ ✗ Zigの知識が必要
238
+ ✗ ビルドプロセスが複雑化
239
+ ✗ デバッグが難しい
240
+ ✗ クロスプラットフォーム対応が必要
241
+
242
+ #### 実装工数
243
+
244
+ - **開発**: 2-3日
245
+ - **テスト**: 1日
246
+ - **ドキュメント**: 0.5日
247
+ - **合計**: 約3.5-4.5日
248
+
249
+ ---
250
+
251
+ ### 方式2: Rust (Magnus) ネイティブ実装
252
+
253
+ #### 概要
254
+ Rustとmagnusクレートでネイティブ拡張を実装。
255
+
256
+ #### 実装アプローチ
257
+ ```rust
258
+ // 擬似コード
259
+ fn preview_file(ruby: &Ruby, path: String, max_lines: usize) -> Result<Value, Error> {
260
+ // BufReaderで効率的な読み込み
261
+ let file = File::open(&path)?;
262
+ let reader = BufReader::new(file);
263
+
264
+ // バイナリ検出
265
+ if is_binary(&path)? {
266
+ return create_binary_response(ruby);
267
+ }
268
+
269
+ let mut lines = Vec::with_capacity(max_lines);
270
+ for (i, line) in reader.lines().enumerate() {
271
+ if i >= max_lines { break; }
272
+
273
+ let line = line?;
274
+ let truncated = if line.len() > MAX_LINE_LENGTH {
275
+ format!("{}...", &line[..MAX_LINE_LENGTH])
276
+ } else {
277
+ line
278
+ };
279
+
280
+ lines.push(truncated);
281
+ }
282
+
283
+ create_ruby_array(ruby, lines)
284
+ }
285
+ ```
286
+
287
+ #### 予想性能改善
288
+
289
+ | max_lines | 現在 (ms) | Rust予想 (ms) | 改善率 |
290
+ |-----------|-----------|---------------|--------|
291
+ | 50 | 0.056 | 0.025 | 2.2x |
292
+ | 1,000 | 0.193 | 0.070 | 2.8x |
293
+ | 10,000 | 1.378 | 0.500 | 2.8x |
294
+
295
+ **Zigと同等の性能を想定**
296
+
297
+ #### メリット
298
+
299
+ ✓ 2-3倍の高速化
300
+ ✓ 型安全性が高い
301
+ ✓ エラーハンドリングが堅牢
302
+ ✓ Rustエコシステムの活用
303
+
304
+ #### デメリット
305
+
306
+ ✗ **バイナリサイズ大** (314.1 KB - NativeScannerの実績)
307
+ ✗ コンパイル時間が長い
308
+ ✗ Rustの学習コスト
309
+ ✗ Zigより約6倍大きいバイナリ
310
+
311
+ #### 実装工数
312
+
313
+ - **開発**: 2-3日
314
+ - **テスト**: 1日
315
+ - **ドキュメント**: 0.5日
316
+ - **合計**: 約3.5-4.5日
317
+
318
+ ---
319
+
320
+ ### 方式3: Pure Ruby 最適化
321
+
322
+ #### 概要
323
+ 現在のRuby実装をアルゴリズムレベルで最適化。
324
+
325
+ #### 実装アプローチ
326
+
327
+ **最適化1: IO.readlines使用**
328
+ ```ruby
329
+ def read_text_file_optimized(file_path, max_lines)
330
+ # 一度に読み込んでから処理
331
+ lines = IO.readlines(file_path, chomp: true, encoding: 'UTF-8')
332
+ .first(max_lines)
333
+ .map { |line|
334
+ line.length > MAX_LINE_LENGTH ? line[0...MAX_LINE_LENGTH] + "..." : line
335
+ }
336
+
337
+ {
338
+ content: lines,
339
+ truncated: IO.readlines(file_path).size > max_lines,
340
+ encoding: "UTF-8"
341
+ }
342
+ end
343
+ ```
344
+
345
+ **最適化2: バイナリ検出の改善**
346
+ ```ruby
347
+ def binary_file_optimized?(sample)
348
+ return false if sample.empty?
349
+
350
+ # Set使用で高速化
351
+ allowed = Set.new([9, 10, 13])
352
+ binary_count = 0
353
+
354
+ sample.each_byte do |byte|
355
+ binary_count += 1 if byte < 32 && !allowed.include?(byte)
356
+ end
357
+
358
+ (binary_count.to_f / sample.bytesize) > BINARY_THRESHOLD
359
+ end
360
+ ```
361
+
362
+ **最適化3: 早期リターン**
363
+ ```ruby
364
+ def preview_file_optimized(file_path, max_lines: DEFAULT_MAX_LINES)
365
+ # stat一度だけ呼ぶ
366
+ stat = File.stat(file_path)
367
+ return empty_response if stat.size == 0
368
+
369
+ # ... 以下同様
370
+ end
371
+ ```
372
+
373
+ #### 予想性能改善
374
+
375
+ | max_lines | 現在 (ms) | 最適化後 (ms) | 改善率 |
376
+ |-----------|-----------|---------------|--------|
377
+ | 50 | 0.056 | 0.050 | 1.1x |
378
+ | 1,000 | 0.193 | 0.155 | 1.2x |
379
+ | 10,000 | 1.378 | 1.100 | 1.3x |
380
+
381
+ **10-25%の改善を想定**
382
+
383
+ #### メリット
384
+
385
+ ✓ **最小限の変更**で改善
386
+ ✓ **保守性**を維持
387
+ ✓ デプロイが簡単
388
+ ✓ デバッグが容易
389
+ ✓ クロスプラットフォーム対応不要
390
+
391
+ #### デメリット
392
+
393
+ ✗ 改善幅が限定的(10-25%)
394
+ ✗ ネイティブ実装には及ばない
395
+ ✗ 大規模ファイルで依然として遅い
396
+
397
+ #### 実装工数
398
+
399
+ - **開発**: 0.5-1日
400
+ - **テスト**: 0.5日
401
+ - **ドキュメント**: 0.5日
402
+ - **合計**: 約1.5-2日
403
+
404
+ ---
405
+
406
+ ### 方式4: YJIT 有効化
407
+
408
+ #### 概要
409
+ Ruby 3.4のYJIT(Just-In-Timeコンパイラ)を活用。
410
+
411
+ #### 実装アプローチ
412
+ ```bash
413
+ # rufioの起動時にYJITを有効化
414
+ ruby --yjit bin/rufio
415
+ ```
416
+
417
+ または、コード内で有効化:
418
+ ```ruby
419
+ # lib/rufio.rb
420
+ if defined?(RubyVM::YJIT)
421
+ RubyVM::YJIT.enable
422
+ end
423
+ ```
424
+
425
+ #### 予想性能改善
426
+
427
+ | max_lines | 現在 (ms) | YJIT (ms) | 改善率 |
428
+ |-----------|-----------|-----------|--------|
429
+ | 50 | 0.056 | 0.053 | 1.06x |
430
+ | 1,000 | 0.193 | 0.174 | 1.11x |
431
+ | 10,000 | 1.378 | 1.240 | 1.11x |
432
+
433
+ **5-11%の改善を想定**
434
+
435
+ #### メリット
436
+
437
+ ✓ **コード変更不要**
438
+ ✓ すぐに試せる
439
+ ✓ アプリケーション全体が高速化
440
+ ✓ 標準Ruby機能
441
+
442
+ #### デメリット
443
+
444
+ ✗ 改善幅が小さい(5-11%)
445
+ ✗ メモリ使用量増加(~40MB)
446
+ ✗ ウォームアップ時間が必要
447
+ ✗ ネイティブ実装には及ばない
448
+
449
+ #### 実装工数
450
+
451
+ - **開発**: 0.1日(設定のみ)
452
+ - **テスト**: 0.5日
453
+ - **ドキュメント**: 0.5日
454
+ - **合計**: 約1日
455
+
456
+ ---
457
+
458
+ ### 方式5: Rust (FFI) 実装
459
+
460
+ #### 概要
461
+ RustライブラリをFFI経由で呼び出し。
462
+
463
+ #### 予想性能改善
464
+
465
+ NativeScannerの経験から、Rust FFIはMagnus/Zigより**やや遅い**可能性があります(JSON シリアライゼーションのオーバーヘッド)。
466
+
467
+ | max_lines | 現在 (ms) | Rust FFI (ms) | 改善率 |
468
+ |-----------|-----------|---------------|--------|
469
+ | 50 | 0.056 | 0.030 | 1.9x |
470
+ | 1,000 | 0.193 | 0.085 | 2.3x |
471
+ | 10,000 | 1.378 | 0.600 | 2.3x |
472
+
473
+ **2-2.5倍の改善を想定(Magnusよりやや劣る)**
474
+
475
+ #### メリット
476
+
477
+ ✓ 2倍程度の高速化
478
+ ✓ 既存のRust FFI インフラ活用
479
+
480
+ #### デメリット
481
+
482
+ ✗ FFIオーバーヘッド
483
+ ✗ JSONシリアライゼーションコスト
484
+ ✗ Magnus/Zigより遅い
485
+ ✗ 複雑性増加
486
+
487
+ #### 実装工数
488
+
489
+ - **開発**: 2-3日
490
+ - **テスト**: 1日
491
+ - **ドキュメント**: 0.5日
492
+ - **合計**: 約3.5-4.5日
493
+
494
+ ---
495
+
496
+ ## 改善方式の総合比較
497
+
498
+ ### 性能比較(max_lines=1000の場合)
499
+
500
+ | 方式 | 処理時間 | 改善率 | バイナリサイズ | 工数 | 保守性 |
501
+ |-------------------------|----------|--------|----------------|--------|--------|
502
+ | **現在の実装** | 0.193ms | - | - | - | ⭐⭐⭐⭐⭐ |
503
+ | **Pure Ruby 最適化** | 0.155ms | 1.2x | - | 1.5日 | ⭐⭐⭐⭐⭐ |
504
+ | **YJIT** | 0.174ms | 1.1x | - | 1日 | ⭐⭐⭐⭐⭐ |
505
+ | **Rust (FFI)** | 0.085ms | 2.3x | - | 3.5日 | ⭐⭐⭐ |
506
+ | **Rust (Magnus)** | 0.070ms | 2.8x | 314 KB | 3.5日 | ⭐⭐⭐ |
507
+ | **Zig** | 0.070ms | 2.8x | 53 KB | 3.5日 | ⭐⭐⭐ |
508
+
509
+ ### コストパフォーマンス分析
510
+
511
+ | 方式 | 改善率 | 工数 | CPP (改善率/日) | 推奨度 |
512
+ |-------------------------|--------|-------|-----------------|--------|
513
+ | **YJIT** | 1.1x | 1日 | 0.11 | ⭐⭐⭐ |
514
+ | **Pure Ruby 最適化** | 1.2x | 1.5日 | 0.13 | ⭐⭐⭐⭐ |
515
+ | **Rust (FFI)** | 2.3x | 3.5日 | 0.37 | ⭐⭐ |
516
+ | **Rust (Magnus)** | 2.8x | 3.5日 | 0.51 | ⭐⭐⭐ |
517
+ | **Zig** | 2.8x | 3.5日 | 0.51 | ⭐⭐⭐⭐⭐ |
518
+
519
+ ---
520
+
521
+ ## 推奨事項
522
+
523
+ ### 即座に実施すべき改善(Phase 1)
524
+
525
+ #### 1. YJIT 有効化 ⭐⭐⭐⭐
526
+
527
+ **理由:**
528
+ - コスト: 最小(設定のみ)
529
+ - 効果: 全アプリケーションで5-11%改善
530
+ - リスク: 非常に低い
531
+
532
+ **実装:**
533
+ ```ruby
534
+ # lib/rufio.rb の先頭に追加
535
+ if defined?(RubyVM::YJIT) && !RubyVM::YJIT.enabled?
536
+ RubyVM::YJIT.enable
537
+ end
538
+ ```
539
+
540
+ **期待効果:** 0.193ms → 0.174ms(10%改善)
541
+
542
+ ---
543
+
544
+ #### 2. Pure Ruby 最適化 ⭐⭐⭐⭐⭐
545
+
546
+ **理由:**
547
+ - コスト: 低(1.5日)
548
+ - 効果: 10-25%改善
549
+ - リスク: 低(既存コードベース)
550
+ - 保守性: 高
551
+
552
+ **優先実装項目:**
553
+
554
+ **a) バイナリ検出の最適化**
555
+ ```ruby
556
+ ALLOWED_CONTROL_CHARS = Set.new([9, 10, 13]).freeze
557
+
558
+ def binary_file?(sample)
559
+ return false if sample.empty?
560
+
561
+ binary_count = sample.each_byte.count { |b|
562
+ b < 32 && !ALLOWED_CONTROL_CHARS.include?(b)
563
+ }
564
+
565
+ (binary_count.to_f / sample.bytesize) > BINARY_THRESHOLD
566
+ end
567
+ ```
568
+
569
+ **b) ファイル読み込みの最適化**
570
+ ```ruby
571
+ def read_text_file(file_path, max_lines)
572
+ content = File.read(file_path, encoding: 'UTF-8')
573
+ lines = content.lines(chomp: true).first(max_lines)
574
+
575
+ # 長い行の処理
576
+ lines.map! { |line|
577
+ line.length > MAX_LINE_LENGTH ? "#{line[0...MAX_LINE_LENGTH]}..." : line
578
+ }
579
+
580
+ {
581
+ content: lines,
582
+ truncated: content.count("\n") > max_lines,
583
+ encoding: 'UTF-8'
584
+ }
585
+ rescue Encoding::InvalidByteSequenceError
586
+ # Shift_JIS fallback
587
+ fallback_read(file_path, max_lines)
588
+ end
589
+ ```
590
+
591
+ **期待効果:** 0.193ms → 0.155ms(20%改善)
592
+
593
+ ---
594
+
595
+ ### 中長期的な改善(Phase 2)
596
+
597
+ #### 3. Zig ネイティブ実装 ⭐⭐⭐⭐⭐
598
+
599
+ **理由:**
600
+ - 最大の性能改善(2.8倍)
601
+ - 最小のバイナリサイズ(53 KB)
602
+ - NativeScannerでの実績あり
603
+ - コストパフォーマンス最高
604
+
605
+ **実装タイミング:**
606
+ - Phase 1完了後
607
+ - パフォーマンスがまだ不足している場合
608
+ - 大規模ファイルの頻繁な閲覧がユースケースに含まれる場合
609
+
610
+ **実装ロードマップ:**
611
+ 1. NativeScannerの実装パターンを踏襲
612
+ 2. FilePreviewZig クラスとして実装
613
+ 3. 既存のFilePreviewとの互換性を維持
614
+ 4. モード切り替え可能にする('zig', 'ruby')
615
+
616
+ **期待効果:** 0.193ms → 0.070ms(2.8倍高速化)
617
+
618
+ ---
619
+
620
+ ### 推奨しない方式
621
+
622
+ #### Rust (FFI)
623
+ - Zigと同等の工数だが、性能はやや劣る
624
+ - FFIオーバーヘッドが不要
625
+ - 既にZigの実績がある
626
+
627
+ #### Rust (Magnus)
628
+ - Zigと同等の性能だが、バイナリが約6倍大きい
629
+ - 特別な理由がない限りZigを推奨
630
+
631
+ ---
632
+
633
+ ## 実装ロードマップ
634
+
635
+ ### フェーズ1: 即効性の高い改善(推奨)
636
+
637
+ **目標:** 20-30%の性能改善を1週間以内に達成
638
+
639
+ | タスク | 工数 | 担当 | 期待効果 |
640
+ |--------|------|------|----------|
641
+ | YJIT有効化 | 0.5日 | Backend | +10% |
642
+ | Pure Ruby最適化 - バイナリ検出 | 0.5日 | Backend | +5% |
643
+ | Pure Ruby最適化 - ファイル読み込み | 1日 | Backend | +15% |
644
+ | テスト・ベンチマーク | 0.5日 | QA | - |
645
+ | ドキュメント更新 | 0.5日 | Backend | - |
646
+ | **合計** | **3日** | | **+30%** |
647
+
648
+ **成果物:**
649
+ - 最適化されたFilePreviewクラス
650
+ - ベンチマーク結果レポート
651
+ - 更新されたドキュメント
652
+
653
+ ---
654
+
655
+ ### フェーズ2: ネイティブ実装(オプション)
656
+
657
+ **目標:** 2-3倍の性能改善
658
+
659
+ **前提条件:**
660
+ - フェーズ1が完了していること
661
+ - 性能要件がまだ満たされていないこと
662
+ - 大規模ファイルの頻繁な閲覧が必要
663
+
664
+ | タスク | 工数 | 担当 | 期待効果 |
665
+ |--------|------|------|----------|
666
+ | Zig実装 - コア機能 | 2日 | Backend | - |
667
+ | Zig実装 - Ruby統合 | 1日 | Backend | - |
668
+ | テスト(単体・統合) | 1日 | QA | - |
669
+ | ベンチマーク・検証 | 0.5日 | Backend | - |
670
+ | ドキュメント | 0.5日 | Backend | - |
671
+ | **合計** | **5日** | | **+180%** |
672
+
673
+ **成果物:**
674
+ - FilePreviewZig ネイティブ拡張
675
+ - フォールバック機構
676
+ - 包括的なテストスイート
677
+ - パフォーマンスベンチマーク
678
+
679
+ ---
680
+
681
+ ## 付録
682
+
683
+ ### A. ベンチマーク詳細データ
684
+
685
+ #### テスト環境
686
+ ```
687
+ OS: macOS 14.x (Apple Silicon)
688
+ CPU: Apple M1/M2
689
+ RAM: 16GB
690
+ Ruby: 3.4.2
691
+ Zig: 0.15.2 (フェーズ2実装時)
692
+ ```
693
+
694
+ #### テストファイル
695
+ ```
696
+ small.txt: 1KB (50行)
697
+ medium.txt: 100KB (1,000行)
698
+ large.txt: 1MB (10,000行)
699
+ huge.txt: 10MB (100,000行)
700
+ long_lines.txt: 長い行 (10,000文字/行)
701
+ ```
702
+
703
+ ### B. 実装リファレンス
704
+
705
+ #### 参考コード
706
+ - `lib/rufio/native_scanner.rb` - FFI実装パターン
707
+ - `lib/rufio/native_scanner_zig.rb` - Zig統合パターン
708
+ - `lib_zig/rufio_native/src/main.zig` - Zig実装例
709
+
710
+ #### 関連ドキュメント
711
+ - [YJIT_BENCHMARK_RESULTS.md](../directory-scanner-test/YJIT_BENCHMARK_RESULTS.md)
712
+ - [BENCHMARK_RESULTS.md](../directory-scanner-test/BENCHMARK_RESULTS.md)
713
+
714
+ ### C. リスク分析
715
+
716
+ | リスク | 確率 | 影響度 | 軽減策 |
717
+ |--------|------|--------|--------|
718
+ | Ruby最適化で互換性問題 | 低 | 中 | 包括的なテスト |
719
+ | Zig実装でクロスプラットフォーム問題 | 中 | 高 | CIでマルチOS検証 |
720
+ | YJITでメモリ不足 | 低 | 中 | メモリ使用量監視 |
721
+ | 性能改善が期待以下 | 中 | 低 | フォールバック維持 |
722
+
723
+ ---
724
+
725
+ ## 結論
726
+
727
+ ### 推奨戦略: 段階的改善アプローチ
728
+
729
+ **即座の対応(フェーズ1):**
730
+ 1. **YJIT有効化** - 最小コストで10%改善
731
+ 2. **Pure Ruby最適化** - 1.5日で20%改善
732
+ 3. **合計30%改善** を3日で達成
733
+
734
+ **将来の対応(フェーズ2、必要に応じて):**
735
+ 1. **Zig ネイティブ実装** - 5日で2.8倍高速化
736
+ 2. 大規模ファイルの頻繁な閲覧が必要になった場合に実施
737
+
738
+ ### 期待される成果
739
+
740
+ #### フェーズ1完了時
741
+ ```
742
+ 小規模ファイル (50行): 0.056ms → 0.039ms (1.4x高速化)
743
+ 中規模ファイル (1000行): 0.193ms → 0.135ms (1.4x高速化)
744
+ 大規模ファイル (10000行): 1.378ms → 0.965ms (1.4x高速化)
745
+ ```
746
+
747
+ #### フェーズ2完了時(オプション)
748
+ ```
749
+ 小規模ファイル (50行): 0.056ms → 0.025ms (2.2x高速化)
750
+ 中規模ファイル (1000行): 0.193ms → 0.070ms (2.8x高速化)
751
+ 大規模ファイル (10000行): 1.378ms → 0.500ms (2.8x高速化)
752
+ ```
753
+
754
+ ---
755
+
756
+ **レポート作成日:** 2026-01-03
757
+ **作成者:** Claude Sonnet 4.5
758
+ **バージョン:** 1.0
759
+ **ステータス:** 最終版