Unterschiede C++/C#
-
Manuelh87 schrieb:
Walli schrieb:
Ich habe nie bestritten, dass es Supercodes gibt, mir war nur neu, dass sie aktuellen Compiler schon damit umgehen können, obwohl Mathias Fradmann sein Buch noch nicht herausgebracht hat.
Hör ich da ironie raus? pf... keine Supercodes... als nächstes willst du mir erklärenen das es keinen Weinachtsmann gibt
Du kannst mir ja mal erzählen, was DU unter Supercodes verstehst, ich muss jedenfalls schon schmunzeln weil ich dabei an den besagten Thread erinnert werde. Und dann erklärst du mir am besten noch, warum Assembler-Code niemals so schnell sein kann wie inline und Template-Tricks.
-
otze schrieb:
[
vector<int> vec; //... for(std::size_t i=0;i<vec.size();++i){ //... }
sry aber sowas würd ich auch nie machen... zeig mir mal bitte ein "nicht offensichtliches Beispiel... ich mein du redest nur von der existenz solcher beispiele aber bis jetzt war das alles völlig klar.
Da waren ja noch die Müllbeispiele von deiner seite besser *BöseKritikMach*
Na ihr wisst schon wie ich das mein... irgendwie seh ich einfach nirgendst nen richtigen anwendungsbereich... ich mein das sind alles nur fehler im stil sonst nix.@ Walli Ich hab doch schon bedeuert dass ich das vorschnell geschrieben habe! Ich hab eben nicht an die asm templates gedacht und inline. Aber an sonsten find ich schon das dieser code extrem gut ist (kann leider keinen link geben weil ich ned weiß wo genau das war...) immerhin viel schneller als die gewöhnliche variante (mit voller optimierung vom compiler) und ich kann mir nicht vorstellen das mann es viel besser in pure asm hinkriegt zumindest nicht mit meinem Wissen. Hab ja schon beschrieben wie die struktur ist und ich mein was will man da noch verbessern? Ich weiß nix. Und wenn du jetzt ne funktion in asm machst dann ist sie so wie sie ist... da wird nixmehr optimiert und defakto kann er keine werte in registern halten (konkretes beispiel vektoraddition) da es ja nicht so geschrieben ist aber da bei c++ die register nicht fix sind kann da unter umständen besserer gesamtcode rausschauen (mit dieser funktion die irgendwo aufgerufen wird (bzw geinlined) ) allerdings mein ich da jetzt nur asm ohne templates und so. Zum Beispiel eine Vektoraddition die von vornherein schon klar ist oder wo ein teil bekannt ist da könnte es doch sein das gleich ne ganze menge erstzt wird.. das ist doch so in der asm routine nicht möglich?? Meint ihr nochimmer das es blödsinn ist... ich kann mir das genau vorstellen... na sagt mir halt was ihr davon haltet.
Nochwas:
warum Assembler-Code niemals so schnell sein kann wie inline und Template-Tricks.
Davon rede ich ja nicht... was ich sagen will ist das die implementation von einer gut geschriebenen trickreichen C++ routine bzw ausdruck durch optimierungen von vielleicht fixen sachen die schon bekannt sind (z.b. ein vektor in der gleichung oder geschicktes sachen im register lassen) besser sein KANN als die einer asm routine da man hier ja fix sagen muss welche register man verwendet und wie soller er das optimiertn?? (templates ausgenommen)
Früher wollt ich auch viel mit asm optimieren aber die einzig gute möglichkeit das zu tun mit gcc ist das man eben diese template asm sachen verwendet und die sind meiner Meinung nach nicht so einfach... alles andere schlägt sich nur mit den optimierungen des compilers und wird unter umständen gar nicht so gut übersetzt weil der compiler nix damit anfangen kann....
mfg Manuelh87
-
Optimizer schrieb:
und dass es auch was bringt, kannst du schon glauben
Kann mir das zwar nicht so gut vorstellen (wie er da die hotspots rausfindet und nicht beim suchen schon so viel verschießt) aber glauben kann ichs ja trotzdem
Na wenn das echt so viel bringt...
Aber im Grunde bessert es ja nur programmierfehler aus so wie ich das sehen! Zumindest meistens...Naja wäre klug wenn er diese hotspots schon vorher irgendwie kennzeichnet, so könnte ich mir das schon vorstellen. Das er sozusagen die kritischen stellen sucht und dann nurmehr überprüft ob das ersetzbar ist oder nicht...
mfg Manuelh87
-
Manuelh87 schrieb:
Kann mir das zwar nicht so gut vorstellen (wie er da die hotspots rausfindet und nicht beim suchen schon so viel verschießt)
Oh, das ist ziemlich einfach: Du läßt das Programm einfach mal laufen und zählst mal mit wie oft Du so an ner Stelle vorbeikommst. Wenn Du in ner gewissen Zeit oft genug vorbeikommst schmeißt Du den Optimierer an (kostet dann etwas Zeit) und danach läuft genau die Stelle viel schneller. Da ein Programm normalerweise 90% seiner Zeit in 10% des Codes verbringt haste auf die Art und Weise ziemlich schnell die wichtigsten Stellen gefunden.
Btw. kannst Du noch kurz erklären was asm-templates sind?
Bei den geposteten Beispielen, die der Compiler nicht optimieren kann, weil er nicht weiß, daß nix geändert wird hat doch die HotSpot-VM das gleiche Problem, oder? Die Java-VM kann ja auch nicht einfach einmal laufen lassen und dann sagen hat sich einmal nicht geändert, wird sich wohl nie ändern. Sie muß es auch "beweisen" und steht an der Stelle vor dem selben Problem wie ein normaler Compiler auch.
-
und ich kann mir nicht vorstellen das mann es viel besser in pure asm hinkriegt zumindest nicht mit meinem Wissen.
eventuell SIMD anwenden, da könnte je nach dem nochmal eine Steigerung um 50% drin sein.
ich kann mir auch nicht vorstellen dass man das hier in C++ besser hinkriegt:Mersenne Twister Random Number Generator optimization tutorial. The author of the mersenne twister's C code runs in 258 cycles. Agner Fog's P4 SSE2 code for the mersenne twister runs in 44 cycles. My ALU code runs in 25 cycles ( 10 times faster than the author's code, and almost twice as fast as Agner's SSE2 code). Yes, you read that right, my ALU code is running faster than Agner's SSE2 code. It's because I optimized it specifically for the P4, and you can execute up to 4 ALU instructions in parallel if you do it right. I then wrote an SSE2 version that runs in 14 cycles ( 18.5 times faster than the author's code, and 3.1 times faster than Agner's SSE2 code).
http://www.old.masmforum.com/viewtopic.php?t=3565&highlight=mersenne+twisterWenn schon Flamewar dann richtig!
sry aber sowas würd ich auch nie machen...
wenn Leute überhaupt keine Ahnung haben was der Compiler daraus macht, dann machen die noch ganz andere Dinge
. Zumindest sagst Du dass die Assembly nicht fremd ist - und das beeinflüsst einen schon ganz gut, wenn man weiß dass "einfache" Datenstrukturen und Operationen in Assembly gaaanz anders aussehen.
Das mit Compilerotimierungen ist auch nichts neues - hab noch irgednwo eine CD mit Intels Compiler drauf die ist bestimmt 2-3 Jahre alt. Ich muss auch sagen dass er nicht schlecht die Mikrooptimierungen leistet - die Schleifen und das ganze Zeug, allerdingts ist der Compiler keine höhere Intelligenz
und kann keine größeren Zusammenhänge erkennen. Damit meine ich es ist schön und gut dass Compiler immer besser optimieren, aber man sollte sich nicht aussschließlich darauf verlassen denn ein Compiler kann weder den falschen Algoritmus noch die falschen Datenstrukturen wegoptimieren. Und wenn die Datenstrukturen falsch gewählt wurden (bleiben wir mal bei abstraktion) dann belegen diese nicht nur (viel) mehr Speicher - je nach dem was damit gemacht wird hat es zur Folge dass verarbeitende Operationen unnötig mehr machen ( perfomance minus), mehr als nötig in den Speicher geladen wird (nochmal minus),die Strukturen nicht mehr in den Cache passen (größeres minus) und so weiter.
immerhin viel schneller als die gewöhnliche variante (mit voller optimierung vom compiler)
siehe schon oben: wenn jemand nicht wirklich weiß in was der Code übersetzt wird - wie soll er wissen welche Variante besser ist? Wenn Du meinst dass es schneller ist als "gewöhliche Variante" - es kommt wohl aber nicht jeder drauf - und nur weil es hier, in diesem Beispiel so gut geklappt hat muss es immer noch nichts heißen - vielleicht war das ja die Ausnahme schließlich wird die "gewöhnliche Variante" ja nicht in automatisch in diese optimiert
-
Jester schrieb:
Bei den geposteten Beispielen, die der Compiler nicht optimieren kann, weil er nicht weiß, daß nix geändert wird hat doch die HotSpot-VM das gleiche Problem, oder? Die Java-VM kann ja auch nicht einfach einmal laufen lassen und dann sagen hat sich einmal nicht geändert, wird sich wohl nie ändern. Sie muß es auch "beweisen" und steht an der Stelle vor dem selben Problem wie ein normaler Compiler auch.
da tritt dann die zweite optimierungstechnik in kraft: dynamisches compilieren. die variable scheint konstant zu sein, also nimmt man sie einfach als konstant-bis sich der wert ändert.
Aber im Grunde bessert es ja nur programmierfehler aus so wie ich das sehen! Zumindest meistens...
ne, du siehst das teilweise falsch. Code muss lesbar sein, und wenn ich dazu 1-2 takte opfern muss, ist mir das schnuppe, macht auf heutigen pcs eh nichts mehr aus. normal bringt es auch nichts, sone lausige for schleife umzuschreiben, weil das programm dort eh nur 2-3x durchläuft. so what? wieso an stellen optimieren, wo es nichts bringt? An der richtigen stelle einen anderen Algorithmus kann tausende dieser micro optimierungen ersetzen.
-
otze schrieb:
Jester schrieb:
Bei den geposteten Beispielen, die der Compiler nicht optimieren kann, weil er nicht weiß, daß nix geändert wird hat doch die HotSpot-VM das gleiche Problem, oder? Die Java-VM kann ja auch nicht einfach einmal laufen lassen und dann sagen hat sich einmal nicht geändert, wird sich wohl nie ändern. Sie muß es auch "beweisen" und steht an der Stelle vor dem selben Problem wie ein normaler Compiler auch.
da tritt dann die zweite optimierungstechnik in kraft: dynamisches compilieren. die variable scheint konstant zu sein, also nimmt man sie einfach als konstant-bis sich der wert ändert.
Das ist mir unklar wie das funktioniert. Ich stelle also fest, der Wert ändert sich nicht. Also nehm ich mal als konstant an... was wenn er sich nun doch mal ändert? Das find ich doch nur raus, indem ich den Wert regelmäßig prüfe und genau dazu brauch ich doch den Aufruf von z.B. vector::size. Also spare ich da nix.
Oder wie genau meinst Du das?
-
Optimizer schrieb:
Wie auch immer, ich will ja gar keinen Vergleich anstellen, ob es vielleicht besser ist, als klassische Compilierung. Aber das zur Laufzeit auf Grund des Laufzeitverhaltens nochmal nach-optimiert wird, und dass es auch was bringt, kannst du schon glauben.
Naja, "nach-optimieren" ist zumindest bei Java nicht so ganz richtig. Angeblich optimiert der javac zur Compilezeit selbst gar nicht. Es wird da oft gesagt, dass die Hotspot-JVM nicht so gut mit einem optimierten Code arbeiten kann und diesen nochmal optimieren kann. Das soll angeblich mit unoptimiertem Code besser funktionieren. Naja, ich weiß nicht so ganz, was man davon halten soll, aber meines Wissens nach führt der javac zumindest keine klassischen Optimierungen zur Compilezeit durch. Alle Optimierungen werden von der Hotspot-JVM durchgeführt. Wobei es natürlich ein paar einfache Ausnahmen geben wird: Ersetzung von konstanten Variablen durch ihre Werte usw.!
Vielleicht ändert sich das mit der Zeit ja auch nochmal. Könnte IMHO was bringen.
-
@jester wie das funktioniert ist mir leider nicht bekannt, bin mir aber fast sicher, dass nicht size() überprüft wird, sondern vec. wahrscheinlich machts bei nem simplen size noch nicht viel aus, aber wenn man mehrere variablen hat die alle von den veränderungen von vec abhängig sind, kann das schon was bringen
-
Gregor@Home schrieb:
Naja, "nach-optimieren" ist zumindest bei Java nicht so ganz richtig. Angeblich optimiert der javac zur Compilezeit selbst gar nicht. Es wird da oft gesagt, dass die Hotspot-JVM nicht so gut mit einem optimierten Code arbeiten kann und diesen nochmal optimieren kann. Das soll angeblich mit unoptimiertem Code besser funktionieren. Naja, ich weiß nicht so ganz, was man davon halten soll, aber meines Wissens nach führt der javac zumindest keine klassischen Optimierungen zur Compilezeit durch. Alle Optimierungen werden von der Hotspot-JVM durchgeführt. Wobei es natürlich ein paar einfache Ausnahmen geben wird: Ersetzung von konstanten Variablen durch ihre Werte usw.!
Vielleicht ändert sich das mit der Zeit ja auch nochmal. Könnte IMHO was bringen.
Nach dem, was ich bis jetzt gelesen habe, ist die Server-VM (die man ganz einfach mit -server startet) in der Lage, umfassende de- und recompilierungen durchzuführen (wie z.B. inlining rückgängig machen), beispielsweise für (halb-)konstante Werte. Auch interpretiert die Server VM erst einmal eine ganze Weile den Code und sammelt dabei Informationen wie z.B. Sprungverhalten. Das kann man dann vielleicht nicht nach-Optimieren nennen, aber wenn jetzt z.B. der Fall eintritt, dass sich ein scheinbar konstanter Wert nach vielen Durchläufen ändert, muss der entsprechend optimierte Code verändert werden -> und wird wohl dann möglicherweise auch auf einen neuen konstanten Wert optimiert. Bis zu dem Pfeil ist es auf jeden Fall eine gesicherte Aussage.
@Jester: Ja, ich denke, dass die VM bei solchen Optimierungen regelmäßig als konstant angenommene Werte prüfen muss. Aber das kann signifikant weniger Arbeit sein, als ein- und die selbe Berechnung n-mal mit gleichen Werten durchzuführen. Ich gehe nicht davon aus, dass jede Variable auf mögliche Konstantheit hin untersucht wird, aber wenn ich Berechnungen habe, die lange dauern, könnte es sich lohnen, die beteiligten Variablen zu untersuchen. Ein klassischer Compiler kann diese Art der Optimierung IMHO nicht so oft durchführen, weil er wissen muss, dass sich eine Variable nicht ändert. Ein JIT-Compiler kann das einfach annehmen und evtl. darauf reagieren, wenn sich doch etwas ändert.
Oder nimm zum Beispiel Programmparameter/Werte, die du einmal aus einer Datei liest. Wenn ich irgendwie Code hab, der den Wert meines Programmparameters in Berechnungen nutzt, dann kann ich mit einem JIT-Compiler nachsehen, welchen Wert er hat und den Wert in alle Berechnungen inlinen. Bei
static final int foobar = readFromFile();
Sind Änderungen hier wohl unwahrscheinlich, da fällt dann sogar die Prüfung flach.
Inlining von Funktionsaufrufen ist vielleicht auch so ein Punkt, könnte man von Hand aber auch durchführen. Zu viel zu inlinen ist bekanntlich auch ungesund, die Hotspots intensiver zu inlinen ist wohl meistens das bessere.Ob es das so wahnsinnig bringt, anstatt klassisch gut zu optimieren, weiß ich auch nicht. Aber diese Hotspot-Optimierung hat Java definitiv einen ordentlichen Schub gegeben. Interessant ist allerdings auch, dass Microsoft mit .Net anscheinend nicht so darauf setzt.
-
Angeblich optimiert der javac zur Compilezeit selbst gar nicht.
Die statischen Optimierungen macht auch der JIT-Compiler, beispielsweise das Vertauschen der Reihenfolge von Berechnungen, um schneller wieder ein Register frei zu kriegen. Ist vielleicht auch nicht unvernünftig, da es dann mehr egal ist, wenn ich meinen Code vom Eclipse Compiler generieren lasse.
Auch das ist bei .Net scheinbar wieder anders, da scheint der statische Compiler bei aktiviertem Schalter schon einiges zu optimieren. Ich bin ja sowieso gespannt, wie hier das Rennen ausgeht, Sun hat ja da doch einige Zeit erstmal verpennt, wie ich finde. Lustigerweise hat Microsoft als erstes auf JIT-Compilierung bei der Java VM gesetzt, während die Sun VM noch interpretiert hat.