Source Control 활성화

Editor Preference

  • Edit -> Editor Preference -> Loading & Saving에서 활성화 가능

Automatically Checkout on Asset Modification

  • 활성화 시 변경된 Asset을 자동으로 Checkout 한다.

Prompt for Checkout on Package Modification

  • 활성화 시 Source Control로 제어되는 Package가 변경될 때 해당 Package를 Checkout 할지 묻는 창을 띄운다.

Add New Files when Modified

  • 새 파일이 추가되면 Source Control에도 추가된다.

Use Global Settings

  • Project 단위가 하닌 Global Source Control Login Setting을 사용한다.
  • 옵션 변경 시 다시 Login 해야 한다.

Tool for Diff'ing text

  • Text File Version비교에 사용할 Tool의 File Directory를 지정한다.

contents Browser

  • Asset/Folder 우클릭 -> Source Control Sesction에 Connect to Source Control 선택

상태 아이콘

Source Control 작업

  • Source Control 활성화 상태에서 Asset 우클릭 시 다음 메뉴를 볼 수 있다.

Check Out

  • Asset을 편집 가능한 상태로 Check out
  • Asset을 다른 사용자가 동시에 편집하지 못하도록 한다.

Refresh

  • Asset의 Source Control 상태를 새로고침 한다.

History

  • 선택된 Asset의 Revision History를 확인하여 기존 수정 내용을 볼 수 있다.

Diff Against Depot

  • 이 Asset을 현재 Source Control Depot에 저장된 Version과 비교할 수 있다.

Check Out/Check In

  • Asset 편집을 위해 Checkout 하기 위해서는 우클릭해서 Check Out을 선택하면 된다.
  • 하지만 Checkin 할 때에는 다음 규칙을 따라야 한다.
    • Asset 우클릭 -> Check In 선택
      • 선택 시 필요한 Changelist 설명을 입력하라는 창이 뜬다.
      • 필수 사항으로, 입력하지 않으면 Ok 버튼이 나타나지 않는다.
    • 설명을 입력하면 Asset의 Revision History에 추가된다.

Contents Hot Reload

  • Source Control 작업에 의해 Contents가 변경되었을 때 Eidtor 내 Source Control에서 Contents를 Reload 해준다.
  • 현재 Editor 내의 통합된 Source Control을 통해 작업을 할 때에만 작동한다.
    • 외부에서 변경했을 때에는 Reload가 발생하지 않는다.
  • Contents Hot Reload는 명령이 있을 때 ASset의 지난 저장 상태에서 Reload 하는 기능도 제공한다.
    • Asset 우클릭 -> Asset Action -> Reload 선택
    • Asset을 저장하지 않는 변경사항을 revert 하고 Disk 버전으로 되돌리고자 할 때 매우 유용하다.

Source Control 비활성화

  1. Level Editor 우상단 구석에 초록생 화살표 아이콘을 클릭해 Source Control Login 창으로 접속한다.
  2. Run Without Source Control 버튼을 클릭해 초록색 아이콘을 클릭한다.
    • 클릭하면 금지 아이콘으로 변경되어 Source Control이 비활성화 된다.

 

'UE5 > Utility' 카테고리의 다른 글

[Basic] Packaging  (0) 2024.05.09
[Programming Tool] LLM(Low-level Memory Tracker)  (0) 2024.05.07
[ProgrammingTool] Sparse Class Data  (0) 2024.05.07

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/packaging-unreal-engine-projects

 

프로젝트 패키징 | 언리얼 엔진 5.4 문서 | Epic Developer Community

언리얼 게임 프로젝트의 배포용 패키지 만들기입니다.

dev.epicgames.com

  • Packaging으로 모든 Code와 Contents가 최신인지, Target Plartform에서 실행하기 적합한 포맷인지 확인한다.
  • File -> Package Project 옵션에서 Package에서 만들 수 있는 대상 Platform 확인 가능

Process

  • Project Source Code를 Compile
  • Cooking
    • 필수 컨텐츠를 Target Platform에서 사용 가능한 Format으로 변환
  • Compile 된 Code와 Cooking된 Contents를 묶어 Windows Installer와 같은 배포 파일 생성
    • Android Packaging은 몇 가지 선택사항이 더 있다.

Game Default Map 설정

  • Packaging을 하려면 Game 시작 시 Load 할 Game Default Map 설정이 필요
    • Default Map이 설정되지 않으면 Packaging 된 Game 시작 시 검은 화면이 나온다.
    • Edit -> Project Setting -> Map & Modes에서 설정

Package 만들기

  • File -> Project Package -> [Platform Name] 선택
  • Target Directory 선택한다.
    • Target Directory를 확인하고 나면 선택된 Platform용으로 Project를 Packaging한다.
  •  Packaging은 매우 오래 걸리는 작업이라 Process가 Background에서 진행된다.
    • 이 때 Editor는 계속 사용할 수 있다.
    • Cancel로 취소 가능
    • Show Log 링크로 자세한 로그 표시 가능
      • Packaging Process가 실패했을 때 오류 사항을 확인하여 버그가 될 수 있는 Warning을 잡아낼 수 있다.
      • 보이지 않을 경우 Window -> Developer Tool -> Output Log / Message Log 옵션으로 활성화 가능
  • Packaging이 성공적으로 끝나면, Target Directory에 Packaging 된 Project가 들어간다.

Distribution

  • App Store나 Google Play Store에 제출하려면 Distribution Mode로 Game Package를 만들어줘야 한다.
    • Packaging -> Packaging Setting -> Distribution 옵션을 체크

IOS

  • Apple의 Developer site에서 배포 Certificate와 MobileProvision을 생성해줘야 한다.
  • Development Certificate와 같은 방식으로 Distribution Certificate 설치
    • 배포 Provision 이름에 "Distro_" 접두사를 붙여준다.
      • Distro_MyProject.mobileprovision이 MyProject.mobileprovision이 된다.

Android

  • .apk File Signing을 할 Key를 생성
  • BuildTool에 정보를 줘야 한다.
    • Engine/Build/Android/Java/SigningConfig.xml
    • 이 파일을 직접 수정하면 모든 Project에 적용
    • Project/Build/Android Directory에 복사하면 해당 Project에만 적용 된다.

Advanced Setting

  • File -> Project Package -> Package Setting
    • 또는 Edit -> Project Setting -> Packaging

Build Configuration

  • Code based Project를 Compile 할 때의 Build Configuration
    • Blueprint 전용 Project에서는 이 옵션이 없다.
  • Code Project Debuging의 경우 DebugGame 선택
    • 이 외의 Debuging은 최소한으로 지원
  • Performance가 좋은 개발용으로는 대부분 Development 선택
  • 최종 빌드의 경우 Debuging 정보와 기능이 제거된 Shipping을 선택

Statging Directory

  • Packaging 된 Build가 들어가게 될 Directory
  • Target Directory 선택 창에서 다른 Directory를 선택하면 자동으로 업데이트

Full Rebuild

  • Code를 전부 다 Compile 할지 여부
    • 비활성화 하면 수정된 Code만 Compile
    • 잘 활용하면 Packaging Process 속도가 빨라질 수 있다.
  • Shipping 빌드의 경우 누락/오래된 버전 갱신을 위해 항상 활성화를 해주는것이 좋다.
  • 기본적으로 활성화 되어있다.

Use Pak File

  • Project의 Asset들을 개별 Fiel로 둘지, 하나의 Package로 만들지 여부
    • 활성화하면 모든 Asset은 하나의 .pak 파일에 들어간다.
    • 비활성화 하면 모든 파일을 하나하나 복사한다.
  • Asset File이 많은 경우, 전송해야 하는 File 양이 줄어들어 배포가 쉬워질 수 있다.
  • 기본적으로 비활성화 되어 있다.

Generate Chunks

  • Streaming Install에 사용할 수 있는 .pak File Chunk 생성 여부

Build Http Chunk Install Data

  • HTTP Chunk Installer 용 Data 생성 여부
  • 이를 통해 Web Server에서 Hosting하여 Runtime에서 설치가 가능

Http Chunk Install Data Directory

  • Build가 완료되면 Data가 설치되는 Driectory

Http Chunk Install Data Version

  • HTTP Chunk Install Data의 Version Name

Include Prerequisites Install

  • Packaging된 Game의 사전 요구사항 Installer를 포함시킬지 여부
    • OS Component 재배포판

Signing and Crypto

  • 출시 때 .Pak 파일을 서명하거나 암호화
    • Data 추출이나 Hacking을 방지
    • Unreal Engine 4.22 이후에서는 OpenSSL Library로 통합 함
  • Project Setting -> Crypto Section

Encrypt Pak INI Files

  • Project의 .pak File에 존재하는 모든 .ini File을 암호화
    • 최소한의 Runtime 비용으로 Data Mining 혹은 변조를 방지할 수 있다.

Encrypt Pak Index

  • .Pak File Index를 암호화
    • 최소한의 Runtime 비용으로 UnrealPak File을 열고 확인
    • 제품의 .Pak File을 Unpack하지 못하도록 한다.

Encrypt UAsset Files

  • .Pak File의 .Uasset 파일을 암호화
    • 이 파일에는 Asset의 Header 정보만 있고 Data 자체는 없다.
  • 이 Data를 암호화 하면 보안성은 향상한다.
    • 하지만 Runtime 비용이 추가되고, Data Entropy가 증가해 Patch 크기가 커질 수 있다.

Encrypt Assets

  • ,Pak File 안의 모든 Asset을 암호화
    • Runtime File I/O Performance에 영향을 준다.
    • Package Data의 Entropy를 증가시켜 Patching System 효율을 떨어트린다.

Enable Pak Signing

  • .Pak File Sign을 활성화/비활성화한다.

Contents Cooking

  • Packaging 없이 특정 Target Platform Contents만 Cooking
    • 반복 작업에서 길고 지루한 Packaging Process를 피할 수 있음
  • File -> Contents Cooking -> [Platform Name] 선택
    • Local Developer Workspace에 있는 Contents를 Update하지, Staging Directory에 Asset을 복사하는 것은 아니다.

Optimize Load Time

  • Package Process 도중 Project Load Time을 최적화 하는 메서드 제공
    • 결과적으로 Game Load Time이 감소함

Event Driven Loader 및 Asynchronous Loading Thread 사용

Event Driven Loader

  • 기본적으로 활성화 되어있는 옵션
    • Project Setting - Engine - Streaming에서 비활성화 가능
  • 대부분의 Project에서는 EDL을 사용하면 Load Time이 절반으로 줄어든다.
    • 안정적이다.
    • Unreal Engine 구버전에 대한 하위 Porting, 수정dl rksmdgkek.
    • Customized Engine Version에 맞게 조정 가능하다.

Asynchronous Loading Thread

  • 기본적으로 비활성화 되어있는 옵션
    • Project Setting - Engine - Streaming에서 활성화 가능
  • Engine을 Customize한 경우 미세조정이 필요할 수 있지만, 보통 ALT는 전반적인 Load Time을 배가시켜준다.
    • 게임의 최초 Load Time
    • 지속적인 Data Streaming Time
  • ALT는 Serialize와 Post-Loading Code를 2개의 별도 Thread에 동시에 실행시키며 동작한다.
  • 이에 따라 Game Code의 다음 항목은 반드시 Thread-safe 해야 한다.
    • UObject Class Construct
    • PostInitProperties Function
    • Serialize Function
  • ALT는 가동되면 Load 속도가 2배가 된다.

Compress .pak File

  • Project Setting -> Packaging -> Advanced Option -> Create compressed cooked packages 체크
  • 대부분의 Platform에서는 자동 압축을 제공하지 않기에 .pak File을 압축하면 Load Time이 단축된다.
  • 다만 플랫폼 별로 고려사항이 있다.

Sony PlayStation 4

  • 모든 PS4에 자동 적용되는 압축과 .pak File 압축은 중복되어도 File Size가 줄어드는 혜택이 없다.
    • 압축 작업만 중복한다.
  • 때문에 .pak File 압축은 하지 않는 것이 좋다.

Nintendo Switch

  • 압축된 File Load가 더 빠를 수 있지만, 압축을 해제하는데 시간이 더 오래 걸릴 수 있다.
  • 타이틀마다 테스트를 해보고 결정해보는 것이 좋다.

Microsoft XBoxOne

  • 가장 빠른 Load Time을 내기 위해서 매우 중요하다.

Steam

  • 사용자가 다운로드 도중에 파일을 압축하므로 다운로드 시간이 .pak File에 영향을 받지 않는다.
    • 하지만 미압축 File의 경우 Steam의 Differential Patch Steam이 더 나을 수 있다. 
  • 압축된 .pak File은 소비자의 시스템 디스크 공간을 절약해준다.
    • 하지만 Patch 할 때 다운로드 시간은 길어진다.

Oculus

  • .pak file 압축을 지원하지 않는다.

Order pak File

  • Load Time 단축을 위해서는 .pak File 순서를 잘 지정해야 한다.
    • Unreal에서는 Data Asset의 필요 순서를 알아내어 더 빠른 Loading Package를 제작하는 Tool을 제공한다.
    • 개념적으로 이 Process는 Profile Drived Optimization와 비슷하다.
  1. -fileopenlog Command-line Option으로 Package Game을 build, Launch해 Engine이 File 순서를 기록하도록 한다.
  2. 게임 주요 영역을 전부 확인하고 게임을 종료한다,
    • 모든 Level, Character, Weapon, Vehicle 등
  3. GameOpenOrder.log 파일을 /Build/WindowsNoEditor/FileOpenOrder/ Directory에 복사한다.
    • Deployed Game에서 .pak File 순서 최적화에 필요한 정보가 들어있다.
    • 예를 들어 Windows Build는 WindowsNoEditor/(YourGame)/Build/WindowsNoEditor/FileOpenOrder/ 에 있다.
  4. Log File을 배치하고 .pak File을 리빌드한다.
    • 그러면 이번에 생성된 File가 앞에 생성된 모든 ,pak File은 Log File에 나타난 순서를 사용한다.
  • Production 환경에서는 다음 사항을 반드시 해줘야 한다.
    • Log File을 Source Control에 Check-in
    • 주기적으로 -fileopenlog를 붙여 실행한 뒤 업데이트
    • 발매 준비가 되면 마지막으로 한번 더 실행

'UE5 > Utility' 카테고리의 다른 글

[Basic] Source Control  (0) 2024.05.09
[Programming Tool] LLM(Low-level Memory Tracker)  (0) 2024.05.07
[ProgrammingTool] Sparse Class Data  (0) 2024.05.07

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/using-the-low-level-memory-tracker-in-unreal-engine?application_version=5.3

 

언리얼 엔진에서 로우 레벨 메모리 트래커 사용하기 | 언리얼 엔진 5.4 문서 | Epic Developer Community

언리얼 프로젝트의 메모리 사용량을 트래킹합니다.

dev.epicgames.com

  • Unreal에서 제공하는 Memory 사용량 Tracking tool
  • Scoped-Tag System을 사용해 Unreal Engine과 OS에서 할당한 모든 Memory에 대한 Account를 유지
  • Unreal Engine에서 사용하는 모든 Platform에 대한 LLM을 지원

LLM Tracker

Default Tracker

  • Engine의 모든 Alloc에서 사용하는 High-Level Tracker
  • FMemory::Malloc을 통해 이루어진 할당을 기록
  • Stat LLM, Stat LLMFULL Console Command에 대한 통계를 제공
  • Platform Tracker의 Subset

Platform Tracker

  • OS에서 이루어진 모든 Alloc을 기록하는 Low-Level Tracker
    • BindMalloc
      • OS 단위에서 발생하는 Memory Allocation을 더 효율적으로 사용하기 위한 Wrapper
      • 큰 규모의 Memory를 OS로부터 할당 받고, Application에 작은 단위로 쪼개서 제공한다.
    • AnsiMalloc
      • 표준 C++ Library 기반 Allocator
    • TBBMalloc
      • Intel의 Thread Building Blocks 기반의 Allocator
    • JeMalloc
      • 성능 최적화가 강조된 Allocator

LLM Configuration

Command-line Argument

  • -LLM
    • LLM 활성화
  • -LLMCSV
    • 모든 값을 csv 파일에 지속적으로 기록
      • saved/profiling/llm/ 에 기록
      • csv 파일에는 현재 값(MB)을 표시하는 각 Tag에 대한 Row가 포함된다.
      • 기본적으로 5초마다 새 Row가 작성된다.
        • Console 변수인 LLM.LLMWriteInterval을 사용하여 주기를 변경할 수 있다.
    • -LLM이 자동으로 활성화
  • -llmtagsets=Assets
    • 각 Asset별 할당된 합계를 표시
    • 5.3 기준 실험 기능
  • -llmTagSets=ASsetClasses
    • 각 UObject Class Type의 합계를 표시
    • 5.3 기준 실험 기능

Console Command

  • stat LLM
    • LLM 요약을 표시
    • 모든 Low-Level Engine 통계는 단일 통계로 그룹화 된다.
  • stat LLMFULL
    • 모든 LLM 통계를 표시
  • stat LLMPlatform
    • OS에서 할당된 모든 Memory에 대한 통계를 표시
  • stat LLMOverhead
    • LLM에서 내부적으로 사용하는 Memory 표시

LLM Tag

  • Engine과 Game Code에 의해 이루어진 모든 Memory Allocation에는 속한 Category를 식별하는 Tag가 할당된다.
    • 즉, Memory는 한번만 Tracking 되고, 누락되지 않는 한 두 번 계산되지 않는다.
    • 모든 Category의 합계가 Game에서 사용하는 총 Memory에 추가 된다.
  • Tag는 Tag Scope Macro를 사용하여 적용된다.
    • 해당 Tag 범위 내에서 이루어진 모든 Allocation은 지정된 Tag가 제겅된다.
  • LLM은 Tag Scope Stack을 유지/관리하고, Allocation에 최상위 Tag를 적용한다.

Engine에서 제공하는 Tag Category

UObject

  • UObject에서 상속된 모든 Class와 Property를 포함하여 해당 Class에 의해 Serialize 된 모든 것을 포함
    • UObject는 어떤 Category에서도 Tracking 되지 않는 모든 Engine/Game Memory에 대한 포괄적 Tag
  • 별도로 Tracking되는 Mesh, Animation Data는 포함되지 않는다.
  • Level에 배치된 Object의 수에 대응

EngineMisc

  • 다른 Category에서 Tracking되지 않는 모든 Low-Level Memory

TaskGraphTasksMisc

  • 자체 Category가 없는 Task Graph에서 시작되는 모든 Task
  • 보통은 상당히 낮아야 한다.

StaticMesh

  • UStaticMesh Class 및 관련 Property
  • 실제 Mesh Data를 포함하지는 않는다.

Custom Tag

  • Memory Profiling 할 때 Memory Insight에서 LLM Untracked Tag가 지정된 Allocated Memory가 있을 수 있다.
    • 이 때 LLM_DECLARE_TAG, LLM_DEFINE_TAG 매크로를 이용해 Custom Tag를 만들어 대응한다.
  • 이 매크로들은 Engine File을 수정하지 않고 Game Modue이나 Plugin에서 수행할 수 있다.
  • 자세한 구현은 Runtime/Core/Public/HAL/LowLevelMemTracker.h에서 확인할 수 있다.

LLM_DECLARE_TAG

  • 더보기
    /**
    * Declare a tag defined by LLM_DEFINE_TAG. It is used in LLM_SCOPE_BYTAG or referenced by name in other LLM_SCOPEs.
    * @param UniqueName - The name of the tag for looking up by name, must be unique across all tags passed to
    *        LLM_DEFINE_TAG, LLM_SCOPE, or ELLMTag.
    * @param ModuleName - (Optional, only in LLM_DECLARE_TAG_API) - The MODULENAME_API symbol to use to declare module
    *        linkage, aka ENGINE_API. If omitted, no module linkage will be used and the tag will create link errors if
    *        used from another module.
    */
    #define LLM_DECLARE_TAG(UniqueNameWithUnderscores) extern FLLMTagDeclaration PREPROCESSOR_JOIN(LLMTagDeclaration_, UniqueNameWithUnderscores)
    #define LLM_DECLARE_TAG_API(UniqueNameWithUnderscores, ModuleAPI) extern ModuleAPI FLLMTagDeclaration PREPROCESSOR_JOIN(LLMTagDeclaration_, UniqueNameWithUnderscores)

LLM_DEFINE_TAG

  • 더보기
    /**
     * Define a tag which can be used in LLM_SCOPE_BYTAG or referenced by name in other LLM_SCOPEs.
     * @param UniqueNameWithUnderscores - Modified version of the name of the tag. Used for looking up by name,
     *        must be unique across all tags passed to LLM_DEFINE_TAG, LLM_SCOPE, or ELLMTag.
     *        The modification: the usual separator / for parents must be replaced with _ in LLM_DEFINE_TAGs.
     * @param DisplayName - (Optional) - The name to display when tracing the tag; joined with "/" to the name of its
     *        parent if it has a parent, or NAME_None to use the UniqueName.
     * @param ParentTagName - (Optional) - The unique name of the parent tag, or NAME_None if it has no parent.
     * @param StatName - (Optional) - The name of the stat to populate with this tag's amount when publishing LLM data each
     *        frame, or NAME_None if no stat should be populated.
     * @param SummaryStatName - (Optional) - The name of the stat group to add on this tag's amount when publishing LLM
     *        data each frame, or NAME_None if no stat group should be added to.
     */
    #define LLM_DEFINE_TAG(UniqueNameWithUnderscores, ...) FLLMTagDeclaration PREPROCESSOR_JOIN(LLMTagDeclaration_, UniqueNameWithUnderscores)(TEXT(#UniqueNameWithUnderscores), ##__VA_ARGS__)

LLM_SCOPE_BYTAG

  • 더보기
    #define LLM_SCOPE_BYTAG(TagDeclName) 
    FLLMScope SCOPE_NAME(PREPROCESSOR_JOIN(LLMTagDeclaration_, TagDeclName).GetUniqueName(), false /* bIsStatTag */, ELLMTagSet::None, ELLMTracker::Default);\
    UE_MEMSCOPE(PREPROCESSOR_JOIN(LLMTagDeclaration_,TagDeclName).GetUniqueName());

