Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

ラピッドイテレーションを実現するRE ENGINEの設計

Architecture of RE ENGINE.
First presented at Game Creators Conference 2017.
http://gc-conf.com/event_2017/

Download the .pptx file to watch embedded movies and animations.

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all
  • Be the first to comment

ラピッドイテレーションを実現するRE ENGINEの設計

  1. 1. ラピッドイテレーションを実現 するRE ENGINEの設計 株式会社カプコン 石田智史
  2. 2. RE ENGINE • カプコン内製の次世代ゲームエンジン • MT Frameworkからアーキテクチャを一新 • マルチプラットフォーム対応 • PS4,XboxOne,PC(Steam/UWP)… • バイオハザード7で採用 • 今後、様々なタイトルで活用
  3. 3. RE ENGINEの特徴 •高いパフォーマンス •高解像度で高フレームレートを実現 •高い開発効率 •高速なイテレーションを実現 このセッションで扱う内容
  4. 4. ゲーム開発のイテレーション コーディ ング ビルド 動作確認 DCC編 集 コンバート 実機確 認 調整 起動 プレイ バグ修正 パッケージ 生成 QA 長い 長い 手間 遅い 多い 手間 遅い
  5. 5. RE ENGINEのイテレーション
  6. 6. リモートでの実機編集
  7. 7. 全リソースのリロード対応
  8. 8. リアルタイムコーディング
  9. 9. パッケージ作成
  10. 10. ラピッドイテレーションを実現 • 待ち時間が減る • トライ&エラーの回数が増える • 実機で動かす頻度が増える • QAでのバグが減る 余力をゲームの品質向上に費やせる
  11. 11. バイオハザード7の開発結果 • 最終プロジェクト規模 • C#ゲームコード約28万行、アセット総数約15万 • 高速なイテレーションを維持 • フルビルド~10秒、開発終盤まで何度もレベル調整が繰り返えされた • 実機での安定したパフォーマンスを実現 • VRで60fpsを切る=発売できない • 平穏なQA • 大規模タイトルでは弊社史上初? 炎上なし!
  12. 12. アジェンダ • ツールアーキテクチャ • リソースアーキテクチャ • スクリプトアーキテクチャ
  13. 13. ツールアーキテクチャ RE ENGINE
  14. 14. • ランタイム上でツールが動作 • 独自のUIシステム • 実機上でのリアルタイム編集と調整 • 問題点 • 実機上では解像度や性能に制約がある • UIを自作する必要がある • 実機動作までに手間がかかる • ランタイムクラッシュで編集データが消失 旧ツールアーキテクチャ
  15. 15. 新ツールアーキテクチャ • ツールプロセスを完全に分離 • ランタイム、ツール間はTCP/IPで同期 • ツールはPC上で動作しWPF/C#で実装 • 利点 • 高速、高解像度なPC上で動作 • 豊富なWPFのUI機能 • 異なる実機上で即座に編集 • ランタイムのクラッシュに影響を受けない TCP/IP
  16. 16. 新ツールアーキテクチャの課題 • 言語間の互換性がない • ランタイムはC++言語、ツールはC#言語を使用 • ランタイム操作を非同期で行う必要がある • コードが煩雑で冗長になり易い • 通信コストが問題になり易い • データ転送速度が限られる
  17. 17. RE ENGINEのソリューション • 通信プロトコルの統一 • リモートオブジェクトシステム
  18. 18. 通信プロトコルの統一 • ランタイム、ツール間の通信方法を統一 • 全ての通信を共通のプロトコルで行う • 効率的なプロトコルの実装 • C#とC++言語間の定義の共通化 • バイナリ形式の通信 • 非同期コードの簡潔な記述
  19. 19. 通信プロトコル (1/2) • リモートエンティティ • C++/C#言語間で相互にバイナリシリアライズ、デシリアライズ可能なクラ ス • C#言語で定義し、対応するC++ヘッダを自動生成 runtime/remote.h 自動生成
  20. 20. 通信プロトコル (2/2) • Query/Responseプロトコル • Query/Responseはリモートエンティティ継承 • QueryはExecuteメソッドを持ち、戻り値にResponseを返す • Responseが返ると、対応するハンドラが実行される Query Query Serialize Deserialize Response SerializeDeserialize Response ExecuteTCP/IP Handler Tool Runtime
  21. 21. Query/Responseプロトコル(1/3) • プロトコル実例 • ツールのマウスカーソル位置に対応するワールド座標をランタイムから取得 する • Query/Responseをツール側で定義(C#)
  22. 22. Query/Responseプロトコル(2/3) • C++ヘッダファイルを自動生成 • Queryの実行コードをランタイム側に実装(C++) • ワールド座標を計算し、Responseとして返す 自動生成 runtime/remote.h runtime/remote.cpp
  23. 23. Query/Responseプロトコル(3/3) • ツールからランタイムにQueryを送信 • Responseが返るとコールバックが実行 • Responseを元に任意の処理を記述  ランタイムからツールへのQueryも同様の流れ
  24. 24. リモートオブジェクトシステム • ツール上でランタイムのオブジェクトを透過的に扱う仕組み • プロセスや言語の違いを吸収できる • リモートオブジェクト • ツール上の仮想的なランタイムインスタンス • 任意にランタイム上に実体化 • ツール/ランタイム間で状態を同期
  25. 25. リモートオブジェクト(1/3) • ランタイムから全ての型情報を取得 • 型名とプロパティ情報で構成 0 Int Param 1 Bool Flag 2 String Name SampleClass RuntimeType Runtime(C++) Tool(C#) TCP/IP
  26. 26. リモートオブジェクト(2/3) • リモートオブジェクトの作成 • ランタイムタイプから仮想的なインスタンスを構築 • 各プロパティに対応する値を持つ 0 Int Param 1 Bool Flag 2 String Name SampleClass 0 10 1 True 2 “Test” SampleClass RemoteObject Create RuntimeType
  27. 27. リモートオブジェクト(3/3) • リモートオブジェクトのラップ • RuntimeObjectを継承し、アクセッサを実装 • 使用頻度の高い基本型など • ランタイム型を直接扱うように記述できる RuntimeWrapper ラッパークラスなし ラッパークラスあり
  28. 28. リモートオブジェクトの同期(1/2) RemoteObjectA Sync ID:11 • 初回同期時にインスタンスIDを割り当て • ツールから同期したインスタンスは正のID • ランタイムから同期したインスタンスは負のID • インスタンスをテーブルでマッピング • ツール、ランタイム双方が2つのテーブルを持つ 2 3 4 1 2 3 4 1 2 3 4 ID:-11 2 3 4 ObjectA ObjectB Sync RemoteObjectB TCP/IP Tool Runtime New New
  29. 29. リモートオブジェクトの同期(2/2) • 基本的な状態の同期 • 適時Syncを手動で呼び出す • 自動的な状態の同期 • モニターリストに登録 • 毎フレーム、ランタイムインスタンスの状態 を監視 • 変化があったプロパティのみをツール側に自動送 信 • 負荷が高い • インスペクタ表示時など限定的に利用 RemoteObject Object Sync(OneWay) Sync(TwoWay) RemoteObject Object RemoteObject Object Sync(OneWayToSource)
  30. 30. ウィジェットシステム • ランタイム上で動作するツール機能 • ツール側からリモートオブジェクトを介して操作 • 通信コストやレスポンスを改善 Tool RemoteObject FrameProfileWidget LightViewWidget ManipulatorWidget RemoteObject RemoteObject Runtime
  31. 31. リモートオブジェクトの動作
  32. 32. まとめ • ツールプロセスの分離は非常に効果的 • ランタイムを自由に切り替えできる • 実機でしか調整できないことも多い • VRやモバイル端末など • ランタイムはクラッシュしやすい • 通信プロトコルや同期の仕組みを整備 • プロセス分離の煩雑さが軽減できる
  33. 33. リソースアーキテクチャ RE ENGINE
  34. 34. 旧リソースアーキテクチャ • ファイルベースのリソース管理 • リソースロードはゲームコードで行う • 問題点 • 同期ロードによるスパイク • 再起動が必要なリソース更新 • コンバートによる長い待ち時間 • 手動でのパッケージ作成 • 不要リソースの混入、必要リソースの不足
  35. 35. 新リソースアーキテクチャ • アセットベースのリソース管理 • リソースロードはエンジン側で自動的に行う • 利点 • リソースロードの完全なコントロール • 全リソースの非同期ロード対応 • 全リソースの動的リロード対応 • キャッシュによるコンバート時間の短縮 • 自動的なパッケージ作成 • 必要なリソースのみを最適な順序で自動パック
  36. 36. 新リソースアーキテクチャの課題 • シーン再生時 • 使用リソースを事前にロードする必要がある • パッケージ作成時 • 使用リソースやロード順序を把握する必要がある • エンジン側で非同期ロード、リロード対応が必要 • 全てのリソースで徹底するのは難しい
  37. 37. RE ENGINEのソリューション • 静的なアセット間依存情報の構築 • リソースアクセスの制約
  38. 38. 静的なアセット間依存情報の構築 • アセットの概念を導入 • ファイルにメタデータを追加したもの • メタデータに他のアセットへの依存情報を含める • ゲームコードによるリソースロードを廃止 • ゲームコードからは使用リソースがわからない • ゲームは一つの巨大なシーンアセットで構築 マスターシーンアセット
  39. 39. Resource アセットの概念を導入 • アセット • 中間データとメタデータのファイルで構成 • メタデータに依存関係を保存 • アセットをコンバートしたものがリソースになる • ツール起動時に全アセットのメタデータをロード • 全アセット間の依存関係を静的に構築できる Asset Sample.fbx Sample.fbx.meta Sample.mesh Sample.meshConvert
  40. 40. アセット間の依存情報 • 依存関係はReferenceとIncludeの2種類 • リソースが他のリソースを参照する=Reference • リソースが他のアセットの内容に依存する=Include Mesh Material Texture Texture Shader HLSL HLSL HLSL HLSL Effect UVSequence Texture Scene MotionList HLSL Motion Sequence Motion Sequence Reference Include
  41. 41. Reference情報の活用 • リソースロード/パッケージ作成時 • Referenceのリソースのみを抽出 Mesh Material Texture Texture Shader HLSL HLSL HLSL HLSL Effect UVSequence Texture Scene MotionList HLSL Motion Sequence Motion Sequence Reference Include
  42. 42. Include情報の活用 • アセット更新時のコンバート処理 • 全てのInclude元のアセットをコンバート • コンバート済みリソースの共有 • 全IncludeアセットのハッシュからリソースIDを計算 • リソースIDを元にサーバーにアップロード/ダウンロード Scene MotionList Motion Sequence Motion Sequence Update Convert Convert Convert MotionList ResourceID
  43. 43. マスターシーンアセット • ゲームを構成する全てのシーンアセットが含まれる • アセット間の依存関係のルートになる • 進行に応じてシーンをアクティブ化 • シームレスロードも容易に実現 MasterScene SystemScene TitleScene Chapter1Scene Chapter2Scene Stage1Scene Stage2Scene Stage3Scene Mesh Material Texture Texture Texture Chapter3Scene TitleScene Chapter1Scene Stage1Scene
  44. 44. アセット間の依存関係
  45. 45. リソースアクセスの制約 • 同期ロードは実装しない • スパイクの大きな要因になる • リソースのロードが完了するまでコードをブロック • 直感的で使い易いので多用されがち • 非同期ロードのみをサポート • リロード対応は強制 • 古いリソースアクセスは警告 ゲームコードへの影響はない • リソースに直接アクセスする手段は存在しない
  46. 46. 非同期ロード時のリソースアクセス • リソース作成直後はアクセスできない • ロード完了前にアクセスするとASSERTに失敗 • リソースのロード完了を待ってからアクセス ASSERT ハンドルが有効かを判定 有効な場合のみアクセス可能
  47. 47. 全リソースが非同期ロード対応 • ロードによるスパイクが原理的に発生しない • ロード順序の並び替えが可能になる • コンバート時間が隠蔽される A BConvert B C D E同期ロード A B Convert B C D E 非同期ロード
  48. 48. リロード時のリソースアクセス • 更新リソースを先行してロード • 旧リソースと新リソースの両方がメモリに存在 • 旧リソースに新リソースへの参照を追加 • リソースハンドルに更新を問い合わせ • 更新がある場合、新旧リソースを入れ替え • 全リソースハンドルの更新完了時に旧リソースが解放 • リロードは開発時のみ有効化 ResourceHandle Texture NewTextureNewTexture
  49. 49. 全リソースがリロード対応 • リソースアクセス前に更新がないかを判定 • 更新がある場合はリソースの更新処理を行う • 更新対応せずに旧リソースにアクセスした場合 • 大量の警告ログ(クラッシュはしない) 更新があるか判定(リリース時は常にfalse) 新旧リソースを交換
  50. 50. 非同期ロード&コンバートの動作
  51. 51. まとめ • ゲームコードによるリソースロードを廃止 • リソース間の依存関係が静的に決定できる • 依存関係を元に様々な効率化、自動化が可能 • エンジン側でリソースロードを完全に制御できる • 全リソースの非同期ロード、リロード対応。シークタイムの最適化 • エンジン側のリソースアクセスは制約を設ける • 同期ロードは最初から用意しない • リロードは先に行って対応を強制
  52. 52. スクリプトアーキテクチャ RE ENGINE
  53. 53. 旧スクリプトアーキテクチャ • 全ゲームロジックをC++言語でコーディング • プログラマはスクリプト言語を使用しない • 問題点 • 長大なビルド時間 ~15分 • 分散ビルドを利用しても! • 多発するクラッシュ • メモリリーク、メモリ破壊 • 広大で混沌としたC++言語仕様
  54. 54. 新スクリプトアーキテクチャ • 全ゲームロジックをC#言語でコーディング • アプリケーション固有のC++コードは存在しない • 利点 • ビルドが圧倒的に早い ~10秒 • クラッシュしない • 自動メモリ管理 • メモリリーク、メモリ破壊が起こらない • 洗練されたC#言語仕様 バイオハザード7のコードメトリクス
  55. 55. 新スクリプトアーキテクチャの課題 • 実行速度がC++より遅い • ネイティブコードとのマーシャルコスト • 例外等の厳密なハンドリング • ガベージコレクションによる停止時間 • 全スレッドが不定期に長時間停止(StopTheWorld) • コンソールゲーム機との互換性が低い • JITコンパイル禁止、ロンチハードへの対応リスク
  56. 56. RE ENGINEのソリューション • 独自の仮想マシン(REVM)を開発 • 独自のガベージコレクションを実装
  57. 57. 独自の仮想マシンREVMを開発 • AOTコンパイル前提の設計 • JITコンパイルはサポートしない • C++言語との高い親和性 • マーシャルコストの大幅な削減 • コンパクトな標準ライブラリ • Core FXから、必要最小限の機能をインポート • MITライセンス
  58. 58. AOTコンパイル前提の設計 • C#コードをILに変換しAOTコンパイル • ジェネリクスなどを事前に展開し静的にリンク • 開発時 • 型情報とマイクロコードを出力 • リリース時 • 型情報とC++コードを出力 CSC AOTコンパイラ MicroCode C++ Develop Release application.dll mscorlib.dll runtime.dll
  59. 59. 開発時 • イテレーション速度を優先 • ILを独自のマイクロコードに変換 • ILはインタプリタ実行に適さないため • マイクロコードをインタプリタで実行 • ホットパッチに対応 • 再起動なしにリアルタイムにコード変更を反映 IL MicroCode
  60. 60. リリース時 • 実行パフォーマンスを優先 • ILをC++コードに変換(IL2CPP) • C++のランタイムコードと静的リンク • マーシャルコードは全てインライン展開 • ランタイムのビルドが必要 • 分散ビルドして~15分程度 IL C++
  61. 61. C++言語との高い親和性(1/4) • マネージドオブジェクト • C++/C#でインスタンスモデルを統合 • C#のオブジェクトは全てマネージドオブジェクト • C++で定義されたクラスをC#で継承可能 • 参照カウンタ(RC)でインスタンスの寿命を管理 マーシャルコストなしで双方向にやり取りできる VTable RC Flags C++ Fields C# Fields ManagedObject
  62. 62. C++言語との高い親和性(2/4) • 自動的なC++クラスのC#への公開 • ClangでC++のソースコードを解析 • マネージドオブジェクト継承クラスをC#に公開 • シングルトンクラスをStaticクラスとしてC#に公開
  63. 63. C++言語との高い親和性(3/4) • C++からC#メソッド呼び出し • C++のTemplateを活用し静的に解決 関数ポインタ呼び出しと同等のコスト • 変換コードは全てインライン展開される
  64. 64. C++言語との高い親和性(4/4) • C#からC++メソッド呼び出し • IL2CPP用とインタプリタ用の2段マーシャルコード C++メソッドを直接呼び出すのと同等コスト • IL2CPP時のマーシャルコードはインライン展開される IL2CPP Interpreter
  65. 65. REVMのパフォーマンス(1/2) 0 200 400 600 800 1000 1200 1400 Ackermann's Function ArrayAccess Fibonacci Numbers List Operations Method Calls Object Instantiation String Concatenation N-Body C#(REVM+NoException) C#(REVM) C++ The Great Win32 Computer Language Shootout (PS4) • C++コードとC#コードの速度比較 (ms)
  66. 66. REVMのパフォーマンス(2/2) • 開発時(インタプリタ)とリリース時(IL2CPP)の比較 1.53 1.69 3.85 4.77 0 2 4 6 BehaviorUpdate BehaviorLateUpdate Develop Release Release(PS4) 16.36ms Develop(PS4) 22.11ms
  67. 67. 独自のガベージコレクションを実装 • 既存のガベージコレクタはゲームに適さない • 世代別GC方式 • メジャーGCによる不定期な長時間の停止 • コンカレントGC方式 • GC実行中の速度低下、メモリに十分な空きが必要 • 自動参照カウント方式 • 循環参照リーク、カウンタ操作の高いオーバーヘッド • ゲーム用途に適したリアルタイムGCを実装 • FrameGC方式
  68. 68. FrameGC方式 • ゲーム用途に限定したアルゴリズム • メインループによる定期的な同期ポイントが必要 • C#コードはスクリプトとしての利用が前提 • 特徴 • 予測と制御可能な停止時間 • 即時解放性 • メモリを限界近くまで利用可能 • マルチコアでの高いパフォーマンス • C++言語との高い親和性 • アルゴリズムの詳細 • 付録の解説と疑似コードを参照
  69. 69. FrameGCの流れ C++Method C#MethodStack LocalTable C#Method C#Method RC(-1) RC(-2) RC(-3) RC(-4) RC(-5) LocalFrameGC C++Method C#MethodStack LocalTable RC(-1) RC(-2) C#Method Thread1 Thread2 RC(-6) LocalGC RC(-3) RC(1) RC(1) GlobalTable RC(1) RC(1) RC(1) LocalFrameGC GlobalFrameGC RC(0) RC(0) RC(0)
  70. 70. FrameGCの要点 • 参照カウンタの利点を活かす • 負荷がオブジェクト数に依存しない • 不要なオブジェクトは即座に解放できる • C++言語との高い親和性 • 参照カウンタの欠点を解消する • 参照カウンタで管理するオブジェクト数を減らす • オブジェクトを所属スレッドからのみ参照可能なローカルと、全スレッドから参照 可能なグローバルに分け、グローバルオブジェクトのみを参照カウンタ管理 • 参照カウンタ操作を減らす • グローバルオブジェクトへの書き込み時のみカウンタを操作 • 循環参照ゴミを効率的に回収する • 循環参照する可能性のある型とフィールドのみを対象にインクリメンタルに処理
  71. 71. FrameGCの最適化 • ローカルフレームGCの高速化が重要 • C++からC#メソッド呼び出し毎に最も高頻度で発生する • ローカルヒープの導入 • スレッド毎に4KBのヒープ領域を保持 • 小さなローカルオブジェクトはローカルヒープから割り当て • 確保時はポインタをインクリメント • 解放時はポインタをリセット • スタック割り当てに近い速度 LocalHeap 4KB Local A Local B Local C Local DGlobal B Local A
  72. 72. FrameGCの動作
  73. 73. FrameGCのパフォーマンス • 探索/戦闘シーンの1フレームのプロファイル 探索シーン 戦闘シーン C++>C#メソッドコール 2063 2093 ローカルオブジェクト生成 2457 5085 グローバルオブジェクト生成 5 14 ローカル>グローバル変換 55 330 グローバルテーブル登録 49 300 サイクルテーブル登録 4 18 ローカルフレームGC 1018 1143 ローカルGC 0 0 グローバルフレームGC 4 8 ローカルフィールドストア 5039 6714 グローバルフィールドストア 1059 2385 ローカルフレームGC時間(ms) ※ 0.116 0.174 グローバルフレームGC時間(ms) 0.042 0.166 サイクルGC時間(ms) 0.013 0.037 PS4※ローカルフレームGC時間はマルチコアで並列に実行されるので実際は数倍高速
  74. 74. まとめ • C#は素晴らしい! • プログラマの生産性を大きく向上させる • アプリケーションによるストップバグが発生しない • パフォーマンスの問題はない • REVMは下手なC++コードよりも高速に動作する • FrameGCはゲームにGCは向かないという常識を変える
  75. 75. ご清聴ありがとうございました • ご質問は?
  76. 76. 付録 • FrameGCアルゴリズム解説 • FrameGCアルゴリズム疑似コード
  77. 77. FrameGCアルゴリズム(1/7) • ローカルオブジェクト • 生成されたスレッドからのみ参照可能なオブジェクト • スレッド毎にローカルテーブルに登録される • 参照カウンタ(RC)は負でローカルテーブルのインデックスを指す • C#から生成したオブジェクトは全てローカルオブジェクトになる LocalTable RC(-1) RC(-2) RC(-3) RC(-4) RC(-5)
  78. 78. FrameGCアルゴリズム(2/7) • グローバルオブジェクト • 全てのスレッドから参照可能なオブジェクト • 参照カウンタ(RC)は正でオブジェクトの参照数を表す • C++から生成したオブジェクトは全てグローバルオブジェクトになる RC(1) RC(1) RC(1) RC(2) RC(2)
  79. 79. FrameGCアルゴリズム(3/7) • ローカル>グローバル変換 • 全スレッドから参照可能になる時に変換 • 静的フィールドにストア時 • グローバルオブジェクトのフィールドにストア時 • ローカルテーブルから消去されRCは1になる • 参照先も全てグローバルに変換する LocalTable RC(-1) RC(-2) RC(-3) RC(-4) RC(-5) RC(1) RC(-2)
  80. 80. FrameGCアルゴリズム(4/7) • ローカルフレームGC • 対象スレッドのC#スタックが無くなったとき • 全てのローカルテーブルのオブジェクトを解放 • 非常に高速かつ最も高頻度に起こるGC C++Method C#MethodStack LocalTable C#Method C#Method RC(-1) RC(-2) RC(-3) RC(-4) RC(-5) LocalFrameGCThread
  81. 81. FrameGCアルゴリズム(5/7) • ローカルGC • ローカルテーブルが一杯になったとき • スタックから参照されないローカルオブジェクトを解放 • 対象スレッドのスタックからローカルオブジェクトを保守的に検索 • アドレスがローカルテーブルに存在するかで判定 • 参照される全てのローカルオブジェクトを再帰的にスワップ • 参照されないローカルオブジェクトを解放 C++Method C#MethodStack LocalTable C#Method RC(-1) RC(-2) RC(-3) RC(-4) RC(-5) Thread RC(-5)RC(-1) RC(-2) RC(-4)RC(-2)
  82. 82. FrameGCアルゴリズム(6/7) • グローバルオブジェクト解放 • 参照カウンタが0になった時 • いずれかのスレッドにC#スタックが存在する • 参照カウンタをインクリメントし、グローバルテーブルに登録 • 全スレッドにC#スタックが存在しない • 即座に解放 • 全スレッドのC#スタックが無くなったとき グローバルフレームGC • 全てのグローバルテーブルのオブジェクトを解放
  83. 83. FrameGCアルゴリズム(7/7) • 循環参照する型のグローバルオブジェクト • 自身のフィールド内から自身へ到達可能性がある場合 • 参照カウンタデクリメント時 • 参照カウンタが1以上の時 • サイクルルートに登録 • 参照カウンタが0の時 • サイクルルートから消去 • 通常のグローバルオブジェクト解放処理 • 毎フレーム インクリメンタルサイクルGC • サイクルルートを一定数スキャンし循環参照を検出 ClassA ClassA FieldA ClassB String FieldA String FieldB 循環する 循環しない
  84. 84. インクリメンタルサイクルGC(1/5) • グローバルオブジェクトは参照カウンタ • 循環参照を解放できない • 参照カウンタデクリメント時にサイクルルートに登録 • 循環する可能性のある型のみ • 毎フレーム、サイクルルートをスキャンして循環参照を検出 RC(1) RC(1)RC(1) RC(1) RC(1) RC(2) CycleRoot RC(1) RC(1) CycleGarbage String RC(1) 循環参照しない
  85. 85. インクリメンタルサイクルGC(2/5) • トレースサイクル • サイクルルートからオブジェクトを取り出す • 循環する可能性のある参照を再帰的にトレース • トレース済みのオブジェクトのRCは負で、トレーステーブ ルのインデックスを示す • MCに直前のRCの値を入れる • TCをトレース毎にインクリメント RC(1) RC(1)RC(1) RC(1) RC(1) RC(2) CycleRoot RC(1) RC(1) 1 0 1 1 1 1 1 1 2 1 1 0 RC(-1) RC(-1) RC(-2) RC(-2) RC(-3) RC(-3) RC(-4) RC(-4) 1 RC(-5) RC(-5) TraceTable RC(-6) RC(-6) 2 MC TC String RC(1)
  86. 86. インクリメンタルサイクルGC(3/5) • スキャンサバイバー • MCとTCが一致しないオブジェクトを見つける • 見つけたオブジェクトをルートとしてRCを再帰的 に元に戻す(MCで上書き) RC(1) RC(1)RC(1) RC(1) RC(1) RC(2) 1 0 1 1 1 1 1 1 2 2 1 0 RC(-1) RC(-1) RC(-2) RC(-2) RC(-3) RC(-3) RC(-4) RC(-4) 1 RC(-5) RC(-5) TraceTable RC(-6) RC(-6) MC TC String RC(1)
  87. 87. インクリメンタルサイクルGC(4/5) • コレクトサイクル • トレーステーブル内のオブジェクトの参照先を解放 • トレーステーブル内のオブジェクトを解放 RC(1) RC(2) 1 0 1 1 1 1 1 1 RC(-1) RC(-1) RC(-2) RC(-2) RC(-3) RC(-3) RC(-4) RC(-4) 1 TraceTable MC TC String RC(1) RC(1)
  88. 88. インクリメンタルサイクルGC(5/5) • トレースサイクルのインクリメンタル化 • トレース数が閾値を超えた場合、トレースを中断 • 中断時のオブジェクトを、サイクルルートに再登録 • 閾値で1フレームの最大負荷を調整 注)閾値を超える深さの循環参照は解放できない • フルサイクルコレクション • サイクルルートが溢れた場合には、閾値なしの完全なト レースを行う RC(-1) RC(-2) RC(-3) RC(-4) TraceTableCycleRoot RC(1) RC(2) Threshold RC(1)
  89. 89. FrameGCのオーバーヘッド • ライトバリア • 参照型のフィールドストア時にストア先がローカル(RCが負)かを判定 • グローバルならAtomicな参照カウンタ操作を伴う • ローカル>グローバル変換 • 参照するローカルオブジェクトもグローバル化 Local to GlobalWrite Barrier
  90. 90. FrameGCアルゴリズム疑似コード • スレッドローカル変数 • LocalTable • LocalCount • LocalFrame • グローバル変数 • GlobalTable • GlobalCount • GlobalFrame • CycleRootTable • CycleRootCount ※グローバル変数へのlockは省略
  91. 91. インスタンス作成 Create(S) LocalCount >= MaxLocalCount LocalGC() RC(S) = -LocalCount LocalTable[LocalCount++] = S
  92. 92. 参照カウンタ操作 AddRef(S) RC(S) < 0 ToGlobal(S) else InterlockedIncrement(RC(S)) Release(S) RC(S) >= 0 IsCycleType(S) ToCycleRoot(S) else InterlockedDecrement(RC(S)) == 0 ToLocal(S)
  93. 93. ローカル/グローバル変換 ToGlobal(S) L = LocalTable[--LocalCount] RC(L) = RC(S) LocalTable[-RC(S)] = L RC(S) = 1 for T in children(S) AddRef(T) ToLocal(S) GlobalFrame > 0 AddRef(S) GlobalTable[GlobalCount++] = S else for T in children(S) Release(T) Free(S)
  94. 94. サイクルルート登録 ToCycleRoot(S) InterlockedDecrement(RC(S)) == 0 CycleRootIndex(S) > 0 RemoeCycleRoot(S) ToLocal(S) else CycleRootIndex(S) == 0 CycleRootIndex(S) = CycleRootCount CycleRootTable[CycleRootCount++] = S RemoveCycleRoot(S) L = CycleRootTable[--CycleRootCount] CycleRootIndex(L) = CycleRootIndex(S) CycleRootIndex(S) = 0 CycleRootTable[CycleRootIndex(L)] = L
  95. 95. 参照型フィールドストア StoreField(T,F,S) RC(T) < 0 T.F = S else AddRef(S) P = T.F while InterlockedCAS(T.F,S,P) != P P = T.F Release(P) StoreStaticField(F,S) AddRef(S) P = F while InterlockedCAS(F,S,P) != P P = F Release(P)
  96. 96. C++>C#メソッド呼び出し Invoke(M) ++LocalFrame == 1 ++GlobalFrame M() --LocalFrame == 0 LocalFrameGC() --GlobalFrame == 0 GlobalFrameGC()
  97. 97. ローカルフレームGC LocalFrameGC() while LocalCount > 1 Free(LocalTable[--LocalCount])
  98. 98. グローバルフレームGC GlobalFrameGC() while GlobalCount > 0 Release(GlobalTable[--GlobalCount])
  99. 99. ローカルGC LocalGC() ScanPoint = 1 for Address in Stack IsValidAddress(Address) T = Address RC(T) < 0 && -RC(T) < LocalCount && LocalTable[-RC(T)] == T ScanLocal(T) while LocalCount > ScanPoint Free(LocalTable[--LocalCount]) ScanLocal(S) -RC(S) >= ScanPoint L = LocalTable[ScanPoint] L != S RC(L) = RC(S) RC(S) = -ScanPoint LocalTable[-RC(S)] = S LocalTable[-RC(L)] = L ScanPoint++ for T in children(S) ScanLocal(T)
  100. 100. サイクルコレクション CycleGC() TraceCount = 1 while CycleRootCount > 1 L = CycleRootTable[--CycleRootCount] CycleRootIndex(L) = 0 TraceCycle(L) for TB in TraceTable TB.MC != TB.TC ScanSurvivor(TB.Ref) CollectCycle()
  101. 101. トレースサイクル TraceCycle(S) RC(S) >= 0 CycleRootIndex(S) > 0 RemoveCycleRoot(S) TraceTable[TraceCount].Ref = S TraceTable[TraceCount].MC = RC(S) TraceTable[TraceCount].TC = 0 RC(S) = -TraceCount TraceCount++ for T in children(S) IsCycleType(T) TraceCycle(T) RC(T) < 0 TraceTable[-RC(T)].TC++
  102. 102. スキャンサバイバー ScanSurvivor(S) RC(S) < 0 RC(S) = TraceTable[-RC(S)].MC for T in children(S) ScanSurvivor(T)
  103. 103. コレクトサイクル CollectCycle() for TB in TraceTable RC(TB.Ref) < 0 for T in children(TB.Ref) Release(T) for TB in TraceTable RC(TB.Ref) < 0 Free(TB.Ref)

    Be the first to comment

    Login to see the comments

  • nezuku

    Apr. 24, 2017
  • neredy

    May. 3, 2017
  • ssuserf5384a

    May. 11, 2017
  • ShunMoriya

    May. 15, 2017
  • keisukedate

    May. 30, 2017
  • SenrozoiAC

    Jul. 2, 2017
  • HirotakaKodani

    Sep. 1, 2017
  • takutoitami

    Sep. 19, 2017
  • HiroshiJouichi

    Dec. 26, 2017
  • yorung

    Jan. 21, 2018
  • leaveszj

    Dec. 25, 2018
  • JinTakenaka

    Sep. 24, 2019
  • junichikamai

    Sep. 27, 2019
  • hiyono_y

    Sep. 27, 2019
  • wlkyos

    Sep. 29, 2019
  • sneakSH

    Nov. 20, 2019
  • ChiHoHung

    Mar. 17, 2020
  • YutakaOwada

    Jul. 19, 2020
  • sogajapan

    Feb. 26, 2021
  • koshiusami

    May. 6, 2021

Architecture of RE ENGINE. First presented at Game Creators Conference 2017. http://gc-conf.com/event_2017/ Download the .pptx file to watch embedded movies and animations.

Views

Total views

39,666

On Slideshare

0

From embeds

0

Number of embeds

10,726

Actions

Downloads

251

Shares

0

Comments

0

Likes

86

×