본문 바로가기
프로그래밍 놀이터/안드로이드, Java

[도서 정리] 안드로이드 앱 성능 최적화 #4 화면과 UI 성능 개선하기

by 돼지왕 왕돼지 2018. 6. 25.
반응형

안드로이드 앱 성능 최적화 #4 화면과 UI 성능 개선하기


이 글은 “안드로이드 앱 성능 최적화” 의 일부 내용만 정리한 것입니다.

자세한 내용은 책을 구매하여 보세요~

ab 테스팅, ANDROID_HVPROTO, ColorFilter, DDM, Draw, dumpsys gfxinfo, dumpsys gfxinfo <packageName> framestats, dumpsys gpuinfo <packageName>, frame 누락, gpu rendering, gpu rendering profile, gpu 랜더링 프로파일링, GPU 렌더링, GPU 오버드로 디버깅, GPU 프로파일링 도구, hardware accelerate, hierarchy viewer, jank, layout, LinearLayout, linearlayout weight, measure, optimistic action, overdraw, overdraw counter, overdraw 회피, ProgressBar, RelativeLayout, setcolorfilter, SurfaceFlinger, systrace, The application may be doing too much work on its main thread, tinting, ui benchmark, ui 성능 개선 역사, ui 성능 벤치마킹, ViewServer, viewtree, viewtree depth, vsync, vsync 정의, WEIGHT, 계층 구조 뷰어, 낙관적 조치, 랜더링 역사, 로딩 시간을 숨겨주는 애니메이션, 리소스 줄이기, 리소스 틴팅, 버터 프로젝트, 뷰 구성하기, 사용자 테스트, 스피너, 안드로이드 앱 성능 최적화 #4 화면과 UI 성능 개선하기, 오버드로, 오버드로 영역 표시, 오버드로 카운터, 인지 성능, 인지 성능을 향상시키기 위한 팁, 쟁크, 쟁크 분석, 정보 수집 옵션, 즉각적인 업데이트의 착한 거짓말, 지터, 징크, 칩 공급 업체별 도구, 프레임 누락, 프레임 생략, 프레임 타이밍 정보, 프로필 GPU 랜더링

4.1. UI 성능 벤치마킹


-

0~100ms 의 지연은 순간으로 인식.

100~300ms 는 약간 느리다.

300~1000ms 는 뭔가 기계가 동작 중이구나

1000ms 이상이면 집중력을 잃기 시작한다.



-

웹 페이지의 경우 3~4초 안에 페이지 로딩이 되지 않으면 사용자의 50% 이상이 보던 페이지를 벗어난다.

같은 논리로 앱도 당연히 빨리 시작할수록 좋다.




4.1.1. 쟁크 (Jank)


-

안드로이드 팀에서는 프레임 누락으로 인해 화면의 부드럽지 않음 움직임을 쟁크(jank)라고 부른다.





4.2. 안드로이드 UI 및 랜더링 성능 개선의 역사


-

진저브레드 이하 OS 에서는 GPU 를 사용하지 않고 온전히 소프트웨어를 통해 화면을 그렸다.

그러나 기기의 화면은 점점 커지고 픽셀 밀도가 높아지면서 한계에 다달았다.


허니컴부터는 태블릿 지원이 추가되면서 화면 크기가 더욱 커졌다.

랜더링에 GPU 가 이용되기 시작했고, 앱 전체를 GPU 하드웨어 가속을 이용하도록 하는 개발자 옵션이 생겼다.


ICS 이상에서는 GPU 하드웨어 가속이 기본 옵션이 되었다.


JB 부터 안드로이드 개발팀에서 진행한 버터 프로젝트를 통해 쟁크와 지터 문제가 개선되었다.

VSYNC 를 사용해 프레임 생성 스케줄링 타이밍을 개선해 추가적 프레임 버퍼링이 가능해졌다.





4.3. 뷰 구성하기


-

View Tree 가 복잡해지고 렌더링하는 데는 더 오랜 시간이 걸린다.

각각의 뷰가 그려지려면 측정(measure), 배치(layout), 그리기(draw) 세 단계를 거친다.

먼저 XML 레이아웃 계층의 최상위 노드부터 measure 를 위한 탐색이 시작된다.



