2016-07-24 2 views
-2

설명하기가 어려울 것입니다. 알아내는 데 3 일이 걸렸습니다.내가 만난 가장 이상한 버그. V8 최적화 문제가 있습니까?

저는 serialization 라이브러리를 만들고 있는데, 빨리 만들려고합니다. 버퍼간에 객체를 직렬화하는 것뿐입니다.

벤치 마크를 먼저 실행하면 인코딩하는 데 약 500 밀리 초가 걸리는 것으로 나타났습니다. 그러나 테스트 스위트를 먼저 실행하면 벤치 마크 이후에 인코딩하는 데 약 1300 밀리 초가 걸릴 것입니다.

전혀 다른 두 개의 개체로 작동했기 때문에 매우 이상했습니다.

필자는 내 프로그램을 살펴본 후 모든 단일 회선의 벤치마킹을 시작하여 마침내 800 밀리 초 차이를 계산하는 회선을 찾았습니다. 없음 루프의 몸체 중 for (var j = arrLen; j < refLen; j++) {

:

그것은 기능이 행 하였다. for 루프의 헤더.

나는 그것을 고치는 법을 몰랐습니다. 최근에 그냥 침묵에 제외하고 그냥 복사하여 붙여 넣기 기능을 복제하고 이름의 끝에 0을 포함하도록 이름을 바꾸려고했습니다.

그런 다음 테스트 스위트에서 첫 번째 함수를 호출하고 벤치 마크에서 두 번째 함수를 호출하게했습니다. 시차가 사라졌습니다. 함수 내용과 매개 변수 목록은 완전히 동일합니다.

내 주요 이론은 다음과 같습니다.이 함수를 처음으로 호출하면 함수가 최적화되고 루프가 풀린 것으로 추측됩니다. 벤치 마크를 먼저 호출하는 것이 문제가되지 않는 이유는 이것이 처음으로 최적화 된 것이기 때문입니다. 그러나 나중에 호출하면 주어진 입력에 맞게 최적화되지 않으므로 실제로 느리게 실행됩니다.

나의 질문은 : 단지이 기능을 복사하여 붙여 넣기가 번거롭지 않고 각각의 인코딩에이 기능의 다른 버전을 사용하는 것이 부족합니다. 시간 차이를 제거하는 방법으로이 문제를 해결할 방법이 있습니까? 500 밀리 초와 1300 밀리 초 사이의 차이는 엄청납니다.

저는이 테스트 사례를 만들려고했지만이 버그가 너무 애매하기 때문에 매우 어렵습니다. 바라기를 나의 텍스트 설명으로 충분했다.

편집 : 다음은 호출되는 함수입니다.

function endEncodeArray(ref, arrLen, writeRepeatFunction, wBuffer) { 
    var refLen = ref.length; 
    if (refLen - arrLen > 0) { 
    for (var j = arrLen; j < refLen; j++) { // <-- this line slow 
     writeRepeatFunction(ref[j], wBuffer); 
    } 
    } 
} 

편집 2 : 수동으로 문자열로 함수를 작성하는 그것을 evaling 다음 해당 전화의 접근 방식은 성능 문제를 해결하기 위해 보인다. 테스트 케이스를 분리하는 방법을 파악할 수 없으므로 이걸 붕대 고정으로 사용한다고 가정합니다.

+2

벤치 마크를 경청하지 마십시오. https://www.youtube.com/watch?v=65-RbBwZQdU 그들은 혼자 미스테리입니다. – Rudie

+0

@ 루디 : 나는 또한 언급하는 것을 잊어 버렸다 : 나는 이것을'console.time','benchmark.js' 그리고 내 자신의'process.hrtime' 솔루션으로 벤치마킹했다.이 문제는 세 가지 모두에서 발생하는 것으로 나타납니다. 매우 실제 성능 손실을 일으키는 매우 실질적인 문제입니다. –

+0

@ChronBag, 함수는 최적화를 위해 일관된 입력으로 약 100-150 호출 후에 표시됩니다. 엔진은 시야 범위 내에있는 모든 것을 최적화하려고 시도하지 않습니다. 나는 들어 본 적이 없다. 그 루프는 JS에서 전개되지만, 틀릴 수도있다. 나는'start' 나'len'의 타입이 바뀌 었다고 생각하고 싶습니다. 어쩌면 (서명 !!)'int32'에서'float'까지? 아니면 병목 현상이 잘못되어 루프 바디의 유형 중 하나가 벤치 마크에서 변경되었으므로 v8에서 해당 기능을 사용 중지했을 수 있습니까? 일부 코드를 게시/링크 할 수 있습니까? – Thomas

답변

0

위에서 언급 한 벤치 마크 및 테스트가 완전히 다른 두 가지 개체로 작동하기 때문에 deopt에 정확하게 직면 할 수 있습니다. 자세한 내용은 http://mrale.ph/blog/2015/01/11/whats-up-with-monomorphism.html을 참조하십시오. 도움이되기를 바랍니다.

+0

방금 ​​확인한 결과 동일한 개체를 사용하더라도 문제가 계속 발생합니다. 나는 아직도 기사를 읽을 것이다. 다른 통찰력을 제공 할 수도 있습니다. –

관련 문제