Speicherbandbreite für x86-Systeme mit vielen Kanälen

Lesezeit: 5 Minuten

Benutzeravatar von Z boson
Z-Boson

Ich teste die Speicherbandbreite auf einem Desktop und einem Server.

Sklyake desktop 4 cores/8 hardware threads
Skylake server Xeon 8168 dual socket 48 cores (24 per socket) / 96 hardware threads

Die Spitzenbandbreite des Systems beträgt

Peak bandwidth desktop = 2-channels*8*2400 = 38.4 GB/s
Peak bandwidth server  = 6-channels*2-sockets*8*2666 = 255.94 GB/s

Ich benutze meine eigene Triadenfunktion von STREAM um die Bandbreite zu messen (vollständiger Code später)

void triad(double *a, double *b, double *c, double scalar, size_t n) {
  #pragma omp parallel for
  for(int i=0; i<n; i++) a[i] = b[i] + scalar*c[i];
}

Hier sind die Ergebnisse, die ich bekomme

         Bandwidth (GB/s)
threads  Desktop  Server         
1             28      16
2(24)         29     146
4(48)         25     177
8(96)         24     189 

Für 1 Thread verstehe ich nicht, warum der Desktop so viel schneller ist als der Server. Laut dieser Antwort https://stackoverflow.com/a/18159503/2542702 reicht SSE aus, um die volle Bandbreite eines Dual-Channel-Systems zu erhalten. Das ist, was ich auf dem Desktop beobachte. Zwei Threads helfen nur geringfügig und 4 und 8 Threads ergeben ein schlechteres Ergebnis. Aber auf dem Server ist die Single-Thread-Bandbreite viel geringer. Warum ist das?

Auf dem Server bekomme ich die besten Ergebnisse mit 96 Threads. Ich hätte gedacht, dass es mit weit weniger Threads gesättigt wäre. Warum sind so viele Threads notwendig, um die Bandbreite auf dem Server zu sättigen? Es gibt eine große Fehlerspanne in meinen Ergebnissen und ich füge keine Fehlerschätzung hinzu. Ich habe das beste Ergebnis aus mehreren Läufen geholt.

Der Code

//gcc -O3 -march=native triad.c -fopenmp
//gcc -O3 -march=skylake-avx512 -mprefer-vector-width=512 triad.c -fopenmp
#include <stdio.h>
#include <omp.h>
#include <x86intrin.h>

void triad_init(double *a, double *b, double *c, double k, size_t n) {
  #pragma omp parallel for
  for(size_t i=0; i<n; i++) a[i] = k, b[i] = k, c[i] = k;
}

void triad(double *a, double *b, double *c, double scalar, size_t n) {
  #pragma omp parallel for
  for(size_t i=0; i<n; i++) a[i] = b[i] + scalar*c[i];
}

void triad_stream(double *a, double *b, double *c, double scalar, size_t n) {
#if defined ( __AVX512F__ ) || defined ( __AVX512__ )
  __m512d scalarv = _mm512_set1_pd(scalar);
  #pragma omp parallel for
  for(size_t i=0; i<n/8; i++) {
    __m512d bv = _mm512_load_pd(&b[8*i]), cv = _mm512_load_pd(&c[8*i]);
    _mm512_stream_pd(&a[8*i], _mm512_add_pd(bv, _mm512_mul_pd(scalarv, cv)));
  }        
#else
  __m256d scalarv = _mm256_set1_pd(scalar);
  #pragma omp parallel for
  for(size_t i=0; i<n/4; i++) {
    __m256d bv = _mm256_load_pd(&b[4*i]), cv = _mm256_load_pd(&c[4*i]);
    _mm256_stream_pd(&a[4*i], _mm256_add_pd(bv, _mm256_mul_pd(scalarv, cv)));
  }        
#endif
}

int main(void) {
  size_t n = 1LL << 31LL; 
  double *a = _mm_malloc(sizeof *a * n, 64), *b = _mm_malloc(sizeof *b * n, 64), *c = _mm_malloc(sizeof *c * n, 64);
  //double peak_bw = 2*8*2400*1E-3; // 2-channels*8-bits/byte*2400MHz
  double peak_bw = 2*6*8*2666*1E-3; // 2-sockets*6-channels*8-bits/byte*2666MHz
  double dtime, mem, bw;
  printf("peak bandwidth %.2f GB/s\n", peak_bw);

  triad_init(a, b, c, 3.14159, n);
  dtime = -omp_get_wtime();
  triad(a, b, c, 3.14159, n);  
  dtime += omp_get_wtime();
  mem = 4*sizeof(double)*n*1E-9, bw = mem/dtime;
  printf("triad:       %3.2f GB, %3.2f s, %8.2f GB/s, bw/peak_bw %8.2f %%\n", mem, dtime, bw, 100*bw/peak_bw);

  triad_init(a, b, c, 3.14159, n);
  dtime = -omp_get_wtime();
  triad_stream(a, b, c, 3.14159, n);  
  dtime += omp_get_wtime();
  mem = 3*sizeof(double)*n*1E-9, bw = mem/dtime;
  printf("triads:      %3.2f GB, %3.2f s, %8.2f GB/s, bw/peak_bw %8.2f %%\n", mem, dtime, bw, 100*bw/peak_bw);
}

  • Ein großer Unterschied zwischen dem Skylake-Server und dem Skylake-Desktop-Prozessor ist die Verbindung zwischen den Kernen. Der Desktop-Prozessor hat eine Ringbus-Verbindung, während der Server-Prozessor ein Mesh-Netzwerk zwischen den Kernen hat. Broadwell-Server-CPUs hatten auch einen Ringbus, aber diese Lösung ist für höhere Kernzahlen nicht sehr skalierbar. Tatsächlich ist der Vorteil des Mesh-Netzwerks von Skylake-SP die große Skalierbarkeit, aber die Single-Thread-Speicherbandbreite ist sehr enttäuschend.

    – Wim

    28. Juni 2019 um 10:19 Uhr

  • Siehe auch diese Beschreibung des Speichersubsystems Skylake-SPund die Testergebnissewas bestätigt, dass die Single-Thread-Speicherbandbreite gering ist.

    – Wim

    28. Juni 2019 um 10:36 Uhr


  • @Zboson: Danke für das Kompliment. TBH, ich glaube, ich bin nicht genug Experte für Speichersubsysteme, um eine endgültige Antwort zu geben. Ich verstehe, dass eine Mesh-Verbindung skalierbarer ist als ein Ringbus, aber warum konnten sie keine Mesh-Verbindung mit mindestens der gleichen Single-Thread-DRAM-Speicherbandbreite wie eine Broadwell-Server-CPU entwerfen? Hätte das zu viel Silizium oder zu viel Strom (Wärme) gekostet? Ich kann nur raten. Mit AVX-512 möchten Sie eigentlich mehr Bandbreite als mit AVX2, nicht weniger.

    – Wim

    28. Juni 2019 um 13:07 Uhr

  • ….(Fortsetzung) Beachten Sie, dass die begrenzte Single-Thread-Bandbreite es einfacher macht, skalierbare Rechenergebnisse zu erzielen. (Was mich an das bekannte Papier erinnert Zwölf Möglichkeiten, die Massen zu täuschen, wenn es um Leistungsergebnisse auf parallelen Computern geht und Goerg Hagers Blog, Die Massen täuschen.)

    – Wim

    28. Juni 2019 um 13:08 Uhr


  • @wim: Nun ja, weil Single-Threaded-Bandbreite auf SKX noch mehr Mist ist als auf BDW-EP. Und im Gegensatz zu BDW beinhaltet das leider L3-Bandbreite (laut Mystcial). Aber mein Punkt war, dass die Form der Kurve bei BDW-EP anders wäre: schneller Aufstieg zu einem Plateau und vielleicht ein Rückgang, wie ZBoson es auf SKL-Client sieht. Statt fast asymptotischer Annäherung an max.

    – Peter Cordes

    29. Juni 2019 um 17:49 Uhr

1419410cookie-checkSpeicherbandbreite für x86-Systeme mit vielen Kanälen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy