Warum wird in den Speicher geschrieben wird viel langsamer voran, als es zu Lesen?

Hier ist eine einfache memset Bandbreite benchmark:

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

int main()
{
    unsigned long n, r, i;
    unsigned char *p;
    clock_t c0, c1;
    double elapsed;

    n = 1000 * 1000 * 1000; /* GB */
    r = 100; /* repeat */

    p = calloc(n, 1);

    c0 = clock();

    for(i = 0; i < r; ++i) {
        memset(p, (int)i, n);
        printf("%4d/%4ld\r", p[0], r); /* "use" the result */
        fflush(stdout);
    }

    c1 = clock();

    elapsed = (c1 - c0) / (double)CLOCKS_PER_SEC;

    printf("Bandwidth = %6.3f GB/s (Giga = 10^9)\n", (double)n * r / elapsed / 1e9);

    free(p);
}

Auf meinem system (details siehe unten) mit einem DDR3-1600-Speicher-Modul Ausgänge:

Bandbreite = 4.751 GB/s (Giga = 10^9)

Ist dies 37% der theoretischen RAM-Geschwindigkeit: 1.6 GHz * 8 bytes = 12.8 GB/s

Auf der anderen Seite, hier ist ein ähnliches "Lesen" test:

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

unsigned long do_xor(const unsigned long* p, unsigned long n)
{
    unsigned long i, x = 0;

    for(i = 0; i < n; ++i)
        x ^= p[i];
    return x;
}

int main()
{
    unsigned long n, r, i;
    unsigned long *p;
    clock_t c0, c1;
    double elapsed;

    n = 1000 * 1000 * 1000; /* GB */
    r = 100; /* repeat */

    p = calloc(n/sizeof(unsigned long), sizeof(unsigned long));

    c0 = clock();

    for(i = 0; i < r; ++i) {
        p[0] = do_xor(p, n / sizeof(unsigned long)); /* "use" the result */
        printf("%4ld/%4ld\r", i, r);
        fflush(stdout);
    }

    c1 = clock();

    elapsed = (c1 - c0) / (double)CLOCKS_PER_SEC;

    printf("Bandwidth = %6.3f GB/s (Giga = 10^9)\n", (double)n * r / elapsed / 1e9);

    free(p);
}

It-Ausgänge:

Bandbreite = 11.516 GB/s (Giga = 10^9)

Kann ich nah an die theoretische Grenze für die lese-performance, wie XORing eine große Auswahl, aber das schreiben scheint viel langsamer. Warum?

OS Ubuntu 14.04 AMD64 (ich kompiliere mit gcc -O3. Mit -O3 -march=native macht die lese-performance etwas schlechter, aber keinen Einfluss auf memset)

CPU Xeon E5-2630 v2

RAM Einem einzigen "16GB PC3-12800-Parity REG CL11 240-Pin DIMM" (das, Was es sagt, auf der box) ich denke, dass ein einzelnes DIMM-Modul macht die Leistung besser vorhersagbar. Ich gehe davon aus, dass mit 4 DIMMs, memset werden bis zu 4 mal schneller.

Motherboard Supermicro X9DRG-QF (Unterstützt 4-Kanal-Speicher)

Zusätzliche system: Ein laptop mit 2x 4GB DDR3-1067 RAM: Lesen und schreiben sind beide etwa 5,5 GB/s, aber beachten Sie, dass es verwendet 2 DIMMs.

P. S. ersetzen memset mit dieser version werden die Ergebnisse in genau der gleichen Leistung

