Registerobjekte werden sicher in Register der CPU geladen und lassen sich schnell verarbeiten und abrufen. Dazu zählen sicherlich Zählvariablen in Schleifen.
"Sicher" ist gar nix, es kann ja z.B. sein, daß alle Register schon belegt sind.
Zitat
Die Hauptspeicherobjekte finden sicherlich im Hauptspeicher platz. Gibt es da etwas zu beachten was die Laufzeit betrifft? Ich habe gehört, dass es günstig ist, wenn die Zieladresse des Sprungs an den Anfang durch 32 teilbar ist.
Das mag auf bestimmten Architekturen von Vorteil sein. Wenn es so ist, wird das ein gescheiter Compiler arrangieren, daß dein Code so ausgelegt ist. Ansonsten kann man mit Heapobjekten nicht sehr viel herumoptimieren außer daß man auf Lokalität achtet, d.h. z.B. bevorzugt benachbarte Array-Elemente begrapschen und nicht weit voneinander entfernte.
Zitat
Es gäbe da angeblich soetwas wie prefetching wo man gleich mehr Cache anfordern kann. Wird das vom Compiler erledigt oder kann das der Programmierer z.B. in c selbst übernehmen?
Als Programmierer kannst du das (in Standard-C) nicht beeinflussen.
Zitat
Gibt es für mich eine Möglichkeit festzustellen welche Variablen von meinem Programm welcher Speicherklasse zugeordnet werden? Werden z.B. arrays grundsätzlich als Hauptspeicherobjekte behandelt?
Sehr wahrscheinlich. Allerdings, wenn du auf Lokalität bei Zugriffen achtest, kommen die Vorteile des Caches zum Tragen, und die Zugriffe sind fast gratis.
Zitat
Kann ich in der Programmiersprache C darauf Einfluss nehmen welche Variable in den Hauptspeicher kommt oder als Zählvariable in ein Register oder macht das ausschließlich der Compiler?
Du kannst bei der Deklaration das register-Keyword verwenden:
Das ist zwar nur ein Vorschlag an den Compiler, aber er kann einiges bringen. Ob es so ist, kannst du nur messen. Beachte, daß die x86-Architektur sehr sehr sehr sehr sehr sehr wenige general-purpose-Register besitzt.
Zitat
for (int a = 0; a < N; a++)
m1[a] += m2[a];
BTW, du weißt eh, daß das nicht (Standard-) C89 ist?
Mal abgesehen vom Unrolling, ein optimierender Compiler wird diesen Code für eine passende Konstante (z.B. 4) ungefähr so lesen:
a = 0;
while (a < N) {
*(m1 + a*4) = *(m2 + a*4);
a++;
}
Ein paar einfache Transformationen, zuerst common subexpression elimination:
a = 0;
temp = 0;
while (temp < N*4) {
temp = a*4;
a++;
*(m1 + temp) = *(m2 + temp);
}
Strength reduction:
a = 0;
temp = 0;
while (temp < N*4) {
temp += 4;
a++;
*(m1 + temp) = *(m2 + temp);
}
Elimination der unnötigen Variablen a;
temp = 0;
while (temp < N*4) {
temp += 4;
*(m1 + temp) = *(m2 + temp);
}
Elimination der unnötigen Variablen temp:
temp2 = m1 + N*4;
p1 = m1;
p2 = m2;
while (p1 < temp2) {
*p1++ = *p2++;
}
Hübsch, nicht? Und du brauchst dich um die Zählvariable nicht kümmern, weil es sie nicht gibt.
Der Schlüssel zu optimalem Code: Möglichst klaren Code schreiben, bei dem kennt sich der Compiler am besten aus. Keine Pointer auf lokale Variablen setzen, Variablen möglichst lokal halten, Array-Zugriffe möglichst einfach halten (z.B. nicht in einer Schleife an verschiedenen Stellen in einem Array rumgurken), Pointer nur dort einsetzen, wo unbedingt nötig.