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;
}