C# Benchmark Erstelen

roi

Lieutenant
Registriert
Sep. 2007
Beiträge
759
Hi, ich möchte einen benchmark erstelllen der die bandbreite des rams und die geschwindigkeit der CPU vergleicht, ich habe mich jetzt schon einige zeit damit beschäftigt, finde aber irgendwie keinen richtigen ansatz. wichtig ist das der Benchmark beliebigviele CPUs und Beliebig viel Ram addressieren können muss

wie fang ich am besten an ?

gruß roi
 
Ich würde sagen, dass C# nicht ganz die richtige Sprache dafür ist, da immer der Compiler dazwischen ist und das ergebnis verfälscht. (Ok ist bei allen dazwischen, aber ich _glaube_ trotzdem dass es ein Problem ist.)

Ansonsten kannst du eigentlich einfach irgendwas tun lassen (rechnen, RAM vollschreiben) und die Zeit messen.

Für Multicores wirst du Multithreading brauchen, ist aber auch so sinnvoll einen Arbeiterthread zu benutzen. Dazu kannst du dir ja mal in der MSDN den Namespace System.Threading anschauen.

mfg
 
Zuletzt bearbeitet: (thrEading ;))
danke schonmal für die tipps schonmal

das C# "eigendlich" nicht die richtige sprache ist weiss ich , aber es geht genau darum verschiedene plattformen zu vergleichen wielange
Windows 2003 .net
Linux 64 Mono
und AIX Mono
und Linux auf POWER Mono

obs überhaupt geht

vorallem auch CPU power und Speicher bandbreite, da reicht einfaches ram voll machen nicht

edit es geht nicht um einen hoch wissenschaftlichen vergleich, nur um eine tendenz
 
Zuletzt bearbeitet:
Ich habe mich zwar noch nie mit diesem Thema beschäftigt, aber ich denke, es müsste doch relativ einfach sein, die Leistung einer CPU zu messen. Und zwar lässt du eine nicht ganz triviale Berechnung durchführen und misst die Zeit, die die CPU zum berechnen braucht. Damit der Unterschied deutlich sichtbar wird, lässt du die Berechnung dann mithilfe einer for-Schleife eine Million Mal (oder wie viel auch immer, musst du dann halt gucken) wiederholen.
 
das habe ich auch erst gedacht das problem ist (das hab ich auf meine 3 ghz c2d ) gemerkt:die CPUS sind zu schnell für sowas, wenn ich einen eine schleife packe und die so oft ausführen lasse wie ein integer großs ist, dann schaft der das in so kurzer zeit das es quasi nicht messbar ist :D bei einer "double" anzahl schleifen druchläufe ist es das gleiche

den ein C2 d hat immerhin schon 3 millarden takte pro sekunde und kann mehrere operationen gleichzeitig ausführen

und das problem ist bei den neuen prozessoren ja auch, das sie die nächste berechnung "erraten" können und dadurch einfach zählen noch viel schneller geht als sowieso schon :D

es gibt natührlich funktionen, die die CPU auslasten können, aber besonders bei dem ganzen exponenzial kram steigt ja der rechenaufwand eben exponential und dadurch kann man schlecht messen

es ist echt garnicht so einfach die CPU auszulasten :-D
 
Zuletzt bearbeitet:
>> die CPUS sind zu schnell für sowas

Welche Berechung hast du denn durchführen lassen? Doch wohl keine simple Addition, Subtraktion, Multiplikation oder Division? Man muss es nur komplex genug machen, dann sollte es auch möglich sein. Irgendetwas Schönes mit vielen Klammern, vielen Potenzberechnungen, vielen Radizierungen und so weiter. Das Ganze dann noch wie gesagt unzählige Male wiederholen.
 
das problem an potenzen ist doch wie gesagt das nicht jeder rechenschrit gleich aufwendig ist und dadurch nicht wirklich messbar

es gibt wahrscheinlich irgendeine ganz einfache lösung dafür aber ich hab grad ein brett vorm kopf

edit was mir bei exponentialfunktionen usw passiert ist halt auch das die datentypen schnell voll sind :D

zu große datentypen will ich auch vermeiden, da ich ja die CPU leistung messen möchte und nicht einfach wie schnell er in den speicher schreiben kann
 
