Unity 검색

Burst 1.5와 함께 도약하는 2021년

2021년 4월 14일 엔진 & 플랫폼 | 5 분 소요
Screenshot of gameplay
Screenshot of gameplay
다루는 주제
공유

Is this article helpful for you?

Thank you for your feedback!

유니티의 HPC#(High Performance C#) 컴파일러 기술인 Burst는 끊임없이 개선되고 있습니다. 이번 포스팅에서는 최신 버전인 Burst 1.5에 담긴 주요 개선 사항을 소개하려 합니다. 개발자가 프로젝트에서 Burst를 최대한 활용할 수 있도록 주요 기능을 설명하고 해당 기능의 이점에 대해 살펴보겠습니다.

Arm Neon 하드웨어 내장 함수

유니티는 협력사 Arm과의 협업으로 Burst 1.5에 Arm Neon 하드웨어 내장 함수를 추가했습니다. 추가된 내장 함수를 사용하면 놀라운 벡터 기술인 Neon을 포함하여 Arm 플랫폼의 특정 하드웨어 명령을 타겟으로 지정할 수 있습니다.

Arm Neon 내장 함수는 Burst 1.4에서 실험 기능으로 처음 도입되었으며, 이제 Burst 1.5에서 완전히 지원됩니다.

버스트는 현재 모든 Armv8-A 내장 함수를 포함하며, Burst 1.5에서 실험 기능으로 포함된 Armv8.1-RDMA와 Armv8.2-DotProd, Armv8.2-Crypto 내장 함수는 다음 버스트 버전에서 완벽하게 지원될 예정입니다.

Arm Neon 내장 함수는 v64 유형을 비롯하여 인텔 내장 함수로 익숙한 v128 유형도 사용합니다. 두 유형은 각각 128비트 또는 64비트로 구성됩니다. 벡터 요소 유형과 수를 확인하고 올바르게 활용하는 것은 사용자의 몫입니다. 이러한 벡터는 CPU에 있는 실제 SIMD 레지스터의 표현이라 할 수 있습니다.

다음은 간단한 사용 예시입니다.

IsNeonSupported 값은 대상 CPU를 기반으로 컴파일 시간에 평가되므로 런타임 성능에 영향을 주지 않습니다. Arm 및 인텔 대상 CPU에 여러 내장 함수를 구현하려면 IIsXXXSupported 블록을 코드에 추가해야 합니다.

Neon 내장 함수는 Armv8-A 하드웨어(64비트)에서만 지원된다는 점에 주의하세요. Armv7-A(32비트)에서 IsNeonSupported는 항상 false입니다. 이전 32비트 Arm 기기를 대상으로 하는 경우에도 버스트를 활용하면 Neon 내장 함수를 직접 사용하지 않고도 관리되는 코드를 자동으로 최적화할 수 있습니다.

Arm 내장 함수와 Neon 내장 함수에 관한 자세한 내용은 후속 블로그 포스팅에서 다룰 예정입니다.

하드웨어 내장 함수는 컴파일러에서 절대적인 최대의 성능을 활용하고, 코드를 미세 조정하여 조금 더 CPU 사이클을 압축하고자 하는 고급 사용자를 대상으로 합니다. 하드웨어 내장 함수를 사용해 보셨다면 피드백을 보내주세요.

Direct Call

Direct Call은 Burst 1.5의 대표적인 최신 기능입니다. 유니티는 버스트에서 HPC# 컴파일러를 사용하여 Unity 잡 시스템에서 실행되는 작업을 가속화하는데 먼저 중점을 두었습니다. 그런 다음 함수 포인터를 추가하여 사용자가 거의 모든 위치에서 버스트 코드의 비트를 관리하고 호출할 수 있도록 하였습니다.

위 코드는 버스트를 통해 실행됩니다. Direct Call 메서드는 메인 스레드에서 호출되는 경우에만 위와 같이 작동한다는 점에 주의하세요.

새로운 최적화 기능의 강력한 성능

최적화 성능을 더 강화하기 위해 새롭고 흥미로운 기능들이 Burst 1.5에 추가되었습니다.

Hint.Likely, Hint.Unlikely, Hint.Assume

어떤 일이 발생하거나 발생하지 않을 가능성을 컴파일러에 알리기 위한 내장 함수의 필요성이 지속적으로 제기되었습니다. 따라서 Burst 1.5에 Unity.Burst.CompilerServices에 Likely와 Unlikely라는 새로운 두 가지 내장 함수가 추가되었습니다.