-

measure 는 뷰가 화면에서 어느 정도의 크기로 보여져야 하는지 알아내는 과정이다.

자식 뷰는 위치 조정을 위해 자신의 크기 정보를 부모 뷰로 전달한다.

부모 뷰는 자신의 크기를 측정하거나 자식 뷰의 크기를 결정하는 데 필요한 정보가 부족하다고 판단되면 강제로 모든 자식 뷰의 크기를 다시 측정한다.

이럴 경우 2~3번씩 measure 가 반복된다.

이런 이유로 view tree 의 depth 가 깊지 않은 구조가 권장된다.



-

뷰 재측정

    재측정 자체가 오류는 아니다.

    RelativeLayout 은 자식 뷰의 배치를 위해 기본적으로 여러 번의 측정 단계가 필요하다.

    LinearLayout 도 weighs 를 사용하는 경우 기본적으로 두 번의 측정 단계를 거친다.

    그래서 LinearLayout 과 RelativeLayout 이 중첩되면 측정 시간이 기하급수적으로 늘어난다.




4.3.1. 계층 구조 뷰어


-

기기가 JB 이상이면 ANDROID_HVPROTO 환경변수를 ddm 으로 설정하고 나면 안드로이드 기기 모니터를 통해 계층 구조 뷰어를 사용 할 수 있다.

이전 버전이라면 루팅된 단말기나 개발자 빌드가 설치되어 있는 기기를 가지고 있어야 한다.

구글러 로메인 기가 만든 ViewServer 를 이용해도 계층 구조 뷰어를 사용할 수 있다.





4.4. 리소스 줄이기


-

하나의 객체만 읽어 들인 후 ColorFilter 를 사용해 색을 변경시키는 방법인 리소스 틴팅(tinting)을 사용하면 리소스 로딩을 많이 줄일 수 있다.

이를 이용하면 하나의 아이콘을 사용해서 온라인/오프라인 상태, 별표/별표 없음 상태 등 여러 상태를 표시할 수 있다.

drawable.setColorFilter(colorValue, PorterDuff.Mode.SRC_IN);




4.4.1. 화면 겹쳐 그리기 문제




4.4.2. 오버드로 확인하기


-

JB 4.2 부터 개발자 옵션에 추가된 “GPU 오버드로 디버깅” 메뉴를 통해 쉽게 오버드로를 확인 할 수 있다.

JB 4.3 이상 버전이면 화면의 평균 오버드로 횟수를 계산해서 화면에 출력해주는 “오버드로 카운터” 기능도 사용해 볼 수 있다.



-

오버드로 카운터는 간편하게 오버드로 정도를 살펴보는 데는 편리하지만 실제로 오버드로가 정확히 화면의 어느 위치에서 발생하고 있는지는 보여주지 못한다.

개발자 설정의 “GPU 오버드로 디버깅” 메뉴에서 “오버드로 영역 표시”를 선택하면 오버드로 정보를 시각화해서 볼 수 있다.

이 도구는 각 영역이 얼마나 겹쳐져있는지를 여러 색으로 표현한다.


흰색

    오버드로가 없는 영역

파란색

    1배 오버로드 ( 화면이 두 번 그려짐 )

녹색

    2배 오버로드 ( 화면이 세 번 그려짐 )

밝은 빨간색

    3배 오버로드

진한 빨간색

    4배 오버로드




4.4.3. 계층 구조 뷰어(Hierarchy Viewer)의 오버드로 확인하기


-

Hierarchy Viewer 를 사용해 트리뷰를 포토샵 문서로 저장해서 분석할 수 있다.

포토샵이 없어도 김프(GIMP)를 사용하거나 다른 도구를 이용해 열 수 있다.




4.4.4. 킷캣에서 오버드로를 없애는 방법


-

킷캣이 설치된 기기에서는 예전보다 오버드로로 인한 지연 문제가 줄었다.

“오브드로 회피” 라고 불리는데, 다른 뷰에 의해 완전히 덮어져 있는 뷰의 경우 시스템에서 아예 그려지지 않도록 미리 제거하는 기술이다.



-

