optimaler Arrayzugriff?
-
Ich bezweifle, dass da ein unterschied bleibt. Warum sollte der compiler nicht sehen, dass a[i] mehrfach benutzt wird und es dennoch nur einmal bestimmen (bzw. Die adresse davon)? Gewissheit kriegst du letztlich nur indem du dir den assembler-output anschaust. Aber ich würde tippe , dass da identischer code rauskommt.
-
Ich bin mir ziemlich sicher, dass keiner der großen Compiler dafür unterschiedlichen Code erzeugt.
-
Mal davon abgesehen, dass der Compiler das wahrscheinlich besser optimieren kann als du, währe es besser über die Pointer zu iterieren, als über die indices.
A* a_end = a+iMax; for (A* pA=a; pA!=a_end; ++pA) fkt(pA->ni, pA->nj, pA->x);Das ist das gleiche, wie:
for (auto pA=std::begin(a); pA!=std::end(a); ++pA) fkt(pA->ni, ->nj, pA->x);und das ist das gleiche wie:
for (auto& pA : a) fkt(pA.ni, pA.nj, pA.x);Wie man hierbei sieht, ist die beste Lösung identisch mit der übersichtlichsten.
-
andreasgeorg schrieb:
for(int i=0; i!=iMax; ++i) { A *pA = &a[i]; fkt(pA->ni, pA->nj, pA->x); }for(int i=0; i!=iMax; ++i) { A *pA = a++; fkt(pA->ni, pA->nj, pA->x); }oder
A* a = ...; A* a_end = a + iMax; while(a != a_end) { A *pa = a++; fkt(pa->ni, pa->nj, pa->x); }
-
Wenn du wirklich so performancekritische Anforderungen hast solltest du dir überlegen, ob du nicht vielleicht eine Bibliothek wie Blitz++ einsetzen kannst/möchtest.
-
Ich danke Euch allen für die Antworten.
Ich werde erstmal den Code weiter bearbeiten wie bisher und nur ganz vorsichtig Änderungen in Angriff nehmen. Die Varianten kann ich dann ja in verschiedenen Simulationen laufen lassen und messen ob es Unterschiede gibt.
Blitz++ schaue ich mir mal an, bin aber eher skeptisch ob ich damit arbeiten werde. Im Zweifel ist eine lauffähige Version wichtiger als der mögliche Gewinn - wie gesagt es handelt sich um alte Codes aus Fortran Zeiten die übersetzt habe bzw. noch daran arbeite.
-
andreasgeorg schrieb:
Die Varianten kann ich dann ja in verschiedenen Simulationen laufen lassen und messen ob es Unterschiede gibt.
Vergiss nicht, die Compileroptimierung auf das bestmögliche einzustellen und gegebenenfalls auch SSE, SSE2 oder so anzugeben oder entsprechende Prozessortypen (z.B. core2) einzustellen.
Im Allgemeinen gilt aber, dass der gesamt Code erstmal so übersichtlich wie möglich geschrieben wird und wenn alles funktioniert, bestimmt man mit dem Profiler die Engpässe und optimiert diese von Hand auf das Maximum, aber vorher nicht.
-
Marthog schrieb:
Im Allgemeinen gilt aber, dass der gesamt Code erstmal so übersichtlich wie möglich geschrieben wird und wenn alles funktioniert, bestimmt man mit dem Profiler die Engpässe und optimiert diese von Hand auf das Maximum, aber vorher nicht.
Nö, das ist mir zu stark. Man soll Performance von Anfang an mit im Auge haben.
-
bestimmt man mit dem Profiler die Engpässe und optimiert diese von Hand auf das Maximum
Und wenn du ein ineffizientes Design gewählt hast?
Oder bestimmte Algorithmen/Methoden, die langsam sind, und von denen die Struktur deines Programmes abhängt?Ich denke, die Faustregel ist doch, all das, was austauschbar ist, nicht im Vorfeld zu optimieren?
-
Sone schrieb:
bestimmt man mit dem Profiler die Engpässe und optimiert diese von Hand auf das Maximum
Und wenn du ein ineffizientes Design gewählt hast?
Effizientes Design gehört zur Grundlage des Programms und nicht zur abschließenden Optimierung.
-
Marthog schrieb:
Effizientes Design gehört zur Grundlage des Programms
Wo kommt jetzt auf einmal diese Ausnahme her? Du hast geschrieben
Im Allgemeinen gilt aber, dass der gesamt Code erstmal so übersichtlich wie möglich geschrieben wird

