Hallo, ich hab auf mehreren Mikrocontrollern das Problem, dass ich, wenn ich eine Datei und die darin enthaltenen Funktionen einzeln ausführe eine andere Laufzeit erhalte, als wenn ich diese Datei als eine von mehreren ausführe. Die einzelnen Module wurden unter C geschrieben und zusammen gelinkt, damit sie auf den jeweiligen Microcontrollern ausführbar sind. Die Programme wurden jeweils unter gleichen Bedingungen ausgeführt (gleiche Compiler- und Linkereinstellungen, gleicher Speicherbereich). Als Compiler kamen Keil und Tasking VX Toolset zum Einsatz, als Controller u.a, XMC4500 (Infineon) bzw. XC2287 (ebenfalls Infineon). Die Laufzeitunterschiede sind deutlich messbar und fallen nicht in den Bereich der Messunsicherheiten - gemessen wurde mittels Oszilloskop. Was könnte die Ursache dafür sein? Viele Grüße, Alex
vergleiche doch einfach mal den ASM code. Wenn aber ein Modul einen Interrupt nutzt, dann wird es für alle anderen natürlich langamer.
Der ASM-Code ist identisch in beiden Fällen. Nur die Adressen, auf denen die Anweisungen stehen, ändern sich logischerweise. Das Programm verwendet keine Interrupts, es ist ein rein sequentieller Durchlauf ohne Unterbrechungen. Viele Grüße
Das könnten Optimierungsunterschiede sein. Sind mehrere Funktionen in einer Übersetzungseinheit enthalten, können sie anders optimiert werden, als wenn sie in getrennten Übersetzungseinheiten enthalten sind. Beispielsweise kann sich der Compiler dazu entschließen, eine Funktion per Inlining aufzurufen (also den resultierenden Code an die Stelle des Aufrufs zu kopieren), das aber setzt naturgemäß voraus, daß der Compiler den Code der Funktion kennt, was er nicht tut, wenn der Code der Funktion in einer anderen Übersetzungseinheit enthalten ist.
Das wäre eine Erklärung - aber das Disassembly ist bis auf die Adressen identisch. Somit kann eigentlich nicht einmal Inlining und einmal kein Inlining (oder eine ähnliche Optimierung) angewendet worden sein, oder?
Wenn Du den disassemblierten final gelinkten Code miteiander vergleichst, und der identisch ist, dann kann es auch keine Laufzeitunterschiede geben. Es sei denn, das Programm wird aus dem RAM ausgeführt, und der µC, auf dem das ganze läuft, verwendet unterschiedlich schnelles RAM, wie z.B. internes SRAM gegenüber externem (S)DRAM bei manchen ARMen. Das würde den Unterschied bei unterschiedlichen Adressen erklären.
Ja, das ist genau das Mysterium. Die Adressen stammen alle aus dem gleichen Speicherbereich, liegen jedoch - je nachdem, was noch eingebunden wird - etwas auseinander. Generell habe ich das Programm aus dem Flash-ROM ausgeführt, und es müsste auch immer derselbe Flash-ROM sein. Deshalb kann ich mir auch keinen Reim darauf machen, wie soetwas sein kann. Ein Detail: Das Projekt bleibt unangetastet. Wenn eine bestimmte, vom Rest unanhängige Funktion ausgeführt werden soll, muss ein Define in einer Konfig-Datei gesetzt sein. Es werden also nur Defines auskommentiert oder eben nicht. Der Aufruf der Funktion wird durch das Define gesteuert. Sonst finden keine Änderungen statt. Der beschriebene Effekt tritt bei verschiedenen - zwischen den Tests immer gleich gehaltenen Einstellungen - auf. Derzeit kann ich dieses Verhalten z.B. unter -O0 in Keil µVision reproduzieren. Der Laufzeitunterschied beträgt hier aktuell 300ms, auf eine Gesamtlaufzeit von etwa 7s, was ja schon erheblich ist. Gemessen wird in 1/100s über Oszi, Debugger läuft nicht mit (Hard-Reset und los). Meine Ideen bisher: -Whole Program Optimization --> ist laut Compiler-String nicht eingeschaltet, aber wer weiß, was der Compiler für generelle Features hat? -near/far Jumps: Aber dann müssten eigentlich andere Sprünge im Disassembly verwendet werden, oder? Ich nehme weitere Vorschläge/Ratschläge/Ideen gern an :-) Habe sowas noch nie gesehen.
Kannst du das Programm hochladen? Oder zum Testen Teile des Programms entfernen bis nur noch die Funktion(en) da ist(sind), die einen Laufzeitunterschied haben? Gruß
Hallo, man macht das in C normalerweise ja nicht, aber rein testhalber, verschieb mal nur ein Programm das betroffen ist im Speicher (absolut adressieren, Null-Blöcke einfügen, es gibt da verschiedene Möglichkeiten), um festzustellen, ob schon allein die Verschiebung eine Änderung der Ausführung bewirkt. Gruss Reinhard
Das Programm und auch Teile kann ich leider nicht hochladen, da das Programm nicht herausgegeben werden soll. Den Rest kann ich erst morgen machen. Danke an alle, die mir bisher geholfen haben.
Wenn das Controller mit Zusatzfunktionen für ISO 26262 "Funktionale Sicherheit" sind, dann machen die nach dem Reset möglicherweise erst mal einen Speichertest. Mißt Du die Laufzeit ab Reset, oder hast Du einen speziellen Marker für den Begin der zu messenden Funktion? So long, Tillomar
Es ist möglich, dass die Controller einen Speichertest machen. Wir messen hier aber erst ab einem definierten Punkt nach dem vollständigen Init, quasi ab einem Punkt in der main(). @Reinhard Kern: Das ist ein guter Tipp, ich wollte ohnehin das Programm soweit zusammenkürzen, bis ich eine minimale Version habe (wie auch im vorherigen Post vorgeschlagen). Dabei könnte ich das gleich mit probieren. Mal noch was anderes: Wenn der Linker selbst Adressen verteilt, auf denen dann irgendwo im gleichen Speicher (gleicher Typ, z.B. das interne Flash-ROM) die Funktionen stehen, kann es sein, dass man da ggf. über irgendwelche Segmentgrenzen hinweg adressieren muss, und das ganz einfach länger dauert? Wenn ja, würde man das anhand der Befehle im Disassembly sehen (geänderte Sprungbefehle), oder würde der Controller das 'stillschweigend' machen? In die Pipeline der Controller können wir ja nicht reinschauen... Vielen Dank für die rege Beteiligung :-)
Alexander Fischer schrieb: > ine > andere Laufzeit erhalte, als wenn ich diese Datei als > eine von mehreren ausführe In welchem Bereich? Minuten? Sekunden? Nanosekunden? ... Wieso ist das relevant? (Wird ein benötigtes Zeitverhalten nicht mehr eingehalten?)
Läubi .. schrieb: > Alexander Fischer schrieb: >> ine >> andere Laufzeit erhalte, als wenn ich diese Datei als >> eine von mehreren ausführe > In welchem Bereich? Minuten? Sekunden? Nanosekunden? ... Wieso ist das > relevant? (Wird ein benötigtes Zeitverhalten nicht mehr eingehalten?) steht alls schon lange da!
Das kommt zum großen Teil auf die Gesamtsituation an. Derzeit sind es bei einem XMC4500 Testprojekt 0,3s auf insgesamt etwa 7,0s. Es hat aber auch schon andere Controller gegeben, bei denen das prozentual noch mehr ausmacht. Es ist halt kein verlässliches Zeitverhalten (ich denke da z.B. an Programme, die unter gewissen Echtzeitanforderungen laufen, und wo durch Hinzufügen / Entfernen von Code sich die Laufzeit anderer Methoden ändert, obwohl die völlig unabhängig arbeiten. Um aber Missverständnisse zu vermeiden: wir haben bei den Tests hier noch KEINE Interrupts am laufen.)
Zusätzliche Erkenntnis: Es ist sogar so, dass eine nur mit Nops gefüllte Methode die Laufzeit der eigentlich zu messenden Methode verändert. Dadurch, dass damit offenbar mehr Code erzeugt wird, muss sich irgendwas im Speicher ja verschieben, und das scheint die Laufzeit zu beeinflussen. Es ist sogar so, dass wenn die Nop-Methode mehrfach aufgerufen wird, mal die Laufzeit der Testmethode steigt, und mal sinkt, je nachdem, wie oft man die Nop-Methode davor aufruft. Wir messen natürlich nur die Laufzeit um die Testmethode, die Nops sind außen vor...
Alexander Fischer schrieb: > Es ist sogar so, dass eine nur mit Nops gefüllte Methode die Laufzeit > der eigentlich zu messenden Methode verändert. gibt es nicht soetwas wie ein simualor? Damit sollte man doch genau erkennen wo die zeit vergeht.
Es ist auch ein zeitlicher Unterschied ob man ganze Speicherblöcke transportiert oder irgendwo einzelne Speicherzellen befehlsweise holen muß.
> kann es sein, dass man da ggf. über irgendwelche Segmentgrenzen hinweg
adressieren muss, und das ganz einfach länger dauert.
Kann sein. Ich kenne diesem µC nicht gut genug, um diese Frage mit
Sicherheit zu beantworten.
Du hast ja schon geprüft, dass der Assembler Code gleich ist. Es kann
also nicht an Unterschieden zwischen Long-Jump und Short-Jump liegen.
Jedoch gibt es eventuell Befehle, die je nach Parameter-Wert
unterschiedlich lange brauchen (wie man es z.B. von Divisionen kennt)
und bei Deinem Fall eine Rolle spielen.
unterscheidet sich der Speichertyp? Level1 / Level2 Cache? landen durch die anderen Adresse die Daten in ungecachten Speicher?
Doch unterschiedliche Speicherbereiche? Im RM zu den XMC4x00 sind zwei Speicherbereiche aufgeführt die zwar auf den selben physischen Speicher gemappt sind, aber einmal gecached das andere mal ungecached. 8.4.3 PMU0 Program Flash Bank non-cached PMU0 Program Flash Bank cached space (different address space for the same physical memory, mapped in the non- cached address space) 8.4.4 The PMU allows 4x64-bit burst accesses to the cached address space and single 32-bit read accesses to the non-cached address space of the PFLASH. The Prefetch generates the 4x64-bit bursts for code and data fetches from the cached address range in order to fill one cache line or the data buffer respectively. Data reads from the non-cached address range are performed with single 32-bit transfers
Nach langem Suchen scheinen zumindest einige Verdächtige ausgemacht: Beim XMC4500 scheint es Unterschiede zwischen Keil µVision 4.60 und 4.70a zu geben, derart, dass unter 4.70a der Effekt kaum nachweisbar ist, umso deutlicher aber in Version 4.60. In den Release-Notes werden diverse Compiler-Probleme, im Zusammenhang mit falschen Condition-Flags genannt, die ab 4.70 behoben sein sollen. Daher könnte dies ein Grund für die Laufzeitunterschiede sein. Zusätzlich scheint auch der Cache eine Rolle zu spielen, wenn man den Code im Cached Flash ausführt (wir haben sowohl cached als auch non-cached Flash untersucht). Man kann durchaus seine Wirkung messen. Zusätzlich kommt - vor allem bei non-Cached Flash - die Wirkung des Instruction Prefetch zum Tragen. Der Effekt ist messbar, verglichen mit den Laufzeiteffekten bei Version 4.60 aber geringer ausgeprägt. Bei ähnlichen Beobachtungen bei einem XC2000 und Tasking VX Toolset habe ich mich an den Tasking-Support gewandt. Eine Antwort steht noch aus, jedoch scheint der Linker auch einen Einfluss zu haben. Streicht dieser z.B. nicht benötigten Code und Daten raus, ändert sich auch (in geringen Maßen) die Laufzeit. Soviel erstmal als Update zu der Problematik. Vielen Dank nochmal für die vielen Beiträge. Weitere Hinweise sind natürlich stets willkommen :-)
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.