6
votes

Comment le code de périphérique de Duff peut-il être compilé?

J'ai compris pourquoi Le périphérique de Duff est plus rapide que le code de boucle normal qui peut être déroulé mais n'est pas optimisé. Mais je ne comprends pas comment le code peut encore être compilé.
Je suppose que c'est un truc sur la syntaxe commutateur . Mais plus maintenant.

Comment peut-on faire pendant que la phrase existe dans commutateur phrase? Très bizarre.
Y a-t-il quelqu'un qui peut expliquer cela?

EDIT: Une autre question. Pourquoi Duff Utilisa-t-il 8? Cela pourrait être 16, 65536 ou autre chose. En raison de la taille du code? Y a-t-il une autre raison? Par exemple, cache ou avantages en pipeline.


23 commentaires

"J'ai compris pourquoi le périphérique de Duff est plus rapide que le code normal qui n'est pas optimisé." Ce n'est pas le cas. Il suffit de confond que le compilateur autant que les humains, ce qui conduit potentiellement à code lent . Et même s'il y avait une différence de faveur de l'appareil de Duff, vous n'avez pas besoin de vitesse si mal, vous devez utiliser cette abomination. Répétez-le avec moi. Vous n'avez pas besoin d'utiliser cette abomination.


Le périphérique de Duff était utilisé plus rapide que le code normal (sur certaines plates-formes au moins) - il n'est presque plus. Dans un projet, nous avons fait sur Windows PCS et MSVC, déjà il y a environ 10 ans, il s'est avéré être plus lent que le code normal optimisé.


La vraie leçon ici est de faire confiance à votre compilateur. Ne poursuivez pas la possibilité de gains marginaux dans la performance (si même que, dans ce cas), au détriment de la lisibilité et de la maintenabilité. Chaque fois que vous devez poser des questions sur afin de comprendre un morceau de code ou de le faire compiler, vous ne devriez probablement pas essayer de l'utiliser.


L'article Wikipedia que vous êtes lié à la réponse à votre question. Quelle partie de cette réponse ne comprenez-vous pas?


Merci les gars. Je ne veux pas utiliser le périphérique de Duff à mon code réel. Et je ne l'ai jamais utilisé et je ne le ferai pas. Je me demande simplement comment le code peut être compilé. Quand j'ai vu le code d'abord, je pensais que cela ne serait jamais compilé.


@Hogan - prétendez-vous qu'il existe une différence entre C et C ++ qui affecte les Duffs Device? La seule chose que je puisse penser serait liée à la portée, à la construction et à la destruction de variables locales déclarées dans l'interrupteur / boucle, ce qui est presque certainement un non-question.


@Ronald: Spécification détendue de l'instruction de commutation dans la définition de la langue. Au moment de l'invention de l'appareil, il s'agissait de la première édition du langage de programmation C qui nécessite uniquement que l'instruction contrôlée de l'interrupteur soit une instruction Syntaxiquement valide (composé) dans laquelle les étiquettes de cas peuvent apparaître au préalage de toute sous-déclaration. Je pense que cela pourrait être ce que je ne peux pas comprendre. Je suis anglaise anglaise.


@delnan, je ferais attention avec ces déclarations générales. Parfois, le périphérique de Duff est plus rapide et vous avez réellement besoin de cette "abomination" afin de répondre aux spécifications de votre projet. Je pense qu'il est probablement plus correct de conseiller de "l'éviter quand il n'est pas nécessaire".


@Benjamin Cela signifie essentiellement que, à l'époque, le Duff est venu avec cette construction, la grammaire pour commutateur était très détendue (c.-à-d. pas très strict ) Vous pouvez donc réellement démarrer une boucle au milieu d'une instruction de commutation et fermer la boucle après quelques case . Cela signifie que vous pouvez utiliser l'instruction commutateur pour démarrer la boucle au milieu de la boucle (car le pendant passera à la faire , qui est au début de la déclaration (code>). C'est vraiment sur un moyen de jouer avec la flexibilité de la définition de la langue pour pouvoir écrire un code optimisé (mais déroutant)


@MRDUCLAW: le périphérique de Duff est une boucle fondamentalement artificielle déroulante; Tout compilateur de nos jours peut le faire seul.


@Matteo Italia, et vous espérez que vous obtenez des compilateurs modernes avec des bibliothèques modernes pour toutes les plates-formes que vous programmez. Je suggère simplement que parfois ce n'est pas le cas et que vous devez programmer comme il est encore 19 1980. C'est Nitpicky, mais ne devrions-nous pas, en tant que programmeurs, se soucier des caisses d'angle?


@MRDUCLAW: vrai par la non négligence des absolus. Mais je préfère être trop zélé avec le condamner (et ses parents). Donc, cela conduit à un code inefficace, alors quoi? Peut être corrigé facilement si vous avez un gourou de performance à bord - vous devriez si cela compte beaucoup! OTOH, ne pas "laisser tomber la bombe d'optimisation prématurée" entraîne de manière proposée à un code plus inutile "optimisé" (lecture: masquis) - je veux vraiment éviter cela.


@Ronald: était très détendu On dirait que ce n'est plus détendu. Mais il est toujours détendu, n'est-ce pas?


@MRDuclaw: point prélevé, bien que ma position soit toujours essentiellement avec @delnan.


@delnan, vous avez raison que si cela compte que vous devriez avoir un gourou de performance sur le personnel. Mais si nous arrêtons d'enseigner ces idées ou si nous prétendons que c'est jamais utile, alors qui remplira les chaussures après la sortie de la performance actuelle? Je suppose que je n'aime tout simplement pas que les gens retirent la goupille de tir sur mon pistolet sans me le dire, je préférerais pouvoir la tirer si j'ai besoin.


@Benjamin C grammaire est toujours assez détendu et je pense que le périphérique de Duff sera toujours compilé sur un compilateur conforme, mais comme tous les autres commentateurs ont dit, vous ne devriez vraiment pas essayer d'optimiser avec ce type de construction ..


@MRDuclaw - Mais vous ne voulez pas garder les forgerons autour, vous, au cas où vous auriez besoin d'un nouveau baril pour votre mousquet? Parfois, des avancées technologiques et certaines connaissances sont tout simplement plus largement nécessaires.


@MRDUCCAW: Eh bien, donneriez-vous à un jeune un plus léger (je réfléchissais à mettre ci-dessus ici à la place, il pourrait s'agir davantage de la manière dont les cas d'utilisation appropriés sont communs) "au cas où ils en ont besoin", ou leur apprendre à Soyez très Attention avec le feu et attendez jusqu'à ce qu'ils soient suffisamment matures pour ne pas allumer leurs propres cheveux avant de les donner un?


@delnan, oui. J'ai grandi autour du feu et des armes à feu, de même que tous mes amis, et avec notre bon instruction, il n'y avait pas d'incident.


@Bo Persson, je pense qu'il est important de comprendre tout ce que vous pouvez sur le monde. Et BTW, cette connaissance existent toujours, avez-vous visité une foire de la Renaissance ces derniers temps? De plus, si vous le souhaitez, je peux vous commander une combinaison de courrier à chaîne pour vérification.


IMO Le problème n'est pas le périphérique de Duff, c'est la boucle manuelle déroulante de tout type que vous devriez vous attendre à ne pas être dérangé par. Sur ces occasions incroyablement rares lorsque vous venez dérouler manuellement une boucle, pour voir si cela bat l'optimiseur (ce qu'il fait parfois), vous pouvez avoir des boucles qui ne sont pas multiples du degré de déroulement. À ce stade, vous pouvez choisir d'utiliser le périphérique de Duff, plutôt qu'un tas de gotos, précisément parce que il permet au compilateur d'optimiser la partie Select-and-sauter de l'opération. Je ne vois pas pourquoi les gens sont tellement déployés par l'idée de quelqu'un qui l'obtient bien, cependant.


@Benjamin - Parce que j'avais tort.


Comment fonctionne le périphérique de Duff?


5 Réponses :


11
votes

Le "Comment ça marche" est assez simple.

C et C ++ sont des langues compilées et compilées normalement sur le code de la machine à plateformes. Le code de la machine n'a pas de concept de structures de blocs - toutes les structures de blocs doivent être traduites sur une forme qui utilise (en vigueur) une certaine mélange de gotos inconditionnels et conditionnels.

Les règles de syntaxe C permettent à la relevé de commutation et à la boucle être combiné d'une manière qui n'est pas une véritable structure de bloc hiérarchique, mais que les piétons contrôlent le flux. Tant que le compilateur peut faire face à ceci (quel bon compilateur doit) il n'y a pas de problème dans le code de la machine sous-jacente. Le résultat sera "spaghetti", mais le code de machine généré qui a été via un optimiseur est toujours spaghetti - il n'est pas destiné à être lisible par l'homme, ce n'est donc pas un problème. Le problème ici est que le code source est également spaghetti aussi, même si les gotos ont été "cachés".

note - bien que tout bon compilateur soit fait face à Duffs Device, comme d'autres ont déjà commenté, cela ne fait pas comment t signifie qu'il va assez bien pour l'optimiser correctement - seulement assez bien pour générer du code exécutable correct. Il s'agit d'un de ces vieux idiomes étranges qui avaient une fois un but, mais qui est plus probable maintenant de confondre votre compilateur et votre sabotage, il est capable de générer du code efficace.

edit

Ce qui suit est lié au périphérique Duffs et peut aider à illustrer l'idée de base ... xxx

ayant des clauses de cas à l'intérieur de la boucle est conceptuellement pas différent pour avoir Les étiquettes goto-cible à l'intérieur de la boucle, comme ci-dessus.

Avertissement - Ceci est purement à l'illustration d'une idée et ne doit pas être copié dans un code de vie réel.


1 commentaires

Incidemment, tous les compilateurs ne génèrent pas de code correct de l'appareil de Duff. Si vous essayez de compiler cela avec C ++ Builder, vous devrez désactiver l'optimisation appelée «Activer la variable d'induction de la boucle et la réduction de la force» ou vous aurez des violations d'accès au temps d'exécution.



4
votes

interrupteur est juste un goto . Donc, il existe plusieurs étiquettes à l'intérieur de la boucle et une instruction commutateur en dehors de la boucle. Le commutateur décide de quelle étiquette pour aller à, et goto s là, à l'intérieur de la boucle.

Une fois l'exécution à l'intérieur de la boucle, il continue de boucler jusqu'à ce que la boucle abandonne le contrôle.

C'est en fait très simple ... et ne devrait pas être utilisé à moins que ce ne soit l'alternative la plus simple.

Ne croyez pas quelqu'un qui vous dit que cela fait quelque chose de rapide.

Je dirais même d'arrêter d'écouter tout ce qu'ils disent du tout , même si c'est votre professeur.

Quant aux compilateurs, ils brisent les choses aux graphiques de contrôle de contrôle génériques et ne se soucient pas de commutateur vs. code> si vs. code> tandis que >. Ils sont tous si (...) goto ...; sinon goto ...; au compilateur.


0 commentaires

2
votes

S'il est vrai que le périphérique de Duff est obsolète pour son objectif initial, il est toujours utile à des fins particulières, comme une machine à états qui cycle normalement à plusieurs reprises à travers n états, mais doit parfois retourner à l'appelant et plus tard être repris à l'état où il s'est arrêté. Mettre l'instruction Switch en dehors de la boucle et du boîtier Etiquettes à l'intérieur de la boucle (je prendrais cela comme la définition d'un "périphérique" de Duff ') ait beaucoup de sens.

