• STATISTIQUES
  • Il y a eu un total de 1 membres et 12795 visiteurs sur le site dans les dernières 24h pour un total de 12 796 personnes!


    Membres: 2 433
    Discussions: 3 585
    Messages: 32 831
    Tutoriels: 78
    Téléchargements: 38
    Sites dans l'annuaire: 58


  • ANNUAIRE
  • [EN] wechall
    Pour les gens n'étant pas familiers avec les sites de challenges, un site de challenges est un site propos...
    Hacking
    [EN] Sabre Films
    Site de challenge présenté sous la forme d'une quête. Vous êtes un détective et devrez résoudre d...
    Challenges
    [FR] Forum-Webmaster
    Une communauté webmaster pour apporter / recevoir de l'aide en création de site internet. Webmaster...
    Webmaster
    [FR] dcode
    dcode.fr est le site indispensable pour décoder des messages, tricher aux jeux de lettres, résoudre des énigmes...
    Outils / Add-on
    [EN] w3challs
    Ce site propose différents types de défis informatiques: piratage, craquage, cryptographie, stég...
    Hacking
    [FR] PHP Débutant
    Apprendre le PHP par l'exemple, facilement et simplement. Réservé d'abord aux débutants....
    Programmation
    [EN] osix
    Site de challenge qui utilise un système de level on chaque épreuve doit être réussie avant d'accédÃ...
    Challenges

  • DONATION
  • Si vous avez trouvé ce site internet utile, nous vous invitons à nous faire un don du montant de votre choix via Paypal. Ce don servira à financer notre hébergement.

    MERCI!

    €



Note de ce sujet :
  • Moyenne : 5 (1 vote(s))
  • 1
  • 2
  • 3
  • 4
  • 5
Le mystère de GNU yes
05-07-2012, 14h32
Message : #1
spin Hors ligne
Contributeur
*****



Messages : 325
Sujets : 15
Points: 38
Inscription : Nov 2011
Le mystère de GNU yes
Salut, je suis confronté à un problème curieux, qui me fait penser que les programmeurs GNU sont vraiment des soricers Big Grin

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

global _start

_start:

push WORD 0x0a79   ;;  "y\n"

x:
    mov eax, 4
    mov ebx, 1
    mov ecx, esp
    mov edx, 2
    int $80
    jmp x

Voici maintenant le code de GNU yes (en C, 88 lignes) : http://git.savannah.gnu.org/cgit/coreuti.../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)
$ timeout 3s ./yes > lol2    # mon 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 ?
+1 (0) -1 (0) Répondre
05-07-2012, 16h52
Message : #2
ark Hors ligne
Psyckomodo!
*****



Messages : 1,033
Sujets : 48
Points: 317
Inscription : Sep 2011
RE: Le mystère de GNU yes
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.
+1 (0) -1 (0) Répondre
05-07-2012, 19h31 (Modification du message : 05-07-2012, 19h36 par spin.)
Message : #3
spin Hors ligne
Contributeur
*****



Messages : 325
Sujets : 15
Points: 38
Inscription : Nov 2011
RE: Le mystère de GNU yes
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
)                      = 2
write(1, "y\n", 2y
)                      = 2
write(1, "y\n", 2y
)                      = 2
write(1, "y\n", 2y
)                      = 2
write(1, "y\n", 2y
)                      = 2
write(1, "y\n", 2y
)                      = 2
write(1, "y\n", 2y
)                      = 2
...


L'output de mon yes, strace ./yes, est exactement le même (mise à part les trucs du début que je n'ai pas).
+1 (0) -1 (0) Répondre
06-07-2012, 10h56 (Modification du message : 08-07-2012, 12h25 par ark.)
Message : #4
ark Hors ligne
Psyckomodo!
*****



Messages : 1,033
Sujets : 48
Points: 317
Inscription : Sep 2011
RE: Le mystère de GNU yes
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)
+1 (0) -1 (0) Répondre
24-11-2012, 18h42
Message : #5
gruik Hors ligne
gouteur de savon
*



Messages : 757
Sujets : 44
Points: 482
Inscription : Oct 2012
RE: Le mystère de GNU yes
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 Wink
+1 (0) -1 (0) Répondre
25-11-2012, 15h33
Message : #6
spin Hors ligne
Contributeur
*****



Messages : 325
Sujets : 15
Points: 38
Inscription : Nov 2011
RE: Le mystère de GNU yes
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 !
+1 (0) -1 (0) Répondre
26-11-2012, 20h07
Message : #7
spin Hors ligne
Contributeur
*****



Messages : 325
Sujets : 15
Points: 38
Inscription : Nov 2011
RE: Le mystère de GNU yes
Voici de nouveaux résultats, mais d'abord le code :

Code :
format ELF64 executable 3

segment readable executable  ; .text
entry $
@@:
    mov eax, 1
    mov rdi, 1 ; STDOUT
    mov rsi, msg
    mov rdx, 2
    syscall
    jmp @b

segment readable writable    ; .data
msg db 'y', $0a

Et les résultats :

Code :
$ timeout 3s yes > gnyes
$ timeout 3s ./yes > myyes
$ wc -l gnyes
178276352 gnyes
$ wc -l myyes
2047836 myyes

Ça devient suspect... Je ne sais plus quoi en penser.
+1 (0) -1 (0) Répondre
26-11-2012, 20h34 (Modification du message : 08-12-2012, 18h18 par gruik.)
Message : #8
gruik Hors ligne
gouteur de savon
*



Messages : 757
Sujets : 44
Points: 482
Inscription : Oct 2012
RE: Le mystère de GNU yes
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 :

#include <unistd.h>

int main (void)
{
        while (1) write(STDOUT_FILENO, "y\n", 2);
        return 0;
}
 


gruik-fwrite.c :
Code C :

#include <stdio.h>

int main (void)
{
        while (1) fwrite ("y\n", 2, 1, stdout);
        return 0;
}
 


et la diff entre les deux :
Code BASH :

$ timeout 3s ./gruik-write > log-write
$ timeout 3s ./gruik-fwrite > log-fwrite
$ wc -l log-*
164644864 log-fwrite
  3200165 log-write
 


bingo Wink
les miracles de la bufferisation

en bonus gruik-fwrite.asm pour la peine :
Code ASM :

; nasm -f elf gruik-fwrite.asm
; gcc gruik-fwrite.o -o gruik-fwrite

        extern fwrite
        extern stdout

        section .data
msg:    db "y", 10              ; 79h,0ah
len:    equ $ - msg

        section .text
        global main

main:
        ; fwrite (msg,len,1,stdout)
        mov eax, stdout
        mov eax, [eax]
        push eax
        push len
        push 1
        push msg
.loop:
        call fwrite
        jmp .loop       ; les parametres sont toujours là, on boucle directement
 
+1 (1) -1 (0) Répondre


Atteindre :


Utilisateur(s) parcourant ce sujet : 1 visiteur(s)
N-PN
Accueil | Challenges | Tutoriels | Téléchargements | Forum | Retourner en haut