Hallo Zusammen, bin in den letzten Tagen auf ein Problem gestoßen, das ich mir nicht erklären kann. Vielleicht hat jemand von euch eine Idee. Ich habe Rechenzeitmessungen durchgeführt und es hat sich herausgestellt, dass die Funktion beim ersten Aufruf mindestens doppelt so lang wie bei den weiteren Aufrufen. Es wird kein Initialisierungscode oder ähnliches durchlaufen. Gemessen wurde die Rechenzeit sowohl mit internem Timer als auch mit Oszilloskop an einem Pin. Ich habe es an zwei Prozessoren (ARM9, Nios) mit zwei Entwicklungsumgebungen probiert. Messungen wurden z.T. mit un ohne Cache gemacht. Es ändert sich zwar einiges an den Absolutwerten und auch das Verhältnis, allerdings ist der erste Aufruf IMMER signifikant länger. Bisher ist mir so etwas nie aufgefallen, weiß jemand, was der Grund dafür ist? Mfg Alex
Der Hellseher spricht die richtige Problematik an: - Welche Programmiersprache? - Welcher Compiler? - Welcher Code? (Minimalbeispiel) - Betrifft es alle Funktionen oder nur die eine? - Andere besondere Umstände? (z.B. Interrupts die dazwischenfunken)
NAja die heutigen CPUs sind halt ganz schön komplex und eigenlich nicht mehr echtzeitfähig (deterministisch). Da sind halt nicht nur chaes sondern auch noch Sprungvorhersage Einheiten drinne. Es könnte halt sein das er beim ersten durchlauf merkt an welchen Stellen wieoft, wohin verzweigt wurde und er beim zweitenmal da schon weiß.
Uwe schrieb: > Es könnte halt sein > das er beim ersten durchlauf merkt an welchen Stellen wieoft, wohin > verzweigt wurde und er beim zweitenmal da schon weiß. nein die Künstliche Intelligenz ist in den aktuellen CPUs noch nicht enthalten. Cache könnte zwar eine auswirkung haben, aber die Sprungvorhersage ist meines wissens nicht lernfähig.
@ Uwe (Gast) >NAja die heutigen CPUs sind halt ganz schön komplex Ja. >und eigenlich nicht >mehr echtzeitfähig (deterministisch). uhhh, da weden aber zwei völlig verschiedene Sachen zusammengerührt. Auch komplexeste CPUs arbeiten VOLLKOMMEN deterministisch. http://de.wikipedia.org/wiki/Determinismus_%28Algorithmus%29 Denn sonst würden sie nicht funktionieren. Das Problem ist jedoch, dass die Vorhersage über das Verhalten sehr komplex geworden ist und damit in vielen Anwendungen, die exaktes Zeitverhalten fordern, praktisch kaum vorhergesagt werden kann, es gibt zuviele Einflußgrößen und Übegrangsmöglichkeiten. Deutlich einfachere Automaten sind eben deutlich leichter und damit praktisch nutzbar vorhersagbar.
Peter II schrieb: > nein die Künstliche Intelligenz ist in den aktuellen CPUs noch nicht > enthalten. Cache könnte zwar eine auswirkung haben, aber die > Sprungvorhersage ist meines wissens nicht lernfähig. Da sagt der Wikipedia-Artikel zur SPrungvorhersage aber etwas anderes.
Ups Sorry :-D.. Ich dachte ich hab alle Infos eingefügt. Programmiersprache: C Compiler: IAR 6.40 für die Tests auf dem ARM9, Nios II IDE 9.0SP2 GCC für den Nios Betrifft alle Funktionen die ich ausprobiert habe. Also so an die 15. Interrupts waren beim NIOS komplett aus, auf dem ARM war der Funktionsaufruf aus einem Interrupt mit der höchsten Priorität Im folgenden Beispielcode mit einer Dummy Funktion. ACKh_OFF und ACKh_ON setzt den Output.
1 | volatile xy; |
2 | void testfcn(void) |
3 | {
|
4 | int i=0; |
5 | int k=0; |
6 | int array[100]; |
7 | for(i=0;i<1;i++) |
8 | {
|
9 | xy=i; |
10 | array[0]=i; |
11 | array[0]=xy; |
12 | }
|
13 | for(k=0;k<1;k++) |
14 | {
|
15 | xy=k; |
16 | array[1]=k; |
17 | array[1]=xy; |
18 | }
|
19 | }
|
20 | |
21 | int main() |
22 | {
|
23 | int i=0; |
24 | ACKh_OFF; |
25 | for(i=0;i<50;i++) |
26 | {
|
27 | ACKh_OFF; |
28 | }
|
29 | while (1) |
30 | {
|
31 | ACKh_ON; |
32 | testfcn(); |
33 | ACKh_OFF; |
34 | }
|
35 | return 0; |
36 | }
|
Ich hoffe jetzt sinds genügend Infos? Gruß Alex
Peter II schrieb: > aber die Sprungvorhersage ist meines wissens nicht lernfähig. Dann besser dein Wissen doch einfach auf: http://en.wikipedia.org/wiki/Branch_predictor
Läubi .. schrieb: > Dann besser dein Wissen doch einfach auf: > http://en.wikipedia.org/wiki/Branch_predictor habe ich gerade nachgeholt. Die Frage ist ob diese CPU denn soetwas schon hat. Und das danach eine funktion doppelt so schnell ist nur wegen der Sprungvorhersage ist nun doch sehr unrealistisch.
Der verwendete NiosII/f hat "Dynamic branch prediction". ARM9 muss ich noch prüfen
Der NIOS-II hat sowas, ARM vermutlich auch, die "Funktion" wird wohl komplett wegoptimiert, sodass ausschließlich der Rücksprung in der while zählt, und der wird sehr wohl von einem branchpredict profitieren (sogar wenn es nur ein sehr simpler 'last-taken' ist und kein statischer).
> uhhh, da weden aber zwei völlig verschiedene Sachen zusammengerührt.
Ich meinte deterministisches Zeitverhalten
Läubi .. schrieb: > die "Funktion" wird wohl > komplett wegoptimiert, sodass ausschließlich der Rücksprung in der while > zählt Daher sollte die Funktion ein paar volatiles enthalten.
volatile ist vorhanden (siehe oben). Funktion wird nicht wegoptimiert. Ich habe den Assembler code vom NIOS angeschaut.
Peter II schrieb: > Der schrieb: >> Daher sollte die Funktion ein paar volatiles enthalten. > > hat sie doch Stimmt, das habe ich übersehen.
1 | volatile xy; |
2 | void testfcn(void) |
3 | {
|
4 | int i=0; |
5 | int k=0; |
6 | int array[100]; |
7 | for(i=0;i<1;i++) |
8 | {
|
9 | xy=i; |
10 | array[0]=i; |
11 | array[0]=xy; |
12 | }
|
13 | for(k=0;k<1;k++) |
14 | {
|
15 | xy=k; |
16 | array[1]=k; |
17 | array[1]=xy; |
18 | }
|
19 | }
|
Der Compiler sollte das so optimieren:
1 | volatile xy; |
2 | void testfcn(void) |
3 | {
|
4 | xy=0; |
5 | xy; |
6 | xy=0; |
7 | xy; |
8 | }
|
Da ist also kaum Code übrig und dann ist der Cache laufzeit entscheidend.
nach der optimierung sollte eigentlich gar kein Sprung mehr vorhanden
sein
> for(i=0;i<1;i++)
wird wohl komplett aufgelöst werden.
Ihr habt recht, ich hatte aber auch schon andere Werte > 1 drin. Was die Cache Laufzeit angeht: da habe ich auch schon Tests dazu gemacht. Hatte am Anfang der Funktion eine Schleife die für einige Zyklen nichts gemacht hat, dann das Ausgangs-Bit getoggelt, und dann den eigentlichen Algorithmus abgearbeitet. So müsste ja der Cache wieder gefüllt sein, oder? Werd mich mal eingehend mit der Branch prediction beschäftien. Vielleicht ist das wirklich die Lösung... Sonnige Grüße aus dem Süden Alex
Eine mögliche Ursache könnten die lokalen Variablen: Das Reeservieren von Speicher für die loaklen Variablen kann davon abhängen was vorher an Speicher genutzt wurde. Ohne sich den erzeugten ASM Code anzusehen ist das ganze aber ein relativ wildes raten.
Ulrich schrieb: > Eine mögliche Ursache könnten die lokalen Variablen: Das Reeservieren > von Speicher für die loaklen Variablen kann davon abhängen was vorher an > Speicher genutzt wurde. lokale Variabel werden doch auf den Stack gelegt, dabei ist egal was vorher vorhanden war.
ab schrieb: > So müsste ja Warum? Man sollte, wenn man irgendwas messen will (und erst recht wenn man auf scheinbare Widersprüche trifft) verifizieren. Die komplette Architektur des NIOS-II ist dokumentiert, auch Caches, Branch-Predict und man kann das ganze sogar simulieren lassen... Also kein Grund zu spekulieren. Der schrieb: > Stimmt, das habe ich übersehen Ich auch, trotzdem ist die Laufzeit konstant wie Peter Dannegger schriebt, vermutlich wird sogar der Funktionsaufruf wegoptimiert, selbst bei > 1 kann der Compiler durch loop-unrolling Sprünge vermeiden. ab schrieb: > eine Schleife die für einige Zyklen nichts gemacht hat Wenn wirklich "nichts" gemacht wird, wird auch diese wegoptimiert, auch ist hier weniger der Instructioncache interessant sondern der Branch-Predict.
Ich wollte nur kurz informieren, dass es der (Instruction) Cache war, der hier die Unterschiede in der Rechenzeit verursacht hat. Bei komplett abgeschaltetem Cache oder Aufruf anderweitiger Funktionen, die zu einer Cache-Umwälzung geführt haben, war die Rechenzeit für die Funktionsaufrufe gleich (langsam). Danke für die Unterstützung hier im Forum! Gruß Alex
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.