Nö, das ist mir zu stark.
-
Sone schrieb:
Wo kommt jetzt auf einmal diese Ausnahme her? Du hast geschrieben
Im Allgemeinen gilt aber, dass der gesamt Code erstmal so übersichtlich wie möglich geschrieben wird
Ich finde die Aussage von Marthog absolut korrekt.
Im Allgemeinen gilt:
- Das Design so effizient wie möglich
- Die Implementation so kurz/einfach wie möglich
- Im Profiler nachgewiesene Engpässe optimieren(Natürlich im Allgemeinen, manchmal lohnt sich schon im Voraus zu micro-optimieren, manchmal ist auch ein effizientes Design schnuppe)
-
codee schrieb:
Im Allgemeinen gilt:
- Das Design so effizient wie möglich
- Die Implementation so kurz/einfach wie möglich
- Im Profiler nachgewiesene Engpässe optimierenDie Punkte widersprechen sich aber. Es geht nicht um Mikrooptimierungen (Ja, die Ausgangsfrage war eine Frage nach einer Mikrooptimierung, aber das ist sicher nicht das, was volkard und Sone meinen). Das Design sollte von Anfang an so effizient wie möglich sein, wozu Überlegungen zählen, was überhaupt effizient ist. Dies zieht dann eventuell aber eine nicht ganz einfache Implementierung nach sich. Ein schlechtes Design kannst du mit dem Profiler so sehr optimieren wie du willst, es wird dadurch nicht gut, außer du veränderst es komplett. Wenn du am Ende alles komplett umschreiben musst, dann wünscht du dir, du hättest von vornherein an Effizienz gedacht.
-
SeppJ schrieb:
Die Punkte widersprechen sich aber.
Ein universeller Ratschlag ist immer widersprüchlich.
Es gibt aber Spielraum, was Design und was Implementation ist. Der Code in den Funktionen kann Implementation sein. Die Wahl des Algorithmus kann Implementation sein. Der ganze Parser (z.B.) kann Implementation sein. Die Strukturen zum Datenaustausch sollten generisch genug sein, mit verschiedenen Implementierungen ohne grobe Änderung klarzukommen.
-
@SeppJ
Wenn man es verstehen will, dann ist da kein Widerspruch. Erfordert nichtmal irgendwelche geistigen Verrenkungen:- Das Design so effizient wie möglich
- Die Implementierung dieses Designs so kurz/einfach wie möglich (d.h. so einfach wie es geht ohne das effiziente Designs zu verändern)
- Im Profiler nachgewiesene Engpässe optimieren
Damit es sinnvoll bleibt setzt das natürlich vorauss dass das "Design" relativ high-level ist, und keine sinnlosen, voreiligen und aufwendigen Optimierungen vorsieht/erfordert.
-
codee schrieb:
Es gibt aber Spielraum, was Design und was Implementation ist. Der Code in den Funktionen kann Implementation sein. Die Wahl des Algorithmus kann Implementation sein. Der ganze Parser (z.B.) kann Implementation sein. Die Strukturen zum Datenaustausch sollten generisch genug sein, mit verschiedenen Implementierungen ohne grobe Änderung klarzukommen.
Das ist ein richtiger, aber sehr allgemeiner Vorschlag. Aber von immer nur Abstrahieren passiert nichts. Irgendwann muss man konkret werden und Code schreiben, der auch wirklich etwas tut. Dann kann und sollte man auch mal im Voraus nachdenken, wie eine gute Implementierung aussieht.
-
SeppJ schrieb:
codee schrieb:
Es gibt aber Spielraum, was Design und was Implementation ist. Der Code in den Funktionen kann Implementation sein. Die Wahl des Algorithmus kann Implementation sein. Der ganze Parser (z.B.) kann Implementation sein. Die Strukturen zum Datenaustausch sollten generisch genug sein, mit verschiedenen Implementierungen ohne grobe Änderung klarzukommen.
Das ist ein richtiger, aber sehr allgemeiner Vorschlag. Aber von immer nur Abstrahieren passiert nichts. Irgendwann muss man konkret werden und Code schreiben, der auch wirklich etwas tut. Dann kann und sollte man auch mal im Voraus nachdenken, wie eine gute Implementierung aussieht.
Hab ich das missverständlich geschrieben? Implementation = Quick and dirty, Gegenteil von Abstraktion.
Abhängig vom Grad der Abstraktion ist halt mehr oder weniger kurz/einfach.
-
Performance ist nicht orthogonal zum restlichen Design und muss bei der Planung des Programms beruecksichtigt werden. Gegebene Mikrooptimierung faellt aber nicht in diesen Bereich.