PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Profiling kontraproduktiv


Gast
2009-02-15, 14:58:42
Nach einer Unterhaltung mit einem recht bekannten Koder habe ich gesagt bekommen, daß Optimieren des Kodes nur auf der eigenen/einen Maschine einige Tücken mit sich bringen kann, weil die Architektur der Pipelines sich gelegentlich so stark verändert, daß man sich nur bei größeren optimierenden Umbauten eines Algorithmus sicher sein kann, daß es auf allen anderen CPUs auch Vorteile bringt. Sonst überhaupt nicht.

Selbst wenn man den Sondermüll Netburst außer Acht läßt.

Ist das richtig? Verändern sich die Pipelines selbst manchmal so stark, daß man mit zb. Profiling nur auf "i686" ausgerichtet auch ins Klo greifen kann?

Gemeint ist erstmal auch nur ANSI-C und nicht ASM. Wobei mich diesbezüglich auch ASM interessieren würde.
Gemeint sind GCC 4.3.3 + gprof und VC2008sp1.

Normalerweise habe ich die Algorithmen natürlich selbst optimiert, anschliessend aber versucht noch das bestmögliche für die i686-Allgemeinheit über den Kompiler rauszuholen. Bzw. versucht die obligatorischen 5% nicht zu verschenken. Damit sind NICHT CPU-spezifischen Optionen gemeint. Ist soetwas aber eher eine Falle als Hilfe?

