J'ai entendu de diverses sources (bien que principalement d'un de mes collègues), que la compilation avec un niveau d'optimisation -O3
en g ++ est en quelque sorte «dangereuse», et devrait être évitée en général à moins que cela ne soit prouvé.
Est-ce vrai, et si oui, pourquoi? Dois-je rester fidèle -O2
?
c++
optimization
g++
compiler-flags
Dunnie
la source
la source
-O3
est considéré comme particulièrement buggy? Je pense que cela peut peut-être aggraver un comportement indéfini, car il peut faire des choses étranges et merveilleuses en fonction de certaines hypothèses, mais ce serait de votre faute. Donc en général, je dirais que ça va.-O2
s'allume-fstrict-aliasing
, et si votre code survit, il survivra probablement à d'autres optimisations, car c'est une erreur que les gens se trompent encore et encore. Cela dit, ce-fpredictive-commoning
n'est que dans-O3
, et l'activation pourrait activer des bogues dans votre code causés par des hypothèses incorrectes sur la concurrence. Moins votre code est erroné, moins l'optimisation est dangereuse ;-)-Ofast
cela, cela désactive par exemple la gestion des NaNs conforme à l'IEEERéponses:
Au début de gcc (2.8 etc.) et à l'époque des egcs, et redhat 2.96 -O3 était parfois assez buggé. Mais cela fait plus d'une décennie, et -O3 n'est pas très différent des autres niveaux d'optimisations (en buggyness).
Il a cependant tendance à révéler des cas où les gens s'appuient sur un comportement indéfini, car ils s'appuient plus strictement sur les règles, et en particulier les cas de coin, de la ou des langues.
À titre personnel, j'exécute depuis plusieurs années un logiciel de production dans le secteur financier avec -O3 et je n'ai pas encore rencontré de bug qui n'aurait pas existé si j'aurais utilisé -O2.
À la demande générale, voici un ajout:
-O3 et en particulier des indicateurs supplémentaires tels que -funroll-loops (non activé par -O3) peuvent parfois entraîner la génération de plus de code machine. Dans certaines circonstances (par exemple sur un processeur avec un cache d'instructions L1 exceptionnellement petit), cela peut provoquer un ralentissement en raison de tout le code, par exemple d'une boucle interne qui ne correspond plus à L1I. Généralement, gcc essaie assez fort de ne pas générer autant de code, mais comme il optimise généralement le cas générique, cela peut arriver. Les options particulièrement sujettes à cela (comme le déroulement de boucle) ne sont normalement pas incluses dans -O3 et sont marquées en conséquence dans la page de manuel. En tant que tel, c'est généralement une bonne idée d'utiliser -O3 pour générer du code rapide, et de ne retomber sur -O2 ou -Os (qui essaie d'optimiser la taille du code) que lorsque cela est approprié (par exemple lorsqu'un profileur indique que L1I manque).
Si vous souhaitez pousser l'optimisation à l'extrême, vous pouvez modifier dans gcc via --param les coûts associés à certaines optimisations. Notez également que gcc a maintenant la possibilité de mettre des attributs sur des fonctions qui contrôlent les paramètres d'optimisation uniquement pour ces fonctions, donc lorsque vous trouvez que vous avez un problème avec -O3 dans une fonction (ou que vous voulez essayer des drapeaux spéciaux pour cette fonction uniquement), vous n'avez pas besoin de compiler tout le fichier ou même tout le projet avec O2.
otoh il semble que des précautions doivent être prises lors de l'utilisation de -Ofast, qui stipule:
ce qui me fait conclure que -O3 est censé être entièrement conforme aux normes.
la source
std::sort
fonctions est peu susceptible de vous aider. Utiliser quelque chose comme stackoverflow.com/questions/109710/… pourrait aider, ou peut-être écrire la source pour tirer parti du tri: scan jusqu'à ce que vous voyez> = 128, puis commencez à additionner. En ce qui concerne le code gonflé, oui, j'ai l'intention de le signaler. : PDans mon expérience quelque peu mouvementée, appliquer
-O3
à un programme entier le rend presque toujours plus lent (par rapport à-O2
), car il active le déroulement et l'incrustation de boucle agressifs qui font que le programme ne tient plus dans le cache d'instructions. Pour les programmes plus importants, cela peut également être vrai par-O2
rapport à-Os
!Le modèle d'utilisation prévu pour
-O3
, après le profilage de votre programme, vous l'appliquez manuellement à une petite poignée de fichiers contenant des boucles internes critiques qui bénéficient réellement de ces compromis agressifs espace-pour-vitesse. Les nouvelles versions de GCC ont un mode d'optimisation guidé par profil qui peut (IIUC) appliquer sélectivement les-O3
optimisations aux fonctions chaudes - automatisant efficacement ce processus.la source
L'option -O3 active des optimisations plus coûteuses, telles que la fonction inline, en plus de toutes les optimisations des niveaux inférieurs «-O2» et «-O1». Le niveau d'optimisation «-O3» peut augmenter la vitesse de l'exécutable résultant, mais peut également augmenter sa taille. Dans certaines circonstances où ces optimisations ne sont pas favorables, cette option peut en fait ralentir un programme.
la source
Oui, O3 est plus bogué. Je suis un développeur de compilateur et j'ai identifié des bogues gcc clairs et évidents causés par O3 générant des instructions d'assemblage SIMD buggy lors de la construction de mon propre logiciel. D'après ce que j'ai vu, la plupart des logiciels de production sont livrés avec O2, ce qui signifie que O3 recevra moins d'attention par rapport aux tests et aux corrections de bogues.
Pensez-y de cette façon: O3 ajoute plus de transformations au-dessus de O2, ce qui ajoute plus de transformations au-dessus de O1. Statistiquement parlant, plus de transformations signifient plus de bugs. C'est vrai pour tout compilateur.
la source
Récemment, j'ai rencontré un problème d'utilisation de l'optimisation avec
g++
. Le problème était lié à une carte PCI, où les registres (pour les commandes et les données) étaient représentés par une adresse mémoire. Mon pilote a mappé l'adresse physique à un pointeur dans l'application et l'a donnée au processus appelé, qui a fonctionné comme ceci:La carte n'a pas fonctionné comme prévu. Quand j'ai vu l'ensemble , je compris que le compilateur écrit uniquement
someCommand[ the last ]
enpciMemory
omettant toutes les écritures précédentes.En conclusion: soyez précis et attentif à l'optimisation.
la source
pciMemory
tant quevolatile
.pciMemory
car toutes les autres écritures n'ont aucun effet. Pour l'optimiseur, c'est génial car il peut supprimer de nombreuses instructions inutiles et chronophages.