Zeitunterschied einer Datei beim Ausführen von mehreren Dateien oder einer

#3133098
Lesenswert?

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
Persönliche Seite #3133127
Lesenswert?

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.
Persönliche Seite #3133203
Lesenswert?

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.
#3133223
Lesenswert?

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.
Gast #3133271
Lesenswert?

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
#3133652
Lesenswert?

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
#3133729
Lesenswert?

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 :-)
Gast #3133792
Lesenswert?

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!
#3133832
Lesenswert?

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.)
#3133841
Lesenswert?

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...
Gast #3133932
Lesenswert?

> 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.
#3133952
Lesenswert?

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
#3142646
Lesenswert?

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 
:-)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren