프로파일러 카운터를 코드에 추가하고 나면 프로파일러 창 또는 애플리케이션 빌드에서 프로파일러 카운터를 시각화할 수 있습니다.
프로파일러 창에서 ProfilerCounter 또는 ProfilerCounterValue가 생성하는 데이터를 보려면 커스텀 Profiler 모듈을 사용하면 됩니다. 이는 다른 시스템 지표와의 관계를 시각적으로 파악하고 성능 문제를 신속하게 식별하는 데 도움이 될 수 있습니다.
다음 예시에서는 GameManager 클래스가 고수준 로직을 처리하며 적을 알고 있다고 가정합니다. 카운터의 값을 업데이트하려면 Update 또는 LateUpdate 메서드(적을 생성하거나 파괴하는 로직을 수행하는 시점에 따라)에서 Sample 메서드를 사용하여 적의 카운터 값을 프로파일러로 푸시합니다.
using UnityEngine;
using Unity.Profiling;
class GameManager : MonoBehaviour
{
Enemy[] m_Enemies;
void Update()
{
GameStats.EnemyCount.Sample(m_Enemies.Length);
}
}
총알 카운트를 프로파일러에 전달하기 위해, 이 예시에서는 총알 라이프사이클을 관리하는 셸 스크립트가 있다고 가정합니다. 그런 다음 GameStats.BulletCount 값을 Awake 단위로 증가시키고 OnDestroy 단위로 줄이면서 게임 내 총알 개수의 변화를 정확히 전달합니다.
using UnityEngine;
using Unity.Profiling;
public class Shell : MonoBehaviour
{
void Awake()
{
GameStats.BulletCount.Value += 1;
}
void OnDestroy()
{
GameStats.BulletCount.Value -= 1;
}
}
참고: Unity는 비개발 빌드의 ProfilerCounter 및 ProfilerCounterValue를 모두 컴파일합니다.
Profiler 모듈 에디터를 사용하여 빌트인 카운터 또는 새로 추가된 카운터를 선택해 시각화합니다. Profiler 모듈 에디터를 여는 과정은 다음과 같습니다.
중요: 프로파일러 창에 로드한 데이터가 없다면 생성한 카운터가 Profiler 모듈 에디터를 로드할 때 Available Counters 창에 표시되지 않습니다. 커스텀 카운터를 보려면 프로파일러로 카운터가 있는 일부 데이터를 캡처하거나 로드한 뒤 Profiler 모듈 에디터를 다시 엽니다.
그러면 프로파일러 창에서 다른 카운터들과 함께 데이터를 볼 수 있습니다. 자세한 내용은 커스텀 Profiler 모듈 생성을 참고하십시오.
참고: 정적으로 선언된 카운터는 유형이 초기화될 때 C# 코드에서 동적으로 초기화되며 실제로 초기화되고 사용되기 전까지 사용할 수 없습니다. 이는 편집 모드와 플레이 모드에 적용됩니다. 카운터가 Profiler 모듈 에디터에 표시되지 않으면 먼저 몇 프레임 동안 프로파일러로 일부 데이터를 기록하십시오.
빌드된 플레이어에서 프로젝트를 실행하면 프로파일러 창에 액세스할 수 없습니다. 하지만 빌드된 플레이어에서 카운터를__ UI__(사용자 인터페이스) 사용자가 애플리케이션과 상호 작용하도록 해 줍니다. Unity는 현재 3개의 UI 시스템을 지원합니다. 자세한 정보
See in Glossary 요소로서 표시할 수 있습니다. 이는 애플리케이션 빌드에 프로파일링 툴을 포함할 수 있다는 의미입니다.
다음은 빌드된 플레이어에서 커스텀 UI를 사용하여 씬의 왼쪽 상단에 카운터를 표시한 이미지입니다.
참고: 릴리스 플레이어(비개발 빌드)에서는 일부 프로파일러 카운터를 사용할 수 없습니다. ProfilerRecorder.Valid를 사용하여 데이터를 사용할 수 있으며 프로파일러가 데이터를 기록할 수 있는지 확인합니다. 또는 ProfilerRecorderHandle.GetAvailable을 사용하여 사용 가능한 모든 프로파일러 통계를 열거할 수도 있습니다.
프로파일러 카운터는 중요한 게임 또는 엔진 시스템 지표에 대한 인사이트를 제공합니다. 지속적인 통합 설정이 있거나 테스트 플레이 중에 애플리케이션의 주요 성능 지표를 시각화하려는 경우, ProfilerRecorder API를 사용하여 커스텀 및 빌트인 프로파일러 카운터 값을 가져올 수 있습니다.
예를 들어 다음 스크립트는 프레임 시간, Mono/IL2CPP 힙 크기, 애플리케이션이 사용하는 총 메모리를 표시합니다.
using System.Collections.Generic;
using System.Text;
using Unity.Profiling;
using UnityEngine;
public class StatsScript : MonoBehaviour
{
string statsText;
ProfilerRecorder systemMemoryRecorder;
ProfilerRecorder gcMemoryRecorder;
ProfilerRecorder mainThreadTimeRecorder;
double GetRecorderFrameAverage(ProfilerRecorder recorder)
{
var samplesCount = recorder.Capacity;
if (samplesCount == 0)
return 0;
double r = 0;
unsafe
{
var samples = stackalloc ProfilerRecorderSample[samplesCount];
recorder.CopyTo(samples, samplesCount);
for (var i = 0; i < samplesCount; ++i)
r += samples[i].Value;
r /= samplesCount;
}
return r;
}
void OnEnable()
{
systemMemoryRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "System Used Memory");
gcMemoryRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "GC Reserved Memory");
mainThreadTimeRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Internal, "Main Thread", 15);
}
void OnDisable()
{
systemMemoryRecorder.Dispose();
gcMemoryRecorder.Dispose();
mainThreadTimeRecorder.Dispose();
}
void Update()
{
var sb = new StringBuilder(500);
sb.AppendLine($"Frame Time: {GetRecorderFrameAverage(mainThreadTimeRecorder) * (1e-6f):F1} ms");
sb.AppendLine($"GC Memory: {gcMemoryRecorder.LastValue / (1024 * 1024)} MB");
sb.AppendLine($"System Memory: {systemMemoryRecorder.LastValue / (1024 * 1024)} MB");
statsText = sb.ToString();
}
void OnGUI()
{
GUI.TextArea(new Rect(10, 30, 250, 50), statsText);
}
}
중요: ProfilerRecorder.Dispose를 사용하여 ProfilerRecorder와 연결된 관리되지 않는 리소스를 해제합니다.
에디터에서 프로파일러 프레임 데이터를 처리할 때 프로파일러 카운터 값을 가져오려면 FrameDataView API를 사용하십시오.
다음과 같이 FrameDataView.GetCounterValueAsInt, FrameDataView.GetCounterValueAsLong, FrameDataView.GetCounterValueAsFloat 및 FrameDataView.GetCounterValueAsDouble을 사용하여 특정 카운터의 프레임 값을 가져올 수 있습니다.
using UnityEditor.Profiling;
class Example
{
static int ExtractMyCounterValue(FrameDataView frameData, string counterName)
{
var counterMarkerId = frameData.GetMarkerId(counterName);
return frameData.GetCounterValueAsInt(counterMarkerId);
}
}