Performance-Problem BIT-Masking

Hi,

ich möchte gerne den Wert eines Bits in einem 32-Bit Unsigned Integer ermitteln.
(Linux/ElinOS g++)

Also als Funktion fallen mir 2 Lösungen ein:

Entweder 2 mal shiften

unsigned int getBitwert(unsigned int myWord, unsigned int Bitnummer){
return ((myWord \> 31);
}

oder einmal shiften und dann bitweises UND mit 1

unsigned int getBitwert(unsigned int myWord, unsigned int Bitnummer){
return ((myWord \>\> (bitnummer -1)) & 1);
}

Der Wertebereich für bitnummer sei in diesem Fall 1…32 gesetzt.

Da ich das ganze auf Performance für ein Echtzeitsystem trimmen soll, möchte ich gern wissen, welche Funktion schlußendlich schneller ist; wenn ein Wertebereich 0…31 für Bitnummer eine bessere Performance liefert, bitte auch dieses bitte dann bemerken.

Hallo Fragewurm,

Da ich das ganze auf Performance für ein Echtzeitsystem
trimmen soll, möchte ich gern wissen, welche Funktion
schlußendlich schneller ist; wenn ein Wertebereich 0…31 für
Bitnummer eine bessere Performance liefert, bitte auch dieses
bitte dann bemerken.

Da hilft nur messen, bzw. sich den Maschinencode anzusehen.

Keiner weiss, was die Optimierung deines Compilers aus dem Sourcecode macht.

MfG Peter(TOO)

Hallo,

Also als Funktion fallen mir 2 Lösungen ein:
Entweder 2 mal shiften

unsigned int getBitwert(unsigned int myWord, unsigned int
Bitnummer){
return ((myWord > 31);
}

oder einmal shiften und dann bitweises UND mit 1

unsigned int getBitwert(unsigned int myWord, unsigned int
Bitnummer){
return ((myWord >> (bitnummer -1)) & 1);
}

Ich denke, das ist hier nebensächlich. Vielmehr kommt
es auf den Aufrufkontext an. Die „Operation“ läßt sich
so und so zu je zwei vergleichbaren Maschinenbefehlen
zusammenoptimieren.

Da ich das ganze auf Performance für ein Echtzeitsystem
trimmen soll, möchte ich gern wissen, welche Funktion
schlußendlich schneller ist; wenn ein Wertebereich 0…31 für
Bitnummer eine bessere Performance liefert, bitte auch dieses
bitte dann bemerken.

Je weniger Operationen, desto besser. Wenn Du die „Bitnummer“
sofort als shift-Argument verwenden kannst, sparst Du die
Zyklen für die Subtraktion ein, das ist doch logisch.

Was willst Du denn überhaupt erreichen? Vielleicht könnte man
dort ansetzen. Wenn es „schnell“ sein soll und wenn es
unter gcc/ia32 (gcc 4.x) läuft, würde auch folgendes gehen:

#include "stdio.h"

 unsigned int GetBit(unsigned int myWord, unsigned int Bitnummer)
{
 \_\_asm\_\_ \_\_volatile\_\_( 
 "shrl %%cl, %%eax \n"
 "andl $1, %%eax \n"
 : /\* empty \*/ : "eax"(myWord),"cl"(Bitnummer)
 );
 /\* implicit return of EAX on ia32 \*/
}


 int main(int argc, char \*argv[])
{
 unsigned int i, myWord=991;
 
 for(i=0; i
Aber obige for-Schleife würde man natürlich \*komplett\*
in Assembler schreiben, wenn es darauf ankommt :wink:

Grüße

CMБ

Hi,

Wie Peter schon sagt: Messen!

zusätzlich:

  • lieber „lesbar“ implementieren, dann später messen. Meist stellt sich später heraus, dass nur wenige Zugriffe vorkommen.

  • über vergleich nachdenken (siehe nächste Zeile)

  • Statt Bitnummer direkt die Maske verwenden. Z.B.

    #define BITMASK_0 (0x0001)
    #define BITMASK_1 (0x0002)
    #define BITMASK_2 (0x0004)

    #define BITMASK_15 (0x8000)

    unsigned int checkBitMask(unsigned int myWord, unsigned int BitMask){
    return (BitMask & myWord) != 0;
    }

  • als Returnvalue (0,1) evt über einen typ bool nachdenken. erhöht nur! die lesbarkeit

  • Über #inline nachdenken, bzw. #define

    #define checkBit(val, pos) ((((unsigned int) val) & (1

    Meist kommt man dahin, dass der Bitvergleich, je nach Prozessor auch die Bitmaskierung, in einem oder wenigen Taktzyklen gemacht wird, während man bei der vermeintlichen Optimierung dahin den Compiler zu den abstrusestens Dingen zwingt. Beispiel:

    • vielleicht wird die Routine auch mit Typen und Prozessoren