-         

Ergebnis 1 bis 7 von 7

Thema: PROGMEM und Optimierung

  1. #1
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    11.12.2007
    Ort
    weit weg von nahe Bonn
    Alter
    33
    Beiträge
    2.380

    PROGMEM und Optimierung

    Anzeige

    SMARTPHONES & TABLETS-bis zu 77% RABATT-Kostenlose Lieferung-Aktuell | Cool | Unentbehrlich
    Hardware ATXMEGA64 @ 32MHz

    Ich sitze hier an einem sehr interssantem Thema und habe auch schon einiges an Tatsachen hervorgeholt und wollte mal eure Meinung dazu hören.

    Ich habe eine quasi Konstante Tabelle (Array) const somestruct_t data[SOMESIZE] = {...} welche ich per PROGMEM in den ROM befördert habe

    Nun stellt sich das Problem dar, dass ich von extern einen 16bit Wert erhalte den ich mit einem 16bit Wert innerhalb der Struktur vergleichen muss um anschließend je nach Lage die ein oder andere Funktion via FPointer aufzurufen.

    ich habe insgesamt 4 Ansätze probiert und das Disassembly dazu studiert um die Laufzeit zu ermitteln

    1. memcpy_P in eine statische tempvariable welche ich in einem if() vergleiche -> 32 Zyklen

    2. direkter memcmp_P im if() -> 28 Zyklen

    3. if(pgm_read_word() == extern) -> 25 Zyklen

    4. lookup im RAM über die Keys -> 9 Zyklen und später dann Zugriff auf die Pointer (in den Fällen 1-3 würde exakt dasselbe passieren)

    die Schleife sieht im moment unschön aus und soweit ich das Disassembly überschaue ist sie quasi nicht optimiert worden!

    Mein erster Gedanke war es den Vergleich zu optimieren (Option 3 oder 4) und aus der SChleife heraus einen Call zu starten um die passende Reaktion zu starten und dem Compiler das optimieren zu überlassen.

    Option 5: Mein zweiter Gedanken jedoch ging in die Richtung einen unschönen Switch() aufzubauen, ihn aber per Precompiler strukturiert zu definieren, da ich im moment für die Tabelle eh schon relativ viel funktionspointer einsetze!

    Seht ihr aus der sicht extremer RAM knappheit und eingeschränkter ROM Verfügbarkeit(mehr ROM als RAM aber nicht sehr viel mehr) noch andere Optionen oder Ansätze? Kann man eventuell noch anders Daten im ROM ablegen und effizient darüber iterieren welche ich vielleicht übersehen habe? Oder hat jemand noch einen Assembler Ansatz in der Hinterhand?

    MfG

    Ceos
    Es gibt 10 Sorten von Menschen: Die einen können binär zählen, die anderen
    nicht.

  2. #2
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.08.2008
    Ort
    DE
    Beiträge
    523
    Seh ich das richtig, dass dir diese ~25 Zyklen für den Zugriff zu lange sind oder worauf willst du hinaus?

    mfg

  3. #3
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    11.12.2007
    Ort
    weit weg von nahe Bonn
    Alter
    33
    Beiträge
    2.380
    korrekt, ich versuche gerade eine ISR zu optimieren, leider ist der restliche Teil des Programms relativ komplex und eine Neugestaltung erscheint mir aus derzeitiger Sicht unmöglich sonst hätte ich schon am Design optimert, aber es ist mir nun leider im Moment vorgegeben dass ich über eine PROGMEM Tabelle zu suchen habe um einen geeignete Reaktion auszulösen .... die eigentliche ISR ist weit größer und unnötig kompliziert weswegen keien Optimierung gelingt, zumindest daran kann ich was ändern wenn ich die Schleifen entsprechend umgestalte!

    Am liebsten wäre mir die Tabelle durch ein, per Precompiler übersichtlich gestaltetes, Switch Case zu ersetzen um dem Compiler die Optimierung voll und ganz anzuvertrauen!

    54 Einträge mit jeweils mind. 50 Zyklen für PROGMEM Zugriffe auf diese Einträge sehe ich kritisch wenn man versucht nebenbei einen 200us Cycle-Prozess laufen zu lassen und im worst case 84us nur für das Durchlaufen der Tabelle draufgehen
    Es gibt 10 Sorten von Menschen: Die einen können binär zählen, die anderen
    nicht.

  4. #4
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.08.2008
    Ort
    DE
    Beiträge
    523
    Wie siehts mit externer HW aus? Vlt nen extra RAM-IC?

    Ansonsten kann ich dir nur raten, dein Design zu überprüfen. Eine ISR sollte immer sehr kurz gehalten werden. Hört sich bei dir jetzt nicht so kurz an.

    mfg

  5. #5
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    11.12.2007
    Ort
    weit weg von nahe Bonn
    Alter
    33
    Beiträge
    2.380
    "dein Design zu überprüfen" das ist der Haken ich fress mich gerade durch das Programm weils eben nicht mein Design ist und versuch es zu schmieren! Und nochmals back to Topic bitte, ich hatte schon mehrere Ansätze gebracht und hoffte auf ein wenig Feedback zu denen oder vielleicht doch noch eine optimalere Lösung ...

    Die Kommunikation ist nicht anders als wie oben beschriebe zu lösen im Moment, das Timing ist und bleibt kritisch und der timed Prozess hat schon exklusiv höhere prio als die com ISR! Trotzdem muss ich die Com ISR in einem gewissen zeitrahmen bearbeiten und mich durch eine commandliste fressen welche im moment ineffizient in einem progmem array steckt
    Es gibt 10 Sorten von Menschen: Die einen können binär zählen, die anderen
    nicht.

  6. #6
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.08.2008
    Ort
    DE
    Beiträge
    523
    Was sind denn das für Werte in der Tabelle? 1, 2, 3, ... oder völlig Random und wie entstehen die?

    mfg

  7. #7
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    11.12.2007
    Ort
    weit weg von nahe Bonn
    Alter
    33
    Beiträge
    2.380
    es ist ein Befehlssatz und die Anordnung ist nicht zwingend Sortiert oder in irgend einer Art fortlaufend, im Moment habe ich versucht den Worst-Case zu unterdrücken indem ich die Befehle in der Initialisierungstabelle einfach nach Aufruf-Häufigkeit und nachfolgendem Rechenaufwand sortiert habe(Rechenaufwand = "decodierung" von Parametern <kurzwierig> oder instant-response <langwierig>, z.B.), aber das kann nicht das Maß der Dinge sein dass ich an der Datenbasis tunen muss! Ich tune lieber die Verarbeitung.

    Einen Teilerfolg habe ich ja schonmal mittels 108Byte RAM erkauft indem ich eine LookUp dort hinterlegt habe und einfach den Index synchron halte mit der Tabelle was aber nicht Failsafe ist! Und die 108Byte RAM schmerzen gewaltig wenn ich mir das alle so ansehe. Und es werden noch einige Befehle hinzukommen was wieder jeweils 2 Byte weniger RAM bedeutet.

    Die Hardware ist im übrigen bereits ausgereizt, da gibt es keine Luft mehr. Aber ich habe mir vorgenommen, wenn ich mal meine eigenen Vorstellungen umsetzen darf, dass ich das EBI Interface des XMega zu meinem Vorteil nutzen werde! 64MHz Bustakt und Memory Mapping sollten mit einem guten Framework-Design die Möglichkeiten erweitern ... aber auch die Platinengröße :<

    [NACHTRAG]
    okay in meinem disassembly ist mir ein feines aber BÖSES detail entgangen, ich habe eine "CALL" answeisung ignoriert welche mir überraschenderweise bei memcpy und memcmp zusätzliche 28 zyklen serviert ... ich denke mit der ersparnis durch pgm_read_word() sollte sich die Lage schon einmal gewaltig entspannen. Statt 32+28 bzw. 28+28 nur 25 Zyklen scheint mir schon ausreichend und würde auch erklären warum die Zyklen Anzahl sich im Praxistest als nicht nachvollziehbar darstellte, jetzt ergeben meine Zeitmessungen auch wesentlich mehr sinn! Mittlerweilen bin ich mir auch ziemlich sicher dass bei allen 3 Varianten mit progmem die Endianess mir einen Strich durch die Rechnung macht oder wie kann man folgendes Disassembly sinnvoll erklären ?
    Code:
    000010C9 1 MOVW R24,R16        Copy register pair 
    000010CA 1 MOVW R22,R24        Copy register pair 
    000010CB 1 LSL R22        Logical Shift Left 
    000010CC 1 ROL R23        Rotate Left Through Carry 
    000010CD 1 LSL R24        Logical Shift Left 
    000010CE 1 ROL R25        Rotate Left Through Carry 
    000010CF 1 LSL R24        Logical Shift Left 
    000010D0 1 ROL R25        Rotate Left Through Carry 
    000010D1 1 LSL R24        Logical Shift Left 
    000010D2 1 ROL R25        Rotate Left Through Carry 
    000010D3 1 ADD R22,R24        Add without carry 
    000010D4 1 ADC R23,R25        Add with carry 
    000010D5 1 SUBI R22,0x5F        Subtract immediate 
    000010D6 1 SBCI R23,0xFD        Subtract immediate with carry 
    000010D7 1 MOVW R30,R22        Copy register pair 
    000010D8 3 LPM R24,Z+        Load program memory and postincrement 
    000010D9 3 LPM R25,Z        Load program memory 
    000010DA 1 CP R24,R10        Compare 
    000010DB 1 CPC R25,R11        Compare with carry 
    000010DC 2 BRNE PC-0x1A        Branch if not equal
    [FACEPALMMODE]
    ja jetzt wird mir einiges klarer
    Code:
    if(pgm_read_word(&table[i].someval) == input)
    er muss ja erst den offset der Variable im Struct umrechnen bzw. den Offset im Array ... ich sollte manchmal nicht einfach das übernehmen was mir vorgegeben wurde
    Code:
    uint16_t *ptr = &table[i].someval;
    if(pgm_read_word(ptr) == input)
    das sollte auch unnötige Takte bei der späteren Verarbeitung sparen!
    [/FACEPALMMODE]
    [NACHTRAG]
    Code:
          const uin16_t ptr= &progmemtable[i].someval;
    000010C8  MOVW R24,R16        Copy register pair 
    000010C9  MOVW R30,R24        Copy register pair 
    000010CA  LSL R30        Logical Shift Left 
    000010CB  ROL R31        Rotate Left Through Carry 
    000010CC  LSL R24        Logical Shift Left 
    000010CD  ROL R25        Rotate Left Through Carry 
    000010CE  LSL R24        Logical Shift Left 
    000010CF  ROL R25        Rotate Left Through Carry 
    000010D0  LSL R24        Logical Shift Left 
    000010D1  ROL R25        Rotate Left Through Carry 
    000010D2  ADD R30,R24        Add without carry 
    000010D3  ADC R31,R25        Add with carry 
    000010D4  SUBI R30,0x5F        Subtract immediate 
    000010D5  SBCI R31,0xFD        Subtract immediate with carry 
          if(pgm_read_word(ptr) == input)
    000010D6  LPM R24,Z+        Load program memory and postincrement 
    000010D7  LPM R25,Z        Load program memory 
    000010D8  CP R24,R10        Compare 
    000010D9  CPC R25,R11        Compare with carry 
    000010DA  BRNE PC-0x18        Branch if not equal
    und schon spare ich mir runde 14Takte bei folgeaufrufen auf die Variable ... leider muss ich mir jeden Wert einzeln pointern

    Frage: gib es einen weg die Adresse eines Wertes innerhalb eines Structs auf Basis eine Pointers auf den Anfang selbigen Structs zu ermitteln?

    Code:
    tyble_t *ptr = &table[i];
    if(pgm_read_word(ptr+offset(someval)) == input)
    Antwort: JA und es ist optimiert sich quasi von allein weg!

    Code:
          table_t *pt = &progmemtable[i];
    000010C8  MOVW R22,R16        Copy register pair 
    000010C9  LSL R22        Logical Shift Left 
    000010CA  ROL R23        Rotate Left Through Carry 
    000010CB  MOVW R24,R16        Copy register pair 
    000010CC  LSL R24        Logical Shift Left 
    000010CD  ROL R25        Rotate Left Through Carry 
    000010CE  LSL R24        Logical Shift Left 
    000010CF  ROL R25        Rotate Left Through Carry 
    000010D0  LSL R24        Logical Shift Left 
    000010D1  ROL R25        Rotate Left Through Carry 
    000010D2  ADD R22,R24        Add without carry 
    000010D3  ADC R23,R25        Add with carry 
    000010D4  MOVW R30,R22        Copy register pair 
    000010D5  SUBI R30,0x5F        Subtract immediate 
    000010D6  SBCI R31,0xFD        Subtract immediate with carry 
          if(pgm_read_word(pt+offsetof(table_t,someval)) == input)
    000010D7  LPM R24,Z+        Load program memory and postincrement 
    000010D8  LPM R25,Z        Load program memory 
    000010D9  CP R24,R10        Compare 
    000010DA  CPC R25,R11        Compare with carry 
    000010DB  BRNE PC-0x19        Branch if not equal

    und bevor hier jetzt sowas kommt von wegen "das hätte ich auch gewusst, ist ja teil von stdlib" ... zeige mir den nicht autistischen menschen der aus dem stehgreif die ganze stdlib ohne nachschlagen oder google herbeten kann da gibt es mehr zu wissen als man wieder vergessen kann und was man nicht alltäglich verwendet vergisst man nach der schule ganz schnell wieder ... ich hab meinen post bewusst so gelassen damit jemand der etwas ähnliches sucht den gedankengang später nachvollziehen kann ...

    und zum thema Design .... Design ist ne Frage der Sicht auf die Bäume ... mal sieht man den Wald mal nicht, kommt drauf an wie tief man drinsteckt


    Schade ... gerade eben habe ich erfahren dass offsetof() laut misra verboten ist weil unzuverlässig ... bleibt wohl doch nur das redesign
    Geändert von Ceos (09.10.2013 um 12:12 Uhr)
    Es gibt 10 Sorten von Menschen: Die einen können binär zählen, die anderen
    nicht.

Ähnliche Themen

  1. Probleme mit PROGMEM Zugriff
    Von vklaffehn im Forum C - Programmierung (GCC u.a.)
    Antworten: 2
    Letzter Beitrag: 07.06.2013, 23:14
  2. PROGMEM
    Von masasibe im Forum C - Programmierung (GCC u.a.)
    Antworten: 4
    Letzter Beitrag: 24.01.2011, 16:26
  3. Code Optimierung
    Von Siro im Forum C - Programmierung (GCC u.a.)
    Antworten: 10
    Letzter Beitrag: 19.08.2010, 23:45
  4. Zusammenbau Optimierung (Spule)
    Von Ichiban im Forum Asuro
    Antworten: 9
    Letzter Beitrag: 11.12.2008, 20:11
  5. PROGMEM array auslesen geht nicht
    Von _maddin im Forum C - Programmierung (GCC u.a.)
    Antworten: 2
    Letzter Beitrag: 12.05.2007, 21:14

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •