Wir haben einen einfachen Benchmark für den Arbeitsspeicherdurchsatz. Alles was es tut, ist wiederholt für einen großen Speicherblock zu speichern.Warum ist Skylake so viel besser als Broadwell-E für Singlethread-Speicherdurchsatz?
Mit Blick auf die Ergebnisse (für 64-Bit kompiliert) auf einigen verschiedenen Maschinen, Skylake-Maschinen deutlich besser als Broadwell-E, Betriebssystem (Win10-64), Prozessorgeschwindigkeit und RAM-Geschwindigkeit (DDR4-2133) das Gleiche. Wir sprechen nicht ein paar Prozentpunkte, sondern eher einen Faktor von etwa 2. Skylake ist zweikanalig konfiguriert, und die Ergebnisse für Broadwell-E variieren nicht für Dual/Triple/Quad-Channel.
Irgendwelche Ideen, warum dies passieren könnte? Der Code, der in Release in VS2015 kompiliert folgt, und meldet durchschnittliche Zeit, um jede Memcpy abzuschließen an:
64-Bit: 2,2 ms für Skylake vs 4.5ms für Broadwell-E
32-Bit : 2,2 ms für Skylake vs 3,5 ms für Broadwell-E. Wir können einen größeren Speicherdurchsatz auf einem Vierkanal-Broadwell-E-Build erreichen, indem wir mehrere Threads verwenden, und das ist nett, aber ein so drastischer Unterschied für den Single-Thread-Speicherzugriff ist frustrierend. Irgendwelche Gedanken darüber, warum der Unterschied so ausgeprägt ist?
Wir haben auch verschiedene Benchmark-Software verwendet, und sie validieren, was dieses einfache Beispiel zeigt - single-threaded Speicherdurchsatz ist viel besser auf Skylake.
#include <memory>
#include <Windows.h>
#include <iostream>
//Prevent the memcpy from being optimized out of the for loop
_declspec(noinline) void MemoryCopy(void *destinationMemoryBlock, void *sourceMemoryBlock, size_t size)
{
memcpy(destinationMemoryBlock, sourceMemoryBlock, size);
}
int main()
{
const int SIZE_OF_BLOCKS = 25000000;
const int NUMBER_ITERATIONS = 100;
void* sourceMemoryBlock = malloc(SIZE_OF_BLOCKS);
void* destinationMemoryBlock = malloc(SIZE_OF_BLOCKS);
LARGE_INTEGER Frequency;
QueryPerformanceFrequency(&Frequency);
while (true)
{
LONGLONG total = 0;
LONGLONG max = 0;
LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds;
for (int i = 0; i < NUMBER_ITERATIONS; ++i)
{
QueryPerformanceCounter(&StartingTime);
MemoryCopy(destinationMemoryBlock, sourceMemoryBlock, SIZE_OF_BLOCKS);
QueryPerformanceCounter(&EndingTime);
ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;
ElapsedMicroseconds.QuadPart *= 1000000;
ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;
total += ElapsedMicroseconds.QuadPart;
max = max(ElapsedMicroseconds.QuadPart, max);
}
std::cout << "Average is " << total*1.0/NUMBER_ITERATIONS/1000.0 << "ms" << std::endl;
std::cout << "Max is " << max/1000.0 << "ms" << std::endl;
}
getchar();
}
Entspricht die Memcpy-Bibliotheksfunktion von MSVC einer Strategie, die auf CPUID oder anderem basiert? z.B. AVX-Schleife gegen 'rep movsb' Haben Sie sichergestellt, dass beide Puffer für alle Tests mindestens 64B-ausgerichtet sind? Hast du die Leistungsindikatoren überprüft, um zu sehen, ob du irgendwelche TLB-Fehler oder nur L3-Cache-Fehler bekommst? (Skylake kann zwei TLB-Wanderungen parallel machen). Ist Ihr Broadwell-E ein Multi-Socket-System (NUMA)? –
Haben Sie das BIOS Ihres Broadwell-Systems überprüft, um sicherzustellen, dass der Prefetch nicht deaktiviert ist oder so? Konnten Sie sich mit anderen Broadwell- oder Haswell-Desktop-Systemen vergleichen? (Ausschließen, dass auf der spezifischen Broadwell-Maschine, an der Sie testen, etwas seltsam ist). –
2.2ms zu kopieren 23.8MiB ist etwa 10.6GiB/s jeweils lesen und schreiben, für gemischte lesen + schreiben. Intel sagt [Skylake i5-6600] (http://ark.intel.com/products/88188) (und andere SKL-Modelle mit DDR4-2133) haben eine theoretische maximale Speicherbandbreite von 34,1 GB/s (oder 31,8 GiB/s). Selbst wenn jede Ladung und jeder Speicher in L3 fehlt und in den Hauptspeicher gehen muss, ist das nur etwa 2/3 des theoretischen Maximums. Das kann für einen einzelnen Thread jedoch normal sein. –