Wie programmiere ich performant? Literaturtipps?
-
hast du jetzt schon mal nen profiler verwendet?
-
Just in diesem Moment habe ich den CodeAnalyst von AMD mal angeschmissen.Und wollte auch gleich eine Frage dazu stellen.
Also: Der Analyst zeigt an, dass die meiste Zeit "an der ersten Klammer meiner Funktionen" verbraucht wird. Was sagt mir das? Würde da inline was helfen, weil ich da nicht für jeden Aufruf jede Menge quatsch auf den Stack schreibe (vorsicht, Halbwissen)? Wie kann ich den Plot, bzw. die Timesamples, überhaupt interpretieren?
Heißt das konkret, wieviel Zeit der Prozessor mit einem bestimmten Befehl beschäftigt ist?
Hab mal die ASM-übersetzuung angeschaut. Die meiste Zeit (über 50%) verbringt er mit:rep stosd es:[edi]und zwar bei jeder funktion. Weiss jemand, was das heißt?
Grüße
Sören
-
Wenn du unter Windows programmierst könnte ich aus eigener Erfahrung:
http://www.glowcode.com/
empfehlen. Der ist einfach zu verwenden und der Output ist, meines
Erachtens, nahezu selbsterklärend.
-
Kenn den CodeAnalyst nicht. Aber kann es sein, dass du ne große Struktur/Klasse oder was anderes großes als Kopie und nicht als Pointer/Referenz übergiebst?
-
hmmm...... schrieb:
Kenn den CodeAnalyst nicht. Aber kann es sein, dass du ne große Struktur/Klasse oder was anderes großes als Kopie und nicht als Pointer/Referenz übergiebst?
Eigentlich nicht, weder in dieser funktion (die ist void (void)) noch in irgendwelchen anderen Funktionen übergebe ich Objekte oder Strukturen, wenn dann als Pointer. Meine betroffenen funktionen sind alle void (void) oder seltener float (void) und zuletzt float (float).
Vielleicht hat der Compiler ne falsche Einstellung?
Ist der VC++ 2005 Express Edition-Compiler.
Grüße
Sören
-
Wie ich das jetzt rausgefunden habe, hat der rep stosd den zweck, Daten zu kopieren, in meinem Falle die unnützen Daten aus eax (cccccccch) 33h-mal an [edi]etc...pp... zu kopieren. Warum schreibt mein dummer Compiler das an den Anfang meiner Funktion?
Grüße
SörenAchja, Worauf edi zeigt? Keine Ahnung, es gab ein
mov ebp,esp lea edi,[ebp-000000cch]vorher, mehr weiß ich nicht.
-
ich wuerde vermuten dass du riesige datenmengen per value uebergibst oder zumindestens riesige datenmengen zuweist (kann auch ein ctor einer localen variable sein der das macht).
-
Mit Exception Handling wie try catch oder __try __except kann es nichts zu tun haben?
-
rapso schrieb:
ich wuerde vermuten dass du riesige datenmengen per value uebergibst oder zumindestens riesige datenmengen zuweist (kann auch ein ctor einer localen variable sein der das macht).
Nö, tut mir leid. Als lokale Variablen gibts nur einfache floats und ints. Funktionen sind, wie gesagt ohne oder nur mit float-parameter.
Es gibt auch sonst keinen sinnvollen Grund in einen 33h - mal 4 ByteGroßen Speicher cccccccch reinzuschreiben, oder?
Aber im Laufe meiner Nachforschungen habe ich rausgefunden, dass genau der Code auch bei anderen Funktionen (nicht von mir, siehe hier:
http://forums.devshed.com/c-programming-42/convert-c-to-assembly-language-183227.html vorne dran gehängt wird. Kann doch nicht Sinn der Sache sein, oder? Vielleicht sollte ich mal im Assembler-Forum nachfragen.
Grüße
Sören
-
yogle schrieb:
Mit Exception Handling wie try catch oder __try __except kann es nichts zu tun haben?
Hmmm, auch nicht. Hab in meinem kompletten Code kein __try drin
-
soerenP schrieb:
rapso schrieb:
ich wuerde vermuten dass du riesige datenmengen per value uebergibst oder zumindestens riesige datenmengen zuweist (kann auch ein ctor einer localen variable sein der das macht).
Nö, tut mir leid. Als lokale Variablen gibts nur einfache floats und ints. Funktionen sind, wie gesagt ohne oder nur mit float-parameter.
Es gibt auch sonst keinen sinnvollen Grund in einen 33h - mal 4 ByteGroßen Speicher cccccccch reinzuschreiben, oder?doch, debuggen.
-
Du kompilierst aber nicht im debug modus bei der performance messung?
Kannst die die Codestellen mal zeigen (funktion+aufruf)?
-
Ok, stimmt, wenn ich nicht debugge, schmeißt er anderen Code raus, der auch nicht wesentlichs schneller ist, aber die o.g. Aufrufe nicht hat. Vielleicht versteh ich den Profiler auch nicht so ganz. Jetzt zeigt er mir an, dass ein fstp ca.40% der Rechenzeit einer Funktion verbaucht. Kann ja auch nicht wirklich sein, oder?
Ich probier mal den Glowcode aus..[edit: NOOOOOOOT, wer gibt mir die 499$]
-
dapadu schrieb:
Du kompilierst aber nicht im debug modus bei der performance messung?
Kannst die die Codestellen mal zeigen (funktion+aufruf)?
Ja, sorry, ich wusste nicht, dass der Debug die performance so einschränkt. Ausserdem bekomm ich es nicht hin, nicht zu debuggen und im Profiler noch c++ code zu bekommen

Code folgt://Um nicht ständig return werte zu bekommen und in die nächste Funktion zu //stecken habe ich die Module durch Pointer verbunden, wo sie ihren Eingang her //beziehen und ihren Ausgang reinschreiben float CSVoice::computeNextSample() { if(!m_active)return 0; m_initWave[0].computeNextSample();//displayed on the lefthand side m_initWave[1].computeNextSample(); (*m_mixOut)+=m_inGainModulated*(m_mixModulated*m_mixIn1+m_oneMinusMix*m_mixIn2)+m_sympathyInput; m_mixIn1=0; m_mixIn2=0; m_filter.computeNextSample(); m_antiFixpointHP.computeNextSample(); m_delay.computeNextSample(); m_nonlinearity.computeNextSample(); if(m_loopInput<0.0000000001&&m_loopInput>-0.0000000001&&m_loopInput!=0)m_denormalCounter++; else m_denormalCounter=0; if(m_denormalCounter>500) { m_delay.clear(); m_active=false; } return m_loopInput; } //Ein variables nicht-integer delay void CSVFDelay::computeNextSample() { //linearInterpolation (*m_output)=m_delayLine[m_readPointer2]*m_integerRemainder+m_delayLine[m_readPointer]*(1-m_integerRemainder); //if(m_loopOutput)(*m_loopOutput)=(*m_output); m_delayLine[m_writePointer]=m_input; m_input=0; m_writePointer++; m_readPointer++; m_readPointer2++; if(m_writePointer==kMaxDelay)m_writePointer=0; if(m_readPointer==kMaxDelay)m_readPointer=0; if(m_readPointer2==kMaxDelay)m_readPointer2=0; } //Ein brute-force fir-filter mit 5 bzw. 13 koeffizienten //Wollte noch ausprobieren, ob es mit Ringpuffer schneller geht, siehe //diskussion im Forum void CSParamFilter::computeNextSample() { memmove(&m_inBuffer[m_activeInBuffer][1],&m_inBuffer[m_activeInBuffer][0],m_lengthMinusOne[m_activeInBuffer]*sizeof(float)); float sum=0; m_inBuffer[m_activeInBuffer][0]=m_input; for(int i=0;i<m_filterLength[m_activeCoeff];i++) sum+=m_inBuffer[m_activeInBuffer][i]*m_theCoeffs[m_activeCoeff][i]; (*m_output)+=sum; if(m_loopOutput)(*m_loopOutput)=sum; m_input=0; } //wendet eine nichtlineare funktion auf den Input an. Diese ist definiert durch //eine Tabelle (functionLut), die im x-Bereich von -1 bis 1 geht. void CSNonlinearity::computeNextSample() { m_input*=m_preGain; if(m_input>1) { m_input=1; } if(m_input<-1) { m_input=-1; } int in=(int)(m_input*m_hLutSize); float rest=m_input*m_hLutSize-in; in+=m_hLutSize; //linearInterpolation:1. between two LookUpTable values, 2. linear/nonlinear float temp=(m_functionLut[in]*(1-rest)+m_functionLut[in+1]*rest)*m_nonlinearity+(1-m_nonlinearity)*m_input; (*m_output)=temp*m_postGain; m_input=0; }Mit Sicherheit lässt sich da einiges tun, aber sooo schlecht wie mein Ergebnis hätte ich es nicht erwartet...
Grüße
Sören
-
soerenP schrieb:
Ok, stimmt, wenn ich nicht debugge, schmeißt er anderen Code raus, der auch nicht wesentlichs schneller ist, aber die o.g. Aufrufe nicht hat.
die stelle die 50% der zeit zieht ist weg und es laeuft immer noch gleich schnell? ja...
Vielleicht versteh ich den Profiler auch nicht so ganz. Jetzt zeigt er mir an, dass ein fstp ca.40% der Rechenzeit einer Funktion verbaucht. Kann ja auch nicht wirklich sein, oder?
doch, die allermeisten programme sind speicherlimitiert, da die compiler wenn alle optimierungen eingeschaltet sind akzeptablen code generieren und fuer den misst der dann noch uebrig bleibt, dafuer sind die x86 cpus angepasst worden.
was unoptimiert bleibt ist meist der speicher-teil, durch allignment und padding kann der compiler nur maginal aushelfen, da auch dafuer die x86-cpus ausgelegt sind.
-
Naja, es ist schon schneller, aber nicht so, wie ichs brauche.
Zum vergeich:
Für etwa den selben Algorithmus (vom Syntheseprinzip her) schafft es ein anderes Plugin anstatt mit 30% CPU-Auslastung mit sowenig dass ich die Anzeige nicht lesen kann. (2-3%)
Ich kann mir beim besten Willen nicht vorstellen, wie man aus dem Code noch 90% rausholen kann. Aber scheint ja zu gehen...
Gibt es denn Techniken oder allgemeine Regeln, wie ich die Speicherzugriffe minimieren kann? Ich kann mir grad nicht vorstellen, wie ich das Optimieren/vermeiden kann...
-
Meistens sind eindimensionale array schneller als mehrdimensionale. Kannst du ja mal umbauen.
Zu deinen if
if(m_input>1) { m_input=1; } if(m_input<-1) { m_input=-1; } //sollte etwas schneller sein, aber macht vielleicht sogar schon der compiler if(m_input>1) { m_input=1; } else if(m_input<-1) { m_input=-1; }
-
Pointer Zugriff auf Array sollte schneller sein, als mit Index.
Und wenns Hardware abhängig sein darf
http://de.wikipedia.org/wiki/SIMD (SSE Zeugs)
-
Wenn m_delayLine ein std::vector ist könntest du mal versuchen nen einfachen Pointer draus zu machen. Je nach STL Implementierung macht das durchaus nen Unterschied.
Und natürlich immer nur den Release Build profilen.
Source-Code beim Debuggen/Profilen bekommst du im Release-Build indem du einfach im Release-Build auch die Erzeugung von Debug-Infos einschaltest. Hat bei mir zumindest immer funktioniert.
-
soerenP schrieb:
Für etwa den selben Algorithmus (vom Syntheseprinzip her) schafft es ein anderes Plugin anstatt mit 30% CPU-Auslastung mit sowenig dass ich die Anzeige nicht lesen kann. (2-3%)
das könnte in assembler geschrieben worden sein. möglicherweise solltest du das mit deinem code auch tun (zumindest die flaschenhälse).
