벤치마킹과 튜닝
var start = (new Date()).getTime();
var end = (new Date()).getTime();
console.log( "Duration:", (end - start) );
// 결과 Duration: 0문제점
1. 0으로 표시 즉 1밀리 초도 안되는 시간동안 실행이 끝났다고 가정하기 때문에 부정확하다.
2. 결과 수치야 어떻든 작업을 딱 한번 실행할때 정도만 알수 있다.
3. 시간이 나왔다고 쳐도 start, end 타임 스탬프를 얻는 과정의 지연이 생길수도 있음
1. 반복
평균치만으로는
전체 애플리케이션의 성능에
관하여 결론을 내리기 어렵다.

왜곡을 좀더 상쇄하려면
최고의 샘플은 얼마나 느린지, 최고의 샘플을 얼마나 빠른지,
최악/최고 간 격차 등등..
1-1. Benchmark.js

똑똑한 사람들이 통계학적으로 검증된 도구를 만들어놨으니 가져다 쓰면 된다.
즉, 유의미한 벤치마킹은 반드시 통계적으로 검증
API 문서에 잘 정리되어있으니 API문서를 보고 잘활용하자
1-2. 엔진 최적화
var twelve = "12";
var foo = "foo";
// test 1
var X1 = parseInt( twelve );
var X2 = parseInt( foo );
// test 2
var Y1 = Number( twelve );
var Y2 = Number( foo );데이코드 제거라는 컴파일러의 최적화 옵션으로
두 테스트 모두 아무 일도 하지 않음
엔진 깊숙한 곳에서는 무슨 일이 벌어질지 알수 없다.
결정을 내릴 만한 구체적인 증거 또한 없다.
2. jsPerf.com
Benchmark.js는 자바스크립트 실행 환경에 구애받지 않고 코드 성능을 테스트 할 수 있지만 다양한 환경에서 테스트한 결과를 취합하기엔 어려움
즉, 일일이 다 결과를 취합해야 함
엔진마다 최적화된 방법이 달라 크롬에서 빠른 함수가 다른 브라우저에서 오히려 더 느릴 수도 있음
jsPerf는 이런 목적으로 개발된 사이트로 Benchmark.js 라이브러리를 이용하여
좀 더 믿음성 있는 테스트를 제공
2-1.정상적인 테스트
// Case 1
var x = [];
for (var i=0; i<10; i++) {
x[i] = "x";
}
// Case 2
var x = [];
for (var i=0; i<10; i++) {
x[x.length] = "x";
}
// Case 3
var x = [];
for (var i=0; i<10; i++) {
x.push( "x" );
}배열 x에 원소를 추가할때 성능의 영향을 알아보기 위한 테스트 하지만 이 테스트에서의 문제점은?
1. 반복은 Benchmark.js 에서 처리
2. x를 선언/초기화를 반복해서 해주는데 불필요하다.
3. 덩치큰 배열? 작은 배열? 어떤것에 대해 초점을 맞추려고 한것인지 다시한번 생각해봐야함
문제점
// Case 1
var x = ["John","Albert","Sue","Frank","Bob"];
x.sort();
// Case 2
var x = ["John","Albert","Sue","Frank","Bob"];
x.sort( function mySort(a,b){
if (a < b) return -1;
if (a > b) return 1;
return 0;
} );내장 sort와 커스텀 sort의 속도 비교 테스트
이 테스트의 문제점은?
1. mySort()가 인라인 함수 표현식인 이유로 테스트 반복시 함수 표현식도 함께 테스트 함 실제적으로 함수 표현식을 따로 선언으로 빼내 테스트하면 2~20% 더 느림
2. 인라인 함수 표현식의 생성 비용을 확인할 의도였다면 괜찮지만 아니라면 잘못된 테스트
문제점
// Case 1
var x = false;
var y = x ? 1 : 2;
// Case 2
var x;
var y = x ? 1 : 2;x를 강제 변환시 미치는 영향을 알아보기 위한 테스트
이 테스트의 문제점은?
1. case 1에서는 x의 false라는 값을 세팅하지만
case 2에서는 이 작업을 하지 않음
2. 좀 더 동등하게 하기 위해서는 x = undefined라는 값을 할당하는게 정확하지 않을까?
문제점
좋은 테스트를 작성하기 위해서는 의도적인지
비의도적인지를 분석하고 고민해봐야함
테스트와 상관없는 부분은 설정부분에서
미리 선언해 테스트에 포함하지 않는 것이 좋음
3. 미시성능
var foo = 41;
(function(){
(function(){
(function(baz){
var bar = foo + baz;
// ..
})(1);
})();
})();(function(){
(function(){
(function(baz){
var bar = 41 + baz;
// ..
})(1);
})();
})();렉시컬 스코프의 작동원리에 의해 컴파일러는 foo 변수를 아예 없애고 그 자리를 상수로 대체
function factorial(n) {
if (n < 2) return 1;
return n * factorial( n - 1 );
}
factorial( 5 ); // 120실제로 이 예제를 C 언어로 코딩하여 고급 최적화 옵션을 주고 컴파일하면 factorial을 상수 120으로 대체하고 함수를 통째로 날려버림 ㅋㅋ
function factorial(n) {
if (n < 2) return 1;
var res = 1;
for (var i=n; i>1; i--) {
res *= i;
}
return res;
}
factorial( 5 ); // 120js는 재귀 코드를 루프문으로 풀어버리는 습관이 이서 자바스크립트 코드는 임의로 다음과 같이 해석
그냥 개발자는 가장 논리에 맞게 코드를 작성하면 된다.
성능 최적화에 관해서라면 여러분은 자바스크립트 엔진을 능가할 수 없으니 꿈도 꾸지마라
시간 낭비다
3-1 똑같은 엔진은 없다
v8엔진에 딱 맞게 개발됐다 하더라도 수 년후..
엔진 일부의 작동 방식이 변경되면서 느렸던
코드가 빨라진다면?
4. Tail call Optimization
function foo(x) {
return x;
}
function bar(y) {
return foo( y + 1 ); // tail call
}
function baz() {
return 1 + bar( 40 ); // not tail call
}
baz(); // 42함수의 호출부가 다른 함수의 꼬리 부분에 있고 호출이 끝나면 더 이상 수행할 작업을 남기지 않는 방법 ES6가 보증하는 기능
쉽게 말해서 새 함수를 호출하려면 스택 프레임이라는 호출 스택을 쌓기 위해 별도의 메모리 할당이 필요하지만 TCO 능력을 갖춘 엔진은 새로운 스택 프레임을 생성하지 않고 재사용해 속도+메모리의 최적화 효과가 있다.
1. 테스트를 할때에는 통계적인 결과가 필요하므로Benchmark.js에게 맡겨라
2. 디바이스에 따라 다른 결과를 얻게 될 경우가 있으니 테스트는 jsPerf.com에게 맡겨라
3. 미시적인 세부분에 집착하지 말고 자바스크립트 엔진에게 맡겨라
4. TCO같은 최적화는 ES6부터 필수 구현 항목으로 자리 잡았으니 ES6에게 맡겨라
정리
벤치마킹과 튜닝 발표
By leejaemin
벤치마킹과 튜닝 발표
- 185