Zuletzt bearbeitet:
roi schrieb:
das habe ich auch erst gedacht das problem ist (das hab ich auf meine 3 ghz c2d ) gemerkt:die CPUS sind zu schnell für sowas, wenn ich einen eine schleife packe und die so oft ausführen lasse wie ein integer großs ist, dann schaft der das in so kurzer zeit das es quasi nicht messbar ist :D bei einer "double" anzahl schleifen druchläufe ist es das gleiche
Die meisten modernen CPUs haben Taktzähler und Befehle um diese zu lesen. Damit kann man die Dauer kurzer Programmabläufe messen, nur eben nicht in Sekunden sondern erstmal in Takten. Google mal nach RDTSC befragen, falls du auf einem x86-Rechner arbeitest.
 
der benchmark soll auf einem X86, einem IA64 und einem POWER rechner laufen
 
Wenn es dir um die Performance der .NET libaries geht, kannst du doch die inkludierten Klassen und Funktionen verwenden. Ich schlage dir mal eine Testsuite bestehend aus TripleDES / AES / anderer häufig verwendeter Cipher verschlüsseln/entschlüsseln (System.Cryptography), Quicksorten einer sehr langen Liste (k.a. ob Quicksort implementiert ist; die Collections.Sort()-Methoden dürften Quicksort verwenden, das ist aber nur single-threaded), verschiedene Bildrekompressionen (musst du vermutlich für den Benchmark selbst implementieren), für den Speicher einen einfachen Suchtest (erst Speicher von x bis y mit Zufallsdaten füllen, dann eine bestimmte Bitfolge suchen) und zur Abrundung des Ganzen noch evtl. Public Key-Krypto aus dem System.Cryptography-namespace. Sicherlich kein perfekter oder auch nur besonders guter Benchmark, aber der Aufwand zur Erstellung hält sich in Grenzen und die Tendenz wird stimmen.
Ebenfalls interessant wäre folgendes: Programm von einer C++-Hostapplikation aufrufen, welche die Zeit vom Aufruf der .exe bis zur Ausführung des ersten C#-Codeteils misst und damit die Performance des JIT-Compilers testet.

Weil du sagtest, dass du bei deinen "Schleifentests" keine messbaren Ergebnisse hattest: Evtl. hat der Compiler ja in seinen Augen "sinnlose" Berechnungen wegoptimiert? Die Erfahrung, dass es schwer möglich wäre, mit selbstgeschriebenen Programmen die CPU auszulasten, kann ich nicht bestätigen ... ganz im Gegenteil, wenn ich unkonzentriert C# programmiere ist die Performance oft sehr schnell unterm Hund.

Poste doch deine Ergebnisse

LG Alexander
 
Na damit lässt sich doch was anfangen, an verschlüsselungen hab ich noch garnicht gedacht, vielen dank. Messen wielange der JIT braucht werd ich auch mal

Das mit den ergebnissen wird noch was dauern, jetzt ist erstmal wochenende :-D

und das mit dem Wegoptimieren der schleifen stimmt wahrscheinlich

mfg Roi
 
Zuletzt bearbeitet:
>> das problem an potenzen ist doch wie gesagt das nicht jeder rechenschrit gleich aufwendig ist und dadurch nicht wirklich messbar

Ich verstehe nicht ganz. Wo ist das Problem bei Potenzberechnungen?
 
wenn du zb 2 ^1 berchnest dann 2^2 dannn 2^3 wird die berechnugn mti jedem rechenschrit um ein vielfaches aufwändiger, dann kann ich zwar die rechenschritte zählen, aber weiss immernoch nicht wieviel schneller es wirklich wird
 
Habe ich jetzt einen Denkfehler oder du? Es ist doch vollkommen egal, ob die Berechnungen zunehmend aufwendiger werden. Du misst doch einfach die Zeit, die die CPU braucht, um deinen Benchmark auszuführen. Je kürzer die Zeit, desto größer die Leistung der CPU.
 
ich hab den denkfehler

ich bin jetzt davon ausgegangen, den benchmark x minuten laufenzulassen und zu gucken wieviel geschafft wurde
 
