Hallo, zu Optimierungszwecken versuche ich herauszufinden, ob eine bestimmte Variable abc in meinem Code irgendwann mal gelesen wird. Also, es kann ja sein, dass die Variable nur geschrieben wird - das wäre in Ordnung und interessiert mich nicht. Mich interessieren die Lesezugriffe. Der Code wird generiert und ist sehr umfangreich, händische Prüfung scheidet da leider aus. (Gibt ja auch Zeiger auf die Variable, Funktionsübergaben, structs und arrays die indirekt auf die Variable zugreifen etc etc). Debugging ist auch nicht möglich. Daher dachte ich: Der Compiler kann ja zumindest Warnungen anzeigen, wenn eine Variable nicht benutzt wird. Dazu muss er ja auch die Zugriffe prüfen. Kann ich mir beim Compilieren irgend ein Output-file erzeugen, dessen Informationen mir bei meinem Problem helfen? Oder hat jemand vll eien ganz andere Idee, mein Problem zu lösen?
Schnapphase schrieb: > Daher dachte ich: Der Compiler kann ja zumindest Warnungen anzeigen, > wenn eine Variable nicht benutzt wird. Dazu muss er ja auch die Zugriffe > prüfen. Kann ich mir beim Compilieren irgend ein Output-file erzeugen, > dessen Informationen mir bei meinem Problem helfen? Ich unterstelle, daß es sich um 1. AVR-8-Bit Prozessoren, 2. die Programmiersprache "C", 3. den Compiler gcc unter Windows handelt. Die .lss Datei (?) - erzeugbar per Checkbox in den Compileroptionen - enthält genau diese Informationen: Suchen auf den Variablennamen in der Datei, Art des Zugriffs prüfen, fertig. Für globale Daten ist die .map Datei ebenfalls brauchbar. Bernhard
Hi, fast richtig - geht aber um TriCore ;) Sonst passt's, gcc unter Windows und ja, C. Sorry, hätte ich noch erwähnen können. Die .map Datei spuckt er mir auch aus, da sehe ich aber nur, in welchen Objects die Variable verwendet wird. Es wird aber nicht zwischen Lese- und Schreibzugriff unterschieden. Eine .lss Datei hab ich noch nie gesehen. und Checkboxen hab ich bei meinem gcc auch nicht, ist dir evtl das zugehörige Flag für gcc bekannt?
Ein grep mit Variablennamen über alle .c-Files liefert dir schonmal alle Zeilen, in denen die Variable vorkommen. Die musst du dann absuchen. Bei Zugriffen über Pointern, memcopy, unions, und ähnlichen Spielchen kommen die dann noch hinzu. Oder mal doxygen über die Quellen laufen lassen, dessen output ist auch ganz hilfreich, um solche Fragen zu beantworten. Auch schön ist ein hardware-debugger mit break on read ;) Oliver
Vielen Dank erstmal für deine Hilfe. Mein Problem ist, dass die Prüfung wirklich 100%ig korrekt sein muss. Der Debugger fällt daher schonmal raus, denn man kann mit vernünftigem Aufwand nicht absichern, dass wirklich alle möglichen Programmpfade beim Debugging durchlaufen werden. Auch wenn das halt on read natürlich optimal wäre ;) Gleiches gilt für deinen grep-Vorschlag - schließlich gibt es Fälle, bei denen z.B. Zeigerzugriffe erst zur Laufzeit feststehen.
1 | pExample = &iExample + INPUT_PINS; |
Wenn die Belegung der Input-Pins halt zufällig so ist, dass pExample auf den zu untersuchenden Speicherbereich zeigt, hat man verloren. Gut, ob das nun praktisch wirklich relevant ist, sei mal dahingestellt... Am liebsten wäre mir wirklich erstmal ein beim Compilieren generierter Outupt - klar wäre der auch nicht 100%ig sicher, aber der Aufwand wäre gleich Null und man könnte sich Gedanken machen, wie man damit weitermacht. Doxygen schaue ich mir an. Für alle anderen Vorschläge bin ich offen ;)
Schnapphase schrieb: > Am liebsten wäre mir wirklich erstmal ein beim Compilieren generierter > Outupt - klar wäre der auch nicht 100%ig sicher, aber der Aufwand wäre > gleich Null und man könnte sich Gedanken machen, wie man damit > weitermacht. gcc bietet eine Option, beim Compilieren ( Compile - ASM - LINK ) nach dem Compile Schluß zu machen und die entstandenen Assembler-Dateien zu analysieren. Der Name der Opßtion steht in der gcc Dokumentation. Bernhard
Schnapphase schrieb: > Gleiches gilt für deinen grep-Vorschlag - schließlich gibt es Fälle, bei > denen z.B. Zeigerzugriffe erst zur Laufzeit feststehen. > pExample = &iExample + INPUT_PINS; Und genau diesen Fall kannst du nie ausschließen. Dinge die erst zur Laufzeit feststehen kann man nunmal nicht zur Compilezeit prüfen. Du kannst natürlich den erzeugten ASM Quelltext automatisiert untersuchen was etwas einfacher sein sollte als den C-Quelltext, aber auch dort sind Zugriffe mittels Pointer auf die Variable nicht wirklich einfach aufzudecken. Kurz und gut: Vermeide es die Adresse der Variable zu ermitteln (ist ja laut deiner Aussage generierter Code) und prüfe dann auf Schreibzugriffe mittels grep. Matthias
> gcc bietet eine Option, beim Compilieren ( Compile - ASM - LINK ) nach > dem Compile Schluß zu machen und die entstandenen Assembler-Dateien zu > analysieren. Der Name der Opßtion steht in der gcc Dokumentation. > Du kannst natürlich den erzeugten ASM Quelltext automatisiert > untersuchen was etwas einfacher sein sollte als den C-Quelltext Ja, das hab ich mir auch schon gedacht, die ASM files habe ich auch schon generieren können. Also wenn Codeparser, dann wohl mit dem Assemblercode. Ich dachte halt nur, bevor ich mit nem Parser anfange, dass ich erstmal wegen den Compilergeschichten Infos einhole. Weil bei einem einfachen grep wirds nicht bleiben - Reicht ja schon, wenn die Variable als Zeiger einer Funktion übergeben wird, dann muss ja auch diese Funktion analytisiert werden, wobei die Variable dort anders benannt ist. Oder wenn ein Pointer auf die Variable gesetzt wird und dann halt damit zugewiesen bzw. gelesen wird. Und dann kann ja auch wieder ein Pointer auf den Pointer... und Arrays.... und ganz hässlich: Structs, die dann den Speicherbereich der Variable umschließen... usw usw usw. Ein einfaches grep wird da nicht reichen :/ Werde da wohl nicht drumrum kommen... > Vermeide es die Adresse der Variable zu ermitteln Wie meinst du das? Die Adresse steht bei mir nach dem linken ja schon fest.
Schnapphase schrieb: > Ja, das hab ich mir auch schon gedacht, die ASM files habe ich auch > schon generieren können. Also wenn Codeparser, dann wohl mit dem > Assemblercode. Das ist aber nicht viel weniger spassig, als im C-Code. Die Adresse kann in Registern stehen, je nach Compiler wird da noch gepusht und "gepoppt". Ich kenne zwar jetzt den Tricore nicht, aber es würde mich wundern, wenn der keine indirekten oder indizierten Adressierungsarten kennt. Das mit der 100%igen Sicherheit wird da auch schwierig. Oliver
Benenn einfach die Variable um, und schau dir die Fehler an, die der Compiler wirft !
einfach schrieb: > Benenn einfach die Variable um, und schau dir die Fehler an, die der > Compiler wirft ! geht leider nicht wenn irgendwo direkt auf den speicher der variable zugegriffen wird. *((*int)0x1234) = 12;
Ich frage mich ja, in welcher Situation man sich die Frage stellen muss, ob eine bestimmte Variable gelesen wird. Sollte man als Autor nicht wissen, was sein Programm tut? - Und was ist daran so schlimm, wenn besagte Variable gelesen wird?
Schnapphase schrieb: > Mein Problem ist, dass die Prüfung wirklich 100%ig korrekt sein muss. Du hast verloren. Denn das Aliasing-Problem ist unentscheidbar.
Es geht hierbei um ein Universitätsprojekt zur Entwicklung eines Codegenerators. Der vom Codegenerator erzeugte Quelltext soll bestimmten Prüfungen unterzogen werden, daher diese etwas 'weltfremde' Problemstellung. Ist wohl alles ziemlich theoretisch, daher ist auch keine HW vorhanden, auf der man debuggen könnte. Warum jetzt genau nur auf Lesezugriffe geachtet wird, weiß ich leider selbst nicht ;)
Im universitären Umfeld sollte man IMHO schon wissen, daß das prinzipiell nicht geht. Aliasing ist nämlich eines der absoluten Standardprobleme in Compilerbau und Codeanalyse. Also setzt man Heuristiken ein und ignoriert die weltfremden Abweichungen (Codeanalyse) oder übersetzt konservativ (Compilerbau) oder schränkt die Programmiersprache ein (siehe C mit "strict aliasing").
Hi wenn doch aber C-Code generiert wird könnte man den ja mit einem anderen Compiler übersetzen so das der Code auf debugfähiger Hardware (also im einfachsten Fall x86) lauffähig wird. Dann einen entsprechenden Datenbreakpoint erzeugen, das Programm mit Testdaten füttern und mit einem code coverage Werkzeug prüfen ob zumindest alle Zweige durchlaufen werden. Es kann natürlich auch nützlich sein den generierten Code in kleine Einheiten zu teilen und diese dann separat zu testen -> Unit Test. Matthias
Μαtthias W. schrieb: > Dann einen entsprechenden > Datenbreakpoint erzeugen, das Programm mit Testdaten füttern und mit > einem code coverage Werkzeug prüfen ob zumindest alle Zweige durchlaufen > werden. Völlig unausreichend, denn dass aller Code durchlaufen wurde heißt noch lange nicht, dass jeder Pointer auch jeden möglichen Wert angenommen hat. Die gewünschte 100%-Lösung ist wie erwähnt schon theoretisch nicht machbar.
Schnapphase schrieb: > Es geht hierbei um ein Universitätsprojekt zur Entwicklung eines > Codegenerators. Der vom Codegenerator erzeugte Quelltext soll bestimmten > Prüfungen unterzogen werden, daher diese etwas 'weltfremde' > Problemstellung. > > Ist wohl alles ziemlich theoretisch, daher ist auch keine HW vorhanden, > auf der man debuggen könnte. Um einen Codegenerator zu prüfen ist ein Compiler nicht das beste Werkzeug. Da schreibst besser einen Code-Generator-Prüfer ;-) Um zu sehen, ob und wieviele Zugriffe (egal ob lesend und/oder schreibend) geschehen, kommst du nicht umhin, das Programm ablaufen zu lassen und per Profiling Informationen zu sammeln. Da man nicht weiß, wie lange das Programm läuft -- Halteproblem lässt grüssen -- muss die erzeugte Software schon bestimmte Eigenschaften sicherstellen, daß sie zB nach einer bestimmten Zeit oder bestimmter Anzahl Instruktionen terminiert. Andere Bedingung an den Generator wäre, daß der Code statisch analysierbar ist, aber selbst mit dieser starken Restriktion ist ein Compiler nicht das Werkzeug der Wahl. Dierzu gibt es Software zur statischen Analyse, die aber den Uni-Etat sprengen dürfte ;-) Ebenso zu klären ist auch, ob die Anzahl der Zugriffe statisch zu bestimmen sind oder dynamisch. Beides erfordert komplett verschiedene Ansätze. Auch andere Hardware ist keine Lösung, da auf dieser ein anderer Compiler den Code erzeugt. Daß der vielleicht "GCC" heisst tut da nix zur Sache. Ein anderes System ist also kein Modell für deinen TriCore + gcc. Problem beim Profiling ist jedoch, daß es den Code verändert bzw. das Programm andere Ablaufeigenschaften hat; es ist also zunächst zu klären, was in dem Zusammenhang unter "Programm" zu verstehen ist: Es ist ja durchaus möglich, daß ein "foo=1" im C-Programm steht, sich aber nicht mehr im erzeugten Binary findet. Die Übersetzungsprozess sind die Nebenwirkung, die der Code hat, invariant. Mehr nicht. Jedenfalls wird der Code nicht Eins-zu-Eins übersetzt. Am ehesten praktikabel ist die Verwendung eines Simulators und Compilererweiterungen wie Virtual Profiling -- unter der Voraussetzung, daß das Halteproblem-Dingens geklärt ist. Solche Erweiterungen gibt es zB für neuere Verionen des tricore-gcc von HighTec; und viele andere tricore-gccs dürften nicht unterwegs sein. Ergo: den Support fragen, was man dazu braucht. Die Analyse gilt dann allerdings nur für bestimmte Ablaufpfade.
Erstmal an dieser Stelle vielen Dank an alle für die zahlreichen Hinweise. Vor allem Johann, zu deinen Tipps werde ich mich mal belesen.
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.