Testen kann ich auf P-M und C2D. Was ist aber mit den ganzen P2, Bartons, Celerons, Phenoms2 und Sockel939 AMDs allgemein? Erweise ich denen eher einen Bärendienst damit? :(

Andererseits gibt es eine Garanite, daß wenn ich das vom Kompiler weitgehend unberührt lasse, ich da auf einer bestimmten nicht unverhältnismäßig absacke, obwohl der Kompiler auf einer anderen x86-Familie nur +- 2% ausmacht?
Sollte sich zb. so ein XnView Entwickler mindestens 5 Rechner in seinem Zimmerlein hinstellen? :(

Shink
2009-02-15, 20:56:06
Natürlich ist es möglich dass dein Programm auf einer anderen CPU langsamer läuft wenn du die Compileroptionen auf deinen C2D oder P-M optimierst. Extrembeispiel wäre hier z.B. der C7 (längere Pipeline und noch dazu in-order). AMD-Prozessoren sind da gar nicht so schlimm. Ob das sich überhaupt im einstelligen Prozentsatz auswirkt kommt natürlich darauf an was du eigentlich programmiert hast.

Hättest du auch P2, Barton und was weiß ich daheim wär die Frage was du dann machst: 10 Binaries zur Verfügung stellen? Macht eigentlich keiner.

Wenn du wirklich so heiß darauf bist niemanden zu benachteiligen kannst du den Sourcecode zur Verfügung stellen oder für eine VM entwickeln. Es gibt Gründe warum Java und Konsorten immer mehr aufholen.

Gast
2009-02-15, 23:53:17
Natürlich ist es möglich dass dein Programm auf einer anderen CPU langsamer läuft wenn du die Compileroptionen auf deinen C2D oder P-M optimierst.Genau das meinte ich aber nicht. Also nicht in dem Sinne, cpu-flags zu benutzen. So gesehen könnte es aber auch total falsch zu sein überhaupt irgendwelche flags zu benutzen. Oder man muß die Pipelines von jeweils 3 letzten Generationen bei jeweils AMD wie Intel erforschen, um sicher zu gehen. Irgendwie unlustig.

Wenn ich den Kode als open source freigebe bringt das nur etwas Leuten die ihn selbst kompilieren können. Das ist kein Problem (OSS) aber einen Nutzen haben dann die meisten der USER nicht davon.

Ja klar. Bei Java und Konsorten ist es auf jeder CPU gleich lahm. Da kann man sich das tiegrefende Optimieren ganz sparen.

Berni
2009-02-16, 00:30:38
Äh du meinst also, dass du den Code selbst für den jeweiligen Prozessor optimieren willst? Welche Spezialanwendung hast du denn, dass die Performance so dermaßen kritisch ist? Normal macht das niemand (außer für embedded devices oder wenn es um absolut kritische realtime-Systeme geht).

Gast
2009-02-16, 01:12:58
Äh du meinst also, dass du den Code selbst für den jeweiligen Prozessor optimieren willst?Nein. Ich optimiere es selbst so gut es geht und teste es auf dem was ich habe. Optimieren will ich das nur für bzw. ab i686. Also real ab Pentium2 aufwärts. Oder anders gesagt, ich will mir sicher sein, daß meine Optimierungen sich nicht auf eine bestimmte CPU-Familie negativ auswirken und der davor nicht optimierter Kode da schneller laufen könnte. Sowas nervt einfach.
wie sich so nach und nach rausstellt muß dabei nichtmal eine steinzeitliche Architektur leidtragend sein. Ich hab mir am Donnerstag die ersten AMD64 X2 angeschaut und es gegen den Lastverlauf auf einem Wolfdale vergliechen. Nicht einfach sowas :(

Welche Spezialanwendung hast du denn, dass die Performance so dermaßen kritisch ist?Die Performance ist nicht "kritisch", aber ich trace und optimiere meistens das was ich als Grundgerüst zusammenstelle. Für mich sollte das "normalerweise" jeder tun. Das bedeutet hier auch nicht, daß ich hinter der allerletzten Mikrosekunde her bin, aber nicht selten offenbaren sich Leerläufe im Kode die ich sonst nicht vermutet hätte. Also gehört sowas hier zum Pflichtprogramm.
Ich meine wie gesagt keine cpu-flags der Kompiler.

Nur scheint das durch unterschiedliche Pipelines auch kontraproduktiv sein zu können. Auch irgendwelche optimierungen an der Architektur eine Aglorithmus die ich auf dem C2D teste können einem Phenom überhaupt garnicht schmecken :|

Das hat mich jetzt die Tage aus dem Tritt gebracht, weil man sich eigentlich für nichts sicher sein kann und immer großflächige Feldtests veranstalten muß bevor was wirklich rauskommt.
Ich komme aus der UltraSPARC Ecke und da hat man das Theater nicht in dem Masse. Vom ersten 64bitter bis zum SPARC64 VII und gar Niagara.

Mich interessiert eben wie andere das machen oder was man hier darüber schon gehört hat. Sowas wie HashTab ist mit der Performance garantiert nicht an einem Abend entstanden. Das geht überall wirklich gut. Naja ich glaub ich setz mich genau mit dem Typen in Verbindung :)

Nacht

Coda
2009-02-16, 01:24:07
Profiling dient in erster Linie dazu rauszufinden welcher Code überhaupt die meiste Ausführungszeit verbraucht, und diesen dann falls möglich nochmal algorithmisch zu überdenken und dann evtl. bei sehr hartnäckigen Stellen noch SSE-Optimierungen und anderen Low-Level-Kram einzubauen.

Das ist beides normalerweise völlig Architekturunabhängig.

Ja klar. Bei Java und Konsorten ist es auf jeder CPU gleich lahm. Da kann man sich das tiegrefende Optimieren ganz sparen.
Wenn ich sowas schon lese.

Berni
2009-02-16, 01:40:18
Es gilt das Grundprinzip, dass man nur Stellen optimiert, die auch performancekritisch sind. Wenn sie das nicht sind, ist eine Optimierung Verschwendung der Arbeitszeit. Das heißt natürlich nicht, dass man deshalb verschwenderisch programmieren sollte und nicht tracen sollte.
Sinnvoll ist sicherlich das Einsetzen von Features wie SSE und MMX (sofern es für den Einsatzzweck geeignet ist). Für einige letzte paar Prozent macht Optimierung aber bei x86 keinen Sinn weil die Prozessoren intern unterschiedlich arbeiten (wie du ja bereits bemerkt hast). Bzw. Sinn macht es schon, aber dann nur bei absoluten Spezialanwendungen und dann setzt man auch eher direkt Assembler ein. Bei geschlossenen Plattformen wie Konsolen oder eben dein SPARC mag das anders sein.

Ich glaube im Übrigen auch nicht, dass HashTab soweit optimiert. Effiziente Hashalgorithmen gibt es im Übrigen in diversen OpenSource-Bibliotheken (z.B. OpenSSL) und da braucht man das Rad nicht neu erfinden.

Die Aussage zu Java kann ich auch nicht nachvollziehen; man kann auch mit Java sehr effizient programmieren wenn man sich damit auskennt. Ich bestreite aber natürlich nicht, dass es bei manchen sehr speziellen Anwendungen langsamer ist. In Zukunft kann es sicherlich denkbar sein, dass VMs den Code auf die speziell vorhandenen Prozessorfeatures optimieren (was bei fertigen Binaries nur umständlich möglich ist), derzeit ist das aber noch nicht (oder kaum?) der Fall.

Gast
2009-02-16, 02:27:24
Es gilt das Grundprinzip, dass man nur Stellen optimiert, die auch performancekritisch sind. Wenn sie das nicht sind, ist eine Optimierung Verschwendung der Arbeitszeit.Das ist natürlich selbstverständlich :)

Sinnvoll ist sicherlich das Einsetzen von Features wie SSE und MMX (sofern es für den Einsatzzweck geeignet ist).Dazu hätte ich was prominentes als Beispiel. Adobe und Lightroom1. Einmal haben sie SSE im Entwickeln-Modus optimiert, was auf Core2 funktionierte, auf AMD64 aber zur Darstellungsfehlern (!) führte.
Ein anderes Mal haben sie die Thumbvorschau des Dateidialogs beschleunigt, was auf allen AMDs wie erwartet lief, auf Core aber oft (ich meine vor allem bei TIFF) zur garkeinen Vorschau führte. Die Felder waren nur grau.

Wie man also sieht gibt es genug Tücken beim "generic" :uup: x86 :(

Für einige letzte paar Prozent macht Optimierung aber bei x86 keinen Sinn weil die Prozessoren intern unterschiedlich arbeiten (wie du ja bereits bemerkt hast)Auch richtig. Ich überlege aber ob meine "allgemeinen" Optimierungen manchmal nicht krachen. Solche Fausformeln wie "auf C2D 3% gebracht, bringt auf dem P-M bestimmt auch seine 2% und wird auf einem Barton nicht langsamer als davor" gibt es nicht. Es könnte auch sein, daß sowas dann auf einem AMD64 X2 -3% bringt :confused: Hätte ich das nicht verfolgt, wären vielleicht alle auf +- 0% gebleiben und gut wäre es. Sowas meinte ich.

Die einzige Faustregel ist mmx in Assembler. Das geht immer und überall wie erwartet. Das ist aber keine Universallösung für alles und wirklich einfach ist das auch nicht immer ;)
Ich werd mich wohl durch paar "Endfreaks" Seiten durchkämpfen müßen. Ist doch nicht verkehrt, daß sowas in der heutigen Zeit noch Programmierer interessiert ;)

