Re: exercice python

Top Page

Reply to this message
Author: Edgar Bonet
Date:  
To: Liste Guilde
Subject: Re: exercice python
Le mardi 8 février, jeanluc a écrit :
> En prenant un fichier en entrée, il faut concatener deux lignes
> pour n'en former plus qu'une et sortir le resultat dans un fichier.
>
> Le fichier d'entrée : in.txt est généré comme suit:
>     bash# man perlfunc | col -b > perlfunc.man.txt
>     bash# for i in $(seq 1 500); do cat perlfunc.man.txt >>in.txt; done
>     bash# wc -l in.txt
>     3297081 in.txt

>
> Voici les tests sur les codes qui sont affichés à la fin du mail :
> [...]


Je sais bien que c'est hors sujet, mais je n'ai pas résisté à la
tentation de coder ça en C. Voici les résultats des tets. J'ai testé
chaque programme trois fois de suite, en effaçant out.txt entre deux
tests, et j'ai gardé le meilleur résultat :

                real    user    sys     syscalls
    --------------------------------------------
    python_v1   21.09   19.29   1.32     72212
    python_v2   13.69   12.00   1.34     57921
    perl_v1     11.69   10.24   1.16     71878
    perl_v2     10.21    8.77   1.16     71878
    c_v1         3.27    2.15   0.99     71637
    c_v2         1.31    0.72   0.56        28


python_v2 est le code de Mickael Profeta. La dernière colonne est le
nombre d'appels système, obtenu avec strace -c. Les tests ont été faits
sur un P4 1,5 GHz, 256 ko de cache, 512 Mo de RAM.

Mes codes sont en pièce jointe, je les ai compilés avec -O2.

c_v1.c est d'après moi une façon « naturelle » de coder ce problème en
C, en utilisant la bibliothèque standard C-ANSI (fgets() et fputs()).

c_v2.c est plus unixien (POSIX) : il fait deux mmap() sauvages et fait
tout en mémoire virtuelle. Le vrai travail d'entrées/sorties est donc
réalisé par le noyau via les mécanismes de mémoire virtuelle et le
buffer cache.

Maintenant, c'est sûr que ça n'a pas la lisibilité des langages de
script. Mais quand c'est la performance qu'on recherche, il faut se
souvenir que le noyau Linux met des outils puissants à notre
disposition.

Bon week-end.

-- 
Edgar Bonet           Maison : 04 76 21 29 16    Bureau : 04 76 88 10 96
3 rue Jean Prévost    Mobile : 06 77 19 79 39    Fax    : 04 76 88 11 91
38000 Grenoble        guilde@???     www.edgar-bonet.org

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define INFILE "in.txt"
#define OUTFILE "out.txt"

void die(char *msg)
{
    perror(msg);
    exit(EXIT_FAILURE);
}


int main(void)
{
    FILE *in, *out;
    char buffer[1024];  /* hope it's large enough... */
    int lines;


    in = fopen(INFILE, "r");
    if (!in) die("open("INFILE")");


    out = fopen(OUTFILE, "w");
    if (!out) die("open("OUTFILE")");


    lines = 0;
    while(fgets(buffer, sizeof buffer, in)) {
        buffer[sizeof buffer - 1] = '\0';  /* just in case */
        if (++lines & 1) buffer[strlen(buffer) - 1] = '\0';  /* chop */
        fputs(buffer, out);
    }
    if (lines & 1) putc('\n', out);


    if (fclose(out) == EOF) die("close"OUTFILE")");


    return EXIT_SUCCESS;
}

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>

#define INFILE "in.txt"
#define OUTFILE "out.txt"

void die(char *msg)
{
    perror(msg);
    exit(EXIT_FAILURE);
}


int main(void)
{
    int d_in, d_out;
    struct stat stat_in;
    int lg;
    char *m_in, *m_out;
    int i, j;
    int lines;


    /* Map the files in memory. */


    d_in = open(INFILE, O_RDONLY);
    if (d_in == -1) die("open("INFILE")");


    if (fstat(d_in, &stat_in) == -1) die("fstat("INFILE")");


    lg = stat_in.st_size;


    m_in = mmap(NULL, lg, PROT_READ, MAP_SHARED, d_in, 0);
    if (m_in == MAP_FAILED) die("mmap("INFILE")");


    if (close(d_in) == -1) die("close("INFILE")");


    d_out = open(OUTFILE, O_RDWR|O_CREAT|O_TRUNC, 0666);
    if (d_out == -1) die("open("OUTFILE")");


    m_out = mmap(NULL, lg, PROT_WRITE, MAP_SHARED, d_out, 0);
    if (m_out == MAP_FAILED) die("mmap("OUTFILE")");


    if (ftruncate(d_out, lg) == -1) die("ftruncate("OUTFILE")");


    /* Copy the mmap()ed area. */
    j = 0;
    lines = 0;
    for (i = 0; i < lg; i++) {
        m_out[j++] = m_in[i];
        if (m_in[i] == '\n' && ++lines & 1) j--;
    }
    if (lines & 1) m_out[j++] = '\n';


    /* Cleanly close OUTFILE. */


    if (munmap(m_out, lg) == -1) die("munmap("OUTFILE")");


    if (ftruncate(d_out, j) == -1) die("ftruncate("OUTFILE")");


    if (close(d_out) == -1) die("close("OUTFILE")");


    return EXIT_SUCCESS;


}