응답성(response time)과 처리량(throuthput)은 다르다.

시간당 처리량과 응답성은 분명히 다르다. 시간당 처리량이 떨어져서 응답성이 떨어지는 경우에는 처리량을 높여서 응답성을 개선할 수 있다. 하지만 일정 수준 이상 처리량이 개선되면 응답성을 향상시키지 못한다.

100ms정도가 빠른 응답성이라고 가정하는 세상에선 처리량을 높이는게 응답성 향상으로 연결되겠지만 1ms정도에도 민감하게 반응하는 세상에선 처리량과 응답성이 거의 관련이 없을 가능성이 높다.
프로그래머라 해도 이 차이를 이해하지 못하는 경우가 많다.

회선을 증설해서 클라우드 게이밍의 latency를 줄일수 있지 않은가? 게임에서 멀티스레드를 사용하면 응답성이 좋아지지 않는가? 라고 묻는 경우가 대표적인 케이스다.

SW Occlusion Culling 기능을 구현할때의 경험을 적어보겠다.
KD-Tree를 탐색하면서 렌더링할 오브젝트를 골라낸다.여기서 시스템 메모리에 depth buffer를 만들고 렌더링이 확정된 오브젝트의 z값을 그린다. 그리고 렌더링할지 안할지 모르는 node(오브젝트가 아니다)의 AABB를 z-test한다. z-test결과 렌더링된 픽셀이 한개도 없으면 이 node에 속한 모든 오브젝트는 한꺼번에 트리 탐색에서 제외된다. 당연히 렌더링 파이프라인에도 아예 들어가지 않게 된다. 이걸 구현하는데 있어 핵심은 텍스쳐링만 안하는 SW Rasterizer를 구현하는거다. 당연히 삼각형을 빠르게 그리는게 제일 중요하다.

그러니까… 어떻게든 단위 시간 안에 많은 삼각형을 그리려고 별 짓을 다 했다.
SSE, AVX는 당연히 사용했다.
그래도 성능이 원하는 수준으로 나오지 않아서 절대 도움이 안될거라고 생각했던 멀티 스레드를 도입했다. 어쨌든 노는 코어가 있으니까 얘네들을 최대한 활용하면 성능이 올라가지 않을까.

커널 오브젝트를 Wait하는 경우를 최대한 줄이기 위해서 메인스레드가 나머지 워커스레드들을 깨우고 대기하는 대신 SetEvent()로 깨운 후에 결과를 확인하지 않고 그대로 삼각형 레스터라이즈로 진행한다. 나머지 워커 스레드들은 깨어나는대로 작업큐에 들어있는 삼각형 목록을 경쟁적으로 잡아다가 레스터라이즈 작업에 들어간다.

뭐 이런식이다. 동기화에 걸리는 시간을 최대한 줄이고자 직접 만들어쓰는 가장 가벼운 스핀락만 사용했다. 정말 악착같이 최적화를 했으나…

결과적으로 지금은 멀티스레드 코드는 사용하지 않는다.
가끔은 멀티스레드 코드가 빠를때도 있었다. 하지만 전반적으로 싱글스레드 버전이 더 빨랐다.
그 이유는

1. 다수의 코어가 활성화 되면서 터보 부스트가 꺼진다. 클럭이 떨어지면서 성능이 떨어진다.

2. 컨텍스트 스위칭할때 상당한 클럭을 까먹는다.

3. 아무리 wait를 안하려고 해도 언젠가 한번은 해야되는데 여기서 엄청 지체된다.

결론은 클럭 높은게 짱. 2.4Ghz 6코어 제온으로 멀티 스레드 코드 돌려봐야 4.5GHz 4코어 CPU에서 싱글 스레드 돌리는거보다 한참 느리더라.

물론 1시간 동안 삼각형을 몇개나 찍을수 있나로 테스트했으면 당연히 멀티스레드 버전이 높은 성능을 보였을것이다. 문제는 난 최대 4ms안에 삼각형을 많이 찍는게 중요했거든. 레스터라이즈중에 4ms를 넘기면 그대로 루프를 빠져나와버렸다. 그 이상 시간을 지체하면 프레임레이트에 오히려 나쁜 영향을 주기 때문이다.

‘동영상 인코딩 하는거나 라이트맵 굽는것처럼 병렬화 하기 좋고 애초에 시간 엄청 걸리는 작업 아니면 몇ms 응답성 향상시키자고 멀티스레드 쓰는건 진짜 바보짓이다.’ 라는 사실을 다시 한번 깨닫게 된 경험이었다.


응답성(response time)과 처리량(throuthput)은 다르다.”에 대한 답글 1개

답글 남기기

댓글을 게시하려면 다음의 방법 중 하나를 사용하여 로그인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중