두 내장 함수는 특정 부울 조건(예: "if" 브랜치의 조건)에 도달할 가능성이 있는지 여부를 컴파일러에 알립니다. 컴파일러는 이를 통해 결과 코드를 최적화할 수 있습니다.

Assume 내장 함수도 추가되었습니다.

이 내장 함수는 항상 발생하는 특정 추세를 컴파일러에 알립니다. 예를 들면, Assume을 활용하여 포인터는 절대 null이 아니고, 인덱스는 절대 음수가 아니며, 값은 절대 NaN이 아니라는 사실을 컴파일러에 전달할 수 있습니다. 다만 컴파일러는 Assume의 조건식이 실제로 유효한지 확인하지 않으므로, 가정이 사실인지 사용자가 반드시 확인해야 합니다.

IsConstantExpression

또한 식이 컴파일 시 상수 식으로 표현되는지 여부를 쿼리하는 내장 함수가 추가되었습니다.

위와 같이 이 쿼리를 사용하면 어떤 값이 상수인지 확인할 수 있습니다. 그 외에도 이 쿼리는 특정 값이 결코 NaN이나 null이 아닌 경우와 같이 더 빠른 경로를 가진 알고리즘에도 사용될 수 있습니다.

[SkipLocalsInit]

C#에서는 모든 로컬 변수가 기본적으로 0으로 초기화됩니다. 개발자가 0 초기화 과정을 건너뛰려는 경우도 있으므로 [SkipLocalsInit] 속성이 추가되었습니다. 제로 초기화를 하지 않으려는 함수가 있을 경우 이 속성을 적용하기만 하면 됩니다. 이는 .NET 5의 SkipLocalsInitAttribute 기능과 동일하지만 버스트에 더 빠르게 적용됩니다.

기타 개선 사항

다음은 1.5의 소소하지만 효과적인 개선 사항을 순서 없이 나열한 것입니다.

  • 이제 버스트 코드 내에서 ValueTuple 구조(int, float)를 지원합니다. 단, 유형이 엔트리 포인트의 경계를 벗어나면 안 됩니다. 예를 들어 잡 구조체에 저장하거나 함수 포인터에서 반환할 수는 없습니다.

  • Bmi1 및 Bmi2 x86이 기본 클래스로 Burst 1.5에 추가되었고, 이제 AVX2 지원과 함께 이용할 수 있게 되었습니다. AVX2를 지원하는 CPU라면 이제 코드에서 직접 비트 조작 명령을 사용할 수 있습니다.

  • Unity 2020.2 이상 버전에서는 버스트 코드에서 new ProfilerMarker(“MarkerName”)를 호출할 수 있습니다.

  • 플레이어 빌드에서만 한정적으로 버스트 경고 BC1370을 다시 활성화했습니다. 이 경고는 [Conditional(“ENABLE_UNITY_COLLECTIONS_CHECKS”)](플레이어 빌드에서 지원하지 않음)로 보호되지 않는 함수에서 throws가 나타나는 위치를 알려줍니다.

  • LLVM 11을 기본 코드 생성기로 사용하며, 관련된 수많은 성능 개선과 stackalloc 호이스팅, 무한 루프 제거, 컴파일 시간 개선 등의 최적화가 이루어졌습니다.

Unity 2018.4를 지원하는 마지막 버전

Burst 1.5는 Unity 2018.4를 지원하는 마지막 버전입니다. 다음 버전부터는 최소 Unity 2019.4 이상을 지원합니다.

Burst 시작하기

유니티 기술 스택의 핵심인 Burst를 지금 바로 사용해 보세요. Burst는 안정적이고 검증된 패키지로, 이미 수천 개의 프로젝트에서 사용되고 있으며 그 수가 점점 늘어나고 있습니다. 유니티의 DOTS 기술 스택은 버스트를 활용하여 고도로 최적화된 코드를 제공합니다. 버스트는 또한 DOTS 없이도 스탠드얼론 패키지로 사용할 수 있습니다.

모든 주요 데스크톱과 콘솔, 모바일 플랫폼을 지원하며 Unity 2018.4 이상에서 작동합니다.

버스트에 관한 의견이나 질문, 버스트를 활용하여 진행 중인 작업에 관한 이야기를 Burst 포럼에 남겨주세요.

 

2021년 4월 14일 엔진 & 플랫폼 | 5 분 소요

Is this article helpful for you?

Thank you for your feedback!

다루는 주제
관련 게시물