Le mystère de GNU yes - Version imprimable +- N-PN White-Hat Project (https://dev.n-pn.fr/forum) +-- Forum : Informatique (https://dev.n-pn.fr/forum/forumdisplay.php?fid=12) +--- Forum : GNU/Linux | Unix (https://dev.n-pn.fr/forum/forumdisplay.php?fid=31) +--- Sujet : Le mystère de GNU yes (/showthread.php?tid=2089) |
Le mystère de GNU yes - spin - 05-07-2012 Salut, je suis confronté à un problème curieux, qui me fait penser que les programmeurs GNU sont vraiment des soricers J'imagine que vous connaissez tous le programme yes, qui affiche "y\n" en boucle quand lancé sans argument. J'ai voulu programmer un clone de yes en assembler, dont voici le code : Code : section .text Voici maintenant le code de GNU yes (en C, 88 lignes) : http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/yes.c Je pense pouvoir dire sans prétention que mon yes devrait être plus optimisé, pourtant il n'en est rien. Voici les pseudo-benchmarks que j'ai effectué : Code : $ timeout 3s yes > lol1 # GNU yes (/usr/bin/yes) Sur 3 secondes d'exécution, GNU yes peut me produire 146944000 lignes de 'y', tandis que mon ./yes maison n'en produit qu'un nombre à 5 chiffres, la différence n'est pas moindre ! Je me suis dit que GNU yes devait avoir une priorité d'exécution plus haute que mon ./yes, ce qui faisait de lui un programme plus rapide. En regadant via top, les deux sont fixés à la même priorité NI = 0. Cela demeure un mystère, avez-vous une idée de ce qui peut rendre GNU yes plus rapide que mon programme de 7 instructions assembleur ? Ou bien les codeurs de GNU sont des vraiment sorciers ? Avez-vous une idée d'un autre facteur qu'il faut prendre en considération ? RE: Le mystère de GNU yes - ark - 05-07-2012 Hum, j'ai pas compris ce qui fait que ça va plus vite chez eux ^^' Par contre, ce que tu peux faire, je pense, c'est juste faire ton syscall dans la boucle, ça sera plus rapide déjà. Et sinon, tu peux aussi éventuellement tout stocker dans un buffer, et tu print juste a la fin, comme ça tu limite le nombre de syscall. RE: Le mystère de GNU yes - spin - 05-07-2012 galex-713 m'avait suggéré cette idée de ne mettre dans la boucle que le int, mais le problème c'est que l'exécution de int $80 modifie l'état des registres, il faut donc le remettre bien à chaque fois. En ce qui concerne les buffers, j'ai essayé une solution en utilisant comme pointeur sur ma chaîne une donnée dans .data plutôt que directement la stack. Le résultat est le même, mon yes est infiniment plus lent que GNU yes. Cela dit, je n'ai pas compris grand chose au code de GNU (le C et moi...), mais après relecture plus attentive, je pense qu'il y a en effet une approche avec un buffer, comme tu le dis. À la ligne 84, on affiche argv[ i] et on pourrait supposer qu'il y a donc en effet un buffer contenant les 'y'. Mais je ne comprends pas comment le buffer peut être infini alors. EDIT : Après un coup de strace yes, je m'aperçois que GNU yes aussi affiche deux octets par deux octets ("y\n") en boucle : Code : write(1, "y\n", 2y L'output de mon yes, strace ./yes, est exactement le même (mise à part les trucs du début que je n'ai pas). RE: Le mystère de GNU yes - ark - 06-07-2012 Ah, oui, logique que ça modifie les registres en fait... x) Hum, c'est foireux, j'vais regarder la source en détails parce que y a pas de raisons qu'il aille plus vite... [EDIT] Bon, ben j'ai regardé un peu plus en détails, et j'ai toujours pas compris comment il peux aller plus vite... Mais je pense que ça doit venir de certaines options de compilation, en fait faudrait look le code asm... j'vais voir ça ! [EDIT2] C'est trop abusé, j'ai rien compris x) RE: Le mystère de GNU yes - gruik - 24-11-2012 je déterre un peu le topic, mea culpa, au pif comme ça je dirais que c'est int 80h qui est en cause, essaye avec sysenter RE: Le mystère de GNU yes - spin - 25-11-2012 Je suis désormais en 64 bits depuis la dernière fois où j'ai posté, et après quelques recherches j'ai cru comprendre que l'instruction SYSCALL était utilisé à la place du INT $80 ou du SYSENTER en 32 bits, je me trompe ? Donc je vais essayer de ré-écrire yes en utilisant SYSCALL cette fois, et voir ce qu'il en est. Mais il me semble que je peux faire tourner des ELF32 même avec un système 64 bits, mais dans ce cas les comparaisons avec le GNU yes du système (qui lui est un ELF64 a priori) ne seront plus équitables. Le mieux serait que je me fasse une VM ou que j'aille squatter les Ubuntu du lycée qui sont en 32 bits, il me semble bien :p Bref, merci de ta réponse, je vais tester ça ! RE: Le mystère de GNU yes - spin - 26-11-2012 Voici de nouveaux résultats, mais d'abord le code : Code : format ELF64 executable 3 Et les résultats : Code : $ timeout 3s yes > gnyes Ça devient suspect... Je ne sais plus quoi en penser. RE: Le mystère de GNU yes - gruik - 26-11-2012 yep, j'ai fait quelques tests aussi de mon coté, au temps pour moi ce n'est pas int 80h VS sysenter/syscall qui est en cause, c'est write()... si on fait un test : gruik-write.c : Code C :
gruik-fwrite.c : Code C :
et la diff entre les deux : Code BASH :
bingo les miracles de la bufferisation en bonus gruik-fwrite.asm pour la peine : Code ASM :
|