avec cela dit, n'utilisez pas les appareils de Duff pour "optimiser à la main". Mettre ce qui sont efficacement «goto étiquettes» partout où le compilateur ne vous aidera pas à optimiser le compilateur.


0 commentaires

6
votes

Une explication simple de la Duff's Device compile est que la syntaxe de l'instruction CODE> SWITCH CODE> n'est pas particulièrement spécifique sur le formulaire que le bloc d'instruction code> doit avoir besoin de prendre . Il y a quelques restrictions et quelques objets autorisés dans la déclaration contrôlée qui ne sont pas autorisées en dehors d'un commutateur code> (code code> (code code> et défaut code> Étiquettes). Mais autre que cela, la déclaration contrôlée n'est qu'une autre déclaration, avec la probabilité qu'il existe des étiquettes pour le commutateur code> sur cible.

Voici la syntaxe de C99: P>

switch ( expression ) statement
  • L'expression de contrôle doit avoir un type d'entier li>
  • Il y a des restrictions sur l'endroit où les VLAS peuvent survenir dans la déclaration de commutation LI>
  • case code> Les expressions d'étiquettes doivent être des expressions constantes entier li>
  • Il ne peut pas y avoir duplicata case code> expressions d'étiquettes ou défaut code> étiquettes li> ul>

    autre que cela, toute construction autorisée dans un bloc de relevé doit être autorisée dans l'instruction contrôlée (avec l'addition que case code> et par défaut code> Les étiquettes sont ok ). N'oubliez pas que le cas code> code> et par défaut code> ne sont que des étiquettes que le commutateur saute en fonction de l'expression de contrôle et de l'expression d'étiquette code> étiquette. comme Potatoswatter dit , commutateur code> est juste un goto code>. Donc juste comme goto code> peut passer au milieu d'une boucle, alors peut commutateur code>. P>

    aussi, je pense que les cas où vous pourriez voir un Les avantages de Duff's Device sont assez rares aujourd'hui (je pense qu'ils étaient rares même dans les années 1980). N'oubliez pas que Tom Duff lui-même a dit ce qui suit dans son Description : p>

    • "dégoûtant, non?" li>
    • "Je ressens une combinaison de fierté et de révulsion à cette découverte." Li> ul>

      Encore plus que lorsqu'il a été décrit initialement, le dispositif de Duff doit être considéré comme plus une curiosité qu'un outil à utiliser. P> P>


1 commentaires

La description de Tom Duff est très intéressante. Je ne l'ai pas lu. Merci.



2
votes

Si nous prenons la mise en œuvre de l'article Wikipedia, vous liez ... xxx

... et remplacez le "code de haut niveau"> do / tandis que boucle avec le niveau d'assemblage si / goto que le compilateur le réduit vraiment à ... xxx

... Cela peut vous aider à percevoir cela - dans cet usage où la portée DO / tandis que la portée n'a pas introduit de variables locales - il n'y a vraiment rien de plus à la tâche qu'un saut à la case 0 qui contourne le Basculer et donc la nécessité d'évaluer le nombre% 8 (% est une opération assez coûteuse dans le schéma des choses).

espère que cela aide-le clic, mais ne peut pas ...? : -)

Pourquoi Duff Utilisa-t-il 8? Cela pourrait être 16, 65536 ou autre chose. En raison de la taille du code? Y a-t-il une autre raison? Par exemple, cache ou avantages en pipeline.

Un cas de rendement décroissant. Avoir à faire la vérification - N> 0 et un saut après toutes les copies de données n'est pas un pourcentage de surcharge de pourcentage, mais la taille du code (à la source et comme code compilé dans le cache) est toujours assez serré. Peut-être que ce serait un travail de 90 ou 95% vs des frais généraux, qui était évidemment assez bon. En outre, pour illustrer et partager le concept avec d'autres personnes Tom Duff aurait peut-être préféré qu'il s'agissait d'une valeur de code typique du terminal 80x25 plutôt qu'une page ou 10.


0 commentaires