2016-07-24 28 views
-2

Es wird schwierig sein, dies zu erklären. Ich brauchte drei Tage, um es herauszufinden.Unheimlichste Fehler, die ich je erlebt habe. Mögliches V8-Optimierungsproblem?

Ich mache eine Serialisierungsbibliothek und ich versuche es schnell zu machen. Alles, was es tut, ist Objekte zu und von einem Puffer zu serialisieren.

Mir ist aufgefallen, dass wenn ich meinen Benchmark zuerst laufen würde, würde es ungefähr 500 Millisekunden dauern, um zu kodieren. Wenn ich jedoch zuerst meine Testsuite ausführen würde, würde mein Benchmark danach etwa 1300 Millisekunden benötigen, um zu kodieren.

Das war extrem komisch, weil sie mit zwei völlig verschiedenen Objekten arbeiteten und überhaupt nichts gemeinsam hatten.

Ich ging durch mein Programm und begann, jede einzelne Zeile zu benchmarken, bis ich schließlich die Zeile gefunden habe, die den Unterschied von 800 ms berücksichtigt.

Es war diese Zeile in einer Funktion: for (var j = arrLen; j < refLen; j++) {

Nicht der Körper der entweder Schleife. Nur der Header der for-Schleife.

Ich hatte keine Ahnung, wie es zu beheben ist. Kürzlich habe ich aus reiner Laune versucht, die Funktion zu duplizieren (einfach zu kopieren und einzufügen) und umzubenennen, um eine 0 am Ende des Namens einzufügen.

Ich hatte dann meine Testsuite die erste Funktion aufrufen und meine Benchmark die zweite Funktion aufrufen. Der Zeitunterschied ist verschwunden. Der Funktionsinhalt und die Parameterliste sind genau gleich.

Meine führende Theorie ist: Wenn diese Funktion das erste Mal aufgerufen wird, ist die Funktion optimiert und ich schätze, die Schleife wird abgerollt. Aus diesem Grund hat der Aufruf des Benchmarks nicht das Problem: Weil das erste Mal aufgerufen wird, wird es optimiert. Wenn Sie es später aufrufen, ist es jedoch nicht für die gegebenen Eingaben optimiert und läuft daher sehr langsam.

Meine Frage ist: kurz von nur Kopieren und Einfügen dieser Funktion Tausende von Malen und jeder codieren verwenden eine andere Version dieser Funktion, gibt es eine Möglichkeit, dieses Problem zu beheben, um den Zeitunterschied zu entfernen? Ein Unterschied zwischen 500 Millisekunden und 1300 Millisekunden ist enorm.

Ich habe versucht, einen Testfall davon zu machen, aber es ist extrem schwierig, weil dieser Fehler so unklar ist. Hoffentlich war meine Textbeschreibung genug.

Bearbeiten: Hier ist die Funktion aufgerufen wird.

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); 
    } 
    } 
} 

Edit 2: Der Ansatz der manuell die Funktion als String auszuschreiben, evaling, und dann, dass Aufruf scheint das Leistungsproblem zu beheben. Da ich nicht herausfinden kann, wie man den Testfall isoliert, nehme ich an, dass ich dies nur als Verbandsfix verwenden werde.

+2

Hören Sie nicht auf Benchmarks. https://www.youtube.com/watch?v=65-RbBwZQdU Sie sind ein Geheimnis für sich. – Rudie

+0

@Rudie: Ich habe auch vergessen zu erwähnen: Ich habe dies mit 'console.time',' benchmark.js' und mit meiner eigenen 'process.hrtime' Lösung verglichen.Dieses Problem tritt bei allen drei auf. Es ist ein sehr reales Problem, das sehr reale Leistungsverluste verursacht. –

+0

@ChronBag, eine Funktion wird nach etwa 100-150 Aufrufen mit konsistenten Eingaben für die Optimierung markiert. Der Motor versucht nicht, alles zu optimieren, was in Sichtweite ist. Ich habe noch nie gehört, dass Loops in JS entrollt sind, aber ich kann mich irren. Ich würde eher denken, dass sich die Arten von "Start" oder "Len" geändert haben. vielleicht von (signed !!) 'int32' zu' float'? Oder haben Sie mit dem Bottlenect einen Fehler und einer der Typen im Loop-Body hat sich in Ihrem Benchmark geändert, was dazu geführt haben könnte, dass v8 die Funktion deaktiviert hat? Könnten Sie einen Code posten/verlinken? – Thomas

Antwort

0

Sie können Deopt genau begegnen, weil Ihr Benchmark und Test, wie Sie erwähnt haben, mit zwei völlig verschiedenen Objekten arbeiten. Siehe http://mrale.ph/blog/2015/01/11/whats-up-with-monomorphism.html für Details, hoffe es hilft.

+0

Ich habe gerade überprüft, und selbst wenn ich das gleiche Objekt verwende, tritt das Problem immer noch auf. Ich werde trotzdem den Artikel lesen. Könnte eine andere Einsicht bieten. –