Custom Tag macro 사용 방법

  1. LLM_DELCARE_TAG를 사용해 header File에 Custom LLM Tag를 선언
  2. 관련 .cpp File에서 LLM_DEFINE_TAG를 사용해 Custom LLM Tag를 정의
  3. LLM_SCOPE_BYTAG를 사용해 .cpp 파일의 Memory Tracking

Code 예시

  • CustomTagExample.h
    • 더보기
      #pragma once
      ...
      LLM_DECLARE_TAG(MyTestTag);
  • CustomTagExample.cpp
    • 더보기
      LLM_DEFINE_TAG(MyTestTag);
      
      AMyActor::AMyActor()
      {
          LLM_SCOPE_BYTAG(MyTestTag);
          MyLargeBuffer.Reset(new uint8[1024*1024*1024]);
      }

Tag Set

  • 실험 단계
  • LowLevelMemTracker.h안의 LLM_ALLOW_SSETS_TAGS를 정의하여 사용
  • Tag Set을 사용할 때 각 Allocation은 Asset이나 Object Class 이름을 추가로 저장한다.
  • Memory 사용량과 Runtime Performance에 모두 오버헤드가 추가된다.

Technical Detail Implementation

  • LLM은 Pointer를 Index로 하여 모든 Allocation의 Map을 유지하며 동작한다.
    • 이 Map은 각 Allocation의 크기와 할당된 Tag를 포함한다.
  • Game에는 동시에 최대 400만개의 Live Allocation을 가질 수 있다.
    • 때문에 Memory Overhead를 가능한 작게 유지하는 것이 중요하다.
  • 현재 구현에서는 Allocation 하나 당 21Byte를 사용한다.
    • Allocation Size
      Pointer 8 Byte
      Pointer Hash Key 4 Byte
      Size 4 Byte
      Tag 1 Byte
      Hash Map Index 4Byte
  • OnLowLevelAlloc 함수를 사용하여 Allocation을 Tracking하면
    Tack Stack 제일 위에 있는 Tag가 현재 Tag가 되고, Pointer를 Key로 사용해 그 Allocation이 Map에 저장이 된다.
  • Conflict를 피하기 위해 각 Tag의 Frame Delta는 별도의 FLLMThreadState Class Instance에서 Tracking 된다.
  • Frame이 끝나면 이 Delta를 합산해 통계 시스템과 .csv File에 게시한다.
  • LLM은 초기에 Initialize되므로 Default로 활성화 해야 한다.
    • Command-line에서 LLM이 활성화 되어있지 않으면 자동으로 종료가 된다.
    • 동시에 모든 Memory가 종료되어 Overhead가 발생하지 않는다.
  • LLM은 Test 및 Shipping Build에서 완전히 Compile 된다.
  • LLM은 통계 시스템 없이 실행할 수 있다.
    • 이 경우, 화면에 통계를 표시할 수는 없지만 여전히 .csv File에는 기록이 된다.
    • 이를 위해서는 LowLevelMemTracker.h에서 ENABLE_LOW_LEVEL_MEM_TRACKER를 수정해
      LLM을 활성화 해야 한다.
  • Tag는 Scope Macro를 사용하여 적용하는데, 이에는 2가지가 제공된다.
    • LLM_SCOPE
      • Default Tracker Scope 설정
    • LLM_PLATFORM_SCOPE
      • Platform Tracker Scope 설정
    • LLM_SCOPED_TAG_WITH_STAT
      • 위와 같이 통계를 사용하는 Scope Macro는 Deprecated 되었기에 사용하면 안된다.
  • LLM 내부에서 사용하는 모든 Memory는 Platform에서 제공하는 LLMAlloc/LLMFree 함수로 관리한다.
    • 때문에 LLM이 자체 Memory 사용량을 Tracking 하지 않도록,
      그리고 무한  Loop에 빠지지 않도록 다른 방식으로 할당하지 않는 것이 중요하다.

Additional Technical Detail

  • LLM의 Overhead는 100MB 이상이 될 수 있으므로 Console에서는 대용량 Memory Load를 지양하는 것이 좋다.
  • Test Setting에서의 LLM은 화면에 통계 페이지를 표시하지 않는다.
    • 하지만 .csv File에는 통계를 작성한다.
    • LLM은 Shipping에서 완전히 비활성화가 된다.
  • Asset Tag Tracking은 아직 초기 실험단계이다.