킷캣기기에서 개발자 옵션의 오버드로 도구를 사용하게 되면 자동으로 오버드로 회피 기능이 꺼진다.






4.5. GPU 렌더링 프로파일링으로 쟁크 분석하기


-

앱에서 발생한 쟁크에 대한 정보를 얻으려면 JB 부터 개발자 옵션의 “프로필 GPU 랜더링” 기능을 사용하면 된다.

이것은 프레임이 화면에 표시되는 데 걸리는 시간을 측정한다.

이 결과를 adb shell dumpsys gfxinfo 로 확인할 수 있다.


JB 4.2 이상에서는 기기 화면 위에 실시간으로 표시되게 설정할 수도 있다.




4.5.1. 안드로이드 마시멜로(MOS)에서의 GPU 렌더링


-

마시멜로에서는 adb shell dumpsys gpuinfo <packageName> 명령에 더 많은 정보가 추가되었다.

adb shell dumpsys gfxinfo <packageName> framestats 명령으로 각 프레임 타이밍 정보도 얻을 수 있다.





4.6. 쟁크를 넘어선 프레임 생략


-

GPU 프로파일러를 통해 임계값인 16ms 가 넘어가는 것으로 나타나지 않지만 명백하게 UI 렌더링이 되지 않는 순간을 확인할 수 있다.

CPU 작업 때문에 렌더링이 완전히 차단되어 프레임을 그리는 작업이 생략될 때 이런 문제가 발생할 수 있다.

이 때 Logcat Log 를 보면 "Skipped 193 frames! The application may be doing too much work on its main thread.” 와 같은 문구를 볼 수 있다.




4.6.1. Systrace


-

모든 뷰를 최적화했는데도 여전히 쟁크가 발생한다면 Systrace 를 이용할 때이다.

이 도구는 버터 프로젝트의 일환으로 젤리빈부터 도입되었다.

이를 이용해면 앱이 기기 내 핵심 컴포넌트들과 어떻게 연동되어 동작하는지 빠르게 확인 할 수 있다.


이 친구는 다른 도구들과 다르게 각각의 앱이 아닌 전체 안드로이드 시스템에 대한 정보를 수집한다.

이러한 이유로 되도록 적은 프로세스만을 구동시켜 놓은 상태에서 분석을 수행하는 것이 좋다.



-

Systrace 를 수행한 결과는 HTML 파일로 저장된다.

W/S 로 줌 인/아웃을 할 수 있고, A/D 로 왼쪽/오른쪽 스크롤 할 수 있다.



-

젤리빈 기기에는 개발자 옵션 아래 정보 수집 옵션이 있다.

컴퓨터와 기기 모두에서 이 옵션을 켜야만 정보가 수집된다.


새로운 OS 버전이 나올 때마다 정보는 좀 더 상세해지고 화면 구성도 조금씩 달라진다.




4.6.2. Systrace 로 살펴보는 화면 출력


-

VSYNC 는 화면을 업데이트할 시간을 알려주기 위해 운영체제에서 보내주는 주기적 신호이다.

VSYNC 사이 간격은 약 16ms 이다.

VSYNC 이벤트가 발생하면 surfaceflinger 는 뷰 버퍼로부터 뷰를 가져오고 이를 화면에 그린다.

이론적으로 쟁크가 없다면 surfaceflinger 이벤트가 16ms 에 한 번씩 발생해야 한다.

그러나 어떤 이유로 surfacefligner 가 VSYNC 신호를 처리하지 못해 화면이 갱신되지 않는 경우가 생길 때 쟁크가 발생한다.



-

랜더링을 하는 앱에서 바가 한 개 초과인 것은 버퍼가 있다는 의미이다.

버퍼링이 많아질수록 라인의 높이가 높아진다.



-

랜더링이 가끔 16.6ms 를 초과해도 한두 개의 버퍼가 미리 준비되어 있는 경우에는 괜찮을 수 있다.

하지만 이런 경우에도 랜더링이 두세 번 연속으로 느려진다면 사용자는 여전히 쟁크를 경험한다.




4.6.3. Systrace 와 CPU 로 인한 렌더링 차단


-

