diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..187477e --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# Exécutables, rapports et profils produits localement. +/build/ +/out/ +/analyseur +/rapport.txt +/gmon.out +*.o diff --git a/COMPTE_RENDU.md b/COMPTE_RENDU.md index d7432ed..c8f9e60 100644 --- a/COMPTE_RENDU.md +++ b/COMPTE_RENDU.md @@ -30,8 +30,10 @@ Le profil initial conduit aux priorités suivantes, classées par gain attendu : ## 3. Optimisations et gains mesurés Chaque gain est relatif à la version précédente. Les deux premières étapes -reposent sur une mesure ponctuelle ; les suivantes utilisent la médiane de -cinq exécutions par version. +reposent sur une mesure ponctuelle ; les étapes 03 à 05 utilisent la médiane +de cinq exécutions par version, les étapes 06 et 07 celle de dix exécutions, +et la normalisation celle de cinquante exécutions. Chaque comparaison est +faite sur la même machine ; les conditions peuvent varier entre les étapes. | Optimisation | Modification | Avant | Après | Temps gagné | | --- | --- | ---: | ---: | ---: | @@ -40,29 +42,41 @@ cinq exécutions par version. | Table de hachage | Recherche et insertion en O(1) en moyenne | 0,888 s | 0,831 s | 6,4 % | | Longueurs et chaînes | Champ `taille`, arrêt sur `\0`, position de fin conservée | 0,832 s | 0,362 s | 56,5 % | | Tri par tas | Tri en O(n log n), sans tableau supplémentaire | 0,367 s | 0,113 s | 69,3 % | +| Bigrammes | Deux lettres précédentes conservées, aucun appel à `est_lettre` | 0,1252 s | 0,1123 s | 10,3 % | +| Mots vides | Filtre par longueur et index de hachage séparé | 0,1007 s | 0,0543 s | 46,1 % | +| Normalisation | Table de conversion des octets, comparaison sur le même PC | 0,0569 s | 0,0508 s | 10,7 % | -La version finale utilise le hachage à la place de la dichotomie. Son gain +Le programme utilise le hachage à la place de la dichotomie. Son gain supplémentaire reste limité car la recherche était déjà efficace. Tous les appels à `longueur` sont supprimés. Le tri ne fait plus que **129 602 appels à `doit_echanger`**, soit environ **133 fois moins**. Le classement reste par fréquence décroissante, puis par ordre alphabétique. +La recherche des mots vides passe de **12 045 671 à 202 444 appels à +`egales`**. Les appels à `est_lettre` et `en_minuscule` sont supprimés. +Le gain de normalisation a été confirmé sur `salle235-06` : la nouvelle +version est plus rapide dans les 50 paires de mesures, en temps réel et CPU. + ## 4. Bilan et validation -Une comparaison directe des versions initiale et finale donne les médianes -suivantes, sur cinq exécutions par version dans les mêmes conditions : +Le bilan global ci-dessous a été mesuré après le tri par tas (étape 05), +sur cinq exécutions par version dans les mêmes conditions. Les gains des +étapes suivantes sont mesurés séparément dans le tableau précédent. -| Mesure | Version initiale | Version finale | +| Mesure | Version initiale | Après le tri par tas | | --- | ---: | ---: | | Temps réel | 2,81 s | 0,11 s | | Pic mémoire résident (RSS) | 6 664 Kio | 6 668 Kio | -Le programme est environ **25,5 fois plus rapide**, soit **96,1 % de temps -en moins** sur ce jeu de données. +Après le tri par tas, le programme est environ **25,5 fois plus rapide**, +soit **96,1 % de temps en moins** sur ce jeu de données. Le rapport et la sortie console sont identiques octet par octet. -L'empreinte reste **`1d53de903efd2b7c`**. +L'empreinte reste **`1d53de903efd2b7c`**. -Sources : [notes](notes.md), [profil initial](out/profil_avant.txt), -[profil final](out/profil_apres_tri.txt) et [mesures globales](out/mesures_bilan.csv). +Sources : [notes](docs/notes.md), [ordre des profils](resultats/README.md), +[profil initial](resultats/profils/00_initial.txt), +[profil actuel](resultats/profils/08_normalisation.txt), +[mesures du bilan après tri](resultats/mesures/mesures_bilan_tri.csv) et +[comparaison de normalisation](resultats/mesures/comparaison_normalisation_meme_pc.csv). diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..cff8866 --- /dev/null +++ b/Makefile @@ -0,0 +1,32 @@ +CC = gcc +CFLAGS ?= -std=c11 -Wall -Wextra -Wpedantic -O0 + +SOURCE = src/analyseur.c +PROGRAMME = build/analyseur +PROGRAMME_PROFIL = build/profil/analyseur + +.PHONY: all run check profile clean + +all: $(PROGRAMME) + +$(PROGRAMME): $(SOURCE) Makefile + mkdir -p $(@D) + $(CC) $(CPPFLAGS) $(CFLAGS) $< -o $@ $(LDFLAGS) $(LDLIBS) + +run: $(PROGRAMME) + cd build && ./analyseur + +check: run + cmp resultats/rapport_reference.txt build/rapport.txt + +$(PROGRAMME_PROFIL): $(SOURCE) Makefile + mkdir -p $(@D) + $(CC) $(CPPFLAGS) $(CFLAGS) -pg $< -o $@ $(LDFLAGS) $(LDLIBS) + +profile: $(PROGRAMME_PROFIL) + cd build/profil && ./analyseur + cd build/profil && gprof -b ./analyseur gmon.out > profil.txt + @printf 'Profil disponible dans build/profil/profil.txt\n' + +clean: + rm -rf build diff --git a/README.md b/README.md index f025b60..912c6de 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,52 @@ -# TD — Consignes +# Analyseur de fréquence de mots — TD R5.A.04 -## Travail demandé +Optimisation d'un analyseur C par mesure du temps, étude des profils et +réduction du travail répété. Le rapport doit conserver l'empreinte +**`1d53de903efd2b7c`**. -1. **Mesurer** +## Organisation - Compilez le programme sans `-pg`, lancez-le avec `time`, puis notez le - temps d'exécution et l'empreinte mémoire. +```text +src/analyseur.c Programme principal +exemples/exemple.c Exemple de profiling fourni +docs/CONSIGNES.md Consignes originales du TD +docs/R5A04_Profiling_MM.pdf Support du cours +docs/notes.md Journal détaillé des mesures +resultats/profils/ Profils historiques numérotés de 00 à 08 +resultats/mesures/ Mesures brutes CSV et conditions des expériences +resultats/rapport_reference.txt Rapport attendu +COMPTE_RENDU.md Compte rendu noté +build/ Fichiers générés localement, ignorés par Git +``` -2. **Profiler** +## Compiler et vérifier - Recompilez en `-O0` avec `-pg`, lancez le programme, puis générez le - profil dans `profil_avant.txt` avec `gprof`. +GCC, GNU Make et `gprof` sont nécessaires pour les commandes de profiling. +Depuis la racine du dépôt : -3. **Analyser** +```bash +make # Compiler en -O0, sans instrumentation +make run # Exécuter ; le rapport est écrit dans build/rapport.txt +make check # Exécuter et comparer le rapport à la référence +make profile # Produire build/profil/profil.txt avec -pg et gprof +make clean # Supprimer les fichiers générés de build/ +``` - Étudiez le profil plat et le graphe d'appels : où le temps est-il passé, - et pourquoi ? +Pour mesurer le temps du programme après compilation : -4. **Proposer** +```bash +cd build +time ./analyseur +``` - Listez les pistes d'amélioration, classées par gain attendu. +Les mesures de temps utilisent le binaire sans `-pg`. Les profils archivés +dans `resultats/` sont les résultats des différentes étapes ; `make profile` +écrit le nouveau profil dans `build/profil/`. -5. **Optimiser** +## Documents et résultats - Réalisez une optimisation par commit. L'empreinte mémoire doit rester - identique. - -6. **Valider** - - Reprofilez le programme dans `profil_apres.txt` et chiffrez le gain - obtenu. - -## Compte rendu noté - -Le fichier `COMPTE_RENDU.md` doit être présent à la racine de votre fork. -Il doit contenir : - -- les temps avant et après optimisation ; -- l'analyse du profil ; -- les pistes d'amélioration proposées ; -- les optimisations réalisées ; -- les gains mesurés. - -> **Contrôle continu** — Le compte rendu est évalué dans le cadre du TD. +- [Compte rendu](COMPTE_RENDU.md) +- [Consignes du TD](docs/CONSIGNES.md) et [support PDF](docs/R5A04_Profiling_MM.pdf) +- [Journal des mesures](docs/notes.md) +- [Ordre des profils et expériences](resultats/README.md) +- [Comparaison de la normalisation sur le même PC](resultats/mesures/comparaison_normalisation_meme_pc.csv) diff --git a/docs/CONSIGNES.md b/docs/CONSIGNES.md new file mode 100644 index 0000000..f025b60 --- /dev/null +++ b/docs/CONSIGNES.md @@ -0,0 +1,45 @@ +# TD — Consignes + +## Travail demandé + +1. **Mesurer** + + Compilez le programme sans `-pg`, lancez-le avec `time`, puis notez le + temps d'exécution et l'empreinte mémoire. + +2. **Profiler** + + Recompilez en `-O0` avec `-pg`, lancez le programme, puis générez le + profil dans `profil_avant.txt` avec `gprof`. + +3. **Analyser** + + Étudiez le profil plat et le graphe d'appels : où le temps est-il passé, + et pourquoi ? + +4. **Proposer** + + Listez les pistes d'amélioration, classées par gain attendu. + +5. **Optimiser** + + Réalisez une optimisation par commit. L'empreinte mémoire doit rester + identique. + +6. **Valider** + + Reprofilez le programme dans `profil_apres.txt` et chiffrez le gain + obtenu. + +## Compte rendu noté + +Le fichier `COMPTE_RENDU.md` doit être présent à la racine de votre fork. +Il doit contenir : + +- les temps avant et après optimisation ; +- l'analyse du profil ; +- les pistes d'amélioration proposées ; +- les optimisations réalisées ; +- les gains mesurés. + +> **Contrôle continu** — Le compte rendu est évalué dans le cadre du TD. diff --git a/R5A04_Profiling_MM.pdf b/docs/R5A04_Profiling_MM.pdf similarity index 100% rename from R5A04_Profiling_MM.pdf rename to docs/R5A04_Profiling_MM.pdf diff --git a/notes.md b/docs/notes.md similarity index 94% rename from notes.md rename to docs/notes.md index 73a262a..fd6522a 100644 --- a/notes.md +++ b/docs/notes.md @@ -1,3 +1,10 @@ +# Journal des mesures et optimisations + +Ce journal conserve les commandes et sorties historiques, avec les chemins +utilisés au moment des mesures. Les liens vers les profils et les données +pointent vers leur emplacement actuel. Pour compiler et exécuter le projet +avec la nouvelle arborescence, voir le [README](../README.md). + Lancement du programme après la compilation avec `gcc -O0 analyseur.c -o analyseur` ```bash @@ -96,7 +103,7 @@ qu'à la première apparition de chacun des 5 866 mots distincts. Le tableau existant est réutilisé, sans allocation supplémentaire. Le tri final par fréquence produit le même classement. -Résultats du nouveau profil, conservé dans [out/profil_apres.txt](out/profil_apres.txt) : +Résultats du nouveau profil, conservé dans [01_dichotomie.txt](../resultats/profils/01_dichotomie.txt) : | Mesure | Avant | Après | | --- | ---: | ---: | @@ -166,9 +173,9 @@ paramètre à `ecart_type_longueur`. La boucle utilise directement cette valeur. Le calcul des statistiques passe ainsi de O(n²) à O(n), sans allocation supplémentaire ni modification de la formule de variance. -Profil enregistré dans [out/profil_apres_moyenne.txt](out/profil_apres_moyenne.txt). +Profil enregistré dans [02_moyenne.txt](../resultats/profils/02_moyenne.txt). La colonne « Avant » correspond à la version déjà optimisée pour -`chercher_mot`, dont le profil reste dans `out/profil_apres.txt`. +`chercher_mot`, dont le profil reste dans `../resultats/profils/01_dichotomie.txt`. | Mesure | Avant | Après | | --- | ---: | ---: | @@ -242,9 +249,9 @@ cette machine. L'index est libéré après le comptage, avant le tri final qui déplace les entrées. L'empreinte du rapport est conservée, mais cette version utilise davantage de mémoire pendant le comptage. -Profil enregistré dans [out/profil_apres_hachage.txt](out/profil_apres_hachage.txt). +Profil enregistré dans [03_hachage.txt](../resultats/profils/03_hachage.txt). La comparaison porte sur la version précédente avec dichotomie et moyenne -calculée une seule fois, conservée dans `out/profil_apres_moyenne.txt`. +calculée une seule fois, conservée dans `../resultats/profils/02_moyenne.txt`. | Mesure | Dichotomie | Hachage | | --- | ---: | ---: | @@ -304,9 +311,9 @@ Le champ supplémentaire fait passer `sizeof(Entree)` de 36 à 40 octets sur cette machine : le tableau alloué pour 20 000 entrées prend 80 000 octets supplémentaires, soit environ 78 Kio. -Profil enregistré dans [out/profil_apres_longueurs.txt](out/profil_apres_longueurs.txt). +Profil enregistré dans [04_longueurs.txt](../resultats/profils/04_longueurs.txt). La version précédente, avec la table de hachage, est décrite dans -`out/profil_apres_hachage.txt`. +`../resultats/profils/03_hachage.txt`. | Mesure | Avant | Après | | --- | ---: | ---: | @@ -384,9 +391,9 @@ supplémentaire. `doit_echanger` reste inchangée : fréquence décroissante, puis ordre alphabétique croissant. Chaque échange déplace l'entrée entière, y compris la longueur mémorisée. -Profil enregistré dans [out/profil_apres_tri.txt](out/profil_apres_tri.txt). +Profil enregistré dans [05_tri.txt](../resultats/profils/05_tri.txt). La comparaison porte sur la version précédente, décrite dans -`out/profil_apres_longueurs.txt`. +`../resultats/profils/04_longueurs.txt`. | Mesure | Tri à bulles | Tri par tas | | --- | ---: | ---: | @@ -464,9 +471,9 @@ restent identiques. Les deux versions sont en O(nombre de caractères) : le gain vient des vérifications et des appels évités, sans tableau supplémentaire. -Profil enregistré dans [out/profil_apres_bigrammes.txt](out/profil_apres_bigrammes.txt). +Profil enregistré dans [06_bigrammes.txt](../resultats/profils/06_bigrammes.txt). La comparaison porte sur la version précédente, décrite dans -`out/profil_apres_tri.txt`. +`../resultats/profils/05_tri.txt`. | Mesure | Avant | Après | | --- | ---: | ---: | @@ -533,9 +540,9 @@ doublon sont conservés pour produire exactement le même texte. L'index et la longueur maximale occupent 488 octets sur cette machine, sans allocation dynamique supplémentaire. -Profil enregistré dans [out/profil_apres_mots_vides.txt](out/profil_apres_mots_vides.txt). +Profil enregistré dans [07_mots_vides.txt](../resultats/profils/07_mots_vides.txt). La comparaison porte sur la version précédente, décrite dans -`out/profil_apres_bigrammes.txt`. +`../resultats/profils/06_bigrammes.txt`. | Mesure | Avant | Après | | --- | ---: | ---: | @@ -620,9 +627,9 @@ tests et sans appel de fonction pour chaque caractère. La table occupe 256 octets, auxquels s'ajoute l'indicateur d'initialisation de 4 octets sur cette machine, sans allocation dynamique. -Profil enregistré dans [out/profil_apres_normalisation.txt](out/profil_apres_normalisation.txt). +Profil enregistré dans [08_normalisation.txt](../resultats/profils/08_normalisation.txt). La comparaison porte sur la version précédente, décrite dans -`out/profil_apres_mots_vides.txt`. +`../resultats/profils/07_mots_vides.txt`. | Mesure | Avant | Après | | --- | ---: | ---: | @@ -687,6 +694,6 @@ sur cette machine avec `-O0`. Il représente environ 6 ms par exécution. Le rapport et la sortie console sont identiques sur les **110 exécutions**, chauffe incluse. L'empreinte reste **`1d53de903efd2b7c`**. -Les [100 mesures brutes](out/comparaison_normalisation_meme_pc.csv) sont -conservées, ainsi que les [conditions et statistiques détaillées](out/comparaison_normalisation_meme_pc.json), +Les [100 mesures brutes](../resultats/mesures/comparaison_normalisation_meme_pc.csv) sont +conservées, ainsi que les [conditions et statistiques détaillées](../resultats/mesures/comparaison_normalisation_meme_pc.json), qui identifient le commit de référence et les deux sources utilisées. diff --git a/exemple.c b/exemples/exemple.c similarity index 100% rename from exemple.c rename to exemples/exemple.c diff --git a/out/analyseur b/out/analyseur deleted file mode 100755 index 45fcfa2..0000000 Binary files a/out/analyseur and /dev/null differ diff --git a/out/gmon.out b/out/gmon.out deleted file mode 100644 index 7fe4e4c..0000000 Binary files a/out/gmon.out and /dev/null differ diff --git a/resultats/README.md b/resultats/README.md new file mode 100644 index 0000000..55192b8 --- /dev/null +++ b/resultats/README.md @@ -0,0 +1,32 @@ +# Résultats conservés + +Les profils suivent l'ordre des optimisations. Les commits indiqués +contiennent les versions de `analyseur.c` utilisées à ces étapes, avant +le déplacement des sources dans `src/`. + +| Étape | Profil | Version du code | +| --- | --- | --- | +| 00 — Programme initial | [00_initial.txt](profils/00_initial.txt) | `6c6f358` | +| 01 — Recherche dichotomique | [01_dichotomie.txt](profils/01_dichotomie.txt) | `be387e2` | +| 02 — Moyenne calculée une fois | [02_moyenne.txt](profils/02_moyenne.txt) | `d3f1987` | +| 03 — Recherche par hachage | [03_hachage.txt](profils/03_hachage.txt) | `57aaec4` | +| 04 — Longueurs et positions de fin | [04_longueurs.txt](profils/04_longueurs.txt) | `1c4405c` | +| 05 — Tri par tas | [05_tri.txt](profils/05_tri.txt) | `57c9ce9` | +| 06 — Analyse des bigrammes | [06_bigrammes.txt](profils/06_bigrammes.txt) | `e3076e4` | +| 07 — Index des mots vides | [07_mots_vides.txt](profils/07_mots_vides.txt) | `1331811` | +| 08 — Table de normalisation | [08_normalisation.txt](profils/08_normalisation.txt) | `19ad9b7` | + +Les [mesures du bilan après le tri](mesures/mesures_bilan_tri.csv) comparent +le programme initial à l'étape 05. La colonne `final` désigne cette étape. + +La [comparaison de normalisation](mesures/comparaison_normalisation_meme_pc.csv) +compare les étapes 07 et 08 sur le même PC, avec 50 mesures par version. +Les [conditions et statistiques](mesures/comparaison_normalisation_meme_pc.json) +précisent la machine, le compilateur, les sources et le protocole. + +Le [rapport de référence](rapport_reference.txt) conserve l'empreinte +`1d53de903efd2b7c`. `make check` compare le rapport courant à ce fichier. + +Les commandes historiques et les autres mesures sont décrites dans le +[journal](../docs/notes.md). Chaque gain de temps doit être calculé à partir +de versions exécutées dans les mêmes conditions sur la même machine. diff --git a/out/comparaison_normalisation_meme_pc.csv b/resultats/mesures/comparaison_normalisation_meme_pc.csv similarity index 100% rename from out/comparaison_normalisation_meme_pc.csv rename to resultats/mesures/comparaison_normalisation_meme_pc.csv diff --git a/out/comparaison_normalisation_meme_pc.json b/resultats/mesures/comparaison_normalisation_meme_pc.json similarity index 100% rename from out/comparaison_normalisation_meme_pc.json rename to resultats/mesures/comparaison_normalisation_meme_pc.json diff --git a/out/mesures_bilan.csv b/resultats/mesures/mesures_bilan_tri.csv similarity index 100% rename from out/mesures_bilan.csv rename to resultats/mesures/mesures_bilan_tri.csv diff --git a/out/profil_avant.txt b/resultats/profils/00_initial.txt similarity index 100% rename from out/profil_avant.txt rename to resultats/profils/00_initial.txt diff --git a/out/profil_apres.txt b/resultats/profils/01_dichotomie.txt similarity index 100% rename from out/profil_apres.txt rename to resultats/profils/01_dichotomie.txt diff --git a/out/profil_apres_moyenne.txt b/resultats/profils/02_moyenne.txt similarity index 100% rename from out/profil_apres_moyenne.txt rename to resultats/profils/02_moyenne.txt diff --git a/out/profil_apres_hachage.txt b/resultats/profils/03_hachage.txt similarity index 100% rename from out/profil_apres_hachage.txt rename to resultats/profils/03_hachage.txt diff --git a/out/profil_apres_longueurs.txt b/resultats/profils/04_longueurs.txt similarity index 100% rename from out/profil_apres_longueurs.txt rename to resultats/profils/04_longueurs.txt diff --git a/out/profil_apres_tri.txt b/resultats/profils/05_tri.txt similarity index 100% rename from out/profil_apres_tri.txt rename to resultats/profils/05_tri.txt diff --git a/out/profil_apres_bigrammes.txt b/resultats/profils/06_bigrammes.txt similarity index 100% rename from out/profil_apres_bigrammes.txt rename to resultats/profils/06_bigrammes.txt diff --git a/out/profil_apres_mots_vides.txt b/resultats/profils/07_mots_vides.txt similarity index 100% rename from out/profil_apres_mots_vides.txt rename to resultats/profils/07_mots_vides.txt diff --git a/out/profil_apres_normalisation.txt b/resultats/profils/08_normalisation.txt similarity index 100% rename from out/profil_apres_normalisation.txt rename to resultats/profils/08_normalisation.txt diff --git a/out/rapport.txt b/resultats/rapport_reference.txt similarity index 100% rename from out/rapport.txt rename to resultats/rapport_reference.txt diff --git a/analyseur.c b/src/analyseur.c similarity index 99% rename from analyseur.c rename to src/analyseur.c index 44f23f2..55eb298 100644 --- a/analyseur.c +++ b/src/analyseur.c @@ -14,9 +14,11 @@ * L'empreinte affichée à la fin doit rester IDENTIQUE après optimisation : * elle prouve que le résultat du programme n'a pas changé. * - * Compilation : gcc -O0 -pg analyseur.c -o analyseur - * Exécution : ./analyseur - * Profil : gprof ./analyseur gmon.out > profil.txt + * Depuis la racine du dépôt : + * Compilation : make + * Exécution : make run + * Validation : make check + * Profil : make profile (build/profil/profil.txt) */ #include