Wieviel Performance und RAM braucht was?
-
schreib erst mal deine Engine
, dann gehtst du mit einem Profiler drüber und bestimmtst die kritischen Stellen... dann meldest du dich im ASM-Forum (obwohl: vorher doch noch mal hier vorbei schauen - eventuell gibt es einen besseren algo für dein Problem
). Erst optimiert man an dem Algo - eine superoptimierung in ASM bringt absolut nichts wenn der benutzte Algo nicht stimmt.Das Konzept muss erstmal stimmen.
PS:mal zu deiner startfrage: die beiden von dir genannten operationen kosten garnichts, da der compiler das schon während der compilezeit wegoptimiert.
ich muss leider bestätigen dass die neueren Compiler ziemlich gut optimieren, zumindest beim Intelcompiler (habe sonst noch den VC++ 6.0, da finde ich den Ressourceneditor ganz praktisch
) ist es so.
Natürlich ist es von Vorteil zu wissen wie es intern funktioniert da man auch seine Datenstrukturen darauf ausrichten kann, aber im Prinzip optimiert ein (mir bekannt:Intel-compiler) besser als ein Assembler-neuling es schreiben könnte.
-
xBlackKnightx schrieb:
Gibt es vielleicht eine Liste das zeigt wieviel Performance und RAM die verschiedenen Operatoren, Datentypen, Klassen, Pointer, Schleifen, If-Else usw usw... brauchen??
nein.
Wenn ich z.b. die Integer-Zahlen 1+1 oder 21341+15123 rechne, macht es einen Unterschied oder nicht?
macht keinen. aber beim plutimizieren könnte es einen unterschied machen und beimn dividiren machts bestimmt einen. beim radizieren isses wieder egal, wie groß das argument ist.
Ich weiss das heuzutag bei solchen Zahlen kein Unterschied bemerkbar sind aber wenn ich sie Milliarden mal ausführe?
auch dann beim addieren nicht.
Kann man Taktanschläge als Uhr nehmen?
ja. mit
__int64 rdtsc(){ ___asm rdtsc; }
(wird auf deinem compiler evtl etwas anders geschrieben).
Ich möchte meine Programme möglichst Optimal erzielen.
das ist gut. lerne auch welchen speed, die elemetare operationen unter welchen umständen haben. das brauchste ständig als input, wenn du am aussuchen bist, welche der 5 völlig gleichwertig scheinenden lösungen einen tick besser ist.
Wieviel jeder Befehl braucht, mußt du für jeden Prozessor nachschauen.
geht nicht mehr sinnvoll. ein befehl braucht nicht mehr unabhängig von den anderen seine zeit, sondern die machen superskalare tricks, teilen sich fpus und alus, hauen sich zuerst in noch kleinere elemetarbefehle und die teile hüpfen in warteschlangen. die caches machen zugriffe sehr unvorhersagbar, sprungvorhersage auch.
nachschauen, was so ein 386-er brauchte, ist erstmal ein guter anhaltspunkt. und dazu immer wieder mal auf den assembler-code schauen, den der c++-compiler baut. mit erstaunen feststellen, daß er for-schleifen zu schnellerem code macht als while-schleifen (fragt mich nicht, warum).ne ich will schon wissen wieviel was braucht, ich will ein PhysikEngine programmieren mit tausenden von Objekten die sich gleichzeitig bewegen.
begrenzter raum? recht festpunktarithmetik? oder float oder double?
Wenn es ein Assembler sein muss, kann man das mit Visual Studio direkt in C++-Quelldateien einbinden?
inline-assembler, wie oben bei rdtsc gezeigt, ist viel besser, als assembler-dateien einbinden.
Die Frage ist ja auch ob ich die Formeln nur in Addition, Multiplikation und Subtraktion oder ruhig auch mit Wurzel nehmen kann.
wurzeln die lahm. multiplikation ist auch nicht der tollste renner. wenn wurzeln unumgänglich sind, kannste im netz nach fast_sqrt oder so suchen rechtet nicht bis auf letzte bit genau, ist aber sehr flott.
ob ich z.b. für die Kollisionsabfragen nur durch Vergleichsoperatoren oder auch mit Arithmetische Operatoren nehme.
tja, und nu kommen die tricks.
anfangs schreibt ma ja gerne
//wenn berechneter abstand kleiner als 10 centimeter...if(sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y))<0.1)
und dann findet man ne geile funktion
if(__hypot2(b.x-a.x,b.y-a.y))<0.1)
und erst jahre später bemerkt man, daß
if((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y)<0.1*0.1)
noch besser ist.
wenn du überhaupt kein gefüht dafür hast, was die basisopertationen kosten, mußte viel messen (und evtl hier viel fragen).
übrigens ist letzte der trick, der, der am meisten bringt. und wie fast immer isses ein mathematischer trick. mit takte-zählen und assembler-sachen machen schaffste vielleicht mal faktor 3 bei ner glücklichen funktion (im durchschnitt faktor 1.01). mit den mathe-tricks und mathe-ähnlichen tricks schaffste faktoren um 1000 und mehr auch öfters.
schreib erst die physikengine und optimiere danach an den kritischen punkten, sonst wird das nichts.
das ist otzes meinung. wenn man die engine aber baut, ohne im geringsten daran zu denken, was dem prozessor wehtut und was nicht, kann man nacher nicht viele punkte rausholen.
premature optimisation is the root of all evil.
das auf englisch zu zizieren macht es nicht wahrer.
Vorallem, da du nicht weist ob dein eigesetzter asm code nicht vielleicht genau dasselbe ist, was der compiler nach der optimierung ausspuckt.
immer nachgucken, und ein gefüht dafür entwickeln, welchen code der compiler schreibt.
und deine frage ist auch in der hinsicht nicht ganz sinnvoll, da das von betriebsystem zu betriebssystem von prozessor zu prozessor absolut unterschiedlich ist, die hersteller kochen nämlich alle ihr eigenes süppchen
integer-additionen kosten einen takt. das machen sie schon seit jahrzehnten. meinste, heute bauen die ne bremse ein, damit es spannender wird?
Denk auch an die 80-20-Regel. Die besagt, dass 80% der Laufzeit eines Programms in nur 20% Code verweilt. Es ist daher wichtig, den 20% Code ausfindig zu machen und diesen zu optimieren. D.h. es bringt nichts, an unnötigen Stellen zu optimieren.
ja, bescheidenheit tut gut beim optimieren.
am wichtigsten ist, code zu bauen, der von anfang an darauf geplant ist, daß man ihn optimieren kann. und das bedeutet in der praxis fast immer: mach einfachen code, kleine funktionen, mach verständlichen code. mach für einen zweck eine funktion oder klasse. mach in nicht nur übersichtlich, mach ihn extrem durchschaubr. es muss langweilig sein, dein programm zu lesen. denn die optimierungen fallen dir immer erst ein, nachdem du das problem an sich gelöst hast und spätere nochmal drüber nachdenkst. in 2 wochen oder so.
-
volkard schrieb:
es muss langweilig sein, dein programm zu lesen.
DAS gefällt mir.
-
otze schrieb:
premature optimisation is the root of all evil.
hab ich dir schon den code http://wpc.schornboeck.net/viewtopic.php?t=92 gezeigt?
uih, du wirst mich bestimmt hauen, daß das bitgefummle ganz am anfang total premature ist.
aber irgendwie wurde der code am ende auch viel leichter lesbar als update_info von http://wpc.schornboeck.net/viewtopic.php?t=91. naja, es war uch nicht premature, sondern zuerst hatte ich auch viele schleifen und später ist mir der trick eingefallen. und weil ich nicht eine funktion und einen typen für einen zweck hatte, mußte ich auch fein alles wegschmeißen und neu machen. hätt ich doch mal so auf gut glück premature optimiert!
-
zum thema inline-asm:
lohnt sich das, wenn eine funktion schon in c++ gibt, die das selbe macht?
soweit ich weiß kann der compiler den inline-asm nicht optimieren. also er kann den inline-asm nicht mit den ihn umgebenden funktionen "in einklang bringern". dadurch verliert man dann wieder performence..MamboKurt
-
Beantworte diese Frage einfach erstmal mit nein. Und wenn du um's Verrecken keine andere Möglichkeit mehr hast und verzweifelt bist, dann kannst du sie dir nochmal stellen.
-
MamboKurt schrieb:
zum thema inline-asm:
lohnt sich das, wenn eine funktion schon in c++ gibt, die das selbe macht?extrem selten.
also eigentlich nur, wenn es eine funktionalität so in c++ nicht gibt. fürchterlichstes beispiel war man ein string-im-anderen-string-sucher von mir, den ich mit REPNE und so lustigen sachen gebaut hab. von allemblerseite war er das schnellste, was man so zaubern konnte. aber ein in c++ geschriebener boyer-moore macht ihn um längen platt.
für sachen wie strlen und memcpy kann es sinnvoll sein. aber die hat der compiler eh intrinsic, das ist noch schneller.soweit ich weiß kann der compiler den inline-asm nicht optimieren. also er kann den inline-asm nicht mit den ihn umgebenden funktionen "in einklang bringern". dadurch verliert man dann wieder performence.
externe asm-funktionen, die du dazulinkst, kann er nicht.
die mit inline-asm geschriebenen kann er wunderbar machen. der compiler compilier nämlich erstmal sein c++ in schlechtes assembler (und dein assembler wirft er rein). und dann macht er alles assembler zu gutem assembler mit nem optimierer, der die ganzen tricks wie MOV EAX,0 -> XOR EAX,EAX und noch viel bessere kennt. und er sortiert befehle um, um die pipelnines gleichmäßig auszulasten, er aligned speicher und sprungziele und macht viel tolle sachen. er haut nutzlosen code raus.
-
volkard schrieb:
otze schrieb:
premature optimisation is the root of all evil.
hab ich dir schon den code http://wpc.schornboeck.net/viewtopic.php?t=92 gezeigt?
uih, du wirst mich bestimmt hauen, daß das bitgefummle ganz am anfang total premature ist.
aber irgendwie wurde der code am ende auch viel leichter lesbar als update_info von http://wpc.schornboeck.net/viewtopic.php?t=91. naja, es war uch nicht premature, sondern zuerst hatte ich auch viele schleifen und später ist mir der trick eingefallen. und weil ich nicht eine funktion und einen typen für einen zweck hatte, mußte ich auch fein alles wegschmeißen und neu machen. hätt ich doch mal so auf gut glück premature optimiert!"Premature optimisation is the root of all evil." - Donald Knuth
"On the other hand, we cannot ignore efficiency." - Jon Bentley
§6 Struppi und C++ Coding Standards Regel 8
-
was ist plutimizieren ?
warum macht dividieren einen unterschied? von was?
radizieren = wurzel?
also wenn die mit dem Tricks potienz 2 von abstand 10 cm besser ist, als wurzel aus ((x.b-x.a)...blabla). dann ist multiplikation schneller als wurzel, oder? soetwas muss ich unbedingt wissen.für PhysikEngine kein float, nur ganze positive Zahlen, da ich denke floats sind ne Performancebremse und sowieso ungenau...
Datentyp mit dem es am schnellsten geht, ich nehm mal an die Integer-Wertebereich da sie plattformabhängig von 16-, 32-, 64-bit Rechner sind. Unbegrenzter Raum durch dynamische arrays+matrizen, wenn noch grösser dann auf festplatten.was sind festpunktarithmetik?
multiplikaten sind lahm? was wäre dann schneller?
ist
__int64 rdtsc(){ ___asm rdtsc; }
für intels? ich hab amd, wie ermittle ich die takts?
-
ach ja und warum konnte der compiler nicht selbst erkennen dass die potienz von 2 in vergleichoperator schneller ist als wurzel aus 2.
wenn der compiler doch so toll optimieren können soll werd ich da doch skeptisch
-
xBlackKnightx schrieb:
was ist plutimizieren ?
malrechnen.
warum macht dividieren einen unterschied? von was?
dividiren ist im allgemeinen lahmer als plutimizieren.
deswegen schreibt man gerne stattdouble dividend=bla;//irgendwo am anfang x/=dividend;//oft y/=dividend;
ein
double factor=1/bla;//irgendwo am anfang x*=dividend; y*=dividend;
radizieren = wurzel?
jo.
also wenn die mit dem Tricks potienz 2 von abstand 10 cm besser ist, als wurzel aus ((x.b-x.a)...blabla). dann ist multiplikation schneller als wurzel, oder? soetwas muss ich unbedingt wissen.
bei if((b.x-a.x)(b.x-a.x)+(b.y-a.y)(b.y-a.y)<0.1*0.1) hab ich genausooft plutimiziert. beachte, daß das 0.1*0.1 keine plutimikation ist, da steht nur 0.01 im code, hals umständlich geschrieben.
für PhysikEngine kein float, nur ganze positive Zahlen, da ich denke floats sind ne Performancebremse und sowieso ungenau...
ja, langsamer als ints.
Datentyp mit dem es am schnellsten geht, ich nehm mal an die Integer-Wertebereich da sie plattformabhängig von 16-, 32-, 64-bit Rechner sind.
typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; typedef unsigned long long u64;
und dann nimm den, der am besten zu deinem problem passt.
Unbegrenzter Raum durch dynamische arrays+matrizen, wenn noch grösser dann auf festplatten.
also kleine nehmen.
was sind festpunktarithmetik?
wenn du meter immer in anzahl der centimeter darstellst.
also nicht double 3.13, sondern int 314 umd 3 meter und 14 centimeter zu meinen.ist schneller als double oder float. hat aber immer ne feste anzahl von nachkommastellen. und man muß ein wenig aufpassen beim rechnen.
int r=200;//radius von 2 metern
int flaeche=r*r*314;//falsch!
int flaeche=r*r*314/10000;//vielleicht richtig. man muss beim plutimizieren und dividieren noch nen stellen-ausgleich machen. naja, man schreibt sich nen datentyp dafür, der das macht, dann issses so praktisch wie double. aber schnell wie ein int. und natürlich nicht 100 also faktor sondern ne zweierpotent.multiplikaten sind lahm? was wäre dann schneller?
addieren und subtrahieren.
wenn du die fläche ausrechnen willst, kannste aber plutimikationen nicht vermeiden.ist
__int64 rdtsc(){ ___asm rdtsc; }
für intels? ich hab amd, wie ermittle ich die takts?
müßte auch für amds laufen. windows wurd ja auch nicht (außer mal bei win95 und dem loop-bug) für den amd geschrieben, sondern für intel und läuft auch.
-
xBlackKnightx schrieb:
ach ja und warum konnte der compiler nicht selbst erkennen dass die potienz von 2 in vergleichoperator schneller ist als wurzel aus 2.
weil die automatische umsetzung falsch wäre.
mal ein krasses beispiel:
if(a/3>b)
macht er dummerweise zu
(ifa>b*3)
und sobald b gräßer als MAX_INT/3 ist, gibts einen überlauf und er rechnet total falsch.
nee, du als coder mußt leider wissen, was los ist.wenn der compiler doch so toll optimieren können soll werd ich da doch skeptisch
skepsis ist gut. weiter so.
-
<OT>
@volkard: Der Wert vom url-Attribut kommt (unlogischerweise) nicht in Anführungszeichen.
</OT>
-
wurzeln die lahm. multiplikation ist auch nicht der tollste renner. wenn wurzeln unumgänglich sind, kannste im netz nach fast_sqrt oder so suchen rechtet nicht bis auf letzte bit genau, ist aber sehr flott
soweit ich weiß bauen die CPU-hersteller schon seit geraumer Zeit feste Tabellen zur Wurzelbestimmung ein, so dass wurzenlziehen bis zu einem gewissen Grad ziemlich schnell ist (muss ich noch mal Nachschlagen, aber imho ist es die genauigkeit bis hundertstel und das gibts schon bei AMD seit amd k5).
__int64 rdtsc(){
___asm rdtsc;
}es funktioniert auf einem AMD k6-2 und auch auf Intel ;
-
hmm vielen dank, eine frage noch:
wenn ich statt multiplikation
c=a*b
die addition in forschleife nehme
for( unsigned int i=0 ; i < a ; ++i) { c += b; }
ist es genau so schnell?
dass problem ist dass ich die zahl 0 in integerzyklus symbolisch als ganze positive zahl definieren will - also 0 = (die letzte zahl von integer), und die Null rausschmeisse die ich sowieso nicht gebrauchen kann
-
xBlackKnightx schrieb:
ist es genau so schnell?
Nur wenn der Compiler sehr klug ist.
-
[quote="xBlackKnightx"]wenn ich statt multiplikation
c=a*b
die addition in forschleife nehme
ist es genau so schnell?
[quote]
nein. bei *sehr* wenigen schleifendurchläufen könntest du vielleicht leicht schneller sein. bei vielen durchläufen bestimmt nicht mehr.dass problem ist dass ich die zahl 0 in integerzyklus symbolisch als ganze positive zahl definieren will - also 0 = (die letzte zahl von integer), und die Null rausschmeisse die ich sowieso nicht gebrauchen kann
das hab ich jetzt nicht verstanden.
-
[quote="volkard"][quote="xBlackKnightx"]wenn ich statt multiplikation
c=a*b
die addition in forschleife nehme
ist es genau so schnell?nein. bei *sehr* wenigen schleifendurchläufen könntest du vielleicht leicht schneller sein. bei vielen durchläufen bestimmt nicht mehr.
dass problem ist dass ich die zahl 0 in integerzyklus symbolisch als ganze positive zahl definieren will - also 0 = (die letzte zahl von integer), und die Null rausschmeisse die ich sowieso nicht gebrauchen kann
das hab ich jetzt nicht verstanden.
die Zahl 0 hat keine Funktion mit der division
von daher wäre 4 / 0 = error - was falsch wäre wenn die 0 als ganze positive zahl betrachtet wird?mal anders gesagt:
die Wertebereiche sind alles Zahlen, wie eine Uhr-Arimethik
Wenn ich short 65535 noch eine eins hinzuaddiere geht es wieder von vorn: die Null
so wäre short 65536er-Uhr-Arimethik.wenn ich jetzt 2 65536er-Uhrer-Arimethiken nehme: die erste zeigt auf 3 und die andere auf 456, und möchte die beiden uhren multiplizieren -> so muss 456 in der multiplikation 3 mal um 456 gedreht werden. und anders rum 456 mal um 3. die dritte uhr zeigt dann auf 1368
jetzt ein anderes beispiel:
wenn ich sie 0 mal 3 multipliziere, so kommt 0 raus. wenn 65536 * 3 wird es nur 3x ganz herumgedreht zeigt es wieder auf 65536 also die nullso weit so gut
so jetzt mal aufgepasst:
wenn die erste uhr auf 32768 zeigt und die andere auf NULL und die beiden dann dividiere, so kommt eine fehlermeldung raus was unlogisch wäre
denk daran dass die Null die 65536te Zahl ist, also:
32768 / 65536 = 0,5 wäreda spuckt also was
vielleicht sollte ich die division ganz vermeiden.
und etwas mehr praktizierendes machen