1. Burst Compiler
https://docs.unity3d.com/Packages/com.unity.burst@1.8/manual/index.html
About Burst | Burst | 1.8.2
docs.unity3d.com
이번에는 Burst Compiler에 대해 조금 더 찾아봤습니다.
유니티에서 소개하는 내용으로는 단점은 전혀 나오지 않아서 어떨 때 써야 하는지 명확하지 않아 좀 더 들여다보기로 했습니다.
https://ko.wikipedia.org/wiki/SIMD
SIMD - 위키백과, 우리 모두의 백과사전
위키백과, 우리 모두의 백과사전.
ko.wikipedia.org
Burst Compiler는 C#코드를 SIMD방식으로 바꾸어 Native코드로 만들어주는 컴파일러입니다.
찾아보니 SIMD의 단점은 코드가 어려워지는 것이 있는데, Burst Compiler가 자동으로 코드를 변환해 주어서 이 단점이 해소된 것으로 보이네요.
[BurstCompile(FloatPrecision.Med, FloatMode.Fast)]
BurstComplie Attribute에는 FloatPercision, FloatMode 타입을 넣을 수 있도록 되어있습니다.
https://docs.unity3d.com/Packages/com.unity.burst@1.8/manual/compilation-burstcompile.html
BurstCompile attribute | Burst | 1.8.2
BurstCompile attribute To improve the performance of Burst, you can change how it behaves when it compiles a job with the [BurstCompile] attribute. Use it do the following: Use a different accuracy for math functions (for example, sin, cos). Relax the orde
docs.unity3d.com
아마도 Burst Compiler를 통해 코드가 만들어지면서 계산을 빠르게 하는 대신 부동소수점 정확도가 떨어지는 것 같습니다.
아마도 대부분 프로젝트에서 부동소수점 계산을 사용하게 될텐데, 정확도가 필요한 경우 Burst Compiler를 사용하지 않거나 위 옵션을 사용하라고 만들어둔 것 같습니다.
https://docs.unity3d.com/Packages/com.unity.burst@1.8/manual/aliasing.html
Memory aliasing | Burst | 1.8.2
Memory aliasing Memory aliasing is a way to tell Burst how your code uses data. This can improve and optimize the performance of your application. Memory aliasing happens when locations in the memory overlap each other. The following documentation outlines
docs.unity3d.com
https://blog.unity.com/kr/technology/enhanced-aliasing-with-burst
버스트 컴파일러로 앨리어싱 개선 | Unity Blog
이 블로그 포스팅에서는 앨리어싱의 개념, 데이터 구조의 메모리가 앨리어싱되는 방법을 설명하기 위한 [NoAlias] 속성 사용 방법, 유니티의 새로운 앨리어싱 컴파일러 내장 함수를 사용하여 컴파
blog.unity.com
Memory Alias 문제가 있다고 하는데 자세한 내용은 위 링크 보시면 될 것 같습니다.
NativeContainer들은 주의해서 사용해야할 것 같습니다.
[BurstCompile]
public partial struct ProcessMovableJob : IJobEntity
{
private void Execute(ref LocalTransform transform, in MovableComponent movable)
{
// ...
}
}
적용은 BurstCompile Attribute만 추가하면 됩니다.
정말 쉽습니다.
Burst Inspector로 변환된 코드를 확인 가능한데, 어셈블리는 하나도 몰라서 봐도 알 수가 없네요.
기회가 된다면 어셈블리를 간단하게 찍먹이라도 해보면 보일까 모르겠네요.
2. Execution Order
유니티의 MonoBehaviour는 위 옵션에서 Execution Order를 조절할 수 있는데, ECS의 System도 가능하지 않을까 해서 찾아봤습니다.
[CreateAfter(typeof(ShootableSystem))]
[CreateBefore(typeof(ShootableSystem))]
[UpdateAfter(typeof(ShootableSystem))]
[UpdateBefore(typeof(ShootableSystem))]
public partial struct BulletSystem : ISystem
CreateAfter, CreateBefore, UpdateAfter, UpdateBefore Attribte로 Execution Order와 비슷하게 사용할 수 있습니다.
순서를 한 눈에 볼 수 없어서 프로젝트 규모가 커졌을 때 조금 걱정되긴 하네요.
[UpdateBefore(typeof(ShootableSystem))]
public class BulletSystemGroup : ComponentSystemGroup { }
[UpdateInGroup(typeof(BulletSystemGroup))]
public partial struct BulletSystem : ISystem
위 코드처럼 ComponentSystemGroup으로 묶어서 관리도 가능합니다.
3. 코드개선
Burst Compiler를 추가하고 입력, 실행으로 System을 구분해서 순서를 정해서 실행하도록 수정했습니다.
public partial struct InputEnemyControlMovableJob : IJobEntity
{
public NativeReference<Unity.Mathematics.Random> random;
public double elapsedTime;
private void Execute(ref MovableComponent movable, ref InputEnemyControlComponent inputEnemyCtrl)
{
if (inputEnemyCtrl.nextMovableUpdateTime > elapsedTime)
return;
movable.moveDir = Quaternion.Euler(0f, random.Value.NextFloat(360f), 0f) * Vector3.forward;
inputEnemyCtrl.nextMovableUpdateTime = elapsedTime + random.Value.NextFloat(0.5f, 2.0f);
}
}
InvalidOperationException: InputEnemyControlMovableJob.JobData.random is not declared [ReadOnly] in a IJobParallelFor job. The container does not support parallel writing. Please use a more suitable container type.
Job 내부에서 랜덤 하게 적을 움직이도록 하는 코드인데 에러가 났는데, ReadOnly, WriteOnly를 나눠보기도 하고 해결 방법이 보이지 않아서 아래처럼 코드를 수정했습니다.
public partial struct InputEnemyControlMovableJob : IJobEntity
{
public double elapsedTime;
private void Execute(ref MovableComponent movable, ref InputEnemyControlComponent inputEnemyCtrl)
{
if (inputEnemyCtrl.nextMovableUpdateTime > elapsedTime)
return;
var random = inputEnemyCtrl.random;
movable.moveDir = Quaternion.Euler(0f, random.NextFloat(360f), 0f) * Vector3.forward;
inputEnemyCtrl.nextMovableUpdateTime = elapsedTime + random.NextFloat(0.5f, 2.0f);
inputEnemyCtrl.random = random;
}
}
Entity마다 Random을 가지고있도록해서 해결했습니다.
이게 더 DOTS에 맞는 코드 같네요.
'Study Log' 카테고리의 다른 글
Unity ECS Study Log - 8 (0) | 2023.01.24 |
---|---|
Unity ECS Study Log - 7 (0) | 2023.01.21 |
Unity ECS Study Log - 5 (0) | 2023.01.14 |
Unity ECS Study Log - 4 (0) | 2023.01.09 |
Unity ECS Study Log - 3 (1) | 2023.01.07 |