Computer Graphics

[Computer Graphics] 출력문이 렌더링 속도에 미치는 영향

Razelo 2023. 1. 19. 18:32

오늘 시간이 남아서 평소 관심있던 컴퓨터 그래픽스를 살펴보고 있었다. 
 
자바로 3D 오브젝트를 구현하는 내용을 공부 중이었는데 정말 흥미로운 문제를 만났다. 
 
화면에 랜덤으로 색을 입힌 256 x 256 사이즈의 정사각형을 그려내고 해당  정사각형을 지속적으로 움직이도록 했는데 그려내는 속도가 연산 속도를 따라가질 못했다. 
 
한마디로 화면에 그려내는 속도가 너무 느렸다. 아래 영상을 보면 무슨 말인지 알 것이다. 
 
아래 영상을 보면 얼마나 느린지 체감이 될 것이다. (원래는 계속 이어지면서 그려야 한다는 걸 감안하면 뭔가 문제가 있다는 걸 알 수 있다. )
 

 
그래서 추측을 해보게 되었다. 
 
모니터에 그려내는 동작은 IO 작업이 굉장히 많이 일어나는 작업인데 분명 이 과정 어딘가에 병목이 있다고 생각했다.
 
어떻게 해결할 수 있을까? 
 
가장 처음 시도한 해결 방법은 지금 생각해도 재밌는 아이디어다. 
 
원래 듀얼 모니터를 사용하고 있는데 혹시나 이 듀얼모니터에 지속적으로 화면을 쏴주고 있는 작업이 IO에 어느정도 부하를 줘서 문제가 발생했을 수 있다는 생각이 들었고 듀얼모니터를 꺼보았다. 역시나 결과는 똑같았다. (ㅋㅋㅋ... 시도는 좋았죠...?)
 
전혀 도움이 되지 않았다. 
 
그래서 실제 렌더링이 일어나는 코드를 살펴보았는데 여기서 문제를 발견하게 되었다. 
 
제목에서 이야기한 것처럼 연산이 있는 부분에서 지속적으로 출력문을 호출했던 것이 원인이었다. 
 
코드는 아래와 같다.
 
출력문을 주석처리한 것을 볼 수 있을 것이다.
 
출력문이 속도 저하의 원인이었기에 주석처리했다. 
 

public void draw(Render render, int xOffset, int yOffset){
        for(int y = 0; y < render.height; y++) {
            int yPix = y + yOffset;
            if(yPix < 0 || yPix >= display.HEIGHT) {
                continue;
            }
            for (int x = 0; x < render.width; x++) {
                int xPix = x + xOffset;
                if(xPix < 0 || xPix >= display.WIDTH){
                    continue;
                }
                pixels[xPix + yPix * width] = render.pixels[x + y * render.width];
                // System.out.println("x: " + x + " y: " + y);
            }
        }
    }

 
코드를 보면 System.out.println을 주석처리했다. 
 
이 부분을 주석처리하니 아래와 아주 만족스러운 결과를 얻을 수 있었다. 
 
매번 픽셀에 값을 넣는 동작을 할때마다 즉 화면의 한 픽셀에 하나의 점을 찍는 연산마다 매번 출력문을 호출하다보니 속도가 너무 느려지는 점이 핵심이었다. 
 
출력문을 제거함으로써 문제를 해결할 수 있었고 아래와 같은 결과를 얻었다. 딱 봐도 눈에 띄는 개선을 얻었다. 
 
 

 
 
여기서 멈추면 재미가 없다. 
 
그냥 코드 한 줄이 문제였다는 점에서 끝나는데 핵심은 그보다는 단순 코드가 아니라 유독 출력문이 문제가 될 수 있다는 점이다. 
 
꼭 출력문이 아니더라도 어떠한 코드가 들어가던지 간에 속도가 느려지지 않는냐고 반문할 수 있을텐데 그렇지 않다. 출력문 이외의 간단한 코드 한줄이 들어가도 속도에는 큰 변화가 없다. 즉 출력문이 유독 성능에 해가 될 수 있다는 것이다.
 
아래 코드를 실행시키면 전혀 속도에 영향을 받지 않음을 알 수 있다. (물론 아주 조금은 영향을 끼칠 테지만 눈에 띌 정도로 느려지지는 않는다.)
 
아래 코드를 보자. 
 

public void draw(Render render, int xOffset, int yOffset){
        for(int y = 0; y < render.height; y++) {
            int yPix = y + yOffset;
            if(yPix < 0 || yPix >= display.HEIGHT) {
                continue;
            }
            for (int x = 0; x < render.width; x++) {
                int xPix = x + xOffset;
                if(xPix < 0 || xPix >= display.WIDTH){
                    continue;
                }
                pixels[xPix + yPix * width] = render.pixels[x + y * render.width];
                // System.out.println("x: " + x + " y: " + y);
                int a = 1 + 1;
            }
        }
    }

 
int a = 1 + 1; 이라는 코드가 삽입되었다. 
 
이 코드가 삽입되었음에도 불구하고 속도 저하는 거의 없다고 느껴진다. 

logging등을 찍을때 무심코 핵심 렌더링 연산 코드가 있는 곳에 찍지않는게 좋을 것같다. system.println보다는 낫겠지만 어차피 개념은 똑같고 성능저하를 유발할 것이다. (나중에 테스트한번 해봐도 될듯?)
 
출력문은 유독 느리며 성능을 크게 저해한다. 그러니 알 수 없는 이유로 속도가 저하된 것을 느낀다면 혹시나 자신이 디버깅을 위해 출력문을 삽입하진 않았는지 체크하는 습관을 들이자. 
 
 
 

반응형