2009-12-16 5 views
3

Je travaille dans le projet dans lequel j'ai le code suivant:Optimisation pour la division sur "extern const int"

fichier1.c

extern const int z; 
int x; 
do_some_stuff_to_calculate_x(); 
y = x/z; 
do_some_stuff_with_y(); 

fichier2.c

const int z = Z_INIT_VALUE; // some value defined in some .h file. 

Le point d'intérêt est la division en file1.c. Puisque z est extern, il n'est donc pas connu au moment de la compilation [il sera défini en temps de liaison]. Ainsi, le compilateur ne peut pas optimiser la division.

Je sais que si la valeur de z est connue au moment de la compilation, le compilateur convertira la division en multiplication et d'autres manipulations. Notez que file1.c sera livré en tant que bibliothèque, donc recompiler file1.c avec file2.c n'est pas une option.

Est-ce que quelqu'un sait à l'avance que l'éditeur de liens optimise de telles choses? Ou toute autre astuce pour éviter cette division CHERCHANTE?

Thx :)

Mise à jour:

Eh bien, après avoir vu des réponses que je remarquai que quelques détails sont nécessaires pour rendre cette question plus d'information. J'utilise un microcontrôleur de la société renesas (famille SH725).

  • Cette division se trouve dans de nombreux endroits dans le code, avec de nombreuses variantes.
  • La plupart des autres éléments du code sont directement en lecture et écriture dans les registres et les ports (pas de surcharge, c'est-à-dire: 0x0ABCDEFF = 15). Les fonctions qui incluent la division sont normalement semblables à ceci.

    extern const int common_divisor; 
    extern const int common_addition; 
    
    void handleTheDamnInterrupt(void) 
    { 
        int x = *(REG_FOO_1); 
        int y = x/common_divisor; 
        y += common_addition; 
        if(x > some_value) 
        { 
         y += blah_blah; 
        } 
        else 
        { 
         y += foo_bar; 
        } 
    
        *(REG_BAR_1) = y; 
    } 
    

    Cette fonction est la forme de fonction typique dans tout le programme. Je ne peux pas savoir exactement combien de division affecte le programme parce que j'ai beaucoup de ces fonctions avec une périodicité différente.
    Mais quand j'ai essayé d'enlever le extern du const et lui a donné une valeur arbitraire, c'était mieux.

  • +0

    Mettez le const dans un en-tête? –

    +1

    @Pavel: Devrait être un '# define' alors, ou vous vous retrouverez avec plusieurs définitions. – Thomas

    +0

    ++ J'ai toujours upvote newbies :) –

    Répondre

    3

    Vous pouvez effectuer vous-même la même optimisation en effectuant un calcul de configuration au moment de l'initialisation. L'algorithme inventé par Terje Mathisen pour convertir une division entière en une multiplication est décrit ici: http://www.asdf.org/~fatphil/x86/pentopt/27.html

    +1

    ++ C'est * nifty *. –

    2

    L'éditeur de liens Microsoft, pour un, l'optimisera. C'est ce qu'on appelle la "génération de code de lien". Here's an article about it (daté, mais toujours utile). Il est allumé avec le /LTCG flag.

    +0

    bien que je n'utilise pas les compilateurs microsoft, mais il est bon de savoir sur ce LTCG. :) – Yousf

    +0

    Je crois que GCC peut également faire l'optimisation de la liaison, si vous l'utilisez. –

    +0

    Plus tard, j'ai trouvé que mon compilateur faisait aussi l'optimisation du temps de liaison. Faire des trucs d'optimisation pour cette division augmente la charge CPU: D – Yousf

    2

    Ceci est une micro-optimisation si jamais je l'ai vu. Vous devriez profiler, et probablement éditer votre question avec quelques résultats indiquant pourquoi il est si important d'optimiser cette opération d'entier simple. Si z est réellement constante et initialisée à partir d'un symbole de préprocesseur, placez simplement ce symbole dans l'en-tête de la bibliothèque et arrêtez de l'introduire en tant que variable d'exécution.

    +0

    'z' est vraiment const, mais il sera défini dans la phase de liaison. Je vais compiler file1.c pour obtenir file1.o et l'envoyer à une autre équipe. Cette autre équipe ne doit pas voir file1.c. Cette équipe aura aussi une certaine valeur dans ce fichier d'en-tête et compilera ses fichiers puis reliera tout pour obtenir un exécutable. – Yousf

    +0

    Ceci est une micro-optimisation SAUF si vous travaillez sur une plate-forme embarquée très lente où les divisions ne sont pas optimisées dans le processeur (comme dans la plupart des processeurs de bureau) – Earlz

    0

    Vos appels à do_some_stuff l'emporteront de loin sur la division entière.

    +0

    non :) En fait, do_some_stuff_to_calculate_x() lira certaines valeurs de certains registres le microcontrôleur et do_some_stuff_with_y() écriront la valeur dans un autre registre. les deux opérations sont très triviales .. – Yousf

    +0

    @Yousf: Laissez-moi le dire autrement. Cette division devrait prendre environ 10-50 nanosecondes, ou peut-être une microseconde au maximum si le processeur est lent. L'exécutez-vous plus de 100 000 fois par seconde? Sinon, vous avez probablement plus de poisson à frire. –

    +0

    @Mike: Cela dépend de ce sur quoi vous travaillez. Cela pourrait être important sur un processeur embarqué bas de gamme, ce que certaines entreprises pourraient faire pour économiser quelques dollars sur la production de masse de quelque chose. Yousf a mentionné "microcontrôleur" dans son commentaire, après tout. –