Wie Cache ungültig zu machen, wenn das Benchmarking?
-
30-09-2019 - |
Frage
Ich habe diesen Code, dass, wenn Vertauschen der Reihenfolge der UsingAs und UsingCast, ihre Leistung auch Swaps.
using System;
using System.Diagnostics;
using System.Linq;
using System.IO;
class Test
{
const int Size = 30000000;
static void Main()
{
object[] values = new MemoryStream[Size];
UsingAs(values);
UsingCast(values);
Console.ReadLine();
}
static void UsingCast(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int sum = 0;
foreach (object o in values)
{
if (o is MemoryStream)
{
var m = (MemoryStream)o;
sum += (int)m.Length;
}
}
sw.Stop();
Console.WriteLine("Cast: {0} : {1}", sum,
(long)sw.ElapsedMilliseconds);
}
static void UsingAs(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int sum = 0;
foreach (object o in values)
{
if (o is MemoryStream)
{
var m = o as MemoryStream;
sum += (int)m.Length;
}
}
sw.Stop();
Console.WriteLine("As: {0} : {1}", sum,
(long)sw.ElapsedMilliseconds);
}
}
Ausgänge:
As: 0 : 322
Cast: 0 : 281
Wenn dies zu tun ...
UsingCast(values);
UsingAs(values);
... Such folgt aus:
Cast: 0 : 322
As: 0 : 281
Wenn gerade dabei diesen ...
UsingAs(values);
... Such folgt aus:
As: 0 : 322
Wenn gerade dabei diese:
UsingCast(values);
... Such folgt aus:
Cast: 0 : 322
Abgesehen von ihnen unabhängig läuft, wie man Invalidier der Cache so der zweite Code gebenchmarkt wird nicht die im Cache gespeicherte Erinnerung an ersten Code erhalten?
Benchmarking beiseite, liebte die Tatsache, dass moderne Prozessoren diese Caching Magie tun: -)
[EDIT]
Wie empfohlen, diesen schnelleren Code zu versuchen, (angeblich) ...
static void UsingAsAndNullTest(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int sum = 0;
foreach (object o in values)
{
var m = o as MemoryStream;
if (m != null)
{
sum += (int)m.Length;
}
}
sw.Stop();
Console.WriteLine("As and null test: {0} : {1}", sum,
(long)sw.ElapsedMilliseconds);
}
... Das Ergebnis ist dieses:
As and null test: 0 : 342
Langsamer als die beiden Codes oben
[EDIT]:
Wie geraten jede Routine ihre eigene Kopie zur Hand ...
static void UsingAs(object[] values)
{
object[] a = values.ToArray();
Stopwatch sw = Stopwatch.StartNew();
int sum = 0;
foreach (object o in a)
{
if (o is MemoryStream)
{
var m = o as MemoryStream;
sum += (int)m.Length;
}
}
sw.Stop();
Console.WriteLine("As: {0} : {1}", sum,
(long)sw.ElapsedMilliseconds);
}
static void UsingCast(object[] values)
{
object[] a = values.ToArray();
Stopwatch sw = Stopwatch.StartNew();
int sum = 0;
foreach (object o in a)
{
if (o is MemoryStream)
{
var m = (MemoryStream)o;
sum += (int)m.Length;
}
}
sw.Stop();
Console.WriteLine("Cast: {0} : {1}", sum,
(long)sw.ElapsedMilliseconds);
}
... Ausgang:
Cast: 0 : 282
As: 0 : 282
Jetzt haben sie die gleichen Ergebnisse, dank Remus!
Running Cast und als unabhängig ergeben sie auch das gleiche Ergebnis (d. 282). Nun, wie, warum sie werden schneller (von 322 bis 282 Millisekunden), wenn sie ihre eigene Kopie des Arrays übergeben werden, kann ich nichts draus machen kann :-) Das ist eine ganz andere Geschichte
Lösung
Wenn Sie im Bild-Cache die L2 herauszunehmen und die TLB-Fehler dann rufen Sie einfach den zweiten Test auf einem anderen Memorystream von der gleichen Größe.