470 likes | 659 Views
멀티코어 환경에서 크로스 플랫폼 개발을 간소화하기. 개관. Emergent 는 어떤 회사인가 ? 크로스 플랫폼 멀티코어의 동기 부여 멀티쓰레딩의 원리 프로세싱 모델 : 스트림 프로세싱 Gamebryo’s Floodgate 퍼포먼스 분석 결론. 13 개 이상의 장르와 다중 플랫폼의 200 여 타이틀에 쓰인 기초적인 테크놀로지. Customers. 여러 개의 기계로부터 컴퓨팅 리소스를 이용함 . 아키텍처 살펴보기 PC, Multi-Core PC Wii Xbox 360 PS3 CUDA
E N D
멀티코어 환경에서 크로스 플랫폼 개발을 간소화하기
개관 • Emergent는 어떤 회사인가? • 크로스 플랫폼 멀티코어의 동기 부여 • 멀티쓰레딩의 원리 • 프로세싱 모델: 스트림 프로세싱 • Gamebryo’s Floodgate • 퍼포먼스 분석 • 결론
13개 이상의 장르와 다중 플랫폼의 200여 타이틀에 쓰인 기초적인 테크놀로지
여러 개의 기계로부터 컴퓨팅 리소스를 이용함. 아키텍처 살펴보기 PC, Multi-Core PC Wii Xbox 360 PS3 CUDA Larrabee 동기 부여
PC R R CPU L1 L2 Mem GMem GPU
Multi-Core PC R R CPU CPU L1 L1 L2 Mem GMem GPU
Wii R CPU L1 Locked Cache L2 DMA Mem1 / Mem2 GPU
Xbox 360 R R R R R R CPU CPU CPU L1 L1 L1 L2 Mem GPU
PS3 R R R R R R R R CPU CPU CPU CPU CPU CPU CPU L1 Local Store Local Store Local Store Local Store Local Store Local Store L2 Mem DMA GMem GPU
CUDA R R R R R R R R R R R R R R R R R R CPU CPU CPU CPU CPU … CPU … CPU CPU CPU … CPU 100s L1 L1 L2 Shared Constants Texture Shared Constants Texture Mem GMem
Larrabee R R R R R R R R R R R R R R R R R R R R R R CPU CPU CPU CPU CPU CPU … CPU 32? L1 L1 L1 L1 L1 L1 L1 L2 L2 L2 L2 L2 L2 Mem GMem
여러 기기 타입 일부 non-uniform memory uniform memory 시스템들조차 non-uniform data layout의 이득을 볼 수 있다. 미래에는 컴퓨팅 요소들의 수가 더 많아짐. 동기 부여 요약
크로스 플랫폼 쓰레딩의 목표 • 다른 사람들과 플레이를 잘 하기 위해 • 플랫폼 특유의 퍼포먼스 특징을 활용하기 위해 • 엔진과 미들웨어에 있어 고객들의 요구를 잘 맞추기 위해
한 번 작성으로 모든 곳에서 사용 • 기초적인 멀티쓰레드 프리미티브들이 모든 플랫폼에서 복제됨. • 이들을 위한 크로스 플랫폼 wrapper를 정의 • 프로세싱 모델들을 서로 다른 아키텍스처에서 적용할 수 있음. • 이들을 위한 크로스 플랫폼 시스템을 정의 • 개발자가 한 번 작성해두면 그 코드는 모든 플랫폼에서 잘 작동함.
Emergent's Gamebryo • 크로스 플랫폼 및 멀티코어 개발을 위한 기반 • 모듈성과 커스터마이징 • 콘텐트 파이프라인 툴군 • PC, Xbox 360, PS3, Wii지원
크로스 플랫폼 쓰레딩에는 공통의 프리미티브가 필요함. • Threads • 코드를 실행하는 것 • 세부 논점: 로컬 스토리지, 우선순위 • Data Locks / Critical sections • 리소스 경합(contention)을 관리 • 원자 연산(atomic operations) • 다른 쓰레드의 방해 없이 작업을 완성하는 게 보장되는 연산
NiCriticalSection의 예제 #ifdefined (WIN32) || defined(_XENON) CRITICAL_SECTION m_kCriticalSection; /// The ID of the last thread to lock /// the critical section. unsignedlong m_ulThreadOwner; #elifdefined (_PS3) [ps3sdk]mutex_t m_kCriticalSection; [ps3sdk]thread_t m_ulThreadOwner; #elif defined(_WII) [wiisdk]Mutex m_kCriticalSection; unsigned long m_ulThreadOwner; #endif// #ifdef for platforms ... #include"NiCriticalSection.inl"
NiCriticalSection의 예제 inlinevoid NiCriticalSection::Lock() { EnterCriticalSection(&m_kCriticalSection); m_ulThreadOwner = GetCurrentThreadId(); m_uiLockCount++; } inlinevoid NiCriticalSection::Lock() { [ps3sdk]mutex_lock(&m_kCriticalSection, 0); [ps3sdk]thread_get_id(&m_ulThreadOwner); m_uiLockCount++; }
프로세싱 모델 고르기 • 아키텍처적인 특징에 따라 모델을 고름. • 캐시의 일관성(Cache coherence) • Xbox의 prefetch • PS3의 SPU들 • 다중 처리 장치 • 범용 GPU • 스트림 프로세싱은 이런 특성에 맞음. • 이런 식으로 연산하기 위한 인프라를 제공함. • 엔진의 작업을 이 모델로 옮김
Stream Processing (Formal) Wikipedia: 인풋과 아웃풋 데이터 (스트림) 집합이 주어지면 기본적으로 스트림의 각 요소에 적용할 일련의 컴퓨터 집약적인 연산(커널 함수)들을 정의한다. Input 1 Kernel 1 Kernel 2 Output Input 2
일반화된 스트림 프로세싱 • 범용 컴퓨팅을 위한 개선 • 스트림들을 청크들로 분할함. • 커널들은 전체 청크에 접근할 수 있음. • 커널 파라미터(고정 인풋) • 장점 • 엄격한 데이터 지역성의 필요성이 줄어듦. • 루프, non-SIMD processing이 가능 • 하드웨어에 더 잘 맵핑됨.
Morphing+Skinning 예제 Morph Kernel (MK) Skin Vertices Skinning Kernel (SK) Bone Matrices Blend Weights Morph Weights Morph Target 1 Vertices Morph Target 2 Vertices Vertex Locations
Morphing+Skinning 예제 MT 1 V Part 1 Skin V Part 1 Morph Instance 1 Skin Instance 1 MT 2 V Part 1 Verts Part 1 Weights Fixed MW Fixed Matrices Fixed Morph Instance 2 Skin Instance 2 MT 1 V Part 2 Skin V Part 2 Verts Part 2 MT 2 V Part 2
Floodgate • 크로스 플랫폼 스트림 처리 라이브러리 • 플랫폼 당 최적화된 구현 • 고객의 사용을 위해 문서로 입증된 API • 엔진은 내장 기능을 위해 동일한 API를 사용함. • Skinning, Morphing, Particles, Instance Culling, ...
Floodgate의 기본 • Stream:변화하거나 고정된 데이터의 버퍼 • pointer, length, stride, locking • Kernel:데이터 스트림들에서 수행할 연산 • “Execute”함수를 구현하는 코드 • Task: 커널과 IO 스트림들의 wrapper • Workflow: 한 단위로 처리되는 태스크들의 집합
Kernel Example: Times2 // Include Kernel Definition macros #include <NiSPKernelMacros.h> // Declare the Timer2Kernel NiSPDeclareKernel(Times2Kernel)
Kernel Example: Times2 #include "Times2Kernel.h" NiSPBeginKernelImpl(Times2Kernel) { // Get the input stream float *pInput = kWorkload.GetInput<float>(0); // Get the output stream float *pOutput = kWorkload.GetOutput<float>(0); // Process data NiUInt32 uiBlockCount = kWorkload.GetBlockCount(); for (NiUInt32 ui = 0; ui < uiBlockCount; ui++) { pOutput[ui] = pInput[ui] * 2; } } NiSPEndKernelImpl(Times2Kernel)
Workflow의 일생 • 1. Floodgate로부터 Workflow를 구함. • 2. Task들을 Workflow에 추가함. • 3. Kernel을 설정함. • 4. Input Stream들을 추가함. • 5. Output Stream들을 추가함. • 6. Workflow를 보냄. • … 무언가를 함… • 7. 결과가 필요하면 기다리거나 폴링(poll) 함.
Workflow예제 // Setup input and output streams from existing buffers NiTSPStream<float> inputStream(SomeInputBuffer, MAX_BLOCKS); NiTSPStream<float> outputStream(SomeOutputBuffer, MAX_BLOCKS); // Get a Workflow and setup a new task for it NiSPWorkflow* pWorkflow = NiStreamProcessor::Get()->GetFreeWorkflow(); NiSPTask* pTask = pWorkflow->AddNewTask(); // Set the kernel and streams pTask->SetKernel(&Times2Kernel); pTask->AddInput(&inputStream); pTask->AddOutput(&outputStream); // Submit workflow for execution NiStreamProcessor::Get()->Submit(pWorkflow); // Do other operations... // Wait for workflow to complete NiStreamProcessor::Get()->Wait(pWorkflow);
Floodgate Internals • 태스크들을 위해 스트림을 분할함. • 태스크의 의존성 분석 • 플랫폼에 특정한 Workflow 준비 • 플랫폼에 특정한 실행 • 플랫폼에 특정한 동기화
Workflow분석의 개관 • 스트림들에 따라 태스크 의존성을 정의함. • 태스크들을 실행 스테이지들로 분류함. • 다른 태스크들의 결과를 사용하는 태스크들은 뒷 스테이지에서 실행됨. • Stage N태스크들은 Stage N-1 태스크들의 아웃풋에 의존함. • 주어진 한 스테이지의 태스크들을 동시에 실행할 수 있음. • 한 스테이지가 완성되면 다음 스테이지를 실행할 수 있음.
Task 1 Task 2 Task 3 Stream A Stream B Stream C Stream D Stream E Stream F Stream B Stream G Task 5 Stream G Stream H Task 6 Task 4 Stream I Stream G Stream F Stream D 분석: 많은 태스크들로 이루어진 Workflow
Task 1 Stream A Stream B Task 4 Task 5 Stream G Stream H Task 2 Stream D Stream C Sync Task Sync Stream G Task 3 Task 6 Stream E Stream F Stream I 분석: 의존성 그래프 Stage 1 Stage 2 Stage 3 Stage 0
퍼포먼스 노트 • 데이터는 블록들로 나뉨 -> 지역성(Locality) • 좋은 캐시 퍼포먼스 • prefetch나 DMA 전송을 위해 크기를 최적화함. • 제한된 로컬스토리지에 맞춤 (PS3) • #cores에 쉽게 적응함. • 다른 시스템들과의 상호작용을 관리할 수 있음. • Kernel은 프로세싱을 encapsulate 함. • 플랫폼 종속적 최적화에 좋은 타깃
유용성 노트 • 데이터 의존성을 알아서 관리하고 동기화를 간소화함. • 지저분한 플랫폼 특정 정보를 숨김. • Prefetch, DMA 전송,프로세서 검사, ... • 한 개의 API만 알면 그걸 여러 플랫폼들에서 사용할 수 있음. • 생산성의 이득 • 양질의 문서와 샘플을 만들 게 해줌. • 쉬운 디버깅
플랫폼 종속적 최적화 • Wii • Locked cache • 캐시 안팎의 명시적인 DMA • 어떤 경우 150% 빨라짐 • PS3 • 로컬 스토어에서 로컬 스토어로의 직접적인 DMA • 시스템에서 가장 빠른 전송이 가능 • (Gamebryo에 있을 차후의 작업) • 360 • 명시적인 prefetching
엔진에서 Floodgate를 활용하기 • 한 개의 오브젝트에 작용하는 태스크들 • Skinning, morphing, particle systems, ... • 이들을 Floodgate로 옮김: Mesh Modifiers • 실행 도중 어느 시점에 실행 • 애니메이션과 바운드의 업데이트 후 • 가시성 판단 후 • 물리가 끝난 후... • 필요할 때 끝냄 • Culling • Render • etc
샘플 어플리케이션과 새로운 퍼포먼스... 후 전 • 가장 큰 이익은 제품에서 바로 얻을 수 있는 퍼포먼스 • 어떤 결과는 많은 개발 시간으로 달성할 수 있다. • 갖가지 플랫폼에서 디테일을 숨김. (특히 PS3) Skinning Objects 42fps 62fps Morphing Objects 12fps 38fps
Thread profiling, Morphing 전 • 손수 코딩한 병렬 업데이트를 통한 병렬화 • 직렬 실행(serial execution)에서 오버헤드가 높고 85% 정도 나옴.
Thread profiling, Morphing후 • 엔진에서 자동으로 처리되는 병렬화 • Floodgate의 4 개 쓰레드(CPU 4 개) • 대략 이전의 직렬 시간의 50%가 4배 병렬화로 바뀜.
새로운 문제들 • 엔진 안에서 리소스의 사용이 특정한 시간에 극에 이름. • 예: 가시성 컬링과 렌더링 사이에 • 어플리케이션 수준의 작업이 빈 공간을 메울지도 모름. • Physics, AI, Audio, ... • 싱글 프로세서 장치는 어떠한가? 예. Nintendo Wii • 변하기 쉬운 크기의 아웃풋은 어떠한가? • 예: Instance culling
진행 중인 개선 사항 • 개선된 workflow 스케줄링 • 어플리케이션 컨트롤을 강화하기 위한 메커니즘 • 태스크들이 변화하는 때를 최적화 • 스트림 길이의 변화 • 인풋과 아웃풋의 변화 • 더 많은 플랫폼 종속적 개선 사항들 • 엔진의 작업을 더 덜어줌.
게임에서 Floodgate사용하기 • 스트림 프로세싱 기회를 식별한다. • 수많은 데이터가 지역적인 액세스 패턴으로 처리되는 곳 • 작업을 일찍 준비해도 되나 결과는 좀 늦게 필요한 곳 • Floodgate를 쓰도록 re-factor 처리한다. • 태스크에 따라 굉장히 짧은 시간으로 가능. • 어려운 부분은 지역성을 강요하는 부분
미래의 경쟁력을 갖추었는가? • CPU와 GPU 모두 스트림 프로세서들로 기능할 수 있음. • 더 많은 프로세싱 장치들로 쉽게 확장할 수 있음. • 어플리케이션의 변화나 플랫폼 특정 최적화에 작은 문제들이 있을 수 있음.
문의 우편번호: 137-858 서울 서초구 서초2동 1327-29번지 서초파라곤708호 (주)게임베이스 / 게임솔루션사업부 / 실장 박주용 TEL 02-598-6717(대표전화) / FAX 02-598-6714 담당자 E-mail : jypark@gamebase.co.kr Gamebryo의 개발사인 Emergent사 한국 총판 Gamebryo 커뮤니티 : www.gamebryo.co.kr