11
votes

Différence de vitesse entre If-ele et Ternary Operateur en C ...?

Ainsi, à la suggestion d'un collègue, je viens de tester la différence de vitesse entre l'opérateur ternaire et l'équivalent if-block ... et il semble que l'opérateur ternaire donne le code qui soit entre 1x et 2 fois plus rapidement que si Autre. Mon code est: xxx

(désolé d'utiliser getertimeOdday et non clock_gettime ... Je m'efforcerai de mieux me rendre.)

J'ai essayé de changer l'ordre dans lequel j'ai chronométré les blocs, mais les résultats semblent persister. Ce qui donne? En outre, l'IF-sinon montre beaucoup plus de variabilité en termes de vitesse d'exécution. Devrais-je examiner l'assemblée que GCC génère?

d'ailleurs, tout est au niveau d'optimisation zéro (-O0).

Est-ce que j'imagine Ceci ou y a-t-il quelque chose que je ne prends pas en compte, ou est-ce une chose dépendante de la machine, ou quoi? Toute aide est appréciée.


11 commentaires

Encore mieux, essayez a = i% 2? B: C , puis comparez-le avec optimisation -O2 ou -O3 .


Un bon compilateur remarquerait que cela équivaut à a = (n & 1)? C: B . Mais où puis-je trouver un tel compilateur? (Oui, oui, aussi longtemps que n> 0).


Les points de repère avec des optimisations désactivés ne sont pas de sens ...


"Au fait, tout cela est au niveau d'optimisation zéro (-O0)." Cela signifie que vous avez dit au compilateur de ne pas optimiser (fondamentalement), il n'est donc pas surprenant que cela ne soit pas surprenant que ça va générer plus code verbeux (et donc plus lent) pour plus de code verbeux. Si vous lancez même un -O1 à cela, je soupçonne que vous ne remarquerez aucune différence du tout. Ne pas voir beaucoup de point dans la distinction en matière de performance dans un code non optimisé.


Noter: ? est l'opérateur conditionnel, un opérateur ternaire, pas l'opérateur ternaire.


Je comprends que l'analyse comparative sans optimisation n'est pas particulièrement significative, mais encore une fois, je ne me demande pas vraiment de faire que ce code soit aussi rapide que possible ... je vais juste jeter un coup d'œil à l'Assemblée et vérifier les réponses qui mentionnent CMOV.


@Sani: C'est le seul opérateur ternaire de C ++, d'où l'opérateur ternaire.


@Steve Jessop: Peu importe si c'est le seul opérateur ternaire. Il est toujours appelé l'opérateur conditionnel et c'est un opérateur ternaire. Comme je l'ai écrit: c'était une note depuis que j'utilise parfois aussi les termes "l'opérateur ternaire" / "l'opérateur conditionnel", interchangeable, mais ce n'est toujours pas correct. Il pourrait y avoir un autre opérateur ternaire introduit à l'avenir, il serait donc préférable d'apprendre le terme correct pour éviter un mixup éventuel (comme le mettrait le point de Jon).


@Sani: Ouais, et les États-Unis pourraient à l'avenir passer à un système de présentation de plusieurs présidents titulaires, mais jusque-là obama (ou autre titulaire) est le président et Bush est président. Drôle de langue ancienne ;-p


@Steve Jessop: Oui, tout peut arriver. Les USA pourraient même devenir une démocratie ...;)


Dupliqué possible de opérateur ternaire ?: vs si ... autre


6 Réponses :


0
votes

Tout compilateur décent devrait générer le même code pour ceux-ci si l'optimisation est allumée.


2 commentaires

IMO cela aussi devrait être un commentaire, en tenant compte des 2 premières réponses qui sont en fait des réponses


Vous avez raison, mais ... l'un d'entre eux bien que répondre à la question ne parvient sérieusement à mentionner que ce n'est qu'un problème avec -O0 . Les compilateurs font un très bon travail à l'optimisation et les gens ne devraient pas faire de micro optimisations comme celles-ci. désactivé.



24
votes

Il y a de bonnes chances que l'opérateur ternaire soit compilé dans un CMOV pendant que l'IF / SNE donne dans un CMP + JMP . Juste jeter un coup d'œil à l'assembly (en utilisant -s) pour être sûr. Avec des optimisations activées, cela n'aura plus d'importance de toute façon, car tout bon compilateur doit produire le même code dans les deux cas.


1 commentaires

