약간 기분 상한 일..

senah의 이미지

안녕하세요, 저는 프로그래밍 짬밥은 나름대로 먹었다고 생각하는 사람입니다.

여기서 나름대로 짬밥을 먹어봤다는 것은..

1. 일정 기간 이상의 실무 경험이 있으며,
2. 최소한 XML 파서를 만져본 적이 있고(XML 파서를 다룰 줄 아는 능력 + 엿 같은 온갖 문자열을 다뤄본),
3. '직접 new / delete를 확실히 쓰기 때문에 나는 메모리 누수 따위는 없다!'라는 말이 헛소리라는 것을 잘 알며,
4. 멀티스레드 상황에서 버그는 거의 재현불가능해서 직접 추적해서 디버그하는 것은 무모하다는 것 등등을

잘 알고 있다는 정도입니다. 물론 대충 머리속에서 당장 떠오르는대로 적은거라, 그냥 그러려니 해주시면 고맙겠습니다. 여기 이 목록은 그냥 제가 생각하는 수준이 어느 정도라는 것을 짐작하는 용도 이외에는 아무런 의미도 없겠습니다.

여튼, 단도직입적으로 말하면 각 플랫폼(운영체제)에서 각종 API를 제공하기는 하지만, 그야말로 API일 뿐이고, 더구나 API 자체가 2% 약간 모자란 경우도 많습니다. (특히 윈도우) 더구나, 이 기종간의 이식성을 염두에 둔다면, 특히 스레드를 다루는 프로그래밍을 하면서 그런 상황에 처한다면 메모리 같은 리소스나 스레드 안정적인 최소한의 장치는 신중에 신중을 기해서 코드들을 미리미리 갈고 닦아두는게 좋죠.

그런데, 저보다 더 윗 사람에게 대체 뭐하는거냐라는 말을 들었습니다. 네, 학교입니다. 기분 상하죠. 3D 그래픽스를 이제 공부하는터라 잘 모르겠지만.. 여기서는 멀티스레드를 안 쓰나요?? 무조건 GPU가 다 알아서 해준다고 하니.. 제가 뭔가를 대단히 잘못 생각하는건지..

그동안의 프로그래밍 경험으로도 봤을 때, pthread_mutex_lock() / unlock()을 잘 짝지어서 사용하므로 경쟁 상태나 데드락 같은 것은 있을 수 없다!라는 말이 얼마나 허무한 것인지 알고 있는데요, 그런 것을 방지하기 위해 이리저리 궁리하다가 그런 말을 들으니, 힘 빠지더군요.

게다가, 일반적으로 제공하는 new / delete 성능은 바닥이다, 그것을 대신하는 성능 좋은 메모리 할당기를 쓰거나 자신의 메모리 할당기를 제작하는게 얼마나 좋은 것인지 이야기해도 별 반응이 없더군요.

이거.. 제가 잘못된 건가요? 아님 이 바닥(3D)에서는 그런게 쓸 일이 없어서 의미가 없는건가요..??

prio의 이미지

아무래도 조심스럽게 쓰신 글이라 그런지 상황은 잘 모르겠습니다만..
어쨌든 기분 푸시고 힘내십시오.

그리고 학교에 계시다니..
심심하실 때 E. Berger의 "Reconsidering Custom Memory Allocation"을 한 번 읽어보세요.
나름 재밌습니다. ^^

senah의 이미지

교수님은 아닙니다.. ;

drinkme의 이미지

그냥 여쭙니다. 님의 말씀을 문제삼는건 절대 아니니 오해마시고요.

>> 3. '직접 new / delete를 확실히 쓰기 때문에 나는 메모리 누수 따위는 없다!'라는 말이 헛소리라는 것을 잘 알며,
>> pthread_mutex_lock() / unlock()을 잘 짝지어서 사용하므로 경쟁 상태나 데드락 같은 것은 있을 수 없다!라는 말이 얼마나 허무한 것인지