'UE5 > Utility' 카테고리의 다른 글

[Basic] Source Control  (0) 2024.05.09
[Basic] Packaging  (0) 2024.05.09
[ProgrammingTool] Sparse Class Data  (0) 2024.05.07

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/sparse-class-data-in-unreal-engine?application_version=5.3

  • 자주 사용되는 Actor Type의 주복 데이터를 제거하여 Memory를 절약
  • 제공하는 기능
    • Memory에 Property의 사본을 단 하나만 존재하도록 유지
    • Designer가 BP Graph에서 Property 값에 Access하고 Class Default에서 편집 가능
  • 사용을 권장하는 경우
    • In-Game에서 동시에 여러 개의 Instance를 가지는 Actor Class의 Property
      • 상당한 Memory가 중복된 사본에 사용되고 있음을 의미한다.
    • 배치된 Actor Instance를 변경하지 않는 Property
      • Actor Instance가 값을 override하지 않아 EditInstanceOnly나 EditAnywhere 지정자가 필요하지 않는 경우
    • C++ 코드로 수정되지 않는 Property
      • 직접 Access하는 모든 C++ 코드는 접근자 함수에 대한 호출로 대체 되어야 한다.
  • Sparse Class Data를 사용하기 위해서는 Native C++ 코드가 필요하다.