Sur les processeurs d'aujourd'hui, un mouvement conditionnel a une latence fixe, tandis qu'une branche conditionnelle bien prédite est fondamentalement libre. Pour cette raison, vous ne voyez peut-être pas un compilateur d'optimisation générer cmov aussi souvent que vous le pensez.




4
votes

S'il y en a, changez votre compilateur!

Pour ce genre de questions, j'utilise le Essayez LLVM page. C'est une ancienne libération de LLVM (toujours en utilisant le front-end gcc), mais ce sont de vieilles trucs. P>

Voici mon petit programme d'échantillons (version simplifiée de la tienne): P>

  %.pn13 = select i1 %12, i32 %c, i32 %b          ; <i32> [#uses=1]
  %tmp21 = add i32 %N, -1                         ; <i32> [#uses=1]
  %a.1 = add i32 %.pn13, %tmp21                   ; <i32> [#uses=2]

  %.pn = select i1 %16, i32 %c, i32 %b            ; <i32> [#uses=1]
  %tmp = add i32 %N, -1                           ; <i32> [#uses=1]
  %d.1 = add i32 %.pn, %tmp                       ; <i32> [#uses=1]


0 commentaires

13
votes

Vous pouvez également aller complètement sans rampe et mesurer si cela fait une différence: xxx

sur les architectures d'aujourd'hui, ce style de programmation a grandi un peu hors de la mode.


1 commentaires

C'est toujours utile lorsque vous avez une condition dans une boucle qui exécute un grand nombre (par exemple des milliards) de fois.



0
votes

Comprenez qu'il est entièrement à la hauteur du compilateur comment il interprète l'expression ternaire (à moins que vous ne la force pas à ne pas avoir avec (inline) ASM). Il pourrait tout aussi bien comprendre l'expression ternaire comme "si....else" dans sa langue de représentation interne et, selon le backend cible, il peut choisir de générer des instructions de déplacement conditionnel (sur x86, CMOVCC est telle. Il devrait également y avoir des pour min / max, ABS, etc.). La principale motivation de l'utilisation d'un mouvement conditionnel consiste à transférer le risque de défaillance de la branche dans une opération de déplacement de mémoire / enregistrement. La mise en garde à cette instruction est que presque tout le temps, l'opérande enregistre qui sera chargé de manière conditionnelle devra être évaluée au formulaire d'enregistrement pour tirer parti de l'instruction CMOV.

Cela signifie que le processus d'évaluation inconditionnel doit maintenant être inconditionnel, et cela semblera augmenter la longueur du trajet inconditionnel du programme. Mais comprendre que cette branche est la plus souvent résolue comme «rincer» le pipeline, ce qui signifie que les instructions qui auraient fini l'exécution sont ignorées (tournées vers aucune instruction d'utilisation). Cela signifie que le nombre réel d'instructions exécutées est plus élevé en raison des stands ou des NOPS, et l'effet échelle avec la profondeur du pipeline de processeur et le taux de mallette.

Ceci apporte un dilemme intéressant dans la détermination des bonnes heuristiques. Tout d'abord, nous savons certainement que si le pipeline est trop superficiel ou que la prédiction de la branche est complètement capable d'apprendre le modèle de l'historique des succursales, CMOV ne vaut pas la peine de faire. Il ne vaut également pas la peine de faire si le coût de l'évaluation de l'argument conditionnel est plus important que le coût de la mauvaise prédiction en moyenne.

Ce sont peut-être les principales raisons pour lesquelles les compilateurs ont des difficultés à exploiter l'enseignement CMOV, car la détermination de l'heuristique dépend en grande partie des informations de profilage d'exécution. Il est plus logique de l'utiliser sur le compilateur JIT car il peut fournir des commentaires d'instrumentation d'exécution et construire une heuristique plus forte pour l'utiliser ("La branche est vraiment imprévisible?"). Sur le côté du compilateur statique sans données de formation ni profileur, il est très difficile de supposer quand cela sera utile. Cependant, une heuristique négative simple est, comme ci-dessus, si le compilateur sait que le jeu de données est complètement aléatoire ou forçant Cond. à l'inconvénient. L'évaluation est coûteuse (peut-être en raison d'opérations irréductibles et coûteuses telles que FP Divides), il ferait de bonnes heuristiques à ne pas le faire.

Tout compilateur vaut son sel fera tout cela. La question est, que fera-t-elle faire après que toutes les heuristiques fiables ont été utilisées ...


0 commentaires