void *my_memset(void *s, int c, size_t n)
{
    unsigned long i = 0;
    for(i = 0; i < n; ++i)
        ((char*)s)[i] = (char)c;
    return s;
}
  • printf("%4d/%4ld\r", p[0], r); in deinem Maßstab bedeutet, dass Sie wahrscheinlich Zeit, eher als alles andere. I/O ist langsam.
  • Nein! printf genannt wird 101 mal in ein Programm, das läuft für 20 Sekunden
  • Gibt es eine paging-Auftritt?
  • In dem code, den Sie geschrieben es sollte als das 100-fache. Es gibt keinen Grund für es zu sein in dem Teil des Codes, den Sie sind benchmarking.
  • Es ist gute Praxis, um die "Verwendung" der Ergebnisse Ihrer benchmark-Berechnungen, da sonst der compiler kann zu umgehen, aber die ganze Berechnung (in vielen Fällen, je nach den Besonderheiten). Außerdem bietet es "Fortschritte", so dass Sie wissen, wie lange zu warten.
  • Ich versuchte es auf meinem system mit und ohne printf in der Schleife. Der Unterschied war kleiner als ich erwartet hatte (3 mal). Mit, ich habe 9.644, 9.667 und 9.629, ohne bekam ich 9.740, 9.614 und 9.653
  • Wahrscheinlich eine Frage der cache-policy (das Prozessor-spezifisch).
  • Mein 2010 alte MacBook Berichte 1.937 GB/s ohne Optimierung, und 173010.381 GB/s mit Optimierung mit der gepostet code, unverändert 🙂 wahrscheinlich das memset schreibt, um eine cache-Zeile, die Sie zuerst Lesen aus dem RAM-cache, um verändert zu werden, und dann gespült, so dass jeder cache-Zeile gelesen + geschrieben und nicht nur Lesen. Die Verbleibende Differenz wird wahrscheinlich durch das Lesen von/schreiben auf nicht zusammenhängenden Orten. PowerPC hatte die Anweisungen zum löschen von cache-Zeilen, die geholfen hätten.
  • 11.5 GB/s für XORing. Im ernst, printf ist hier vernachlässigbar. Daran habe ich nie gedacht. Ich bin überrascht, die Leute sind besessen mit es hier.
  • In jedem Multiprozessor-Umgebung die Aufrechterhaltung der cache-Kohärenz verursacht, schreibt langsamer als liest, insgesamt.
  • was ist dein compiler? Unterbindung der Optimierungen in einer trivialen benchmark ist ein interaktiver Prozess. Sie wahrscheinlich benötigen, um die "Verwendung" der Ergebnisse mehr irgendwie.
  • Dies ist single-threaded. Wenn Sie denken, dass Ihr Kommentar noch gilt, vielleicht poste es als Antwort?
  • Ich fügte hinzu, ein "Lesen" - benchmark auf die Frage.
  • es gibt kein swapping (verifiziert mit free-m). Das Programm ordnet 1GB auf einem system mit 16GB RAM
  • Ich kann nicht reproduzieren Sie Ihre timing-Unterschied auf meinem Rechner. Im Gegenteil, Ihre xor-Bank ist sogar noch ein bisschen langsamer. Hast du kompilieren mit -O3 -march=native? Auch, für die gleiche Optimierung, die klappern in der Lage ist, zur Optimierung der loop völlig aus für die memset benchmark.
  • Mit -O3 -march=native macht die lese-performance etwas schlechter, aber keinen Einfluss auf memset für mich (bearbeitet die Frage)
  • BTW, Sie sind nicht mess-schreib-performance, aber die performance Ihres memset in der C-Bibliothek (vermutlich glibc) auf Ihre Architektur.
  • Ich wäre daran interessiert, dass dieser benchmark beim kompilieren und ausführen auf einem PC mit FreeDOS-32 als OS. So, der overhead von der virtuellen Speicherverwaltung und paging können dadurch weitgehend vermieden werden.
  • CLOCKS_PER_SEC wird ganz gewiss haben Sie den falschen Wert. Moderne Prozessoren bekommen eine mehr oder weniger dynamische Uhr, es kann sehr stark variieren. Man wird Lesen müssen, um den aktuellen (!) Uhr-Wert, der unmittelbar, bevor Sie es verwenden - aber das funktioniert nur, wenn Ihr Programm ist SEHR schnell .. in der Tat, man müsste Lesen Sie den Wert nach JEDEM PROZESSOR-SCHRITT, aber das ist sehr schwer umzusetzen und würde die Ausbeute nur geringe Genauigkeit-Verbesserungen
  • CLOCKS_PER_SEC hat einen irreführenden Namen, aber seine (Konstanten) Wert ist definiert der C-standard. Ich bezweifle ernsthaft, dass es "falsch"ist.
  • Das ist ein benchmark Vergleich zwischen einem standard-library-Funktion (memset) und Ihre eigenen Funktion (do_xor), nicht zwischen Leseoperation und Schreiboperation.
  • Ich habe eine version mit meiner eigenen Implementierung memset
  • Wenn der C-library-version von memset ist wirklich gleich um die, die Sie geben, ist Ihre installation nicht bekommen, es richtig zu machen. Auf modernen Architekturen, sollte dies anspruchsvoller als die und zu kombinieren, schreibt die nachfolgenden Speicher und Dinge wie, dass. Also das kocht mehr und mehr nach unten, um ein problem mit der Konfiguration dann alles andere. Jede "Antwort" auf deine Frage wäre rein spekulativ. Vielleicht sollten Sie es schließen.
  • warum ist ein Buch zu schreiben, viel langsamer als das Lesen ein? har... das schreiben ist zu finden zugewiesenen Raum und notieren Sie, wo dieser Raum ist für beim Lesen. Lesen genau anschaut, dass die Platte wie ein Inhaltsverzeichnis und die Erträge auf diesen Standorten, die, wie Sie wissen, können Sie nicht zusammen in einem Stück.
  • Für raw-Speicher Lesegeschwindigkeit fand ich es viel genauer zu Lesen, immer 8 bytes in Schritten von 64 bytes (oder wahtever Ihre CPUS cacheline ist). Dies bewirkt, dass alle Speicher übertragen L2, mit minimaler CPU-Auslastung. Ich weiß nicht viel darüber, wie das schreiben funktioniert im detail, aber vielleicht ein ähnlicher Mechanismus kann verwendet werden, um reduzieren alle overhead.
  • Diese Frage scheint off-topic, denn es macht schon eine falsche Behauptung in der Frage-Titel. Es ist viel Architektur abhängig und es kann nicht immer eine eindeutige Antwort.
  • Es kann sicherlich sein, eine klare Antwort: nämlich, "Ihre Annahme ist falsch, es ist Architektur abhängig und hier sind einige der Faktoren, mit Nachweis". Es ist eine sinnvolle Frage, da dieser Fehleinschätzung kommen immer wieder.

InformationsquelleAutor MaxB | 2014-09-13
Schreibe einen Kommentar