実ゲームでの実測
本ページは、実在する GalGame の配布用ビルドで RenMori 1.2.0 を実測した結果を記録したものです。同一ビルドのオリジナル版と RenMori フル保護版を同じデバイス上で比較し、シーケンシャル読み込みのスループット、ランダム読み込みのレイテンシ、コールドスタートのレイテンシを測定しました。保護版はプレイヤーが実際に起動するときと同じく、ネイティブ launcher を経由して起動しています。
パフォーマンスベンチマーク の合成アセットとは異なり、本ページのサンプルは実在する作品の配布用ビルドで、CG、立ち絵、UI 素材、BGM、ボイス、動画を含む約 3.5 GB のアセットから成ります。作品名は本ページでは公開しません。
結果の要約
プレイヤーにとって、暗号化はほとんど体感できません。
- ランダム読み込みで増える遅延は最大でも約 0.15 ms で、60 FPS での 1 フレーム(16.7 ms)の 1% に満たない
- コールドキャッシュでの全アセットのシーケンシャル読み込みスループットは 584 MB/s で、リアルタイムの音声・動画デコードに必要な帯域の 100 倍以上
- 平均的な大きさ(約 1.9 MB)の画像 1 枚の読み込み時間は、コールドキャッシュで約 1.8 ms 増えるのみで、Ren'Py は通常バックグラウンドで画像を先読みする
- コールドスタートから最初のフレームまでの時間は 7.16 s から 8.44 s に増加。増えた 1.3 s は起動時に一度だけ発生し、プレイ中には発生しない
- 保護版の
game/ディレクトリのサイズ増加はわずか 0.09% で、3 プラットフォーム分のネイティブランタイムを含む
テスト環境
テストサンプル
オリジナル版は作品の配布用ビルドで、game/ ディレクトリは合計 3.51 GiB です。アセットは 2.05 GiB の RPA アーカイブと 2 つの独立した動画ファイルに格納されています。保護版は同じビルドから renmori protect で生成したもので、すべてのアセットが暗号化コンテナ renmori.rmc に格納されています。
比較対象は両ビルドに存在し、かつサイズが一致するエントリのみで、合計 1407 件、3593 MB です。コンパイル済みスクリプト 22 件(.rpyc と .rpymc)は保護版でスクリプト層の変換を受けてサイズが異なるため、読み込みテストから除外しています。
本ページの MB はすべて 220 バイトを指します。
テスト方法
すべての測定はエンジンのプロセス内で行い、エンジン自身の読み込み経路である renpy.loader.load を通じて読み込んでいます。そのため、保護版の数値には復号、認証、コンテナインデックスの検索にかかるすべてのオーバーヘッドが含まれます。両ビルドとも .app 内の実行ファイルを直接起動しており、保護版は launcher の起動処理を経由します。
コールドキャッシュとウォームキャッシュ
コールドキャッシュの測定のたびに、APFS クローン(cp -c)でビルドの新しいコピーを作成しています。クローンはディスク上のデータを元のファイルと共有しますが、OS からは新しいファイルとして扱われ、その内容はページキャッシュに一切存在しないため、各ファイルの最初の読み込みは必ずディスクにアクセスします。事前の確認では、クローン直後の 1 回目のランダム 4 KB 読み込みの中央値が 104 µs、2 回目が 1.4 µs となり、1 回目が確かにコールドキャッシュであることを確認しました。
ウォームキャッシュの測定は同じクローン上で読み込みを繰り返すもので、データはすでにページキャッシュにあるため、結果は CPU のオーバーヘッドのみを反映します。
測定項目
ランダム読み込みのコールドとウォームは同じ乱数系列を使い、3 回分の全サンプルをまとめて中央値と p95 を算出しています。
結果
シーケンシャル読み込み
単位は MB/s、値が大きいほど良好です。
保護版のスループットは、コールドキャッシュでオリジナル版の約 45%、ウォームキャッシュで約 27% です。ウォームキャッシュではディスク待ちがなくなるため、保護版の約 420〜560 MB/s が現時点での復号の上限となります。
コールドキャッシュのスループットで換算すると、平均的な大きさ(約 1.9 MB)の画像 1 枚の読み込みにかかる時間は、オリジナル版で約 1.6 ms、保護版で約 3.4 ms です。動画と BGM はエンジンがストリーミングで読み込み、そのビットレートは通常毎秒数 MB 程度で、584 MB/s とは 2 桁以上の差があります。
ランダム読み込み
単位は ms、値が小さいほど良好です。
ランダム 4 KB 読み込みは両者同等で、差は測定誤差の範囲内です。ランダム 64 KB 読み込みの中央値は 0.10〜0.15 ms 増えますが、これは 64 KB の読み込みが通常 2 つのチャンクにまたがり、両方を復号・認証する必要があるためです。小さなファイルのランダムオープンの中央値は 0.04〜0.07 ms 増え、これはコンテナインデックスの検索とファイルごとの鍵導出によるものです。
コールドスタート
単位は s で、実行ファイルの起動から計測した中央値です。括弧内は最小値と最大値です。
launcher の起動処理とコンテナインデックスの構築による時間の増加はほとんどなく、コールドキャッシュでアセットインデックスの準備が完了するまでの差はわずか 0.05 s です。ウォームスタートは回ごとのばらつきが大きいため、両者の差はコールドスタートの数値を基準とします。
増加した時間はスクリプトの読み込み段階に集中しています。保護版はディスク上に平文を残さないよう、バイトコードや画面解析などの Ren'Py のランタイムキャッシュを書き込まないため、起動のたびにスクリプト内の Python コードを再コンパイルします。1 回の実行における Ren'Py のログでは、「Loading script」段階はオリジナル版で 169 ms、保護版で 1967 ms でした。
サイズのオーバーヘッド
保護版のサイズには、暗号化コンテナ、ランタイムローダー、Windows、Linux、macOS の 3 プラットフォーム分のネイティブランタイムが含まれます。暗号化コンテナのみでは、オリジナル版のアセットに対するオーバーヘッドは 0.08% です。
結果の解釈
プレイヤーが体感するパフォーマンスの問題は、主にカクつきと待ち時間です。カクつきは 1 回の読み込みが 1 フレーム内に終わるかどうか、待ち時間は大きなアセットが間に合うかどうかで決まります。ランダム読み込みで増える遅延は最大でも約 0.15 ms で 1 フレームの 1% に満たず、シーケンシャルのスループットはコールドキャッシュでも音声・動画のストリーミング再生に必要な帯域を大きく上回ります。プレイ中に暗号化が体感できるカクつきや待ち時間を生むことはありません。
体感できる唯一の差は起動時に増える約 1 s で、平文キャッシュを書き込まないというセキュリティ上のトレードオフによるものであり、起動のたびに一度だけ発生します。
制限事項
- 実際のプレイ中のフレーム時間は測定していない。本ページのデータはアセットの読み込みのみを対象とし、画像デコード、音声デコード、レンダリングは含まない
- テストは Apple M1 デバイス 1 台のみで実施しており、Windows、Linux、Steam Deck でのデータは未測定
- テストデバイスは内蔵 SSD を使用している。HDD ではコールドキャッシュの読み込みがディスク速度に強く制約され、保護版とオリジナル版の相対的な差は通常小さくなる
- ウォームスタートの数値はばらつきが大きく、参考値にとどまる
- サンプル作品と測定コードは非公開のため、本ページのデータを第三者が直接再現することはできない。再現可能な合成ベンチマークは パフォーマンスベンチマーク を参照