1.) Wenn man einfach etwas sinnloses in einer for-Schleife laufen lässt, dann kann man ganz schön überrascht werden. Ein guter Compiler wird dir da einfach alles streichen, was er für nicht sinnvoll erachtet. Beispiel in Visual C++:

#define max 1024*1024*1024

for(uint32 i=0;i<max;i++)
{
for(uint32 j=0;j<max;j++);
}

Was glaubt ihr, wie lange das läuft? Genau 0ms, weil der Compiler das wegoptimiert. IN VB.NET ca. 7 Takte/Durchlauf

Weiteres Beispiel:

#define max 1024*1024*1024

byte *data=new data[];

for(uint32 i=0;i<max;i++)
data=123;

Wie lange läuft die Schleife? Immerhin tut er ja was. Wenn man es einfach 1:1 in Assembler zerlegt kommt ca. sowas raus (sehr vereinfacht, ich weiß dass es sich so nicht ausführen lässt):

'ANFANG

loadx data 'Cache Zugriff
loady i 'Cache Zugriff
addx y
store 123 dwordx 'Cache Zugriff

loadx i 'Cache Zugriff
comparex max
branchifx ANFANG

'ENDE

Sollten also mindestens 10-20 Takte sein (Cache Zugriff ist normal mindestens 3 Takte). In Wirklichkeit läuft es bei mir ca. 100ms (bei 10GB/s RAM-Bandbreite). In VB.NET wird das sicher auch deutlich langsamer gehen.

C# ist so eine Mischung zwischen C/C++ und VB.NET, also wird es damit auch um ein Eck langsamer gehen.

2.) Wenn du einen Benchmark machen willst, dann brauchst du eine halbwegs reale Anwendung, sonst testest du nur den Compiler. Mit einem 10-Zeiler wirst du damit nicht auskommen. Der richtige Unterschied kommt ja erst zum Tragen, wenn man alle Features des OS wirklich ausschöpft z.B. 4 Threads parallel, synchronisierte Speicherzugriffe, Threads starten/stoppen, neue Prozesse erzeugen, Daten von einem Prozess zum anderen Schaufeln mit Pipes, Implementierung von DirectX und OpenGL mit ihren jeweiligen Features, Datenbankzugriffe, Zugriffe auf Festplatten random, sequentiell, kopieren von einer Platte zur anderen etc, da das Caching auch des OS macht.

Bei einer CPU kommt es hauptsächlich darauf an, wie gut sie ihren Cache verwalten kann. Du kannst also nicht nur 1KB an Daten bearbeiten, alles sequentiell oder random Reads über den RAM (wo kein Data Prefetching stattfinden kann) usw. Ein gutes Data Prefetching erkennt z.B. Zugriffe, die in regelmäßigen Intervallen quer verteilt über den Speicher erfolgen z.B. alle 815Bytes auslesen. Dann kommt auch noch die Branch Prediction zum Tragen, also kurze Schleifen dürfen nicht sein, die sich oft wiederholen oder per Zufallszahl gesteuert. Selbst die Ergebnisse von SPEC kann man in die Tonne treten, obwohl das schon konkrete Anwendungen sind. Es gibt so viele Effekte, an die man vorher nie gedacht hat. Ich habe mir z.B. gedacht ich mache mir einen schnellen Zufallszahlenalgorithmus, wo ich die Bits irgendwie quer vertausche und füge das in einen Baum ein. Dann habe ich einen echten Algorithmus genommen und siehe da es war 3 mal so langsam, obwohl man vorher schon nichts regelmäßiges gesehen hat. Weiters hat das Freigeben von Speicher ewig lange gedauert (ca. 100 mal so lang wie normal), wenn man über 100MB in kurzer Zeit freigegeben hat und das in der selben Reihenfolge, wie man es angefordert hat usw.

3.) Richtige Low Level Benchmarks werden immer mit dem Assembler geschrieben, weil man nicht will, dass es möglichst schnell abläuft, sondern dass man genau einen spezifischen Befehl testet z.B. das dividieren und da ist es nicht sehr hilfreich, wenn der Compiler aus jedem x/2 ein x>>1 macht bzw. aus jedem "Durchmesser=Umfang/PI" ein "Durchmesser=Umfang*(1/PI)", wobei 1/PI eine Konstante ist, die der Compiler schon im Code ersetzt.
 
Zurück
Oben