앞뒤 내용 없이 이 얘기만 들으면,
-. new/delete를 잘 쓴다고 해도, 메모리 누수는 생길 수 있다.
-. pthread_mutex_lock() / unlock()을 잘 짝지어서 사용한다 하더라도, 경쟁 상태나 데드락 같은 것은 있을 수 있다.

처럼 들리는 군요.
제 생각은 그렇습니다.
-. (new/delete를 잘 쓰던, 말던) 메모리 누수는 생기지 않게 작성하여야 한다.
-. (lock/unlock을 잘 쓰던 말던) 경쟁상태(?)나 데드락이 생기지 않게 작성하여야 한다.

senah의 이미지

수동으로, 직접 이런 획득 / 해제 함수를 호출해서 자신은 절대 틀릴 일이 없다고 생각하는 것을 말하는거죠.

절대로 이런 것을 직접 해서는 메모리 누수가 없다는 것을 보장할 수 없다는 것은 모두가 잘 알고 있지 않습니까..? 그러니까, 님이 말씀하신대로 디자인에서 애초에 이런 자원이 빠져나가지 못하도록 메카니즘을 궁리해야죠. 잘 작성된 스마트 포인터를 사용하는 것도 한 방법이 될 수 있겠고, 자원 관리를 대행하는 프락시 비스므리한 것을 만드는 것은 이미 관용구로 널리 알려졌는데, 이런 디자인적인 방어를 뜻합니다.

여튼, 님께서 말씀하신대로 제가 의도한건 API 자체 결함을 뜻하는 것이 아니라(Win32 스레드 이벤트는 조건부 진입이 부족하다는 점에서 pthread에 비해 뭔가 아쉽지만) 개발자가 수작업으로 항상 짝을 맞춰주려는 미련한 짓을 하면서도 자원 누수가 없다고 믿는 것을 뜻하는 것입니다.

chadr의 이미지

어떤 부분에서 안좋은 소리를 들으셨나 모르겠지만 스레드를 사용하셨다고 하니 안좋을 소리를 듣는건 한가지 밖에 없어서
그 부분에 대해서 설명해드립니다.

3D쪽을 좀더 공부해보시면 아시겠지만 렌더링 부분에서는 일반적으로 스레드를 사용하여 렌더링하지는 않습니다.
그 외의 분야에서 렌더링은 렌더링대로 하고 동시에 동적 리소스 로딩이라든가 네트워크쪽이라든가 게임이라면 게임 로직부분을 스레드로
만들어서 돌리기도 합니다. 요즘 멀티코어가 대세이므로 가능한 이렇게 할려고 노력하기도 합니다.

하지만 순수하게 렌더링이라면 스레드를 사용하지 않는게 맞습니다. 스레드를 사용하면 오히려 렌더링시 성능이 떨어집니다.(내부에서 동기화 과정때문에)

또한 GPU는 독립적으로 동작할수 있는 하드웨어이기 때문에 데이터만 그래픽카드로 밀어넣고 렌더링 함수 호출하면 내부적으로 비동기적으로
렌더링을 수행하게 됩니다. 이런 타이밍을 CPU와 적절히 잘 이용해야지만 성능이 잘 나옵니다. 그리고 최종적으로 화면에 렌더링 결과를 출력하는 함수를 호출할때
GPU와 CPU가 동기화를 합니다.(수직 주파수 동기화) 물론 이러한 타이밍을 잘 이용할 수 있도록 API수준에서 기능을 제공합니다.

따라서 렌더링 부분에서 스레드를 사용할 이유는 정말 특별한 경우 빼고는 없습니다.

그 전까지는 GPU는 들어온 3D데이터를 기반으로 열심히 렌더링을 수행합니다.

이런 부분때문이지 않을까 합니다..
-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

senah의 이미지

GPU 자체가 이미 엄청난 스레드를 동시 다발적으로 돌릴 수 있고, 드라이버에서 그걸 처리해주기 때문에 굳이 클라이언트 코드에서 그런 일을 할 필요가 없다는 점은 잘 알고 있습니다.

