Was verursacht den vierfachen Leistungsverlust von Go bei diesem Array-Zugriffs-Mikrobenchmark (im Vergleich zu GCC)?

WBOY
Freigeben: 2024-02-10 08:51:09
nach vorne
608 Leute haben es durchsucht

在这个数组访问微基准测试中(相对于 GCC),Go 的性能损失了 4 倍,是什么原因造成的?

In diesem Array-Zugriffs-Mikrobenchmark (relativ zu GCC) erleidet Go einen 4-fachen Leistungsverlust. Was verursacht das? Dieses Problem betrifft viele Aspekte wie den Laufzeitmechanismus und die Compileroptimierung der Go-Sprache. Erstens verwendet die Go-Sprache beim Zugriff auf Arrays einen Grenzprüfungsmechanismus, dh bei jedem Zugriff auf ein Array-Element werden Grenzprüfungen durchgeführt, was zu einem gewissen Leistungsverlust führt. Zweitens ist der Go-Sprachcompiler relativ schwach optimiert und kann den Array-Zugriff nicht gut optimieren. Darüber hinaus hat der Garbage-Collection-Mechanismus der Go-Sprache auch einen gewissen Einfluss auf die Leistung. Zusammengenommen führten diese Faktoren dazu, dass Go im Array-Zugriffs-Mikrobenchmark einen vierfachen Leistungsverlust erlitt.

Frageninhalt

Ich habe diesen Mikrobenchmark geschrieben, um die Leistungsmerkmale von go besser zu verstehen, damit ich fundierte Entscheidungen darüber treffen kann, wann ich es verwenden möchte.

Aus Sicht des Performance-Overheads wäre dies meiner Meinung nach ein ideales Szenario für go:

  • Keine Zuteilung/kostenlos innerhalb der Schleife
  • Array-Zugriff liegt offensichtlich innerhalb der Grenzen (Grenzüberprüfung kann entfernt werden)

Trotzdem sah ich einen 4-fachen Geschwindigkeitsunterschied im Vergleich zu gcc -o3 auf amd64. Warum das?

(Verwenden Sie das Shell-Timing. Es dauert jedes Mal ein paar Sekunden, daher ist der Start vernachlässigbar)

package main

import "fmt"

func main() {
    fmt.println("started");

    var n int32 = 1024 * 32

    a := make([]int32, n, n)
    b := make([]int32, n, n)

    var it, i, j int32

    for i = 0; i < n; i++ {
        a[i] =  i
        b[i] = -i
    }

    var r int32 = 10
    var sum int32 = 0

    for it = 0; it < r; it++ {
        for i = 0; i < n; i++ {
            for j = 0; j < n; j++ {
                sum += (a[i] + b[j]) * (it + 1)
            }
        }
    }
    fmt.printf("n = %d, r = %d, sum = %d\n", n, r, sum)
}
Nach dem Login kopieren

c-Version:

#include <stdio.h>
#include <stdlib.h>


int main() {
    printf("started\n");

    int32_t n = 1024 * 32;

    int32_t* a = malloc(sizeof(int32_t) * n);
    int32_t* b = malloc(sizeof(int32_t) * n);

    for(int32_t i = 0; i < n; ++i) {
        a[i] =  i;
        b[i] = -i;
    }

    int32_t r = 10;
    int32_t sum = 0;

    for(int32_t it = 0; it < r; ++it) {
        for(int32_t i = 0; i < n; ++i) {
            for(int32_t j = 0; j < n; ++j) {
                sum += (a[i] + b[j]) * (it + 1);
            }
        }
    }
    printf("n = %d, r = %d, sum = %d\n", n, r, sum);

    free(a);
    free(b);
}
Nach dem Login kopieren

Update:

  • Bei bestimmungsgemäßer Verwendung range kann die Fahrgeschwindigkeit um das Zweifache erhöht werden.
  • Andererseits ist -march=native 将 c 速度提高了 2 倍。 (并且-mno-sse给出编译错误,显然与-o3in ​​meinen Tests
  • nicht kompatibel)
  • rangegccgo sieht hier gleichwertig mit gcc aus (und erfordert kein
  • )

Lösung

Sehen Sie sich die Assembler-Ausgabe des C-Programms und des Go-Programms an. Zumindest bei den Go- und GCC-Versionen, die ich verwendet habe (1.19.6 bzw. 12.2.0), ist der direkteste und offensichtlichste Unterschied, dass GCC C-Programme automatisch vektorisieren, was der Go-Compiler offenbar nicht kann.

-march=nativeDies erklärt auch gut, warum Sie eine vierfache Leistungssteigerung feststellen würden, da GCC SSE anstelle von AVX verwendet, wenn es nicht auf eine bestimmte Architektur abzielt, was bedeutet, dass skalare 32-Bit-Anweisungen viermal so breit sind, um damit zu arbeiten. Tatsächlich führte das Hinzufügen von

zu einer zweifachen Leistungsverbesserung, da GCC dadurch AVX-Code auf meiner CPU ausgab.

Ich bin mit Go nicht gut genug vertraut, um Ihnen sagen zu können, ob der Go-Compiler grundsätzlich nicht in der Lage ist, automatisch Vektoren zu erstellen, oder ob es nur dieses spezielle Programm ist, das aus irgendeinem Grund den Fehler verursacht, aber das scheint die Hauptursache zu sein 🎜

Das obige ist der detaillierte Inhalt vonWas verursacht den vierfachen Leistungsverlust von Go bei diesem Array-Zugriffs-Mikrobenchmark (im Vergleich zu GCC)?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:stackoverflow.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!