Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

웨일브라우저 성능 및 메모리 최적화

9,515 views

Published on

웨일브라우저 성능 및 메모리 최적화

Published in: Technology
  • Login to see the comments

웨일브라우저 성능 및 메모리 최적화

  1. 1. 웨일 브라우저의 성능 및 메모리 최적화 이성원, 조명진 NAVER
  2. 2. CONTENTS 1. JavaScript Optimizing AOT 2. 웨일 시동 성능 개선 3. 메모리 프로파일링 4. 메모리 세이버
  3. 3. JavaScript Optimizing AOT
  4. 4. 자바스크립트 성능의 진화 수년에 걸친 자바스크립트 가속화 경합 JIT 컴파일러에 다양한 최적화를 추가하여 지속적인 벤치마크 성능 향상
  5. 5. V8의 자바스크립트 가속화 FullCodeGen + Crankshaft pipeline 1. FullCodeGen: baseline JIT 컴파일러 2. Crankshaft: 최적화 JIT 컴파일러 3. FullCodeGen에 의해 빠르게 생성된 native code를 실행 4. 실행 빈도가 높은(Hot Spot) 자바스크립트는 Crankshaft로 최적화하여 다시 컴파일
  6. 6. V8 JIT 컴파일 Pipeline Parser FullCodeGen Crankshaft *.js Native Code Optimized Native Code Code Cache Hot Spot FullCodeGen으로 startup의 response를 빠르게, Crankshaft로 hot spot의 throughput은 크게. AST
  7. 7. V8 JIT 컴파일러의 구조적 한계 Parser FullCodeGen Crankshaft *.js Native Code Optimized Native Code Code Cache Hot Spot FullCodeGen: depth first traversal 기반 AST 처리의 비효율성 Crankshaft: target ISA에 독립적인 최적화의 추가가 어려운 layer AST
  8. 8. V8 6.0 이후 자바스크립트 실행 Ignition + Turbofan pipeline 1. Ignition: 바이트코드 인터프리터, FullCodeGen의 컴파일 과정 제거 2. Turbofan: 최적화 JIT 컴파일러, 더욱 최적화된 native code 생성 3. 소스코드를 변환한 바이트코드를 Ignition으로 실행 4. 실행 빈도가 높은 자바스크립트는 Turbofan으로 다시 컴파일
  9. 9. V8 6.0 이후 JIT 컴파일 Pipeline Ignition에 의한 응답성 개선 및 메모리 사용량 감소 (5~10%) Turbofan의 최적화된 native code로 벤치마크 성능 향상 (5~10%) Parser Ignition Turbofan *.js Optimized Native Code Code Cache Hot Spot Bytecode
  10. 10. 자바스크립트 성능은 여전히 문제인가? 웹페이지 로딩 시간의 제 1 요소 - 뚜렷한 hot spot이 없는 자바스크립트 로딩 (다량의 객체 생성 및 초기화) - 따라서 Crankshaft나 Turbofan에 의한 최적화는 가성비가 낮음 - 하지만 자주 방문하는 웹페이지라면?
  11. 11. HTTP Cache 기반 JS AOT 컴파일 HTTP Cache 자주 방문하는 URL에 포함된 resource(js, css, img, ...)를 disk cache에 저장 후 재사용 자바스크립트 Ahead-of-Time (AOT) 컴파일 - 자바스크립트를 JIT 컴파일한 native code를 HTTP cache에 저장 후 재사용함 - 동일한 자바스크립트를 매번 JIT 컴파일하는 부담을 버릴 수 있음
  12. 12. V8의 AOT 컴파일 FullCodeGen 기반 AOT 1. FullCodeGen으로 native code 생성 2. Serializer가 native code를 snapshot 형태로 변환 3. Http cache에 의해 snapshot이 disk에 저장 4. Cache hit된 자바스크립트의 snapshot을 disk로 부터 로드 5. Deserializer가 snapshot의 native code 복원
  13. 13. V8 JIT / AOT Pipeline Parser FullCodeGen Crankshaft *.js Disk Cache Native Code Serializer Deserializer Snapshot Annotated Native Code Optimized Native Code Code Cache Snapshot Native Code Http Cache Hit AST
  14. 14. 캐시된 자바스크립트를 더 빠르게 Crankshaft로 AOT 컴파일한다면... 1. FullCodeGen에 포함되지 않은 다양한 코드 최적화 기법 적용 - e.g. loop 최적화, 코드 배치 최적화, 번복 연산 제거, ... 2. AOT 컴파일시 추가적인 최적화 비용 1회 발생 2. 그러나 이후 로딩 시간에 실행되는 캐시된 자바스크립트를 매번 최적화 비용 없이 가속화
  15. 15. 웨일의 V8 JIT/ AOT Pipeline Parser FullCodeGen Crankshaft *.js Disk Cache Native Code Serializer Deserializer Snapshot Annotated Native Code Optimized Native Code Code Cache Snapshot Native Code Optimized Native Code AST
  16. 16. 일부 제한 및 Backup Plan Crankshaft로 AOT 컴파일이 가능하려면... 1. Crankshaft로 재활용 가능한 neutral native code를 생성 - Runtime profiling을 바탕으로 type에 특화된 최적화 제외 - 실행 환경에 종속적인 정보 제거 (e.g. V8 context) 2. 오류 발생 시 FullCodeGen의 native code로 전환될 수 있는 deoptimization 지원 3. 다양한 AOT failure에 대한 대처 - Crankshaft 컴파일, Serialization, Deserialization 실패
  17. 17. 웨일의 V8 JIT/ AOT Pipeline Parser FullCodeGen Crankshaft *.js Disk Cache Native Code Serializer Deserializer Snapshot Annotated Native Code Optimized Native Code Code Cache Snapshot Native Code Neutral Native Code Optimized Native Code Crankshaft AOT Fail Deoptimization AST
  18. 18. 개발 중 가장 큰 시련은... 첫째도, 둘째도, 셋째도 최적화된 native code debugging Source level debugging 불가능 - assembly code, memory dump, register value를 열심히 trace할 수 밖에… 1. JavaScript test에서 발생하면 다행! 2. 100% 재현 가능한 crash면 해볼 만 하고... 3. 간헐적으로 발생하거나 웹페이지 기능에 문제가 생기면 좌절ㅠㅠ - 페이지 로딩이 완료되어도 불규칙한 시간이 지난 후 뻗는다던지, - Smart Editor 3.0 웹페이지의 로딩 후 글이 안 써지기도...
  19. 19. Crankshaft AOT의 성능 웹페이지 로딩 시간 단축 실제 실행 여부에 상관없이 적극적으로 AOT를 적용할(eager AOT) 때 더욱 효과적 92% 93% 94% 95% 96% 97% 98% 99% 100% 101% OnLoad FirstMeaningfulPaint w/o AOT w/ AOT w/ eager AOT
  20. 20. Loding Time Breakdown Whale Vs. Chrome
  21. 21. 웨일 시동 성능 개선
  22. 22. 브라우저에게 시동 시간이란? 아이콘 클릭해도 아무것도 안 뜨고 시계만 돌고 있다면 “뭐, 이리 느려... 빨리 좀 떠라...” 아이콘 클릭과 동시에 창이 뜨고 첫페이지 로딩이 시작돼야 “오~ 빠릿하네! ㅋ” 브라우저 성능의 첫 인상을 좌우하는 지표 초기 웨일은 크롬과 동일하게 창이 뜨기 까지 1초 이상 걸림
  23. 23. 브라우저 시동 Tracing 렌더러와 GPU 프로세스의 시작 순차적 지연 브라우저 프로세스의 구동까지 1초 소모 무엇이 발목을 잡고 있나? whale.exe --trace-startup whale://tracing Load whaletrace.log
  24. 24. Crashpad 프로세스의 생성 시간 Crashpad 프로세스 타 프로세스에서 크래시가 발생하면 stack trace와 여러 metadata를 갈무리하여 저장 브라우저 프로세스의 생성부터 시동 사이에 Crashpad 프로세스 생성 500ms 소모 그래서 Lazy Crashpad Crashpad 프로세스의 생성을 지연시킴으로써 웨일의 시동 시간 단축 브라우저 프로세스의 process launcher thread에서 렌더러와 GPU 이후에 생성
  25. 25. 시동 시간 개선 및 부작용 체감할 수 있는 웨일 시동 성능 개선 500ms 감소 Crashpad 생성 이전에 발생하는 crash dump를 생성할 수 없음 원격으로 해당 crash dump를 수집할 수 없어 재현 경로를 확보하지 못한 크래시의 해결이 어려움
  26. 26. 메모리 프로파일링
  27. 27. 문제 발생
  28. 28. 메모리 모니터링을 해보자 우선 간단하게 브라우저의 메모리를 모니터링 하기로 함 최소 요구 사항 • 브라우저 웹 페이지 전환 • 지정된 프로세스의 메모리 모니터링 • 그래프로 시각화
  29. 29. 메모리 모니터링 결과
  30. 30. 메모리가 계속 증가하는 이유가 뭘까? Cache의 크기가 무한히 늘어나는가? Cache를 사용하지 않게 하여도 메모리가 증가 Memory Pressure가 제대로 동작하는가? Memory Cache 및 Decoded Image 삭제, GC 등으로 꾸준히 메모리 확보 Garbage Collector가 제대로 동작하는가? JavaScript가 없는 페이지에서도 여전히 메모리 증가
  31. 31. 메모리 누수의 범인은 누구인가? 범인은 이 가운데 있어!! WebCore JavaScriptCore Third-Party Library WebCore와 JavaScriptCore 메모리 측정 총 메모리 = WebCore + JavaScriptCore + Third-Party Library 찬조출연 : 소년탐정 김전일
  32. 32. WebCore!!!!!! TOTAL WebCore JS Engine 아.. 안녕? 찬조출연 : 명탐정 코난 범인
  33. 33. WebCore를 모두 들여다 봐야하나? 코드 리딩의 한계 총 317만 라인, .CPP, .H 만 세어보아도 158만 라인 한정된 리소스 소스코드 분석에 너무 많은 인력과 시간이 필요 Document의 부재 분석에 도움이 될만한 상세한 문서가 없음
  34. 34. 기존 메모리 프로파일링 기법 Dynamic Binary Instrumentation Framework Valgrind (Memcheck), Pin, DynamoRio (Dr. Memory) 컴파일러 기반 Instrumentation GCC Instrumentation, LLVM (Leak Sanitizer with ASan) 그 외 DLL Injection, CRT Debug Heap 등
  35. 35. 윈도우에서 사용가능 한 기법은? Dynamic Binary Instrumentation Framework Valgrind (Memcheck), Pin, DynamoRio (Dr. Memory) 컴파일러 기반 Instrumentation GCC Instrumentation, LLVM (Leak Sanitizer with ASan) 그 외 DLL Injection, CRT Debug Heap, WinDbg, UMDH 등
  36. 36. 할 수 있는 건 다 해봤는데... 비정상 종료 안정적으로 실행이 되지 않아 데이터를 뽑을 수 없거나 크래시 발생 무의미할 만큼 많은 데이터 제공 어떤 것이 실제 문제인지 파악할 수 없어 로그 분석에 너무 많은 시간이 소요 너무 느린 속도 데이터 분석에 너무 오랜 시간이 걸려서 사용이 불가능 좌절하는 코이와이 씨 (요츠바랑! 4권 175쪽)
  37. 37. 하지만, 느린 건 빠르게 만들면 된다 WinDbg는 안정적이면서 매우 강력한 도구 분석에 필요한 다양한 명령어 지원, 그러나 수정 불가 User-Mode Dump Heap Snapshot 기반으로 파일로 데이터 저장 및 결과 출력, 역시 수정 불가 하지만, UMDH Log 분석은 빠르게 할 수 있지 않을까? 로그 형식을 분석하여 보다 빠르게 프로파일링 결과 출력
  38. 38. 로그 형식 분석
  39. 39. FastUMDH 구조 1. 파일 분석 3. 심볼 탐색 2. 유효한 데이터 추출 4. 결과 출력
  40. 40. Workload Snapshot #1 (KB) Snapshot #2 (KB) Traces Pure Traces LeakTest 80 80 239 10 PDF Viewer 662 668 2219 19 WebBrowser 2,835 3,076 7,003 1,685 WebBrowser 6,902 6,571 15,133 7,039
  41. 41. 측정 결과 UMDH FastUMDH Parse Extract Symbol Print LeakTest 7.469 0.018 34.9% 0.4% 62.9% 1.8% PDF Viewer 6.353 0.060 72.1% 1.2% 25.6% 1.0% WebBrowser 777.296 3.668 5.3% 0.1% 92.6% 1.9% WebBrowser 11,735.696 17.295 2.7% 0.1% 95.5% 1.7% Symbol은 모두 디스크 캐싱이 된 상태에서 실행
  42. 42. Speed Up 0 100 200 300 400 500 600 700 800 LeakTest PDF Viewer WebBrowser WebBrowser SpeedUp(times) 678배 106배
  43. 43. 이제 문제를 찾아 볼까? 메모리 모니터링 도구에 포함 웹 사이트 이동 마다 Snapshot을 생성하여 결과 분석 어느 사이트가 메모리 누수를 유발하는지 탐색 메모리 할당을 많이 하고 해제하지 않는 로그 분석 주요한 콜 스택 분석 SVG 이미지 관련 로그가 다수 발견됨
  44. 44. SVG만 열심히 돌려보자 Leaky Image : http://static2.wikia.nocookie.net/__cb20100227155641/finalfantasy/images/9/94/Final_Fantasy_10_Sphere_Grid.svg
  45. 45. SVG 버그 수정 후
  46. 46. 장시간 테스트 결과
  47. 47. Continuous Integration 빌드 봇 연동 개발 버전의 메모리를 모니터링하여 리그레션이 발생하는지 확인 다양한 메모리 누수 탐지 Cairo, Font, Translation 등 메모리 누수 탐지 및 해결 겨우 메모리를 안정화했는데... 전격! 크로미움 기반으로 변경! http://cfile24.uf.tistory.com/image/210D9D40536F62892C826C
  48. 48. 메모리 세이버
  49. 49. 만족 35% ActiveX 27% 메모리 26% 속도 6% 오류 3% 배터리 3% 불만족 65% 사내 설문 조사 : “크롬 브라우저, 어떻게 생각하시나요?”, 2016년 7월, 모든 직군 대상, 651명 응답 크롬에 만족하시나요?
  50. 50. 크로미움도 측정해봤더니... 1,000MB 800MB 600MB 400MB 200MB Chromium 52
  51. 51. 프로세스 모델이 다르네? 기본 프로세스 모델 : Process-per-site-instance 사용자가 방문한 사이트 인스턴스 별로 렌더러 프로세스가 할당됨 기존의 탭당 하나의 전담 렌더러 프로세스 구조인 Process-per-tab과 차이가 있음 “새 술은 새 부대에” : Cross-Process Navigations 한 탭에서 다른 사이트로 이동하는 경우 새로운 렌더러 프로세스로 교체됨 - 옴니박스에 새로운 도메인 입력 - 북마크 클릭 - 탭 내에서 링크를 통한 사이트 전환
  52. 52. 언제 메모리가 부족할까? 물리 메모리 크기가 적은 경우 32bit 윈도우와 3GB 이하의 메모리를 사용하는 시스템 탭을 많이 사용하는 경우 검색, 쇼핑, 유튜브 등등 탭은 늘어나는데 닫지 않을 때 다른 프로그램이 메모리를 많이 사용하고 있는 경우 게임 같은 프로그램이 메모리를 많이 사용하여 브라우저가 사용할 메모리가 부족한 경우
  53. 53. 크래시 보다 나쁜 건 없다! 결국은 가용 메모리가 부족한 상황 가용 메모리의 부족으로 OOM 크래시를 만드는 것 보다는 성능을 떨어뜨리더라도 쓰지 않는 메모리를 회수하자 - 물리 메모리 크기가 적은 경우 - 탭을 많이 사용하는 경우 - 다른 프로그램이 메모리를 많이 사용하고 있는 경우
  54. 54. 메모리를 어떻게 회수하지? 우리는 정말 많은 탭을 쓴다 실제로 사용하는 탭은 몇 개 되지 않는다 그렇다면 안쓰는 Inactive 탭에서 메모리를 회수할 수 없을까?
  55. 55. 메모리 세이버 놀고 있는 탭이 있다면 잠시 꺼 두셔도 좋습니다 Tab Discarding 기법을 이용하여 Inactive Tab의 프로세스를 제거하여 메모리 회수 다시 탭을 보고 싶으면 어떡해? 최대한 기존 데이터를 복원하여 불편함을 최소화 결제 중이거나 음악을 듣고 있다면? 결제, 미디어탭 등 중요한 사이트나 복원이 어려운 사이트는 대상에서 제외
  56. 56. 메모리 세이버 레벨 레벨 조건 대상 반복 적용 유지 탭 수 1 (최소) 크래시 직전 10분 한번 최소 4개 2 (기본) 항시 2시간 한번 최소 3개 3 항시 1시간 (최대 4시간) 반복 최소 2개 4 항시 30분 (최대 4시간) 반복 최소 1개 5 (강력) 항시 10분 (최대 2시간) 반복 최소 4개 ※ 사용자 피드백을 바탕으로 추후 변경될 수 있음
  57. 57. 메모리 사용량 비교 프로세스 사용량 (최소) Browser Process 1개 Crashpad Handler 1개 GPU Process 1개 Default Extension Process 1개 PPAPI Process 1개 Renderer Process 17개 총 22개 프로세스, 1,654MB 소모 프로세스 사용량 (강력) Browser Process 1개 Crashpad Handler 1개 GPU Process 1개 Default Extension Process 1개 Renderer Process 3개 총 7개 프로세스, 476MB 소모
  58. 58. Thank you

×