리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

51
리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기 류원하

Transcript of 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

Page 1: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

리소스 중심의 서든어택2 실시간메모리 프로파일링 시스템 개발기

류원하

Page 2: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

사후 공유를 위한 자료이므로발표 당시 내용과 다소 다를 수 있는 점 양해 부탁드립니다.

Page 3: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

발표자 소개KAIST CS 07

algospot.com 운영진

현상금 사냥꾼(?)

2015.1 - 2015.2

넥슨지티 서든어택2실 프로그램팀 외주파트

당시 주요 업무가 발표 주제

Page 4: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

작업 계기방학때 심심해서(?) 짧게 아르바이트를 하기로 했다

언젠가 과거에 32비트 윈도우에서 메모리가 터졌다 가상 메모리 2GB

메모리 사용은 눈에 잘 띄지 않아 시간보다 공간이 저렴 변화를 눈치채기 어렵다

그래서 자체적인 시스템을 구축해 쓰기 시작했고 성과가 있었다

그런데 그걸로는 정확히 어디가 문제인지 알 수 없었다

리소스가 너무 큰가?

패키징이 잘못되어 불필요한 리소스가 올라오고 있나?

엔진에서 리소스를 불러들이고 해제하는 루틴을 개선해야 하나?

...

Page 6: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

선행 작업으로 사내 세미나 진행한 바 있음→ 훌륭한 문서가 존재하고 있었음이 발표 자료에는 필요한 부분을 간략히 요약

Page 7: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

처음에는 UE3 내장 기능을 검토맥락 없는 기능별 수치

엔진 개발자 중심으로 개발된 듯세부사항 없는 기능별 일차원 분류는 자원 관리에는 부적절

모든 할당을 추적하지는 못함 (특히 DirectX)엔진 메모리 할당자는 통합되어 있지만...

그 외에도 이것저것 아쉬운 점이 있다고 함e.g.

출처: UDN, Epic Games, Inc.

https://pzurita.wordpress.com/2015/02/10/limitations-of-memory-tracking-features-in-unreal-engine-4/

Page 8: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

기존 인하우스 시스템메모리 할당자에서 카테고리를 분류

호출 스택을 감고 심볼 조회를 통해 이름 기반

실시간으로 시각화

→ 상황에 따른 메모리 사용 패턴 파악

D3D: 메모리 할당자 DLL 후킹

D3D 할당자는 HeapAlloc()을 바로 호출

IAT 수정을 통한 후킹

아쉬움: 어떻게 더 상세하게 할 수 있나?

후속 작업을 진행하기에는 정보가 부족

할당의 맥락이 필요

Page 9: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

문제 정의하기문제를 명확히 정의하는 것은 중요

오버엔지니어링 방지의견 수렴 과정에서 다양한 관점과 사실, 제약 발견

파인만 알고리즘

1. Write down the problem. ← 여기!2. Think real hard.3. Write down the solution.

Page 10: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

목표 - 결과물의 관점에서메모리를 2GB 아래로 어떻게 줄일 것인가? 이건 일회성 해결책

메모리라는 "자원"이 어떻게 사용되고 있는가?

구체적으로는,

직관적으로 누구나 알아볼 수 있게 예: 에셋이 문제라면 아티스트를 납득시켜야

후속 작업에 도움이 되도록보관, 공유, 분석이 쉬워야

Page 11: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

제약 조건 - 방법의 관점에서

출처: https://www.youtube.com/watch?v=jZcPG_czvpg

Page 12: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

제약 조건 - 방법의 관점에서

출처: https://www.youtube.com/watch?v=jZcPG_czvpg

모르는_엔진_처음_써봄.gif

Page 13: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

제약 조건 - 방법의 관점에서

출처: https://www.youtube.com/watch?v=66Azd9z3l9I

Page 14: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

제약 조건 - 방법의 관점에서

출처: https://www.youtube.com/watch?v=66Azd9z3l9I

카와이하게_별모양으로_리팩토링하면_망함.gif

Page 15: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

제약 조건 - 방법의 관점에서

출처: Ugly Americans, Season 2, The Ring of Powers (2011),http://redd.it/2gjm8c

Page 16: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

제약 조건 - 방법의 관점에서

출처: Ugly Americans, Season 2, The Ring of Powers (2011),http://redd.it/2gjm8c

유지보수_그게_뭔가요_먹는_건가요.gif

Page 17: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

해결책 큰 그림 그리기기본적인 정보는 실시간으로 렌더링자세히 알고 싶을 때 스냅샷

많은 정보와 그것을 탐색할 수 있는 인터페이스를 만들고 싶다!인게임에 구현하는 것보다는 외부에 구현하는 것이 유리

할당의 맥락은(목적은) 관련된 코드만이 앎 → 그 주변에 탐침그 형태는 예를 들면 이렇게:

텍스쳐를 불러들이는 중이라면 어떤 텍스쳐를 불러들이는지 써넣음

PROFILE_HERE("hierarchy/path/string", []() work_hard(); );

Page 18: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

해결 전략: 실행 계획어떤 순서로 행동에 옮길 것인가?

1. 스냅샷을 최대한 빨리 꺼내 보자2. 시각화 도구를 만들자3. 스냅샷을 보고 어느 부분에서 메모리를 많이 쓰는지 파악하자4. 그 부분에 적절한 측정코드를 넣고 잘 되는지 확인하자5. 커버리지가 충분할 때까지 3으로 돌아가 반복한다

_人人人人人人_> 성능은 무시 < ̄Y^Y^Y^Y^Y^Y^ ̄

Page 19: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

데모실제 리소스/코드 이름 등은 가려져 있으며, 동영상으로부터 캡쳐된

이미지이므로 화질이 고르지 못한 점 양해 부탁드립니다.

Page 20: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

실시간 프로파일링메모리 사용량이 최상위 분류를 기준으로 실시간으로 표시

Page 21: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

스냅샷 & 뷰어메모리 사용량을 조사하고 싶은 시점에 스냅샷 촬영 (콘솔 명령어 등)

Page 22: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

스냅샷 & 뷰어별도의 뷰어를 통해 스냅샷을 열면

Page 23: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

스냅샷 & 뷰어각 분류별 사용량이 넓이로 시각화됨

Page 24: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

스냅샷 & 뷰어아래 트리를 따라 조회 가능

Page 25: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

스냅샷 & 뷰어UE3 에셋 패키지 경로를 기준으로 분류하였으나 임의로 변경 가능

Page 26: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

스냅샷 & 뷰어즉 관점에 따라 측정 코드를 달리 삽입해기능 중심으로, 원인 중심으로 볼 수도 있음

Page 27: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

커버리지를 위한 호출 스택 추출호출 정보를 모두 포함한 큰 스냅샷을 찍고 불러들일 수 있음

Page 28: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

커버리지를 위한 호출 스택 추출매 분류의 말단에 더 이상의 소분류가 없는 할당에 대해 호출 체인이끝에서부터 펼쳐짐

Page 29: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

커버리지를 위한 호출 스택 추출추가적으로 분류하려면 호출 체인을 보고 메모리의 용도를 파악 가능

Page 30: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

어떻게 메모리 할당/해제가 추적되는가1. 코드 곳곳에 빨대를 심는다.

2. 런타임에 TagScope()에서 맥락을 저장하고 원래 코드를 실행한다.맥락은 thread-local 객체에 저장됨 boost::thread_specific_ptr

3. 메모리 할당이 발생하면 맥락을 참고해 할당 정보를 재구성한다.

