• [^] # Re: suckless !! More is less !

    Posté par . En réponse au journal Pourquoi un PC ralentit-il ?. Évalué à 3.

    Hum, il y a quand même des « bonnes pratiques », du genre si j'ai quelque chose comme ça (en supposant une archi 64 bits) :

    struct toto_s {
     uint8_t f1;
     uint32_t f2;
     uint16_t f3;
     uint64_t f4;
     uint8_t f5;
    };

    ... Alors comme vous disiez Nicolas et toi, le compilateur sera obligé de remplir les octets pour aligner sur la taille des mots. La structure précédente risque fort d'être générée ainsi (et la norme force les compilateurs à respecter l'ordre des champs d'une structure):

    struct toto_s {
     uint8_t f1;
     uint32_t f2;
     uint16_t f3;
     char padding1[1]; // alignement sur 64 bits
     uint64_t f4; // déjà aligné ! 
     uint8_t f5;
     char padding2[7]; // alignement sur 64 bits
    };

    ... et donc toto_s gaspille 64 bits en alignement. La bonne pratique qu'on m'a toujours indiquée (et qui ne dépend pas de l'endianness à ma connaissance), c'est de toujours trier mes champs par ordre décroissant par défaut :

    struct toto_s {
     uint64_t f4; // déjà aligné ! 
     uint32_t f2;
     uint8_t f1;
     uint16_t f3;
     uint8_t f5; 
     // Pas besoin de padding : tous les champs sont alignés sur 64 bits !
    };

    À ma connaissance (mais mes souvenirs datent, donc je peux me tromper), avec les champs de bit, les problèmes d'alignement sont les mêmes, avec le piège du type entier choisi pour représenter les données :

    struct foo_s {
     uint64_t a1;
     uint16_t f1 : 1;
     uint16_t f2 : 4;
     uint16_t f3 : 8;
     uint16_t f4 : 4; 
    };

    La structure foo_s utilise 17 bits, et déclare qu'ils appartiennent à un u16... et du coup il faut allouer deux u16 l'un après l'autre. Si j'avais utilisé u8, j'aurais pu potentiellement économiser 8 bits. Évidemment, dans l'exemple précédent, il faut de toute façon tenir compte du padding général, et au final, ma structure ressemblera sans doute à quelque chose de ce genre :

    struct foo_s {
     uint64_t a1; // déjà aligné 
     uint16_t f1 : 1;
     uint16_t f2 : 4;
     uint16_t f3 : 8; // fin du premier u16
     uint16_t f4 : 4; // deuxième u16
     char padding1[4];
    };

    Après, il y a toujours des trucs un peu « sioux » à faire, par exemple si le champ f1 de toto_s est partagé par plusieurs threads, il faudra sans doute rajouter du padding autour, pour éviter les problème de faux partage (false sharing), mais là ça devient sans doute un peu trop tordu...