Optimierungsqualitaet von C-Compilern mit CPU-Erweiterungen
-
So langsam habe ich in einigen meiner x86 Asm-Projekte in Hinblick auf Code-Umfang und mir zur Verfuegung stehender Zeit wohl leider ein reichlich unguenstiges Verhaeltnis erreicht.
Deshalb ueberlege ich, einige Teile davon nochmal in C zu implementieren. Dabei stellen sich mir aber einige Fragen, die evtl. jemand mit mehr Erfahrung als ich in Sachen C-Compiler evtl. schnell beantworten koennte:1. Wie gut optimieren aktuelle C-Compiler ihren Asm-Output im Hinblick auf Geschwindigkeit - vor allem auch bei Benutzung von CPU-Erweiterungen wie MMX, SSE, etc.? Gibt es da Compiler, die besonders empfehlenswert oder zu meiden sind? Die letzten Beispiele, die ich fuer x86 ende der 90er gesehen habe, waren irgendwie wenig erbaulich...
2. Ist es dann moeglich (vorausgesetzt, es ist sinnvoll), auf unkomplizierte Weise einzelne Funktionen mit unterschiedlichen CPU-Erweiterungen, bzw. fuer unterschiedliche Ziel-CPU (zB. fuer 386) zu kompilieren? Also so, dass alle Versionen dieser Funktionen mit gelinkt und hinterher im Programm je nach erkannter CPU ausgewaehlt werden koennten. Irgendwelche Ansaetze wie man das geschickt realisieren koennte, wuerden mir reichen.
-
^^C ist auf der PC-plattform so ziemlich out. ich befürchte mal, da wird es keine high-end C-compiler mit so tollen features geben.
-
+fricky schrieb:
^^C ist auf der PC-plattform so ziemlich out. ich befürchte mal, da wird es keine high-end C-compiler mit so tollen features geben.
Wo lebst du? In einer rosaroten Gummizelle? C ist noch lange nicht out. Ausserdem sagst du damit ja, egal was Intel und Co sich ausdenken, es ist alles fuer die Katz'. Denkste!
Zum Thema: Meist bieten Prozessorhersteller fuer ihre Produkte eigene Kompiler an. Intel z.B. hat welche, die das unterstuetzen. Sie generieren nicht optimalen ASM-Code bei komplexen Aufgaben (wie jeder Compiler), aber sollen schon recht gut sein. Auch brauchst du nicht von C++ auf C umsteigen. Von Intel gibt es das auch mit C++.
Der gcc konnte "damals" in Version 3.x keinen MMX, SSE etc. generieren. Habs mal gestest, kann mich daran aber nicht mehr so gut erinnern.
Zu 2)
Lagere deine spezialisierten Funktionen in dll oder .so aus und linke dann zur Laufzeit abhaengig vom erkannten Prozessor die entsprechende Bibliothek.
-
knivil schrieb:
+fricky schrieb:
^^C ist auf der PC-plattform so ziemlich out. ich befürchte mal, da wird es keine high-end C-compiler mit so tollen features geben.
Wo lebst du? In einer rosaroten Gummizelle? C ist noch lange nicht out.
ja, und ich glaube an das rosa einhorn. aber im ernst: was wird denn noch in C auf PCs programmiert? höchtens treiber.
knivil schrieb:
Ausserdem sagst du damit ja, egal was Intel und Co sich ausdenken, es ist alles fuer die Katz'. Denkste!
äääh, nö? wieso?
-
Der Intel- Referenzcompiler ist darauf ausgelegt, die letzten Quäntchen aus den CPU- internen Features herauszuquetschen, aber natürlich nur, wenn die CPUID zu Intel paßt. Je nach Aufgabe sollen die Vorteile zwischen knapp meßbar und knapp spürbar sein und es ist angeblich einstellbar, wie weit er abwärtskompatiblen Code dranhängt.
Da ich durch das ROHS- bedingte Sterben einiger Core- Familien auch etliche Assembler- und FORTH- Ports nach C portiert habe, sind folgende Zahlen in etwa normal:
Ojektgröße Assembler/C-Compilat: 1:5 bis 1:10
Laufzeitverhalten: 1:3 bis 1:1.5Je größer das Projekt, desto näher rücken die Ergebnisse tendenziell zusammen. So ganz genau darf man die Zahlen nicht nehmen, weil ich ja vom ursprünglichen auf ganz unterschiedliche Prozessoren portiert habe, lediglich beim MELPS77 habe ich zwei Projekte, die sowohl in ASM als auch C vorliegen, aber die anderen Geschichten stützen diese Auge- mal Daumen- mal Pi- Schätzung. Der IAR-C für MELPS77 soll angeblich recht gut optimieren, schätze, daß sich so ungefähr der Worst- Case- Rahmen auch bei X86 geben wird.
Was hast Du denn im Schnitt an Folgen für Laufzeit und Codevolumen bei ASM->C?
-
+fricky schrieb:
ja, und ich glaube an das rosa einhorn. aber im ernst: was wird denn noch in C auf PCs programmiert? höchtens treiber.
klar, im Unix Umfeld weiß man nix davon, GTK hat man ja in assembler geschrieben wegen der Geschwindigkeit [ironie out]
im Unix Unfeld gibt es immer noch sehr große Projekte, die C nehmen.
-
supertux schrieb:
im Unix Unfeld gibt es immer noch sehr große Projekte, die C nehmen.
ok, das hab' ich nicht berücksichtigt. aber unter unix ist C ja auch 'ne heilige kuh.
-
+fricky schrieb:
ok, das hab' ich nicht berücksichtigt. aber unter unix ist C ja auch 'ne heilige kuh.
Oioioi, hört, hört
.
Müßtest Du Unix neu aufziehen, wärst Du wohl der Erste, der seinen C++- Compiler auspacken würde oder gar den Netbeans- Baukasten.
Ernsthaft, mit welcher Sprache bastelt man am ehesten einen brauchbaren, flotten Core?
-
pointercrash() schrieb:
Oioioi, hört, hört
so war das doch nicht gemeint. C hat selbstverständlich anwendungsgebiete, wo's nix besseres gibt. nur für diesen fetten pc-programme mit grafischen oberflächen usw. nimmt's kaum noch einer. der m$-compiler z.b. ist seit ~10jahren der gleiche, der kann weder C99, noch sonst irgendwas besonders tolles. da stecken die keine energie mehr rein.
-
Zahlen habe ich nicht. Ich kann mich erinnern, das meine eigene MMX-Implementation (auf einem Athlon) einer Funktion nur unwesentlich schneller war als das C-Aequivalent, wobei ich nur ein Feature von MMX genutzt habe. Jedoch hat nen Kumpel an Yager mitgearbeitet und meinte, SSE Optimierung bringt 's wirklich. Dort war das Problem auch recht optimal fuer SSE, wenn man einen Satz Vektoren gleichzeitig verarbeiten kann. Es war aber handgeschriebener SSE Code ueber inline-ASM.
-
Tja, ist echt schade, denn mit OOP wollte ich den Code nicht auch noch aufblasen, da kann ich ja gleich alles in Java neu schreiben. :p
Und C++ mit ohne OOP fuer quasi-C-Code missbrauchen ist wohl auch nicht das Wahre...?
Diese Laufzeitverhaeltnisse habe ich auch in etwa erwartet. Sehr viel an sinnvollen Alternativen bleibt da IMHO nicht mehr.So weit waere es dann eigentlich sinnvoller, wenn ich meinen Assemblercode auf Kosten von etwas Performance auf die Haelfte der Zeilen zusammenstauche und dann damit weiter arbeite.
-
Kann man so nicht sagen, da ich weder deinen Code noch dessen Einsatzgebiet kenne. Fuer C oder C++ spricht z.B. portabel (write once run everywhere), Typsicherheit, weniger potentielle Fehler, uebersichtlicher und leichter wartbar. Und tausend Sachen mehr ... In Java kann man auch schnelle Programme schreiben, aber da muss man wissen wie (statische Arrays, nicht soviel new ...). Aber ich finde alles, was eine VM braucht erstmal per se suspekt.
-
knivil schrieb:
Kann man so nicht sagen, da ich weder deinen Code noch dessen Einsatzgebiet kenne.
Einsatzgebiet ist ein Audio-Sampler. Da kann man im Prinzip sehr gut mit MMX und SSE basteln, allerdings ist der Code momentan AFAIR noch weitestgehend 386-kompatibel.
Reizt seine Moeglichkeiten aber IMHO schon ziemlich weit aus.knivil schrieb:
Fuer C oder C++ spricht z.B. portabel (write once run everywhere), Typsicherheit, weniger potentielle Fehler, uebersichtlicher und leichter wartbar.
Das ist mir schon klar, wobei ich aber z.B. C++ wegen der OOP-Natur wie gesagt nur ungern einsetzen wuerde. Ich habe halt schon eine mehrere K Zeilen umfassende Code-Base in Asm und will eigentlich zunaechst nicht alles direkt neu schreiben.
-
Beim gcc kannst du auch mal speziell ein MMX oder SSE Flag setzen (k.A. welche Option) und den generierten ASM-Code anzeigen lassen. Wie gesagt, Intel macht es bestimmt. Ist aber nicht so gut wie per Hand, da er nur den Code sieht und Semnatik nicht. Kann aber auch besser sein, falls der Compiler mehr Optimierungsmoeglichkeiten sieht als der Programmierer. Du kannst auch stueckweise portieren, indem du inline-Assembler nutzt. Wobei das auch davon abhaengt, wie den ASM-Code aussieht.
-
Nobuo T schrieb:
Tja, ist echt schade, denn mit OOP wollte ich den Code nicht auch noch aufblasen, da kann ich ja gleich alles in Java neu schreiben. :p
Und C++ mit ohne OOP fuer quasi-C-Code missbrauchen ist wohl auch nicht das Wahre...?Würde das nicht so schwarz sehen. Mit ohne OOP geht doch auch, ich weiß übrigens nicht, ob Intel nicht auch pures C unterstützt, mit einem Trick kann man die CPU- Abfrage weitgehend aushebeln und so AMD- CPUs optimierten Code unterjubeln.
Nobuo T schrieb:
Diese Laufzeitverhaeltnisse habe ich auch in etwa erwartet. Sehr viel an sinnvollen Alternativen bleibt da IMHO nicht mehr.
Die Zeit hat doch für Dich gearbeitet. Vor zehn Jahren etwa hast Du Dich an die Sache gemacht, da waren so 800 MHz "state of the Art", bei mir tuckert so'n 08/15- DualCore, der die Kisten von damals an die Wand pustet, wenn auch nur ein Kern rennt. Ist bei meinen Controllern auch nicht anders, 600 Byte handoptimierten Assembler mit 20 Byte RAM- Verbrauch zahlt mir doch keiner mehr, wenn jeder Dödelcontroller 4k Flash sowie 512 Byte RAM mitbringt (70 Cent Hunderterpreis) und abgeht wie Schmidt's Rennmaus.
Nobuo T schrieb:
So weit waere es dann eigentlich sinnvoller, wenn ich meinen Assemblercode auf Kosten von etwas Performance auf die Haelfte der Zeilen zusammenstauche und dann damit weiter arbeite.
Ich habe keine Ahnung, wie timingempfindlich Dein Zeug ist, aber als ich bei C (wieder) eingestiegen bin, hatte ich noch den Impetus, Laufzeitanalysen zu betreiben und die Zeitmörder dann per Inline- ASM zu killen, eine Möglichkeit, die auch Dir offensteht. Nur: Menschliche Faulheit siegt und zum zweiten war es nie nötig, weil die Dingerchen zu schnell und ressourcenhaltig geworden sind. Das dürfte auch bei Dir so sein.
Mein Tip im Sinne der Wartbarkeit: Schnapp' Dir ein kleines Projekt, portier's und schau' mal, ob es noch tut.
-
Nobuo T schrieb:
Einsatzgebiet ist ein Audio-Sampler. Da kann man im Prinzip sehr gut mit MMX und SSE basteln, allerdings ist der Code momentan AFAIR noch weitestgehend 386-kompatibel.
Reizt seine Moeglichkeiten aber IMHO schon ziemlich weit aus.Sampler? 386? Huh, genau das sind aber nicht die besten Freunde, zudem wird der "Ur-386er" Opcode nicht mehr durchgehend optimal durchgerissen.
Schau' doch mal in die OS- Ecke bei den Soundbearbeitungstools, da gibt es etliches und sieh' Dir an, was die hernehmen.
Es geht auch ohne ASM, jede Wette!
-
pointercrash() schrieb:
Es geht auch ohne ASM, jede Wette!
das denke ich auch. sollte mit dem schäbigsten c-compiler machbar sein.
-
Danke erstmal an alle fuer die ausfuehrlichen Ratschlaege.
Stimmt vielleicht, dass es auf aktuellen CPU wirklich oft ziemlich egal ist, wie gut so mancher Code im Detail optimiert ist und dass 386-Code auf aktuellen CPU nicht optimal laeuft, aber wie gesagt ist mir die 386-kompatibilitaet eben auch nicht so ganz egal.
Sinn und Zweck der Uebung, weshalb ich die Sache auch mal urspruenglich in Asm angefangen habe, war naemlich auch meinem uralten 486er und 586ern noch ein bisschen Multimedia zu entlocken. Aus dem Grund pflege ich u.A. auch noch einen DOS-Port.
Das Ganze laeuft halt auch relativ gut, ist nur eine Bitch zu warten und zu erweitern (zB. auch im Hinblick auf Erweiterungen aktueller CPU). Da waere C oder C++ natuerlich viel besser, aber dadurch sollte eben nicht unbedingt die Abwaertskompatibilitaet komplett draufgehen durch irgendwelchen von den Compilern billig hingeschlunzten x86-Code, der auf den alten Maschinen deutlich langsamer laeuft. Deshalb mache ich mir da schon Gedanken ueber die Code-Qualitaet.
Aus dem Grund auch meine 2. Frage nach der Moeglichkeit, einzelne Funktionen mit unterschiedlichen CPU-Features zu kompilieren und zu linken. Das klappt dann spaetestens im DOS-Port natuerlich auch nicht mehr so einfach mit DLLs.Sry, hoffe ich habe meine Motive jetzt etwas klarer gemacht.
-
nobuo, das hört sich stark nach 'premature optimization' an, was du vor hast. ist das ganze wirklich so zeitkritisch? hast du irgendwelche messdaten, berechnungen, erfahrungswerte, etc. die belegen, dass du bereits auf jeden taktzyklus achten musst?
-
Ich habe zB. einen 486er mit 66MHz, dessen CPU ich unter DOS mit einigen aelteren Versionen des IT-Players locker zu 100% auslasten konnte. Dann stockt der Sound halt unschoen. Reicht das als Erfahrungswert?
Habe das Teil zwar schon eine Weile nicht mehr aufgebaut und getestet, aber ich denke obwohl der Sampler inzwischen vielleicht knapp doppelt so viele Kanaele bringt, wuerde ich da recht schnell an die Belastungsgrenze stossen... mal sehen, vielleicht probiere ich das ueber's Wochenende mal wieder aus.
Der IRQ schlaegt halt gnadenlos zu, und die innersten Schleifen der sampler laufen insgesamt pro Kanal und Buffer ca. 1000mal durch. Ist dann also schon ziemlich zeitkritisch.Ab ~400MHz-CPU ist das natuerlich kaum noch ein Problem mehr, aber ich wuerde halt schon gern moeglichst viel auch auf langsamen Maschinen rausholen.