과도한 쟁크가 확인되지만 렌더링이나 surfaceflinger 에서 특이점을 찾지 못했다면 Systrace 맨 상단에 표시되는 CPU 를 의심해 볼 수 있다.

앱이 그려지는 것을 막는 특정 기능이나 프로세스를 분리해 낼 수 있다면 분리해내면 된다.




4.6.4. ‘구글 I/O 2015’ 에서 발표된 Systrace 업데이트


-

새로운 버전의 Systrace 에서는 각 프레임마다 'F' 표시가 된다.

느리게 그려진 프레임이 노란색 또는 빨간색으로 표시되고 정상적인 프레임은 녹색으로 표시된다.

점을 선택하고 m 을 누르면 분석하기 쉽도록 현재 프레임이 강조되어 표시된다.




4.6.5. 칩 공급 업체별 도구


-

주요 칩 제조업체들은 렌더링의 잠재적인 병목에 대해 더 많은 정보를 알 수 있도록 GPU 프로파일링 도구를 제공하고 있다.

이 도구들을 이용하면 앱에서 GPU 칩별로 세밀한 조정을 할 수 있어 특정 칩셋에서 앱이 더 유연하게 구동하게 할 수 있다.

퀄컴, 엔비디아, 인텔 등이 제공하고 있다.





4.7. 인지 성능


-

기다림에 대한 인식을 변경시키면 사용자가 지연을 더욱 짧게 느끼도록 만들 수 있다.

엘레베이터에 거울을 가져다 놔서 기다리는 시간이 짧다고 느끼게 하는 효과와 비슷한 방법이다.




4.7.1. 스피너 : 좋은점과 나쁜점


-

앱이 로딩될 때 진행 바를 사용하고 있다면 로딩이 마치는 방향의 반대방향으로 애니메이션을 주는 것이 좋다.

그리고 더 빠르게 회전하는 스피너는 느리게 회전하는 스피너보다 앱을 더 빠르게 보이게 하는 효과가 있다고 한다.



-

페이지가 랜더링 될 때 어떤 작업이 수행되고 있다고 알려주기 위해 스피너를 추가했더니 (실제 속도는 같음) 앱이 느려졌다는 피드백과 리뷰를 많이 보냈다.

페이스북에서는 커스텀 스피너를 사용했을 때 사용자들이 앱이 느리다고 느꼈는데, 표준 스피너로 교체하니 사용자들은 운영체제가 느리다고 느꼈다고 한다.


따라서 스피너를 추가할 때는 예상되는 결과를 미리 알아보기 위해 사용자 테스트가 꼭 선행되어야 한다.

일반적으로 새로운 페이지를 열 때나 네트워크로 이미지를 다운받을 때와 같이 지연이 예상되는 경우에 스피너는 용인된다.

만약 1초 미만의 지연처럼 짧은 경우에는 스피너를 생략하는 것이 더 낫다. 이 경우에 스피너를 넣으면 추가 지연이 생긴 것처럼 느낄 수 있다.




4.7.2. 로딩 시간을 숨겨주는 애니메이션


-

모바일 앱에서는 이전 페이지를 유지하는 대신 빠르게 쓸려 올라가는 애니메이션이 다음 뷰가 준비될 수 있는 시간을 벌어준다.




4.7.3. 즉각적인 업데이트의 착한 거짓말


-

낙관적 조치(optimistic action)은 client 에서 미리 작업에 대한 결과를 처리하고, 느린 네트워크 작업 등을 뒤로 미뤄 수행하는 것. ( 실제 결과가 반영 안 될 수도 있음 )



-

미리 업로드 하는 방법도 있다.

인스타그램의 경우 이미지를 설정하면 바로 업로드를 시작한다.

게시물 작성에서 가장 느린 단계가 데이터 입력임을 깨달아서, 이미지에 텍스트를 추가하는 동안 앱은 미리 서버에 사진을 업로드하는 것이다.




4.7.4. 인지 성능을 향상시키기 위한 팁


-

일반적으로 인지 성능 향상은 정량적 측정이 어렵다.

그래서 A/B 테스팅을 통해 사용자가 만족하는지 직접 확인해 보는 것이 좋다.





4.8. 결론





반응형

댓글