MemoryAllocationProfiler::TagScope( // e.g. "Sound/Ambient/Level001/Foo" TEXT("Sound/") + soundName.Replace(TEXT("."), TEXT("/")), [&, this]() original_code(); );

Page 31: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

TAGSCOPE()의 재귀 호출??재귀호출 가능하도록 디자인됨씬 포함 관계 등을 표현 가능

씬 A, 그 부분 씬 B, 그 부분 씬 C를 A→B→C 또는 C→B→A 로 계층화실제로는 거의 안 쓰임

분류의 기준을 개별 리소스로 삼았기 때문다른 관점에서 분류하기로 하고 탐침을 달리 심으면 쓸 수 있음

Page 32: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

부분문제예스답삼형제

출처: 맛의 달인, 38권waifu2x 짱짱맨

Page 33: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

부분문제 1. 뷰어

Page 34: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

일단 이런 거 만들지 뭐 ㅎ처음부터 이런 툴을 만들면

시각적으로 자원을 관리할 수 있지 않을까 하는 발상에서 출발

Page 35: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

어떤 스택을 쓸 것인가?

HTML + CSS + JS

v.

C#/WPF

툴이니 아무래도 상관없다지만...

Page 36: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

웹 스택을 사용하지 않은 이유1. 성능 저하를 극복하려면 엔지니어링을 많이 해야 함

거대한 DOM 트리를 피해야 하고레이아웃 재배치가 자주 발생하지 않도록 디자인을 짜야 하며게으르게 불러들일 수 있도록 파일 포맷을 설계해야 하고 ...

2. 가져다 쓸만한 컴포넌트 없음누군가 다 만들어뒀다면 그냥 가져다 쓰면 되지만 없었음

3. 웹 서버 올려야 하면 어쩌나로컬 웹 페이지의 로컬 파일시스템 접근에 대한 브라우저 보안 이슈

4. C# 대비 유지보수의 어려움컨텍스트 전환 비용이 큼

Page 37: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

<!­­ WPF XAML 예시 ­­><datavis:TreeMap Name="TreeMap" Grid.Row="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="Binding ElementName=MainWindowInstance, Path=TreeMapNode.TreeMapChildren" ItemDefinitionSelector="StaticResource TreeMapItemDefinitionSelector" /><GridSplitter Name="RootGridSplitter" Grid.Row="1" Height="5" HorizontalAlignment="Stretch" /><sd:SharpTreeView Name="TreeView" Grid.Row="2" Root="Binding ElementName=MainWindowInstance, Path=RootNode" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemContainerStyle="StaticResource TreeViewItemStyle" ShowAlternation="True" SelectionMode="Single" GridViewColumnHeader.Click="TreeView_Header_Click" SelectionChanged="TreeView_SelectionChanged"><!­­ ... ­­></sd:SharpTreeView>

WPF Toolkit ( )

#develop SharpTreeView ( )

https://wpf.codeplex.com/

https://github.com/icsharpcode/SharpDevelop

Page 38: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

부분문제 2. 성능속도가 너무 느려요

Page 39: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

빠른 이터레이션이 중요한데...

빌드는 관리를 잘 해도 어쩔 수 없음엄청 느려진 로딩 짐작가는 부분이..

전체적으로도 물론 느려짐

출처: https://xkcd.com/303/

Page 40: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

동기화가 병목로딩이 느려졌다 → 멀티쓰레드를 많이 쓰는 환경에서 느리다CPU 프로파일링을 통해 확인함엔진 내장 프로파일러나 기존 시스템 모두 한번에 한 쓰레드만 처리연산 비용이 비싸졌으므로 병목이 되기 시작

Page 41: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

해결책작업자 쓰레드 하나 두고 작업 큐concurrent_bounded_queue 사용각 쓰레드는 필요한 정보를 스스로 만들어 전달락은 예외적인 상황이 아니면 쓰지 않음주의사항

이벤트가 큐에 들어가는 순서: 주소 X가 쓰레드 A에 의해반납되자마자 쓰레드 B에 의해 할당된다면?

다중 공급자 큐의 구현에 따라 한 쓰레드 내에서의 순서만보장되기도 함

내부 메모리 할당: 별도의 메모리 할당자를 사용하지 않고 쓰레드 맥락객체에 프로파일러 내부 여부를 표시

Page 42: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

부분문제 3. 미들웨어와 라이브러리직접 코드를 고치기에는 단기적이든 장기적이든 비용이 미묘

Page 43: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

말하지 않은 비밀: 64BIT ONLY이미 32비트에선 터지고 있던 상황기술적으로는 32비트도 가능할 것 같으나"리소스 중심": 32비트 빌드나 64비트 빌드나 리소스는 동일비용-효용 트레이드 오프 해서 얻는 게 별로 없지 않을까

Page 44: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

흑마법의 유혹지금 쓰는 스택 되감는 API에서컨텍스트도 다 복구해 주던데..거기서 인자를 얻어올 수 없나?

Windows x64에선 콜링 컨벤션도 통일됐다던데..

읽어보니 인자 개수만큼 스택을 항상 확보한다 하던데거기 들어있는거 쓰면 인자 복구가 되지 않나?

Page 45: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

출처: You've Got Mail (1998), http://redd.it/32ojzg

Page 46: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

출처: You've Got Mail (1998), http://redd.it/32ojzg

사실 블루스크린까진 아니었지만 디버그 빌드에서만 작동

Page 47: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

WINDOWS X64 콜링 컨벤션인자 전달: rcx, rdx, r8, r9 + 스택

리턴 타입, 클래스 여부에 따라max(4, 인자 개수) * 8만큼 항상 스택 확보확보는 꼭 해야 하지만 그렇게 써야 하는 것은 아니라능!!

그 스택은 아무렇게나 쓸 수 있음 최적화에 도움

cf. SystemV x64 "Red zone"

Page 48: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

그냥 후킹하자.. (한숨)정적 링크, DLL 후킹 기법은 사용 불가 →

MinHook ( )https://github.com/TsudaKageyu/minhook

함수 도입부에 트램폴린 함수로의 짧은 점프 덮어씌우기 ± 2GB

트램폴린 함수에서 우리 후킹 함수로 다시 긴 점프우리 후킹 함수에서 임시 함수 호출임시 함수에서 원래 함수 시작부분 복구하고 중간으로 점프

Page 49: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

후킹 예시namespace Scaleform namespace GFx class DetourFontData : public FontData public: void DetourRead(/* arguments */);;

void Scaleform::GFx::DetourFontData::DetourRead(/* ... */) MemoryAllocationProfiler::TagScope(TEXT("ScaleformGFx/Font"), [&]() (this­>*Original_Scaleform_GFx_FontData_Read)(/* ... */); );

미들웨어 업데이트하면 깨질 수도Fail fast - 깨질 거면 빨리 깨지는 편이 낫다

Page 50: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

회고 / 논의의 여지잘 문서화된 선행 작업의 이득빠른 이터레이션 중요확실히 알지 못하면서 요행을 바라면 역시 실패그래픽카드 드라이버는 정말 방법이 없나?

Page 51: 리소스 중심의 서든어택2 실시간 메모리 프로파일링 시스템 개발기

EOD