> For AI agents: the complete documentation index is available at https://renmori.mewbaka.cn/ja/llms.txt, the full documentation bundle is available at https://renmori.mewbaka.cn/ja/llms-full.txt.

# パフォーマンスベンチマーク

本ページは RenMori 1.1.0 のパフォーマンスベンチマーク結果を記録したものです。テストは実際の Ren'Py 8.5.2 エンジン内で行い、同一のアセットから未保護、ベースライン保護、フル保護の 3 種類の配布用ビルドを作成し、エンジン自身の読み込み経路である `renpy.loader.load` を通じてすべてのアセットを読み込む時間を計測しています。そのため、得られる数値は単体の暗号ライブラリの性能ではなく、実際に配布されるランタイムのオーバーヘッドです。

ベンチマークスクリプトはリポジトリの [`tools/benchmark.py`](https://github.com/MewBaka/RenMori/blob/main/tools/benchmark.py) で、本ページのデータに対応する生の結果は [`docs/benchmarks/2026-10-31-apple-m1.json`](https://github.com/MewBaka/RenMori/blob/main/docs/benchmarks/2026-10-31-apple-m1.json) にあります。

## 結果の要約

- フル保護でのエンジン内復号スループットは、ファイルサイズに応じて 567〜1529 MB/s
- 2 MB の CG の読み込みは、フル保護では未保護より約 0.95 ms 長くかかる。参考として、60 FPS での 1 フレームは 16.7 ms
- 動画内でランダムにシークして 64 KB を読み込む時間は、フル保護で中央値 0.086 ms
- すべてのスクリプトを読み込んで解析する `lint` の所要時間は 0.52 s から 0.67 s に増加
- 保護済みビルドの `game/` ディレクトリのサイズ増加はわずか 0.18%
- ビルド時に 319 MB のアセットをフル保護する処理は約 13 s

## テスト環境

| 項目             | 値                              |
| -------------- | ------------------------------ |
| テスト日           | 2026-10-31                     |
| デバイス           | Apple M1、メモリ 8 GB              |
| オペレーティングシステム   | macOS 26.5.1（arm64）            |
| Ren'Py         | 8.5.2.26010301                 |
| RenMori        | 1.1.0、クローズドプラグイン plugin-v1.1.0 |
| ビルドツールの Python | 3.12.12                        |

## テスト方法

### ワークロード

Ren'Py SDK のサンプルプロジェクト `the_question` をベースに、商業ビジュアルノベルの規模を想定した合成アセット計 812 ファイルを `game/` に追加しました。サンプル自体のファイルを含めると `game/` ディレクトリは合計 319.3 MB です。合成アセットの内容はランダムなバイト列で、エンコード済みの画像、音声、動画と同様に圧縮できません。

| カテゴリ  | 拡張子     | ファイルサイズ | ファイル数 |       合計 |
| ----- | ------- | ------: | ----: | -------: |
| CG    | `.png`  |    2 MB |    40 |  80.0 MB |
| 立ち絵   | `.png`  |  600 KB |    60 |  35.2 MB |
| UI 素材 | `.png`  |   24 KB |   400 |   9.4 MB |
| BGM   | `.ogg`  |    4 MB |    10 |  40.0 MB |
| ボイス   | `.opus` |   60 KB |   300 |  17.6 MB |
| 動画    | `.webm` |   64 MB |     2 | 128.0 MB |

### 計測項目

| 項目                  | 方法                                                                                                         |
| ------------------- | ---------------------------------------------------------------------------------------------------------- |
| エンジン内の読み込みスループット    | 各ビルドにベンチマーク拡張を注入し、エンジンの起動段階で `renpy.loader.load` により各ファイルを 1 MB 単位で読み込む。カテゴリごとに 1 回の予備読み込みの後、5 回計測して中央値を採用 |
| 動画のストリーミング読み込みレイテンシ | 64 MB の動画について「開いて先頭 64 KB を読み込む」と「ランダムにシークして 64 KB を読み込む」をそれぞれ 200 回計測し、中央値を採用                             |
| スクリプトの読み込み          | 各ビルドで `renpy.sh <game> lint` を 3 回実行し、中央値を採用。`lint` はコンテナからすべてのスクリプトを読み込んで解析する                             |
| ビルド時間               | 同じ入力に対して `renmori protect` を 3 回実行し、中央値を採用                                                                 |
| サイズのオーバーヘッド         | 保護済みビルドと未保護ビルドの `game/` ディレクトリのサイズ差。コンテナ、ローダー拡張、スクリプト変換の影響をすべて含む                                           |
| チャンクサイズ             | ビルドツールの Python で、リファレンスリーダーにより 64 MB のデータを 4 種類のチャンクサイズで読み込み、シーケンシャルスループットとランダム 4 KB 読み込みのレイテンシを計測         |

本ページの MB はすべて 2<sup>20</sup> バイトを指します。

## 結果

### エンジン内の読み込みスループット

単位は MB/s で、値が大きいほど高速です。

| カテゴリ  | ファイルサイズ |  未保護 | フル保護 | ベースライン保護 |
| ----- | ------: | ---: | ---: | -------: |
| CG    |    2 MB | 5590 | 1529 |      108 |
| 立ち絵   |  600 KB | 5585 | 1463 |      120 |
| UI 素材 |   24 KB |  729 |  567 |      100 |
| BGM   |    4 MB | 4608 | 1048 |      115 |
| ボイス   |   60 KB | 1197 |  749 |       97 |
| 動画    |   64 MB | 3822 | 1287 |      112 |

### ファイルごとの読み込み時間

単位は ms で、1 つのファイル全体を読み込むのに要する時間です。

| カテゴリ  | ファイルサイズ |   未保護 |  フル保護 |   追加時間 |
| ----- | ------: | ----: | ----: | -----: |
| CG    |    2 MB |  0.36 |  1.31 |  +0.95 |
| 立ち絵   |  600 KB |  0.11 |  0.40 |  +0.30 |
| UI 素材 |   24 KB | 0.032 | 0.041 | +0.009 |
| BGM   |    4 MB |  0.87 |  3.82 |  +2.95 |
| ボイス   |   60 KB | 0.049 | 0.078 | +0.029 |

動画はファイル全体ではなくエンジンによってストリーミングで読み込まれるため、次節のレイテンシを参照してください。

### 動画のストリーミング読み込みレイテンシ

単位は ms で、中央値です。

| 計測                     |   未保護 |  フル保護 | ベースライン保護 |
| ---------------------- | ----: | ----: | -------: |
| 開いて先頭 64 KB を読み込む      | 0.051 | 0.082 |    0.596 |
| ランダムにシークして 64 KB を読み込む | 0.035 | 0.086 |    1.113 |

### スクリプトの読み込み

| ビルド      | `lint` の所要時間 |
| -------- | -----------: |
| 未保護      |       0.52 s |
| フル保護     |       0.67 s |
| ベースライン保護 |       0.58 s |

`the_question` には 52 個のコンパイル済みスクリプトが含まれており、3 種類のビルドの差はいずれも 0.15 s 以内です。

### ビルド時間とサイズのオーバーヘッド

| 保護強度     |    所要時間 |       処理速度 | `game/` のサイズ変化 |
| -------- | ------: | ---------: | -------------: |
| ベースライン保護 |  2.52 s | 126.8 MB/s |        +0.147% |
| フル保護     | 13.41 s |  23.8 MB/s |        +0.177% |

ビルド時間は開発者のマシンまたは CI 上でのみ発生し、プレイヤーには影響しません。フル保護はクローズドプラグインが実行し、ビルドごとの構造多態化などの追加処理を含むため、ベースライン保護よりも時間がかかります。

### チャンクサイズ

以下のデータはビルドツールの Python で `cryptography` バックエンドを使用して計測したもので、`chunk_size` 設定のトレードオフを比較するためのものです。エンジン内での絶対的な性能を示すものではありません。

|   チャンクサイズ | シーケンシャルスループット | ランダム 4 KB 読み込み（中央値） | ランダム 4 KB 読み込み（p95） | サイズのオーバーヘッド |
| --------: | ------------: | ------------------: | ------------------: | ----------: |
|     16 KB |     1273 MB/s |            0.011 ms |            0.022 ms |      0.098% |
| 64 KB（既定） |     2008 MB/s |            0.024 ms |            0.050 ms |      0.025% |
|    256 KB |     2339 MB/s |            0.077 ms |            0.124 ms |      0.006% |
|      1 MB |     1461 MB/s |            0.286 ms |            0.482 ms |      0.002% |

チャンクが大きいほどシーケンシャルスループットは向上し、サイズのオーバーヘッドも小さくなりますが、ランダム読み込みのたびに復号するデータ量が増えます。既定の 64 KB は両者のバランスを取った値で、通常は変更する必要はありません。

## 結果の解釈

フル保護はクローズドプラグインが提供するネイティブランタイムを使用し、配布用ビルドの既定値です。ベースライン保護は Python で書かれたリファレンスリーダーを使用し、スループットはフル保護の 1/14〜1/6 程度であるため、プラグインを使用できない場合に限って適しています。詳しくは [保護強度とクローズドプラグイン](https://renmori.mewbaka.cn/ja/cli/plugin.md) を参照してください。

上表の「未保護」の値がメモリコピーに近い速度になっているのは、テスト時にアセットがすでにオペレーティングシステムのページキャッシュ上にあったためです。この条件によりディスク性能の差が除外され、結果は復号そのものの CPU コストのみを反映します。プレイヤーのマシンでは初回の読み込みは通常ディスク速度に制約されるため、保護済みと未保護の相対的な差はその分小さくなります。

## 制限事項

- 実際のプレイ中のフレーム時間は計測していない。本ページのデータはアセットの読み込みと復号のみを対象とし、画像のデコード、音声のデコード、描画は含まない
- 合成アセットはランダムなバイト列で、エンジンは読み込むのみでデコードしない
- ページキャッシュが温まった状態でテストしており、コールドスタート時のディスク I/O は含まない
- テストは 1 台の Apple M1 デバイスのみで行っており、Windows、Linux、Steam Deck でのデータは未計測

## 再現方法

Ren'Py SDK と RenMori のソースリポジトリが必要です。フル保護にはクローズドプラグインが必要で、初回実行時に自動でダウンロードされます。

```bash
git clone https://github.com/MewBaka/RenMori.git
cd RenMori && pip install -e .
python tools/benchmark.py --sdk /path/to/renpy-8.5.2-sdk \
    --game /path/to/renpy-8.5.2-sdk/the_question --json result.json
```

| オプション        | 既定値    | 説明                                        |
| ------------ | ------ | ----------------------------------------- |
| `--scale`    | 1.0    | ワークロード規模の倍率。1.0 で合成アセット約 310 MB           |
| `--passes`   | 5      | エンジン内でのカテゴリごとの計測回数                        |
| `--repeat`   | 3      | `protect` と `lint` の繰り返し回数                |
| `--strength` | `both` | 作成する保護済みビルド。`both`、`baseline`、`full` から選択 |
| `--json`     | なし     | 生の結果と集計結果を指定したファイルに書き込む                   |
| `--keep`     | オフ     | 生成されたビルドを確認できるよう作業ディレクトリを残す               |

絶対値はデバイスによって異なるため、比較の際は同一デバイス上での 3 種類のビルド間の相対的な結果を基準にしてください。
