754 Views
April 23, 18
スライド概要
Unite Tokyo 2018 Training Day「C#JobSystem & ECSでCPUを極限まで使い倒そう ~Entity Component System 編~」の資料です。
講師:大西 康満(ディベロッパーリレーションマネージャー・エンジニア|ユニティ・テクノロジーズ・ジャパン合同会社)
※【Unite Tokyo 2018 Training Day】C#JobSystem & ECSでCPUを極限まで使い倒そう ~C# JobSystem 編~ の資料はこちら
https://www.slideshare.net/UnityTechnologiesJapan/cjobsystem-ecscpu
■ワークショップ内容
C# Job System、ECS(Entity Component System)がUnity2018で使えるようになりました。
C# Job SystemはUnityのシステムと親和性が高く、安全なマルチスレッドプログラミングを容易にする新機能です。ECSは非常に高速な、新しいオブジェクトの管理システムです。この二つを組み合わせて、CPUのパワーを非常に効率よく利用することができます。
※このセッションは、受講者がUnity上での基本的なC#プログラミング・マルチスレッドプログラミングに関する基本的な知識を持っている前提で行います。
※ECSは現在ベータ段階で今後も調整、変更が重ねられる予定です。
リアルタイム3Dコンテンツを制作・運用するための世界的にリードするプラットフォームである「Unity」の日本国内における販売、サポート、コミュニティ活動、研究開発、教育支援を行っています。ゲーム開発者からアーティスト、建築家、自動車デザイナー、映画製作者など、さまざまなクリエイターがUnityを使い想像力を発揮しています。
Entity Component System Yasumichi Onishi Unity Developer Relations Manager/ Engineer
大西 康満 Unity / Developer Relations Engineer 株式会社バンダイナムコスタジオにエンジニアとして 18年在籍した後、5年ほどUnityを使ったモバイルゲー ム開発に注力。2016にユニティ・テクノロジーズ・ジャパ ン合同会社に入社、ディベロッパーリレーションマネー ジャー・エンジニア(DRM/E)として活動中。過去の作品 は『Pac-Man C.E.』、『鉄拳』、『エースコンバット』など。
5〜32倍
• Mono x GameObject 比のスピード向上率 (ECS x JobSystem x Burstコンパイラ) 5〜32倍
ECSとは
記号(色の意味) • ユーザーがする操作 • 対応するUnityの現機能を「言うなれば」で書くとき • Unityエンジンが自動でやること
ECSスタイル • ECSスタイルでコードを書く • GameObject列の処理速度アップ
背景 (近年の計算機の特徴) • Memory Cache機構 • core数、スレッド数の増加 • ベクトル演算器の搭載
背景 (近年の計算機の特徴) • Memory Cache機構 • タイトなメモリレイアウトになるようコントロールしたい • core数、スレッド数の増加 • マルチスレッド処理したい • ベクトル演算器の搭載 • Vectorizationしたい
背景 (近年の計算機の特徴) • Memory Cache機構 • タイトなメモリレイアウトになるようコントロールしたい • core数、スレッド数の増加 • マルチスレッド処理したい • ベクトル演算器の搭載 • Vectorizationしたい • C#で普通にClassをInstanceするとメモリ空間のあちこちにAllocされる • Instanceへの参照列をIterateするとCache効率が悪い • GameObject/ MonoBehaviourスタイルも例外ではない
C#でも • Structの配列ならメモリ配置は連続になる • Structの各メンバの配列の形式にして、かつ処理を局所的(関連メンバを絞る)にすれば さらにフェッチ効率は上がる • JobSystemとの相性も良い • Auto Vectorizationが効くケースも増える
ECSスタイル • Structの配列ならメモリ配置は連続になる • Structの各メンバの配列の形式にして、かつ処理を局所的(関連メンバを絞る)にすれば さらにフェッチ効率は上がる • JobSystemとの相性も良い • Auto Vectorizationが効くケースも増える • ↑ECSスタイルの基本的なアイデア
ECSスタイル • Structの配列ならメモリ配置は連続になる • Structの各メンバの配列の形式にして、かつ処理を局所的(関連メンバを絞る)にすれば さらにフェッチ効率は上がる • JobSystemとの相性も良い • Auto Vectorizationが効くケースも増える • ECSスタイルでゲームコードを書くだけで これらを自然と実現できる
ECSとはなんぞや • Entity: 速いGameObject • Component: MonoBehaviourのデータ部分 • System: MonoBehaviourの振る舞い部分 public struct RotationSpeed : Component { public float Speed; } class EnemyAISystem : System { override protected OnUpdate() { float deltaTime = Time.deltaTime; for (各GameObjectに対して) public struct Energy : Component { public int energy; } { //振る舞い } } }
ECSとはなんぞや • Entity: 速いGameObject • Component: MonoBehaviourのデータ部分 • System: MonoBehaviourの振る舞い部分 • Object-orientedスタイル → データと振る舞いを分離する新スタイル
キーとなる機能
Entity(データを複数合わせたもの) var entity = EntityManager.CreateEntity(); //Entityの生成 EntityManager.AddComponent(entity, new MyComponentData1()); //ComponentDataを追加できる EntityManager.AddComponent(entity, new MyComponentData2()); //ComponentDataは複数持てる EntityManager.SetComponent(entity, new MyComponentData2()); //Setもできる ComponentData Entity
データと振る舞いの関係 データ 振る舞い 要求リスト
データと振る舞いの関係 データ 振る舞い 処理される 処理される Inject
データの記述 public struct RotationSpeed : IComponentData { //Dataのみ public float Speed; } • Struct • Blittable型のみで構成 (C++とC#でメモリ上の表現が同じになる型)
振る舞いの記述
class RotatorSystem : ComponentSystem
{
struct Group //要求リスト (全ての型を含むEntityがマッチ)
{
public int Length;
public ComponentDataArray<MyRotation> myrotation;
public ComponentDataArray<RotationSpeed> rotationSpeed;
}
[Inject] private Group m_Data; //マッチング結果のArrayが自動設定される
override protected OnUpdate() //1Fに一回呼ばれる
{
float deltaTime = Time.deltaTime;
for (int i = 0; i < m_Data.Length; ++i) //同じindexで同じEntityのComponentを参照できる
{
}
}
}
m_Data.mytrotation[i].Rotation *= Quaternion.AxisAngle(m_Data.rotationSpeed[i].Speed * deltaTime, Vector3.up);
振る舞いの記述
• マッチング条件を記述
• [Inject]
class RotatorSystem : ComponentSystem
{
struct Group //要求リスト (全ての型を含むEntityがマッチ)
{
public int Length;
public ComponentDataArray<MyRotation> myrotation;
public ComponentDataArray<RotationSpeed> rotationSpeed;
• OnUpdate()でマッチング結果を処理する
• Job化するのが常套手段
}
[Inject] private Group m_Data; //マッチング結果のArrayが自動設定される
override protected OnUpdate() //1Fに一回呼ばれる
{
float deltaTime = Time.deltaTime;
for (int i = 0; i < m_Data.Length; ++i) //同じindexで同じEntityのComponentを参照できる
{
}
}
}
m_Data.mytrotation[i].Rotation *= Quaternion.AxisAngle(m_Data.rotationSpeed[i].Speed * deltaTime, Vector3.up);
メモリレイアウト
EntityArchType • Prefabのようなもの • ComponentDataの組み合わせに他ならない • メモリレイアウトの最適化に利用される
Chunk Memory • Entityのインスタンス実体 • 1Chunk Memoryは L1キャッシュ並の大きさ • 例えばstructのメンバが • A(4bytes), B(2bytes), C(2bytes)のとき • 各Memory Chunkは自分のEntityArchTypeを知っており効率よく配置される
Jobの記述Classと実行順序
振る舞い記述用Class三種() 下の方が固定機能であるが記述量は少ない • ComponentSystem (前述) InjectionされてOnUpdate()が呼ばれる • JobComponentSystem +自動でJob化される • JobProcessComponentData + JobのExecute()の中身を書くだけ
Jobの実行順序 • 内部的に依存関係グラフが管理されている • 各ComponentSystemに着目し、WriteしているJob→ReadのみのJobの順に実行され るよう依存が設定される Write ReadOnly • [ReadOnly]属性を明示的につけないとWrite判定になる • 自分で依存関係を指定することも可能
開発状況
開発状況 • 絶賛開発中 • 2018.1? (2かも) でexperimental (β機能) • https://github.com/Unity-Technologies/EntityComponentSystemSamples • ↑最新状況を知るには当面上記githubが良い • 色々なAPI方式を試しながら更新されている • README.md→DocumentにもAPI仕様が書かれ更新されている • EntityComponentSystemSamples/TwoStickShooter/PureというUnityプロジェ クトの改造から始めるがお勧め • このページから落とせるUnityとセットでないと動かないので注意
開発状況 • 2018 4月時点 • 色々な仕様の組み合わせを試している状況、細かい仕様は高頻度で変わる • Β版でフィードバックを集め中 • 作りやすい仕様を選択していく
開発状況 • 今後GameObjectと似た感覚で操作できるように整備していく • Hierarchy window やInspector windowで表示、編集可能に • Save Scene / Open Scene / Prefabs感覚で使えるように • さらに Geometry操作、Animation機能、Physicsクエリなどを用意していく... • つなぎ期間用 Hybrid 方式 • 既存のMonoBehaviourコードをECSに移植するとき用 • GameObjectと同じEntityがOnEnable時に作れたり • Monobehaviourへのアダプター