JavaScript Profiling With The Chrome Developer Tools_SYS4U I&C

1,085 views

Published on

0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,085
On SlideShare
0
From Embeds
0
Number of Embeds
142
Actions
Shares
0
Downloads
0
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

JavaScript Profiling With The Chrome Developer Tools_SYS4U I&C

  1. 1. 크롬 개발자 툴을 이용하여 자바스크립트프로파일링 하기 저자: Zack Grossbart 작성일: 2012 년 6 월 12 일 대상: 초급 개발자 번역: 김형석 번역일: 2013 년 2 월 18 일 원문주소: http://coding.smashingmagazine.com/2012/06/12/javascript-profiling-chrome- developer-tools/ 웹 사이트가 정상적으로 동작하고 있다면, 이제 성능을 향상시킬 차례다. 웹 사이트의 성 능이라는 것은 두 가지 요소로 이루어져 있는데, 하나는 페이지 로딩 속도이고 다른 하 나는 페이지 내 코드의 실행 속도가 그것이다. 미니마이저1나 CDN2 등 수많은 외부 서비 스들을 이용하면 로딩 속도를 향상시킬 수 있지만, 코드가 빠르게 실행되도록 하는 것은 온전히 우리 개발자들의 몫이다. 코드상의 아주 작은 변경이 성능에 엄청난 영향을 줄 수 있다. 여기 저기에 산재되어 있 는 고작 몇 개의 코드 라인들 때문에 웹 사이트가 빛의 속도로 응답할 수도, 혹은 아예 다운된 것처럼 응답을 하지 않을 수도 있다. 이 문서는 크롬 개발자 툴(Chrome Developer Tools)을 이용하여 이런 문제가 있는 코드를 발견하는 두세 가지 방법에 대해 설명할 것이다. 기준점 정하기 먼저 색상 정렬기(Color Sorter)라는 간단한 어플리케이션을 살펴보기로 하자. 이 화면을 브라우저에서 열어보면 아래 그림과 같이 무지개 색의 원들이 격자로 정렬되어 보여질1 Minimizer. Javascript 등의 코드 내의 공백문자를 제거하거나 변수/펑션 이름을 짧게 만드는 등,네트워크를 통해 다운로드해야 하는 파일의 크기를 줄여주는 프로그램을 말한다.2 Content Delivery Network. 번역해서 컨텐츠 전송 네트워크라고 한다. 사용이 빈번한 컨텐츠를서버에 저장한 뒤, 병목지점을 피해 고속 서비스하는 시스템을 말한다.
  2. 2. 것이다. 사용자는 각각의 원을 드래그-앤드-드롭하여 이리저리 옮길 수 있다. 각각의 원 들은 CSS로 스타일이 적용된 div 태그이다. (무지개 색의 div는 “Making Annoying Rainbows in JavaScript.”를 이용하여 만들었다.) 웹 페이지 자체는 매우 빠르게 로딩되지만, 전체가 다 그려지기 전에 몇 번 깜빡이는 것 을 볼 수 있을 것이다. 바로 프로파일링을 할 시간인 것이다. 성능을 향상시키기 위한 작업을 할 때에는 항상 이 프로그램이 얼마나 느린지, 혹은 얼 마나 빨라야 하는지 등을 정의한 기준점(baseline)을 만들고 시작해야 한다. 기준점이 있 어야 성능 향상을 위해 수행한 작업이 얼마나 효과적이었는지, 그리고 그에 따른 트레이 드오프 3 는 무엇이고 얼마나 되는지를 알 수 있다. 이 문서에서는 크롬 개발자 툴을 이용 해서 이 작업을 진행할 것이다.3 Tradeoff. Tradeoff는 어떤 일을 목적을 이루기 위한 해결책으로 인해 발생하는 반대급부의 비용을 말한다. (반드시 그런 것은 아니지만) 어플리케이션의 속도를 향상시키기 위해 더 많은 메모리를 사용해야 하는 것이 tradeoff의 예이다.
  3. 3. 프로파일러4는 크롬 개발자 툴의 한 부분으로, 크롬이 설치되어 있다면 언제든 사용할 수 있다. 크롬 개발자 툴은 렌치 5 아이콘을 클릭한 뒤 도구(Tools) 메뉴 하위의 개발자 도구 (Developer Tools) 메뉴를 클릭하면 실행된다. 6 Firebug 7 에도 프로파일링 기능이 있긴 하 지만, 크롬이나 사파리 같은 웹킷 브라우저들이 코드를 프로파일링 하거나 타임라인을 보여주는데 가장 좋다. 크롬 개발자 툴은 스피드 트레이서(Speed Tracer 8 )라고 하는 멋진 이벤트 트레이스 도구를 제공하기도 한다. 기준점을 정하기 위해 일단 타임라인을 확인하기로 하자. 타임라인을 저장하는 방법은 다음과 같다. (1) 크롬 개발자 툴을 이용하여 “Timeline” 탭을 열어두고 웹 페이지에 접속한다. (2) 좌측 하단의 작은 검은 색 원을 클릭하면 타임라인 저장이 시작된다. 그리고 검은 색 원이 붉은 색으로 변한다. (3) 화면 상에서 프로파일링을 수행하고자 하는 동작을 실행한다. (4) (3)에서 붉은 색으로 변한 작은 원을 클릭하여 저장을 종료한다. 타임라인 저장 기능은 페이지 로딩이 시작되기 전까지는 시작되지 않는다. (크롬이 그 정 도는 똑똑하다.) 평균을 내보기 위해 총 세 번을 실행해 보았는데, 필자의 컴퓨터에서는 첫 번째 시도에서 가장 늦게 실행되었다.4 컴퓨터 사이언스에서 프로파일링이라 함은, 프로그램 복잡도, 메모리 사용량, 수행 시간 등 프로그램의 실행 상황에 대해 동적으로 분석하는 행위를 말한다. 프로파일링을 하는 목적은 궁극적으로 프로그램을 최적화하기 위해 문제가 있는 부분을 찾아내기 위함이다. 프로파일링을 할 수 있도록 도와주는 프로그램을 프로파일러라고 부른다.5 예전 버전의 크롬에는 화면 우상단에 렌치 모양의 아이콘이 있었지만, 현재는 三자 모양의 아이콘으로 변경되었다.6 크롬 개발자 툴은 CTRL+SHIFT+I를 이용하여 열 수도 있다.7 http://getfirebug.com8 https://developers.google.com/web-toolkit/speedtracer/
  4. 4. 기준점을 잡기 위해 타임라인을 이용하여 측정해 본 결과, 그러니까 페이지에 대한 최초요청으로부터 화면의 모든 구성요소가 브라우저에 그려지기까지의 시간을 측정해 보니,평균 1.25초가 소요되었다. 아주 느린 것은 아니었지만, 정보의 양이 그리 많지 않다는것을 생각하면 괜찮다고 할 수 없는 수준이다.이제 실행 속도를 좀 더 빠르게 하고 싶지만, 그러려면 정확히 어떤 이유 때문에 느려지는지를 알아야 한다. 이제 프로파일러의 도움을 받을 차례이다.프로파일 해보기타임라인을 보면 코드가 실행되는데 걸리는 시간을 알 수는 있지만, 어떤 이유로 그 정도의 시간이 소요되는지를 알 수는 없다. 코드를 조금씩 바꿔가면서 타임라인을 계속 측정해 볼 수는 있지만, 그것은 그저 때려 맞추는 정도라고밖에 할 수 없다. “Profiles” 탭을이용하면 실제로 어떤 일이 일어나는지를 드디어 확인해 볼 수 있게 된다.프로파일러를 이용하면 어떤 기능이 가장 시간을 많이 소비하는지를 알 수 있다. 이제프로파일 기준점을 잡기 위해 “Profiles” 탭을 이용하기로 해 보자. 프로파일러 탭에서 다
  5. 5. 음 세 가지 프로파일링 유형을 선택할 수 있다.1. JavaScript CPU profile: JavaScript 가 CPU 시간을 얼마나 소비하는지에대한 프로파일링 정보 수집2. CSS selector profile: CSS 셀렉터가 실행되는데 CPU 시간을 얼마나소비하는지에 대한 프로파일링 정보 수집3. Heap snapshot: JavaScript 객체에 의해 소비되는 메모리에 대한프로파일링 정보 수집지금 이 순간에는 JavaScript의 시간적 성능을 높이는 것이 목적이므로, JavaScript CPUprofile 을 사용할 것이다. 타임라인을 저장했던 것과 유사한 방법으로, “Profiles” 탭에서프로파일을 시작하고, 페이지를 갱신한 뒤, 프로파일을 종료하면 된다.프로파일링 결과를 얻고서 딱 느끼는 점은, 뭔가 굉장히 많다는 것이다. 우리가 만든 색상 정렬기는 jQuery와 jQuery UI를 이용하고 있는데, 이 라이브러리들 안에는 플러그인을관리한다거나 정규표현식을 파싱하는 등 수많은 작업을 수행하는 코드들이 포함되어 있다. 물론 우리가 작성한 코드인 decimalToHex 펑션과 makeColorSorter 펑션이 목록의 제일 위쪽에 포함되어 있는 것도 볼 수 있다. 이 두 펑션들이 합쳐서 13.2%의 CPU 시간을
  6. 6. 소비하는데, 이 부분이 코드의 성능을 향상시키는 작업을 위한 좋은 시작점이 될 수 있 을 것이다.9 펑션의 옆에 있는 검은색 삼각형을 클릭하면 해당 펑션에 대한 콜 스택을 확인할 수 있 다. decimalToHex 옆의 삼각형을 클릭해보니, makeColorSorter가 decimalToHex를 호출했 으며, makeColorSorter는 $(document).ready가 호출한 것으로 표시된다. 실제 코드는 다 음과 같다. $(document).ready(function() { makeColorSorter(.05, .05, .05, 0, 2, 4, 128, 127, 121); makeSortable(); }); 이 펑션들이 어디에서 호출되었는지를 확인해보니, 색상을 정렬할 수 있도록 하는 기능10 이 성능을 좀먹는 주된 요인이 아니라는 것을 알게 되었다. 보통은 정렬 가능한 요소들 을 추가하는 데에 더 많은 시간을 소비하지만, 이 코드에서는 DOM 11 엘리먼트를 생성하 는 데 더 많은 시간을 소비하고 있다는 얘기다. 이제 범인을 찾았으니 튜닝을 시작하려 한다. 하지만 그 이전에, 앞으로 수정할 내용이 다른 코드에 영향을 받거나 끼치지 않도록 고립하고 싶다. 페이지가 로딩되기 위해 수많 은 일들이 일어나는데, 튜닝을 하고 프로파일링을 하는 과정에서 이들에 대해 신경 쓰고 싶지 않기 때문이다. 문제 지점 고립시키기 도큐먼트(document)가 준비(ready) 되었을 때 색상 정렬기를 로딩하는 대신에, 버튼 하나 를 클릭한 뒤에야 색상 정렬기가 로딩되도록 하는 두 번째 버전을 만들려 한다. 이렇게 함으로써, 우리의 관심사가 도큐먼트의 로딩으로부터 고립(isolate)될 수 있게 되고, 좀 더9 단순히 CPU 점유율이 높다는 이유만으로 튜닝이 대상이 되는 것은 아니지만, 좋은 시작점이 될수는 있다.10 여기서는 makeSortable() 펑션11 Document Object Model. DOM은 W3C에서 개발한 규격으로, HTML이나 XML 문서의 정보를객체화하여 관리할 수 있도록 설계되어 있다. DOM에 대한 상세한 설명은http://en.wikipedia.org/wiki/Document_Object_Model를 참조하기 바란다.
  7. 7. 쉽게 프로파일링을 할 수 있게 된다. 나중에 성능 튜닝이 끝나고 나면 이 부분만 예전방식으로 돌려놓기만 하면 된다.아래와 버튼을 클릭해서 색상 정렬기가 동작하도록 “clickMe” 버튼과 testColorSorter() 펑션을 작성하기로 하자.function testColorSorter() { makeColorSorter(.05, .05, .05, 0, 2, 4, 128, 127, 121); makeSortable();}<button id="clickMe" onclick="testColorSorter();">Click me</button>코드를 수정한 뒤 프로파일링을 다시 해 보지 않으면, 예측하지 못한 방향으로 성능 문제가 바뀌어 질 수도 있다. 물론 이 정도 수정은 별 문제 없어 보이지만, 그래도 뭔가 잘못 바꾼 것이 있는지 확인하기 위해 다시 한 번 프로파일링을 해 보자. 위에서 해 본 방법으로 프로파일 저장 버튼을 이용하여 새로운 프로파일을 저장해 보았다.
  8. 8. 딱 보니, 다시 프로파일링을 해 본 결과도 decimalToHex가 4.23%로 가장 오랜 시간을소비한 것으로 나타났다. 이제 다시 한 번 타임라인을 확인하여 새로운 기준점을 확인해보도록 하자.버튼을 클릭하기 전에 몇 가지 이벤트가 발생하긴 하지만, 지금 우리가 관심을 가져야할 부분은 버튼이 클릭된 후부터 브라우저 화면에 색상 정렬기가 그려지기까지 어느 정도 시간이 소요되는지 이다. 마우스 버튼은 390ms에 클릭되었고, 그 뒤로 화면에 그리는작업은 726ms에 실행이 시작된 것을 알 수 있다. 726 – 390은 336이므로 새로운 기준점은 336ms가 된다. 물론 이 값은, 처음에 했던 것과 마찬가지로 타임라인을 세 번 측정하여 평균을 낸 결과이다.이제 어떤 코드가 문제가 있고, 그 코드가 얼마나 CPU 시간을 소비하는지 알게 되었다.이제부터 잘못된 부분을 수정하기로 해 보자.
  9. 9. 속도 개선하기 프로파일러는 어떤 펑션이 문제가 있는지를 알려줄 뿐이다. 그러므로 그 펑션이 왜 문제 가 있는지는 우리가 직접 알아보고 명확하게 이해해야 한다. function decimalToHex(d) { var hex = Number(d).toString(16); hex = "00".substr(0, 2 - hex.length) + hex; console.log(converting + d + to + hex); return hex; } 색상 정렬기 내에 포함된 하나하나의 원들은 16진수로 된(예를 들어 #86F01B나 #2456FE) 배경색 정보를 이용하여 색상이 표시된다. 이 값은 앞에서 두 자리씩 Red, Green, Blue 값을 표현하기 위한 것이다. 예를 들어, 의 배경색은 #2456FE인데, 이 값은 10진수로 R = 36, G = 85, B = 254이다. 물론 각각의 값은 0부터 255 사이의 정수이다. 코드를 보니 decimalToHex 펑션은 10진수 색상값을 받아 화면에 출력하기 위한 16진수 색상값으로 변환해주는 작업을 수행한다. 기능 자체는 매우 간단한데, 일단 콘솔에 로그 를 출력하는 코드를 제거하면 손쉽게 성능을 향상시킬 수 있을 것 같다. 로그 코드를 제거한 뒤 조금 더 자세히 보니, 16진수의 길이가 2자리가 안 될 경우 ‘0’을 왼쪽에 덧붙이는 작업 12을 수행하는 부분이 보인다. 13 이 기능 자체를 없앨 수는 없는 이 유는, CSS가 색상 처리를 하기 위해 16진수 값은 항상 두 자리로 이루어져야 하기 때문 이다. 즉, 10진수로 0부터 15까지의 수는 16진수로 한 자리 수(또는 문자)로 표시되는데, 이 경우 앞에 0을 붙여줘야 한다는 말이다. 이 코드를 삼항연산자를 이용하여 약간 수정 하면 다음과 같은 코드를 얻을 수 있다. function decimalToHex(d) { var hex = Number(d).toString(16); return hex.length === 1 ? 0 + hex : hex; }12 일반적으로 이런 작업을 패딩(padding)이라고 한다. 왼쪽에 덧붙이는 것을 LPAD, 오른쪽에 덧붙이는 것을 RPAD라고 한다.13 “hex = "00".substr(0, 2 - hex.length) + hex;“ 코드를 말한다. 분명히 성능이 떨어지는방법이지만, if문을 사용하는 방법보다 참신하긴 하다.
  10. 10. 세 번째 버전 14 은 필요한 경우에만 패딩을 수행하고, 쓸데없이 substr을 실행하지 않도록 변경한 것이다. 이 버전을 이용하여 다시 프로파일링을 수행해보니 이제 실행 시간이 137ms로 줄어든 것을 확인할 수 있다. 그리고 이제 decimalToHex 펑션이 전체 시간 중 0.04%만을 차지하는 것을 확인할 수 있다. – 목록의 아래쪽으로 내려간 것이다. 이제 jQuery의 e.extend.merge가 목록의 가장 위에 있고 가장 오랜 시간을 소비하는 것 을 알 수 있다. 하지만 이 펑션이 정확히 어떤 작업을 수행하는지 알기 어려운데, 그 이14 다음과 같이 바꾸는 것과 이 코드는 어떤 것이 더 빠를까? return d < 16 ? 0 + hex : hex;
  11. 11. 유는 jQuery가 최소화(minimized)되어 있기 때문이다. 15 jQuery의 개발자 버전을 이용하 여 확인해 볼 수도 있지만, 생각해보니 makeColorSorter 펑션이 e.extend.merge 펑션을 호출하는 것 같다. 그렇다면 이제 makeColorSorter를 튜닝 해보기로 하자. 컨텐츠 변경을 최소화하기 색상 정렬기의 무지개빛 색상들은 사인(sine) 곡선을 이용하여 만들어졌다. 코드는 색상 스펙트럼의 중심점을 확인하고 그 지점부터 지정된 너비까지 어떤 파형(wave)를 생성한 다. 이렇게 하면 색상이 무지개빛으로 만들어지는 것이다. 물론 Red, Green, Blue의 주파 수(frequency)를 변경함으로써 무지개빛 색상을 바꿀 수도 있다. function makeColorSorter(frequency1, frequency2, frequency3, phase1, phase2, phase3, center, width, len) { for (var i = 0; i < len; ++i) { var red = Math.floor(Math.sin(frequency1 * i + phase1) * width + center); var green = Math.floor(Math.sin(frequency2 * i + phase2) * width + center); var blue = Math.floor(Math.sin(frequency3 * i + phase3) * width + center); console.log(red: + decimalToHex(red)); console.log(green: + decimalToHex(green)); console.log(blue: + decimalToHex(blue)); var div = $(<div class="colorBlock"></div>); div.css(background-color, # + decimalToHex(red) + decimalToHex(green) + decimalToHex(blue)); $(#colors).append(div); } } 튜닝을 시작했으면, 당연히 로그 코드를 먼저 제거한다. 이런 류의 로그 코드는 불필요한 데, 생각해보면 decimalToHex 펑션에서도 동일한 로그를 출력했으니 두 번 이상 쓸데없15 그리고 일반적으로 사용한 외부 라이브러리는 튜닝을 대상이라고 보기 어렵다.
  12. 12. 는 로그 부하를 준 것이다.코드를 보니 뭔가 DOM에 많은 작업을 하는 것 같다. 매 for문을 순회하면서 colors라는객체에 새로운 div 태그를 입력하는 것이 보인다. 이것이 e.extend.merge를 그렇게 많이호출하는 범인일까? 프로파일러를 이용하면 간단한 실험으로 이것을 확인할 수 있다.아래처럼 코드를 변경하여, div 태그가 for문 안에서 #colors에 추가되는 것이 아니라, 일단 colors라는 문자열에 추가하고, 최종적으로 colors 문자열을 #colors에 한 번만 추가하도록 변경해보자.function makeColorSorter(frequency1, frequency2, frequency3, phase1, phase2, phase3, center, width, len) { var colors = ""; for (var i = 0; i < len; ++i) { var red = Math.floor(Math.sin(frequency1 * i + phase1) * width +center); var green = Math.floor(Math.sin(frequency2 * i + phase2) * width +center); var blue = Math.floor(Math.sin(frequency3 * i + phase3) * width +center); colors += <div class="colorBlock" style="background-color: # + decimalToHex(red) + decimalToHex(green) + decimalToHex(blue) +"></div>; } $(#colors).append(colors);}코드를 아주 조금만 변경하였지만, DOM에 대한 변경은 단 한 번으로 제한된다. 변경된코드를 이용하여 타임라인을 확인해보니 이제 실행속도가 31ms로 줄어든 것을 확인할수 있다. DOM을 한 번만 수정하는 네 번째 버전을 이용했더니 약 87%의 성능 향상이있었던 것이다. 다시 한 번 프로파일러로 확인해보면 e.extend.merge 펑션이 목록에서보이지 않을 만큼 빨라졌음을 확인할 수 있다.다시 생각해보니 decimalToHex 펑션을 사용할 필요도 없는 것 같다. CSS 16진수 색상 코드 대신 10진수를 사용할 수 있기 때문이고, 이것을 이용하면 굳이 10진수를 16진수로변경할 필요도 없기 때문이다. decimalToHex 펑션을 제거한 makeColorSorter 펑션은 다음과 같다.
  13. 13. function makeColorSorter(frequency1, frequency2, frequency3, phase1, phase2, phase3, center, width, len) { var colors = ""; for (var i = 0; i < len; ++i) { var red = Math.floor(Math.sin(frequency1 * i + phase1) * width + center); var green = Math.floor(Math.sin(frequency2 * i + phase2) * width + center); var blue = Math.floor(Math.sin(frequency3 * i + phase3) * width + center); colors += <div class="colorBlock" style="background-color: rgb( + red + , + green + , + blue + )"></div>; } $(#colors).append(colors); } 다섯 번째 버전을 이용하면 전에는 28라인을 이용했던 코드가 26ms가 걸리는 18라인 코 드로 변경된 것을 확인할 수 있을 것이다. 결론16 물론 실제 어플리케이션은 색상 정렬기보다 훨씬 복잡할 것이지만, 프로파일링과 튜닝을 수행하는 기본적인 방법은 크게 다르지 않다. 1. 기준점 세우기: 튜닝을 어디서부터 시작할지를 알 수 있다. 2. 문제점 분리하기: 튜닝의 대상이 되는 코드에만 집중할 수 있게 된다. 3. 튜닝하기: 코드를 수정해 가면서 지속적으로 타임라인과 프로파일을 확인하여 성능을 향상시킨다. 성능 튜닝을 위한 몇 가지 규칙이 있는데 다음과 같다.16 이 문서는 JavaScript를 튜닝하는 방법에 대해 설명하고 있지만, 튜닝 방법에 대한 기본적인 규칙은 모든 언어에 적용될 수 있다. 동일한 방법이 Java, 혹은 C# 언어로 만들어진 어플리케이션을튜닝하기 위해 적용될 수 있다.
  14. 14. 1. 가장 느린 것부터: 처음부터 가장 확실히 튜닝의 효과를 확인할 수 있다.2. 가외 환경을 통제하라: 컴퓨터를 바꾸었거나 코드에 뭔가 변경을 하였다면기준점을 다시 세워야 한다.3. 반복해서 분석하라: 몇몇 변칙들이 측정 결과를 왜곡하는 것을 막아야 한다.누구나 자신의 웹 사이트가 빠르게 동작하길 바란다. 반대로 웹 사이트에 새로운 기능을추가하고 새로운 기능을 추가하여 더 화려하게 만들기도 하는데, 이런 작업들은 대체로웹 사이트가 느려지게 만든다. 그래서 성능을 향상시키기 위해 그만큼의 시간적 인력적비용을 들여야 하는 것이다.프로파일링과 튜닝을 이용한 색상 정렬기 최종버전의 실행 시간은 92%의 성능 향상을이루어 냈다. 여러분의 웹 사이트는 얼마나 빨라질 수 있을까?

×