Vergleich der Leistung von Collectors.summingLong und Collectors.counting

8

Benchmarks werden unter intel core i5, Ubuntu

ausgeführt %Vor%

Ich vergleiche die Leistung von Collectors.counting und Collectors.summingLong(x -> 1L) . Hier ist der Maßstab:

%Vor%

Ich habe das Ergebnis, dass Collectors.counting 3 mal langsamer Collectors.summingLong .

Also habe ich es mit -prof perfnorm mit 25 Gabeln laufen lassen. Hier ist das Ergebnis:

%Vor%

Was mir aufgefallen ist:

branches , instructions , cycles unterscheidet sich fast dreimal. Auch Cache-Operationen. Äste scheinen gut vorhergesagt, auch nicht zu viel Cache vermisst (nur meine Meinung).

Das Problem könnte also beim kompilierten Code liegen. Habe es mit -prof perfasm (zu lange, um es hier zu setzen).

Im kompilierten Code habe ich folgendes bemerkt:

I. Collectors.summingLong Montage

Wir haben 3 Schleifen, die durch das Array iterieren und zählen. Zuerst zählt nur ein Element

%Vor%

Second zählt 4 Elemente für 1 Iteration (Ist diese Schleife entrolling?) und auch nach dem ersten.

%Vor%

Und der dritte zählt den Rest der Elemente.

II . Collectors.counting Assembly

Wir haben nur eine Schleife, die alle Elemente eins nach dem anderen zählt (nicht abgerollt). Außerdem haben wir die Boxen-Konvertierung in die Schleife des Ergebnisses des Zählens integriert. Auch scheinen wir die Boxen-Konvertierung innerhalb der Schleife nicht eingeplant zu haben.

%Vor%

scheint Boxing der 1L in Lambda e -> 1L durchzuführen. Aber das ist nicht klar warum. Beim Ausführen der tatsächlichen Addition haben wir diesen Code:

%Vor%

Außerdem speichern wir das Ergebnis des Zählens im Stack mov %r10d,0x10(%rsp) anstelle des Heaps wie im ersten Fall.

Wenn ich richtig verstanden habe, was vor sich geht, habe ich

FRAGE: Führt das Loop-Entrollen mit Box-Conversions zu dreimaliger Verlangsamung? Wenn ja, warum runtime runtime die Schleife nicht in der counting -Fall?

Beachten Sie, dass Collectors.summingLong 2,5 mehr GC-Druck hat als Collectors.counting . Das ist nicht ganz klar (ich konnte nur vermuten, dass wir Zwischenwerte im Stapel in Collectors.counting speichern).

%Vor%     
St.Antario 30.01.2018, 12:05
quelle

1 Antwort

7

Ich habe die Assembly nicht angesehen oder analysiert, aber ein Blick auf die Quellen liefert bereits einige Informationen.

summingLong() führt zu diesem Kollektor:

%Vor%

counting() führt dazu:

%Vor%

Wie Sie sehen können, macht die counting() Version noch einiges mehr:

  • Boxen
  • ruft op.apply(...) auf

Da op ist Long::sum , das auf primitiven verwendet wird, gibt es eine Menge Boxen und Unboxing invoved.

    
Thomas 30.01.2018, 12:17
quelle

Tags und Links