55
언언 언언언언 언언언언언 ! JYP, 개개 개개개 개개 개개개 NEXON 개개개개개개 개개개

[NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

Embed Size (px)

Citation preview

Page 1: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

언제 어디서나 프로파일링 !JYP, 개발 중이나 배포 후에도

NEXON 인프라기술팀 하재승

Page 2: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

프로파일을 여러 상황에서 자주 수행하기 위해범용 프로파일러를 작성한 경험의 공유 구현에 초점

개발 알파 버전 Windows 용 온라인 게임으로 제한 기초적인 수준의 결과 분석

발표 목표

Page 3: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

프로파일링 ?

Page 4: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

성능 문제를 확인하기 위한 동적 분석 도구

프로그램 실행 중의 메모리 사용량 , 수행 시간 / 횟수 등을 수집

프로파일러

Page 5: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

프로파일링 방식 (CPU)

샘플링 주기적으로 실행 정보를 수집코드 삽입 측정할 부분에 코드를 삽입하여 수집그 외

JYP 에선 샘플링 방식을 이용해 구현

Page 6: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

Self, Deep, Total count

샘플링으로 콜스택을 수집호출 순서 : A → B → C → D

D 는 스스로가 실행 중에 샘플링됨 → Self ++

A, B, C 가 콜스택에 존재하는 상태 → A, B, C 의 Deep ++

모두의 Total ++

Page 7: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

참고자료

최적화와 프로파일링NDC 2008, 송창규님 사례를 통해 살펴보는 프로파일링과 최적화NDC 2013, 김이선님프로파일러를 이용한 게임 클라이언트

최적화 KGC 2014, 김종원님

Page 8: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

한계

지속적으로 성능 문제를 확인하며 개선해야 함

특정 환경 , 특정 시점에서만 재현되는 경우 비개발자 머신에서 발생했을 때 이미 유저에게 배포한 이후

재현된 컴퓨터에 프로파일러 설치하고 attach? (*VerySleepy)

Page 9: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

라이브 프로파일러 JYP

Page 10: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

언제든 프로파일링을 할 수 있게

간단한 준비제공하는 Library 를 사용하거나코드 변경 없이 외부에서 Injection

수집된 내용이 서버로 전송되어 분석 분석 시점에 PDB 파일이 필요 ( 서버 )

Page 11: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

배포 후에도 된다더니 ? (1)

배포 시 보안프로그램이 적용 nProtect, HackShield, XignCode 등 외부 툴 사용이 제한됨

디버거 , ReadProcessMemory, CreateRemoteThread, …

Page 12: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

배포 후에도 된다더니 ? (2)

프로그램 내부에서 수집은 가능→ Library 통해 JYP 적용시 잘 동작→ 렉걸리는 집 컴퓨터에서도 바로 성능 테스트→ ??!?!?!→ PROFIT!!!

Page 13: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

개발 관련 또는 개인 정보 유출 가능성

수집되는 정보 실행 중인 프로그램의 스택 값 읽어들인 모듈 정보= minidump 를 통해 수집되는 정보와 동일

PDB 는 노출되지 않음분석 작업은 서버에서만 이루어짐

Page 14: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

대상 프로그램

JYP Client JYP Controller

Binary

User

Web

JYP Server

Page 15: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

컨트롤러 프로그램으로 시작 / 중지

수집한 내용을 서버로 전송 후 분석

웹 인터페이스를 통해 결과 확인

Page 16: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

컨트롤러 프로그램으로 시작 / 중지

수집한 내용을 서버로 전송 후 분석

웹 인터페이스를 통해 결과 확인

Page 17: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

시연

Page 18: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

테스트 클라이언트

http://www.minetest.net/

C++ 로 구현된 마인크래프트형 게임Irrlicht 엔진으로 구현 ( 이을리흐트 )

엔진과 게임을 직접 빌드하여pdb 를 JYP 에 추가해둠

Page 19: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

캡쳐

컨트롤러로 등록 후 시작 / 멈춤

Page 20: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기
Page 21: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

분석결과 보기

웹페이지에서 결과 조회하는 내용

Page 22: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기
Page 23: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

숫자들

샘플링 시간 34 초분석 7 분샘플 개수 2472 개 72 개 / 초

게임 플레이에 거의 영향 없음

Page 24: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

JYP 내부 구현

Page 25: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

기본 아이디어

쓰레드별 스택을 수집하여 저장

저장된 데이터를 덤프인 것처럼 분석 루틴에 넘겨주자

분석된 콜스택으로부터 Call count, Call graph 등을 추출

Page 26: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

대상 프로그램

JYP Client JYP Controller

Binary

User

Web

JYP Server

Page 27: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

대상 프로그램

JYP Client JYP Controller

Binary

User

Web

JYP Server

Page 28: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

JYP 컨트롤러

JYP 서버를 통해 인증

게임 내부의 JYP 클라이언트와 통신

서버 주소를 클라이언트에 전송함

Page 29: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

대상 프로그램

JYP Client JYP Controller

Binary

User

Web

JYP Server

Page 30: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

JYP 클라이언트 (1)

스택 수집 및 전송 – 부하는 적으면서 자주

SuspendThread → 수집 → ResumeThread→ 전송

수집은 어떻게 ?

Page 31: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

스택

스택이 자라는 방향

ESP / RSP(Stack Pointer)

스택의 시작어떻게 알아낼까 ?

Page 32: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

Thread Information Block (TIB)

FS:[0x04] Stack Base / Bottom of stackFS:[0x08] Stack Limit / Ceiling of stackFrom http://en.wikipedia.org/wiki/Win32_Thread_Information_Block

x86 에선 FS, x64 에선 GS 에 저장

NtQueryInformationThread 함수로TIB 주소를 얻어올 수 있음

Page 33: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

THREAD_BASIC_INFORMATION typedef enum _THREADINFOCLASS { ThreadBasicInformation = 0,} THREADINFOCLASS;

typedef LONG KPRIORITY;

typedef struct _CLIENT_ID { HANDLE UniqueProcess; HANDLE UniqueThread;} CLIENT_ID;

typedef struct _THREAD_BASIC_INFORMATION{NTSTATUS ExitStatus;PVOID TebBaseAddress;CLIENT_ID ClientId;KAFFINITY AffinityMask;KPRIORITY Priority;KPRIORITY BasePriority;} THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;

Page 34: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

ntdll.dll

NtQueryInformationThread(thread, ThreadBasicInformation, &basicInfo, sizeof(basicInfo), NULL);

tib = basicInfo.TebBaseAddresstib->StackBase

Page 35: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

JYP 클라이언트 (2)

모든 쓰레드에 대해 ,

Esp (Rsp) 부터 StackBase 까지 복사

snappy 로 스택 내용을 압축 수십 kb → 수 kb 수준

Page 36: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

대상 프로그램

JYP Client JYP Controller

Binary

User

Web

JYP Server

Page 37: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

JYP 서버 - 수집

asio 서버로 수집컨트롤러로 인증을 하면 모듈 등록을 시작한다 .

컨트롤러를 통해 한 번의 시작 / 멈춤을 기준으로 분석 작업을 생성

Page 38: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

JYP 서버 - 분석

수집된 내용을 분석하는 자식 프로세스 생성

DbgHelp.dll 의 함수들을 이용하여 분석

Process Id 를 임의로 주면 실제 프로세스 없이 메모리 정보만 가지고 분석할 수 있다 .

Page 39: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

SymLoadModule64 DbgHelp 에 분석하려는 덤프에 있는 모듈의 이름 , 메모리 상 위치 , 크기를 알려줌

SymGetSymFromAddr64 SymGetLineFromAddr64 StackWalk64 의 결과로 부터 함수 이름과 줄 위치를 얻어옴

Page 40: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

StackWalk64 주어진 메모리 정보와 레지스터들이 저장된 CONTEXT 로 부터 콜스택을 분석한다 .

ReadMemoryRoutine 을 커스텀 버전으로 대체

StackWalk64 분석과정에서 코드 영역을 읽어 콜스택 분석에 사용하기 때문에 각 모듈의 이미지 정보도 필요하다 .

Page 41: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

JYP 서버 – 결과 조회

Crow + AngularJS

Deep, Self sample 개수 순 정렬Call graph 보여주기

모듈 , 쓰레드 필터링

Page 42: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

JYP 서버 – 결과 조회

Page 43: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

JYP 서버 – 결과 조회

Page 44: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

Crow

http://github.com/ipkn/crow

내일 Crow 세션이 준비되어있습니다 !

간단히 소개하자면 …

Page 45: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

Crow inside JYP

crow::App<crow::CookieParser> app;

app.route_dynamic("/")([&](){ … })

app.route_dynamic("/api/list")app.route_dynamic("/api/detail").methods(crow::HTTPMethod::POST)

Page 46: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

crow::App<crow::CookieParser> app;crow::mustache::set_base(".");

auto tpl_index = crow::mustache::load("index.html");

app.route_dynamic("/")([&]{

return tpl_index.render();});

Page 47: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

crow::json::wvalue val;

for(auto& m : result.modules_){ val["ms"][idx][0] = m.moduleName; val["ms"][idx][1] = m.baseAddr; val["ms"][idx][2] = m.baseSize; idx++;}

...

Page 48: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

AngularJS

https://angularjs.org/

Page 49: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

구현 상의 삽질 (1)

매번 미니 덤프 생성하는 방식 시도 느려서 교체 ( 초당 10 회 수준 )

스택 시작 주소를 얻기 위해 VirtualQueryEx 로 ESP 부터 올라가며 읽기 가능한 페이지 인지 확인했었다 실제 스택보다 더 크게 계산

Page 50: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

구현 상의 삽질 (2)

스택의 binary diff 만 전송 시도 diff 크기가 압축에 비해 훨씬 작다 binary diff 생성이 심각하게 느림 snappy 압축만으로 충분히 작아서 해결

가끔 데드락 발생하던 문제 수정SuspendThread + 메모리 할당

Page 51: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

마무리

Page 52: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

결론 ?

여러 도구들을 결합해서 프로파일러를 만듬

Page 53: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

앞으로 ..

서버 , 모바일로 확장 리눅스 - ELF, DWARF 포맷 지원 유니티

모니터링 기능 추가이벤트 기반 자동 기록

Page 54: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

그리고 더 앞으로 ...

넥슨 라이브인프라 실의실시간 모니터링 시스템을 통한 연계

상황별 정보 ( 현재 게임 상태 , FPS 등 )

특정 퀘스트나 맵에서 렉 유발→ 유저 불만 발생 → 개발팀 인식→ 서버에 상황 등록 → 재현시 자동으로 성능 정보 수집 모님의 우주정복 계획 (?)

Page 55: [NDC2015] 언제 어디서나 프로파일링 가능한 코드네임 JYP 작성기 - 라이브 게임 배포 후에도 프로파일링 하기

QnA

라이브 프로파일러 JYP

게임 클라이언트에 JYP 심어두기컨트롤러 프로그램으로 시작 / 중지수집한 내용을 서버로 전송 후 분석웹 인터페이스를 통해 결과 확인