Ich hab den Thread auch falsch angefangen, denn relevant ist für mich eigentlich eher das was man für "generic i686" von P2 bis i7 vermeiden sollte, damit niemand unverhältnismäßig langsamer wird.

Danke dir für die Unterhaltung :)

Shink
2009-02-16, 08:27:30
Die Performance ist nicht "kritisch", aber ich trace und optimiere meistens das was ich als Grundgerüst zusammenstelle. Für mich sollte das "normalerweise" jeder tun.
Aha. Für mich sollte das "normalerweise" niemand tun. Schön wenn man Leerläufe in seinem Programm erkennt. Blöd wäre es nur wenn es niemanden gestört hätte.

In Zukunft kann es sicherlich denkbar sein, dass VMs den Code auf die speziell vorhandenen Prozessorfeatures optimieren (was bei fertigen Binaries nur umständlich möglich ist), derzeit ist das aber noch nicht (oder kaum?) der Fall.
Eigentlich wird das tatsächlich schon gemacht: Einserseits versucht der HotSpot-Compiler den Bytecode mit Hilfe der am System unterstützten Befehlssatzerweiterungen auszuführen. (Nun ja; bekanntlich bringt diese Art von Optimierung kaum etwas).
Anderes Beispiel: 64 Bit. Mit einer 64Bit-VM wird jede bestehende, compilierte Anwendung als 64 Bit-Anwendung ausgeführt.
Eine pipelineoptimierte Umsortierung des Codes wäre auch möglich, ist mir aber nicht bekannt.

Auf der anderen Seite weiß eine VM welcher Teil vom Code besonders oft/zeitaufwändig ausgeführt wird. Dort kann sie mehr Zeit in die Optimierung des Assemblercodes verwenden.


Nun ja, viel Spaß und Erfolg dem TS bei seinen Optimierungsambitionen.

Ganon
2009-02-16, 08:31:16
Zum Bytecode:

LLVM ist ja darauf aus auf jeder Plattform optimalen Code zu generieren... Funktioniert ja schon ganz gut, wie ich damals mal gezeigt hatte (bis zu 20% mehr gegenüber GCC4). :)

Coda
2009-02-16, 11:29:35
Es gibt allerdings schon einen Unterschied zwischen Bytecode den man mit einem JIT-Compiler ausführt und dem LLVM-Bytecode der eigentlich nur das Ergebnis des Compiler-Frontends darstellt.

