mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Gleiche Funktion. 23 cycles anstelle von 6?


Autor: Simon M. (simon2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frage:

Das ganze läuft auf einem 16Bit, PIC24F

Meiner Ansicht nach würde der zweite code deutlich schneller ablaufen
als der erste.

Jedoch ist genau das gegenteil der Fall.
Warum?

// 6 cycles
typedef union _ade_status1_t
{
    DWORD Val;
    struct __PACKED
    {
//...
            UINT8 SEQERR:1;
//...
    } bits;
} status1_t;

    if (status.bits.SEQERR) {
        Nop();
    }

// 23 Cycles
    #define STATUS1_SEQERR   0x00080000

    if (x & STATUS1_SEQERR) {
        Nop();
    }


ASM1:
0x2406: MOV [W14+2], W4
0x2408: AND W4, #0x8, W4
0x240A: SUB W4, #0x0, [W15]
0x240C: BRA Z, 0x2410

ASM2:
0x2412: MOV [W14+4], W6
0x2414: MOV [W14+6], W7
0x2416: MOV #0x0, W4
0x2418: MOV #0x8, W5
0x241A: MOV W6, W0
0x241C: MOV W7, W6
0x241E: MOV W4, W7
0x2420: MOV W5, W4
0x2422: AND W0, W7, W0
0x2424: AND W6, W4, W4
0x2426: MOV #0x0, W5
0x2428: SL W4, #0, W5
0x242A: MOV #0x0, W4
0x242C: MOV.D W4, W6
0x242E: MUL.UU W0, #1, W4
0x2430: IOR W6, W4, W6
0x2432: IOR W7, W5, W7
0x2434: SUB W6, #0x0, [W15]
0x2436: SUBB W7, #0x0, [W15]
0x2438: BRA Z, 0x243C
0x243A: NOP
0x243C: NOP

: Bearbeitet durch User
Autor: Rainer U. (r-u)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simon M. schrieb:
> Warum?

Weil es der Compiler so übersetzt hat, dass er sinnloserweise mit 16bit 
statt 8 bit Variablen arbeitet?

Autor: Simon M. (simon2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja nur das ist schon nen gewaltiger unterschied.

Ich will mich ja nicht über die paar instruction cycles aufregen, nur 
wenn der das überall so macht, mir ist das ja nur durch zufall 
aufgefallen.

Autor: M. K. (sylaina)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simon M. schrieb:
> Meiner Ansicht nach würde der zweite code deutlich schneller ablaufen
> als der erste.

Warum sollte es das? Beim 2. If machst du eine &-Verknüpfung, beim 1. 
übergibst du nur ein Bit. Ist doch klar, dass der 1. Code viel schneller 
sein muss.

Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und nun sollen wir alle mal raten, welchen Typ x hat oder wie?

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn Nop() das macht, was ich denke, daß es macht: warum muß das 
besonders schnell machen?

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rainer U. schrieb:
> Weil es der Compiler so übersetzt hat, dass er sinnloserweise mit 16bit
> statt 8 bit Variablen arbeitet?

Die PIC24 sind 16-Bitter

Simon M. schrieb:
> #define STATUS1_SEQERR   0x00080000

Ich sehe da 32 Bit

MfG Klaus

Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus schrieb:
> Die PIC24 sind 16-Bitter
>
> Simon M. schrieb:
>> #define STATUS1_SEQERR   0x00080000
>
> Ich sehe da 32 Bit

wo?

auch eine 000000000000000000000008 sind nur 8 bit.

ein define ist überhaupt keine Variable und hat sogar 0 bits.

Autor: Random .. (thorstendb) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sind struct/union Maps generell für ne gute Idee, weil man dann dem 
Compiler ermöglicht, aufzudrehen?

Autor: ui (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter II schrieb:
> wo?
>
> auch eine 000000000000000000000008 sind nur 8 bit.
>
> ein define ist überhaupt keine Variable und hat sogar 0 bits.

absolut richtig. Wenn dann müsstest du schon explizit casten, wenn du 
sicher 32bit haben willst

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter II schrieb:
> wo?

da:

Simon M. schrieb:
> 0x2416: MOV #0x0, W4
> 0x2418: MOV #0x8, W5

MfG Klaus

Autor: Axel S. (a-za-z0-9)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simon M. schrieb:
> Meiner Ansicht nach würde der zweite code deutlich schneller ablaufen
> als der erste.

Mit dieser Ansicht bist du deutlich in der Minderheit.

> Jedoch ist genau das gegenteil der Fall.
> Warum?

Weil der Compiler aus der & Verknüpfung von Variable und Bitmaske nicht 
abliest, daß er in Wirklichkeit nur ein Bit testen muß. Ein exzellent 
optimierender Compiler könnte die konstante Bitmaske natürlich daraufhin 
abklopfen. Aber der real existierende Compiler macht es offensichtlich 
nicht, sondern implementiert das

if (variable & maske) 

auf die kanonische Weise, indem er alle Bits der Variable mit allen Bits 
der Maske ver-UND-et und dann testet, ob irgend ein Bit gesetzt ist.

Auf einer Architektur mit einer 32-Bit ALU wäre das gleich schnell. Dein 
16-Bitter braucht aus offensichtlichen Gründen länger.

Interessant wäre, was der Compiler hieraus macht:

    if (((x>>16)&0xFF) & 0x08) {
        Nop();
    }

und ob das schneller ist als

    if ((x>>16) & 0x08) {
        Nop();
    }


PS: man könnte auch noch probieren:

    if (((uint8_t)(x>>16)) & 0x08) {
        Nop();
    }

: Bearbeitet durch User
Autor: NurEinGast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und
0x00080000 ist auch nicht mit
0x00000008 zu vergleichen.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Axel S. schrieb:
> Ein exzellent optimierender Compiler

... ist das in diesem Fall jedenfalls nicht - oder die Optimierung war 
abgeschaltet. Denn der ASM2 Code ist für optimierten Code wirklich unter 
aller Sau.

Ich meine mich zu erinnern, dass Microchips freie Compiler-Version bei 
Optimierung eingeschränkt ist. Intern ist der Compiler von Microchip der 
GCC plus etwas proprietärem Kram. Und der GCC sollte sich nicht so doof 
anstellen. Wenn man ihn lässt.

: Bearbeitet durch User
Autor: Ste N. (steno)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, ich hab das mal kurz probiert, MBLAP IDE 8.87, Compiler Microchip 
c30
// Code 1
typedef union _ade_status1_t
{
    unsigned long val;
    struct __PACKED
    {
      unsigned char bla:3;
      unsigned char SEQERR:1;
    } bits;
} status1_t;

int main (void)
{    
    volatile status1_t status;
  
    if (status.bits.SEQERR) {
        Nop();
    }
    
    while (1) {
    };
}

Asm1 ohne Optimierung:
00296  78401E     mov.b [0x001c],0x0000
00298  604068     and.b 0x0000,#8,0x0000
0029A  E00400     cp0.b 0x0000
0029C  320001     bra z, 0x0002a0
0029E  000000     nop

Asm1 mit Optimierung -Os:
00296  97F8CF     mov.b [0x001e-4],0x0002
00298  60C068     and.b 0x0002,#8,0x0000
0029A  320001     bra z, 0x00029e
0029C  000000     nop



// Code 2
#define STATUS1_SEQERR   0x00080000
  
int main (void)
{
    volatile unsigned long x;
    if (x & STATUS1_SEQERR) {
        Nop();
    }
  
    while (1) {  
    };
}

Asm2 ohne Optimierung:
00296  90001E     mov.w [0x001c+2],0x0000
00298  9000AE     mov.w [0x001c+4],0x0002
0029A  DE0843     lsr 0x0002,#3,0x0000
0029C  200001     mov.w #0x0,0x0002
0029E  600061     and.w 0x0000,#1,0x0000
002A0  E00400     cp0.b 0x0000
002A2  320001     bra z, 0x0002a6
002A4  000000     nop

Asm2 mit Optimierung -Os:
00296  97B86F     mov.w [0x001e-4],0x0000
00298  97B8FF     mov.w [0x001e-2],0x0002
0029A  A33801     btst.z 0x0002,#3
0029C  320001     bra z, 0x0002a0
0029E  000000     nop

Asm2 mit Optimierung -Os:
Einzige Änderung:
#define STATUS1_SEQERR   0x0008
volatile unsigned int x;
00296  97B87F     mov.w [0x001e-2],0x0000
00298  A33800     btst.z 0x0000,#3
0029A  320001     bra z, 0x00029e
0029C  000000     nop

Welchen Compiler benutzt Du? Von Microchip scheint es ja keiner zu sein.

: Bearbeitet durch User
Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Steffen N. schrieb:
> volatile unsigned long x;

Das "volatile" zwingt den Compiler, alle 32 Bit zu lesen. Ansonsten wäre 
es ein Fehler.

Besser ist für vergleichende Tests, den Code jeweils in eine 
Unterfunktion zu packen mit den Variablen als Argument bzw. Returnwert. 
Dann entfallen alle Seiteneffekte.
Und ein Leser kann den Code compilieren, ohne hellsehen zu müssen, 
welchen Typ Deine Variablen haben.

Autor: Ste N. (steno)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Peter,

Danke für den Tipp. Ja ich hatte die Variable als volatile deklariert, 
da sonst das ganze if-Konstrukt wegoptimiert wurde. Jetzt hab ich es 
nochmal, wie von dir vorgeschlagen, als Funktion getestet. Hier das 
Ergebnis.

typedef union _ade_status1_t
{
    unsigned long val;
    struct __PACKED
    {
      unsigned char :3;
      unsigned char SEQERR:1;
    } bits;
} status1_t;

#define STATUS1_SEQERR   0x00080000

void func1 (status1_t status);
void func2 (unsigned long x);
  
int main (void)
{    
    status1_t status;
    unsigned int x;

    status.val = 0;
    x = 0;
    
    func1 (status);
    func2 (x);
  
    while (1) {
    };
}

void func1 (status1_t status)
{
    if (status.bits.SEQERR) {
        Nop();
    }
}

void func2 (unsigned long x)
{
    if (x & STATUS1_SEQERR) {
        Nop();
    }
}


Asm mit Optimierung -Os:
34:                void func1 (status1_t status)
35:                {
36:                  if (status.bits.SEQERR) {
 00294  600068     and.w 0x0000,#8,0x0000
 00296  320001     bra z, 0x00029a
37:                    Nop();
 00298  000000     nop
 0029A  060000     return
38:                  }
39:                }
40:                
41:                void func2 (unsigned long x)
42:                {
43:                  if (x & STATUS1_SEQERR) {
 0029C  A33801     btst.z 0x0002,#3
 0029E  320001     bra z, 0x0002a2
44:                        Nop();
 002A0  000000     nop
 002A2  060000     return

Autor: Sebastian S. (amateur)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So lange der Vorrat reicht.

... ist eine Strategie, die die Compiler klaglos unterstützen.

Der Bug sitzt meist an der Tastatur.
Werden einfach, kritiklos Variablen definiert, so gehen die Compiler, im 
Allgemeinen, davon aus, dass das Ganze auch ernst gemeint ist. Ihn 
interessiert nicht, ob eine 32-Bit Variable nur im Bereich vom 0 bis 20 
genutzt wird. Setzt also die passenden Rechenalgorithmen ein.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.