순수하게 연구 목적으로 어떤 방법을 테스트해보는 것이 아니라면, 쓸만한 프로그램을 만들 때 기하정보 처리 - 데이터를 렌더링 파이프라인에 넣기 - 와 같은 과정을 순차적으로만 구성하는 것은 크게 좋아보이지 않습니다. 즉, 렌더링 파이프라인 과정 내부를 손 대보려는 것이 아니라(무모한 짓이라는 것을 잘 알고 있습니다. 카멕도 아니고) 일반적으로 쓸만한 프로그램을 만들 때 필요한, 위에서 말한 그런 디자인적으로 안전한 스레드 메카니즘에 대해 궁리하고 있는데 그런 소리를 들으니 기분이 상했다는거죠. 더구나 학교에서라도(학교에서 일하는 사람들이 현장에서 요구되는 그런 피 말리는 누수에 대한 압박은 덜하다고 하더라도) 꽤나 프로그래밍 짬밥이 있을텐데, 어떻게 이런 문제에 대해 그렇게 매도할 수 있는가..라는 생각이 들어서였습니다.

렌더링만 가지고 프로그램을 만들 수는 없는 노릇이잖습니까.. ;)

연구를 중점적으로 하는 사람(뭐라고 한 사람)과 구현을 먼저 생각하는 사고 방식 차이 때문일지도 모르겠군요. 이거 적당한 말이 없어서 이렇게 썼지만, 전자를 비하하는 말도 아니고, 후자를 미화하는 말도 아닙니다. 다만, 정말로 이해할 수 없어서 그럽니다.

senah의 이미지

렌더링 파이프라인 자체를 손 볼 수 있는 것은 라라비와 같은 물건이 나오기 전에는 뭐 딱히 해 볼 여지가 많지 않다는 것을 잘 알고 있고, 또 나온다고 하더라도 그럴 일이 없을거라는 점은 인식하고 있습니다.

여튼 지금까지 잘 알 수 없는 부분은 이쪽에서 과연 멀티스레드와 같은 병렬 프로그래밍 기법이 활용될 수 있는 여지가 있는 부분이 남아 있는가..라는 점입니다. 일반적으로 성능을 끌어올리는 방법으로 사용자 코드에서 짜투리식으로 활용되는 것 외에, 좀 더 근본적으로 적용될 수 있는 부분이 있는지 여부요.

이 부분에 대해서 조언을 듣고 싶습니다.

chadr의 이미지

아래 글에서 이해하신것 같이 이해하시면 됩니다. 제 글에도 있지만 순수하게 렌더링만 하는 프로그램이 아니라
여러가지 알고리즘에 의해서 CPU는 계속 어떠한일을 병렬적으로 하는 동시에 CPU에서 생성한 3D데이터를 GPU에게
밀어 넣어주고 바로 리턴하는 식으로 하면(실제로 이렇게 할 수 있게 API 수준에서 제공합니다.)
CPU는 멀티스레드로 빠르게 3D데이터 생성과 관련 연산을 수행하고 GPU는 열심히 렌더링을 수행하면
최대의 성능을 이끌어낼 수 있습니다.

3D 프로그램에서 스레드를 사용하는게 잘못된건 아닙니다.

잘못된건 여러 스레드에서 동시에 3D관련 API를 호출하는게 문제가 됩니다.

GPU 내부에는 그래픽 처리에 최적화된 정말 CPU와는 비교할 수 없을 정도로 많은 서브 유닛들이
존재합니다. 따라서 파이프라이닝을 극대화 할수 있는 설계로 되어있습니다. 그리고 이러한
파이프라이닝은 GPU가 알아서 제어를 합니다. 따라서 우리가 가장 해야할건 후다닥 빠르게
한꺼번에 많은 데이터를 GPU에게 던져주고 딴일을 하는게 가장 좋습니다.

그런데 스레드를 이용하여 여러곳에서 3D API를 호출하게 되면 그래픽 드라이버에서 이런 호출의 동기화를
하게 되어 추가적은 CPU 자원을 소모하게 됩니다. 이렇게 되면 CPU가 대기하는 시간이 생겨 성능이
떨어지게 됩니다.

결론은 스레드를 사용하셔도 됩니다. 단 여러스레드에서 3D API를 호출하는건 피하셔야합니다.
-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

senah의 이미지

조언 정말 감사합니다.

덕분에 전통적인 3D 프로그래밍은 대충 어떤 식으로 프로그램을 디자인해야 하는지 감이 오네요. 일단 밥줄 스킬은 이쪽으로 시작해봐야겠습니다. 병렬 프로그래밍을 좀 더 활용할 수 있는 부분을 찾아내는 것은, 제가 할 일이 되겠네요.

좋은 말씀 해주신 두 분과 처음 답글을 달아주신 분, 모두에게 감사의 말씀 드립니다.

neogeo의 이미지

실시간 렌더링을 주로 하시냐 비실시간 렌더링을 주로 하시냐에 따라 크게 갈립니다.

비실시간 렌더링을 주로 하신다면 thread 만질 일이 거의 사라집니다. 어차피 GPU 에서 연산 시간 대부분을 잡아먹게 되니까요. ( CPU 는 GPU 에 명령을 밀어넣고 푹~ 쉬게 될겁니다. animation interpolation 이나 간간히 해주고요... )

실시간 렌더링이라도 물리쪽 ( 유체역학 or 강체운동... 등등 ) 연산을 심각하게 하지 않는 이상 thread 로 뽑아서 얻는 이득이 거의 없습니다. 위엣분이 설명하신대로 GPU 는 GPU 대로 따로 노는지라 CPU 는 GPU 상황 봐가며 명령 밀어넣는 역할 하고 나면 거의 펑펑 놀거든요. 게임이라면 사용자 입력, 네트웍 패킷처리 , 인공지능 처리 등등등 할게 많겠지만 그냥 일반 그래픽스 랜더링이라면 animation interpolation 정도가 overhead 의 전부 입니다. ( 그나마 animation 이 아주 동적일경우에 말이지요. )

물론 shader 에 따라 CPU 와 GPU 를 왔다갔다 하는 경우도 있지만 이런일은 최대한 안생기게 하는게 정석입니다.

상황에 따라 다르지만 memory allocator 같은게 필요한것도 그래픽 자료가 방대하고 씬마다 자주 바뀌는 상황에서나 필요합니다. 만들어둬서 나쁠건 없습니다만..... 우선순위가 한참 뒤입니다.

그래픽스에서 주요로 하는 일의 우선순위를 먼저 생각해보시는게 좋을 것 같습니다.

mesh 의 자료구조라던가, texture 를 쉽게 다루는 라이브러리 라던가, sharer fragment 조합폭발을 줄이는 라이브러리라던가, matrix 나 vector 연산을 최대한 빠르게 할 수 있는 SIMD 라이브러라리 라던가, Material property 를 최대한 안바꾸게 모아그리기 라던가 ... 등등이 우선순위가 더 높을 것 같습니다.

Neogeo - Future is Now.

Neogeo - Future is Now.

senah의 이미지

님 말씀은 훨씬 이야기가 되는군요. (물론, 위에서 글을 달아주셨던 분의 말씀도 대단히 도움이 되었습니다)

우선 순위를 생각해보라.., 음, 이건 확실히 그렇군요.

그러니까 렌더링 과정에 필요한 데이터는 GPU에게 최대한 빠르게 밀어넣는 것을 생각하고(여기서 메모리 할당기 등이 이득을 볼 여지는 있지만 데이터 유형에 따라 달라질 수 있다 정도?), GPU가 박터지게 일하는 동안 CPU에게 '멀티코어'스럽게 일하라고 하는 것으로 정리하면 되나요?

그렇다면, 실제로 이쪽에서 스레드 프로그래밍이 적용될 수 있는 것은, 지금까지 해왔던 전통적인 부분이라는 이야기가 되는데, 그렇다면 그런 이야기가 나올만도 하군요.. 음.