예제

  • 더보기
    USTRUCT(BlueprintType)
    struct FMySparseClassData
    {
        GENERATED_BODY()
    
        FMySparseClassData() 
        : MyFloatProperty(0.f)
        , MyIntProperty(0)
        , MyNameProperty(NAME_None)
        { }
    
        // 에디터에서 이 프로퍼티의 디폴트값을 세팅할 수 있습니다.
        // 블루프린트 그래프에서는 액세스할 수 없습니다.
        UPROPERTY(EditDefaultsOnly)
        float MyFloatProperty;
    
        // 이 프로퍼티의 값은 C++ 코드로 설정됩니다.
        // 블루프린트 그래프에서 액세스할 수 있습니다(변경은 불가능함).
        UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
        int32 MyIntProperty;
    
        // 에디터에서 이 프로퍼티의 디폴트값을 세팅할 수 있습니다.
        // 블루프린트 그래프에서 액세스할 수 있습니다(변경은 불가능함).
        // 'GetByRef'는 블루프린트 그래프가 사본 대신 const 참조에 액세스함을 의미합니다.
        UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta=(GetByRef))
        FName MyNameProperty;
    };
    • EditAnywhere, EditInstanceOnly, BlueprintReadWrite가 Tag된 Property 대상으로는 작업할 수 없다
    • Sparse Class Data를 포함하는 Struct는 USTRUCT(BlueprintType) 지정자가 선언되어 있어야 한다.
      • 각 Property는 반드시 EditDefaultsOnly 지정자를 포함해야 한다.
      • 별도의 Category가 없는 경우, Default인 'My Sparse Class Data'를 받게 된다.
  • 더보기
    UCLASS(BlueprintType, SparseClassDataTypes = MySparseClassData)
    class AMyActor : public AActor
    {
        GENERATED_BODY()
    
    #if WITH_EDITOR
    public:
        // ~ 이 함수는 기존 데이터를 FMySparseClassData로 전송합니다.
        virtual void MoveDataToSparseClassDataStruct() const override;
    #endif // WITH_EDITOR
    
    #if WITH_EDITORONLY_DATA
        //~ 이 프로퍼티는 FMySparseClassData 구조체로 이동합니다.
    private:
        // 이 프로퍼티는 에디터에서 변경할 수 있지만, 클래스별로만 변경됩니다.
        // 블루프린트 그래프에서는 액세스하거나 변경할 수 없습니다.
        // 희소 클래스 데이터의 잠재적 후보입니다.
        UPROPERTY()
        float MyFloatProperty_DEPRECATED;
    
        // 이 프로퍼티는 에디터에서 변경할 수 없습니다.
        // 블루프린트 그래프에서 액세스할 수 있지만, 변경할 수는 없습니다.
        // 희소 클래스 데이터의 잠재적 후보입니다.
        UPROPERTY()
        int32 MyIntProperty_DEPRECATED;
    
        // 이 프로퍼티는 에디터에서 클래스별로 편집할 수 있습니다.
        // 블루프린트 그래프에서 액세스할 수 있지만, 변경할 수는 없습니다.
        // 희소 클래스 데이터의 잠재적 후보입니다.
        UPROPERTY()
        FName MyNameProperty_DEPRECATED;
    #endif // WITH_EDITORONLY_DATA
    
        //~ 나머지 프로퍼티는 인스턴스별로 변경할 수 있습니다.
        //~ 따라서 나머지 프로퍼티는 희소 클래스 데이터 구현에서 제외됩니다.
    public:
        // 이 프로퍼티는 배치된 MyActor 인스턴스에서 편집할 수 있습니다.
        // 희소 클래스 데이터의 잠재적 후보가 아닙니다.
        UPROPERTY(EditAnywhere)
        FVector MyVectorProperty;
    
        // 이 프로퍼티는 블루프린트 그래프에서 변경할 수 있습니다.
        // 희소 클래스 데이터의 잠재적 후보가 아닙니다.
        UPROPERTY(BlueprintReadWrite)
        FVector2D MyVector2DProperty;
    };
    • UCLASS(SparseClassDataTypes = [SPARSE_CLASS_DATA_TYPE])
      • 이 선언을 통해 이 Class에서 어느 Sparse Class Data를 사용할지 연결한다.
      • Class당 1개의 Sparse Class Data만 지정할 수 있다.
        • 여러개가 필요한 경우 이를 하나로 묶은 Wrapper를 Sparse Class Data로 지정해야 한다.
      • Sparse Class Data를 지정하면 UBT가 자동으로 Get[SPARSE_CLASS_DATA_TYPE] 함수를 생성해준다.
    • 다음은 기존 변수를 무난하게 Sparse Class Data로 변환하며 값을 설정하기 위한 세팅이다.
      • Sparce Class Data로 이동하는 Property 주변을 #if WITH_EDITORONLY_DATA Precomiler 처리
      • 원본 Class의 property의 변수명에 _DEPRECATED 접미사 추가
        • _DEPRECATED 접미사가 붙은 변수는 Unreal에서 인지하고 사용 시 warning을 발생시켜준다.
      • 원본 Class의 UPROPERTY에 모든 지정자를 제거하고 접근자를 private로 세팅
      • Editor Build(#if WITH_EDITOR) 환경에서 MoveDataToSparseClassDataStruct 함수 override
        • 원본 Class에서 Sparse Class Data로 1회성 복사를 수행해 기존 값을 보존
  • 더보기
    #include "Engine/BlueprintGeneratedClass.h"
    
    #if WITH_EDITOR
    void AMyActor::MoveDataToSparseClassDataStruct() const
    {
        // 이미 저장된 희소 데이터를 덮어쓰지 않도록 하세요.
        UBlueprintGeneratedClass* BPClass = Cast<UBlueprintGeneratedClass>(GetClass());
        if (BPClass == nullptr || BPClass->bIsSparseClassDataSerializable == true)
        {
            return;
        }
    
        Super::MoveDataToSparseClassDataStruct();
    
    
        #if WITH_EDITORONLY_DATA
        // 언리얼 헤더 툴(Unreal Header Tool, UHT)은 GetMySparseClassData를 자동 생성합니다.
        FMySparseClassData* SparseClassData = GetMySparseClassData();
    
        // 이 줄을 수정하여 모든 희소 클래스 데이터 프로퍼티를 포함합니다.
        SparseClassData->MyFloatProperty = MyFloatProperty_DEPRECATED;
        SparseClassData->MyIntProperty = MyIntProperty_DEPRECATED;
        SparseClassData->MyNameProperty = MyNameProperty_DEPRECATED;
        #endif // WITH_EDITORONLY_DATA
    }
    #endif // WITH_EDITOR
  • Sparse Class Data의 영향을 받은 Property를 Editor에서 편집/Access 하는 사용자는 차이를 느끼지 못한다.
  • Memory 사용량은 줄어든다.
  • Property가 C++에서 Reference되는 경우, Getter 함수 호출로 모두 대체 되어야 한다.
    • 예를 들어 SparceClassData::MyFloatPropertyData에 접근하려면 GetMyFloatProperty를 대신 호출해야 한다.
    • 다행히도 이러한 함수는 UHT가 자동으로 생성한다.
  • 해당 PROPERTY에 NoGetter MetaData 지정자를 선언하면 Getter 함수 생성을 방지할 수 있다.
  • 해당 PROPERTY에 값 대신 상수 참조로 Access 하고 싶은 경우 GetByRef MetaData 지정자를 사용해야 한다.

'UE5 > Utility' 카테고리의 다른 글

[Basic] Source Control  (0) 2024.05.09
[Basic] Packaging  (0) 2024.05.09
[Programming Tool] LLM(Low-level Memory Tracker)  (0) 2024.05.07

+ Recent posts