LLVM ist vor allem deshalb so schnell gegenüber GCC4, weil es eigentlich nur ein viel besserer Compiler ist (GCCs Backend ist unglaublich grottig), der eben in zwei Teile zertrennt wurde. Das hat mit dem Bytecode-Konzept nicht viel zu tun.

Ganon
2009-02-16, 20:21:21
Es ist aber im Prinzip nichts anderes. Es geht halt nur nicht soweit Betriebssystemunabhängig zu sein.

Nichtsdestotrotz entspricht es den Wünschen des Thread-Starters "optimalen" Code für die einzelnen CPUs zu erhalten. Zumal LLVM ja auch einen AOT-Compiler hat, für die, die Angst vor JIT-Cs haben (auch wenn AOT zuweilen langsamer ist). ;)

Coda
2009-02-16, 21:04:27
Es ist aber im Prinzip nichts anderes
Doch, ist es. Der Bytecode unterscheidet sich so weit wie es nur geht.

Java und .NET kompilieren für den Bytecode direkt in eine Stackmachine mit ein paar wenigen Opcodes.

LLVM übergibt den kompletten Parse-Tree und alles was sonst noch vom Compiler-Frontend ausgespuckt wird. AFAIK wird dabei auch immer der komplette Bytecode übersetzt bevor es ausgeführt wird.

Ganon
2009-02-16, 23:33:18
AFAIK wird dabei auch immer der komplette Bytecode übersetzt bevor es ausgeführt wird.

Also die Beschreibung vom JiTC sagt was anderes. Siehe z.B. auch hier:

http://llvm.org/docs/tutorial/LangImpl4.html#jit


In summary, the JIT will lazily JIT code, on the fly, as it is needed. The JIT provides a number of other more advanced interfaces for things like freeing allocated machine code, rejit'ing functions to update them

...

, the JIT started execution of a function and got to a function call. It realized that the function was not yet JIT compiled and invoked the standard set of routines to resolve the function

Coda
2009-02-17, 03:43:32
Whatever. Jedenfalls kann man LLVM nicht mit der .NET oder Java-Runtime vergleichen.

Gast
2009-02-17, 12:57:30
Whatever. Jedenfalls kann man LLVM nicht mit der .NET oder Java-Runtime vergleichen.
Das liest sich sinngemäß etwa wie "Mir gehen zwar die Argumente aus, aber ich hab trotzdem Recht!" :ugly:

Coda
2009-02-17, 13:57:40
Die Jittbarkeit ist dabei nur Nebenaspekt. Ich habe extra "As far as I know" daneben geschrieben, weil ich mir nicht sicher war was das angeht.

Bei .NET/Java-Bytecode entsteht die Architekturabstraktion nach dem Compiler-Backend, bei LLVM davor. Das ist einfach nicht von der Hand zu weisen.

Ectoplasma
2009-02-17, 14:47:04
Dazu hätte ich was prominentes als Beispiel. Adobe und Lightroom1. Einmal haben sie SSE im Entwickeln-Modus optimiert, was auf Core2 funktionierte, auf AMD64 aber zur Darstellungsfehlern (!) führte.
Ein anderes Mal haben sie die Thumbvorschau des Dateidialogs beschleunigt, was auf allen AMDs wie erwartet lief, auf Core aber oft (ich meine vor allem bei TIFF) zur garkeinen Vorschau führte. Die Felder waren nur grau.

Wie man also sieht gibt es genug Tücken beim "generic" :uup: x86 :(

Ich glaube kein bischen von dem, was da oben steht. Da möchte ich Beweise und den Code sehen, der zu solch unterschiedlichem Verhalten führt. Persönlich glaube ich, dass der Code einfach fehlerhaft ist.

Gast
2009-02-23, 02:33:22
Ich glaube kein bischen von dem, was da oben steht.Das kannst du handeln wie der Dackdecker.

Da möchte ich Beweise und den Code sehen, der zu solch unterschiedlichem Verhalten führt. Persönlich glaube ich, dass der Code einfach fehlerhaft ist.Niemand sagte, daß es nicht fehlerhaft war. Es funktionierte ja nicht. Unglücklicherweise bei den erwähnten Beispielen mal auf Intel, mal auf AMD nicht.

@Shink
Wenn es niemand machen würde, würde es letztendlich doch stören. Wenn genug Fliegen an eine Stelle kacken wird daraus schnell ein Haufen der sich vor einem Kuhflatschen nicht verstecken muß. Das Problem momentan heißt Leistung im Überfluss. Was oft zum Programmierer der Marke "Volldepp" führt.
Das soll aber niemanden daran stören seinem Handwerk vernünftig nachzugehen.