Abend zusammen,
Ich habe eine Frage zum zugegebenermasen eher exotischen Tool avrtest.
Ich gehöre wohl nicht wirklich zu der Zielgruppe dieses Tools, aber
vielleicht löst es mein Problem.
Ich arbeite unter Linux und würde oft gern spontan die Takte einer
Funktion zählen. Zb um optimieren zu können.
Einen Windowsrechner mit Avr Studio würd ich nur ungern benutzen
auserdem müsst ich dann jedesmal meinen Quellcode erst irgendwie ins
Studio hringen.
Also kurze Frage: kann avrtest das was ich will?
Laut winavr.cvs.sourceforge.net/viewvc/winavr/avrtest/README?view=markup
kann es ja irgendwie Takte zählen...
Vielleicht verirrt sich ja einer der avr-gcc Developer hierher und kann
mir diese Frage beantworten...
Schönen Abend noch!
Am einfachsten wäre es, die entsprechende Funktionalität in avrtest
direkt einzubauen, die Quellen hast du ja. Wobei CVS nicht mehr aktuell
ist, inzwischen ist SVN:
http://sourceforge.net/p/winavr/code/HEAD/tree/trunk/avrtest/
avrtest ist einfach genug, sich darin zurechtzufinden. Implementiert
werden könnte das über eine spezielle Adresse im SFR-Bereich analog wie
z.B. ABORT_PORT:
16-Bit Wert (oder größer) schreiben --> Ticks setzen
16-Bit Wert (oder größer) lesen --> Ticks lesen
Die entsprechende Variable ist program_cycles.
Danke dir, Johann L.!
Ich hab mit dem Tool bisl rumgespielt und testweise darin rumgebastelt
und es sieht schonmal ganz brauchbar aus.
Mein Testcode:
1
intmain(void)
2
{
3
uint8_ti;
4
5
CYCLE_PORT=0xFF;
6
7
asm("nop");
8
asm("nop");
9
asm("nop");
10
11
i=CYCLE_PORT;
12
}
produziert mir die Ausgabe:
1
Cycles:4
2
exitstatus:EXIT
3
reason:infiniteloopdetected(normalexit)
4
program:test/test.elf
5
exitaddress:0000b6
6
totalcycles:29
Das Ganze gehört natürlich noch bisl sauber gemacht und getestet, aber
für einen ersten Schuß bin ich zufrieden.
Könnte genau das sein was ich mir immer gewünscht habe. Und man kann das
Tool wunderbar in eine Make-Umgebung einbauen, etwa wie in "make
cycles".
Wie verhält sich avrtest denn wenn es zu bedingten Sprungbefehlen kommt?
Kann/muss man dazu einen Testharness oder so bedaten um den Kontrollfluß
zu lenken? Geht das überhaupt?
Grüße!
saggi schrieb:> Wie verhält sich avrtest denn wenn es zu bedingten Sprungbefehlen kommt?
avrtest folgt dem Pfad, der der Bedingung entspricht.
> Kann/muss man dazu einen Testharness oder so bedaten um den Kontrollfluß> zu lenken? Geht das überhaupt?
Ich verstehe die Frage nicht.
Prinzipbedingt liefert ein Laufzeittest für eine bestimmte Eingabe
(Daten, Programm, Daten- und Programmablage, etc.) immer eine zu diesen
gehörende Zeit bzw. Anzahl von Ticks und damit nur eine untere
Abschätzung für die WCET (Worst Code Execution Time). Egal wieviele
Tests du durchlaufen lässt, du bekommst keine Abschätzung der WCET nach
oben -- es sei denn du kannst nachweisen, dass dein Programm für alle
Eingaben und für alle möglichen Codeablagen und sonstigen möglichen
Einstellungen durchgelaufen ist.
Für AVRs ist das zwar in der Regel etwas einfacher, da z.B. die Anzahl
der Ticks pro Instruktion weder von der Ablage im Speicher noch von den
nachfolgenden oder vorhergehenden Instruktionen abhängig ist (keine
Caches, kein Pipelining, keine nicht-bekannten Wait-States, ...), aber
für nicht-triviale Programme / Algorithmen ist es immer noch keineswegs
einfach, an eine obere Abschätzung für die WCET zu kommen, die zudem
noch halbwegs brauchbar und nicht total überschätzt ist.
Eine Möglichkeit solcher statischer Codeanalyse ist die "abstrakte
Interpretation" wie sie in folgender Software:
http://www.absint.com/ait/
Allerdings gibt's die nicht für AVRs soweit ich weiß.
Ok, ich glaube ich verstehe langsam wie avrtest arbeitet.
Das Tool kennt den kompletten RAM und Flashinhalt (und damit auch
globale Variablen) und alle Funktionen (natürlich auch .c-File
übergreifend).
Allerdings ist der test rein statisch (ich hoffe das ist das richtige
Wort in diesem Zusammenhang). Externe Ereignisse können nicht simuliert
werden. Darunter verstehe ich zum einen Interrupts, zum anderen Werte
die "von außen" kommen, bspw. der Wert einer ADC-Wandlung, der aus einem
SFR gelesen wird.
Ohne externe Ereignisse ist der komplette Programmablauf bis zum
Sankt-Nimmerlein-Tag natürlich fest vorherbestimmt. D.h. es gibt nur
einen Pfad durch das komplette Programm. Selbst wenn es auf dem Weg zu
Abzweigungen kommen sollte (if-Konstrukte) kann genau bestimmt werden
welcher Weg genommen werden muss, da die "Startbedingungen" ja bekannt
sind.
Ok, folgende Funktion:
1
voidfoo(void)
2
{
3
uint8_tsomeLocalValue;
4
...
5
...
6
someLocalValue=Adc_GetResult(CHANNEL_05);
7
8
CYCLE_PORT=0xFF;
9
10
if(someLocalValue<VOLTAGE_CRITICAL)
11
{
12
...
13
...
14
...
15
}
16
else
17
{
18
...
19
...
20
...
21
}
22
...
23
CYCLE_PORT;
24
}
Ich hab mal meinen CYCLE_PORT aus meinem letzten Beitrag übernommen.
Wenn ich nun die Laufzeit der Funktion (ohne den ADC-Teil) messen will
ist das so erstmal nicht möglich.
Ich müsste meinen Code ändern, um zu steuern welcher Pfad der
If-Bedingung durchlaufen wird.
1
uint8_tmyControlFlag=123;
2
voidfoo(void)
3
{
4
uint8_tsomeLocalValue;
5
...
6
...
7
someLocalValue=Adc_GetResult(CHANNEL_05);
8
9
CYCLE_PORT=0xFF;
10
11
if(myControlFlag<VOLTAGE_CRITICAL)
12
{
13
...
14
...
15
...
16
}
17
else
18
{
19
...
20
...
21
...
22
}
23
...
24
CYCLE_PORT;
25
}
In diesem Beispiel habe ich mir eine globale Variable angelegt, die mir
den Ablauf steuert.
Jetzt kann ich meinen Test einmal im if- und einmal im else-Pfad
durchlaufen lassen.
Versteh ich das nun richtig?
Dann noch eine Frage zum ersten Beispiel:
Angenommen, irgendwo in den Tiefen von Adc_GetResult() wird aufs
ADC-Ergebnis-Register lesend zugegriffen (oder UART-Eingangsregister,
oder PIND, du verstehst was ich meine).
Was wird daraus gelesen? 0x00 vielleicht?
Viele Grüße, und danke für bisher!
saggi schrieb:> Angenommen, irgendwo in den Tiefen von Adc_GetResult() wird aufs> ADC-Ergebnis-Register lesend zugegriffen (oder UART-Eingangsregister,> oder PIND, du verstehst was ich meine).> Was wird daraus gelesen? 0x00 vielleicht?
avrtest ist in C geschrieben und RAM als Array im Static Storage
realisiert; dieses wird also beim Starten von avrtest genullt. Erste
Schreibeaktionen werden dann getriggert durch den Startcode des
geladenen Programms: SP setzen, .data und .bss initialisieren.
Allerdings ist avrtest nicht für Programme gedacht, die I/O verwenden --
egal ob intern oder extern -- oder die Interrupts verwenden. avrtest
ist ein reiner Code-Simulator für algorithmische Tests, der möglichst
schnell aufen soll, damit die GCC testsuite in erträglicher Zeit fertig
wird. Aus dem README:
1
The main intention of avrtest is to supply a fast, easy-to-use
2
simulator to run the GCC testsuite for avr-gcc. [...]
3
avrtest does not simulate internal peripherals like timers,
4
I/O ports, interrupts, etc.
Momentan ist die einzige Möglichkeit, Eingabe in ein Programm zu
bekommen, die Verwendung von STDIN_PORT.
Am ehesten kann man mit avrtest "normale" C-Programme simulieren wie
1
#include<stdio.h>
2
3
intmain(void)
4
{
5
printf("Hallo World!\n");
6
return0;
7
}
was ein "Hallo World!" auf die Console ausgibt -- vorausgesetzt, das
Programm wird gelinkt wie im README erklärt. Ansonsten kann die obige
hallo-Quelle unverändert verwendet werden.
Abgesehen vom Testen von avr-gcc eignet sich avrtest zum Auffinden von
Fehlern in komplexen Algorithmen, die man ansonsten, etwa durch scharfes
Nachdenken, nicht findet. Dazu llässt man eine Trace schreiben und
schaut, wo es hakt. Verwendet habe ich dies z.B. bei der
Implementierung der Fixed-Point Erweiterung im avr-gcc; einerseits um
schnelle Lösungen zu finden und andererseits, um für die Algorithmen
vernünftige Testabdeckung zu erlangen, wofür es immer ein kleines
Framework braucht.
Oliver schrieb:> In der Richtung gibt es ja nun noch mehr, z.B. das hier:>> http://www.nongnu.org/simulavr/>> Oliver
Den hab ich mir auch schonmal angeschaut. Wird der überhaupt noch aktiv
entwickelt? Damals wurde zB mein ATmega1284P nicht unterstützt...
Wenn er noch entwickelt werden würde wäre er super, kann immerhin als
Backend für gdb dienen.
@ Johann:
Ok, genauso hab ich mir das gedacht.
I/O ist eigentlich nicht nötig. Mir gehts eben hauptsächlich darum,
Laufzeiten von Programmteile zu messen, z.B. um Algorithmen zu
verbessern.
Das ist ja möglich, so wies aussieht.
Einzige Einschränkung: Um eine If-Abfrage in eine bestimmte Richtung zu
lenken muss ich globale Variablen verwenden. Ich werd mal bisl weiter
damit spielen und dann berichten!
Viele Grüße!
saggi schrieb:> Ich habe eine Frage zum zugegebenermasen eher exotischen Tool avrtest.> [...] Ich arbeite unter Linux und würde oft gern spontan die Takte> einer Funktion zählen. Zb um optimieren zu können.>> [...]>> Also kurze Frage: kann avrtest das was ich will?
Jupp, inzwischen kann avrtest das: heißt TICKS_PORT, ist ein
Glitch-freier 32-Bit-Zähler und kann per -ticks aktiviert werden. Das
Define zu TICKS_PORT befindet sich wie die anderen auch in avrtest.h,
das man direkt includen kann oder per -include avrtest.h.