forked from menault/2026_TD1_DEV51_Qualite_Algo
Optimisation des performances en mémorisant la longueur des mots et en supprimant les parcours redondants
This commit is contained in:
+20
-18
@@ -46,14 +46,6 @@ unsigned long alea(void)
|
||||
/* Fonctions utilitaires sur les chaînes */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
int longueur(const char *s)
|
||||
{
|
||||
int n = 0;
|
||||
while (s[n] != '\0')
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
void copier(char *dest, const char *src)
|
||||
{
|
||||
int i = 0;
|
||||
@@ -83,9 +75,14 @@ int comparer(const char *a, const char *b)
|
||||
return (unsigned char)a[i] - (unsigned char)b[i];
|
||||
}
|
||||
|
||||
void ajouter(char *dest, const char *src)
|
||||
/* position indique la fin de dest et avance avec les caractères ajoutés. */
|
||||
void ajouter(char *dest, const char *src, size_t *position)
|
||||
{
|
||||
copier(dest + longueur(dest), src);
|
||||
size_t fin = *position;
|
||||
for (size_t i = 0; src[i] != '\0'; i++)
|
||||
dest[fin++] = src[i];
|
||||
dest[fin] = '\0';
|
||||
*position = fin;
|
||||
}
|
||||
|
||||
char en_minuscule(char c)
|
||||
@@ -128,9 +125,10 @@ char **generer_vocabulaire(void)
|
||||
for (int i = 0; i < NB_MOTS_VOCAB; i++) {
|
||||
vocab[i] = malloc(TAILLE_MOT);
|
||||
vocab[i][0] = '\0';
|
||||
size_t position = 0;
|
||||
int nb_syllabes = 2 + alea() % 3;
|
||||
for (int j = 0; j < nb_syllabes; j++)
|
||||
ajouter(vocab[i], SYLLABES[alea() % NB_SYLLABES]);
|
||||
ajouter(vocab[i], SYLLABES[alea() % NB_SYLLABES], &position);
|
||||
}
|
||||
return vocab;
|
||||
}
|
||||
@@ -211,7 +209,7 @@ char **decouper_lignes(const char *texte, int *nb_lignes)
|
||||
|
||||
void normaliser_ligne(char *ligne)
|
||||
{
|
||||
for (int i = 0; i < longueur(ligne); i++) {
|
||||
for (int i = 0; ligne[i] != '\0'; i++) {
|
||||
if (est_lettre(ligne[i]))
|
||||
ligne[i] = en_minuscule(ligne[i]);
|
||||
else
|
||||
@@ -226,6 +224,7 @@ void normaliser_ligne(char *ligne)
|
||||
typedef struct {
|
||||
char mot[TAILLE_MOT];
|
||||
int occurrences;
|
||||
int taille;
|
||||
} Entree;
|
||||
|
||||
int est_mot_vide(const char *mot)
|
||||
@@ -263,7 +262,8 @@ int chercher_mot(const Entree *table, const int *index_mots, const char *mot)
|
||||
return -(position + 1);
|
||||
}
|
||||
|
||||
void compter_mot(Entree *table, int *nb_entrees, int *index_mots, const char *mot)
|
||||
void compter_mot(Entree *table, int *nb_entrees, int *index_mots,
|
||||
const char *mot, int taille)
|
||||
{
|
||||
int indice = chercher_mot(table, index_mots, mot);
|
||||
if (indice >= 0) {
|
||||
@@ -278,6 +278,7 @@ void compter_mot(Entree *table, int *nb_entrees, int *index_mots, const char *mo
|
||||
indice = *nb_entrees;
|
||||
copier(table[indice].mot, mot);
|
||||
table[indice].occurrences = 1;
|
||||
table[indice].taille = taille;
|
||||
index_mots[position] = indice + 1;
|
||||
(*nb_entrees)++;
|
||||
}
|
||||
@@ -302,7 +303,7 @@ void compter_mots_ligne(Entree *table, int *nb_entrees, int *index_mots,
|
||||
if (k > 0) {
|
||||
(*nb_mots_total)++;
|
||||
if (!est_mot_vide(mot))
|
||||
compter_mot(table, nb_entrees, index_mots, mot);
|
||||
compter_mot(table, nb_entrees, index_mots, mot, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -339,7 +340,7 @@ double longueur_moyenne(const Entree *table, int n)
|
||||
{
|
||||
long total = 0;
|
||||
for (int i = 0; i < n; i++)
|
||||
total += longueur(table[i].mot);
|
||||
total += table[i].taille;
|
||||
return (double)total / n;
|
||||
}
|
||||
|
||||
@@ -348,7 +349,7 @@ double ecart_type_longueur(const Entree *table, int n, double moyenne)
|
||||
{
|
||||
double somme = 0.0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
double ecart = longueur(table[i].mot) - moyenne;
|
||||
double ecart = table[i].taille - moyenne;
|
||||
somme += ecart * ecart;
|
||||
}
|
||||
return somme / n; /* variance ; la racine est prise dans main */
|
||||
@@ -399,12 +400,13 @@ char *construire_rapport(const Entree *table, int n)
|
||||
char *rapport = malloc((size_t)n * 64 + 256);
|
||||
char ligne[128];
|
||||
rapport[0] = '\0';
|
||||
size_t position = 0;
|
||||
|
||||
ajouter(rapport, "rang;mot;occurrences\n");
|
||||
ajouter(rapport, "rang;mot;occurrences\n", &position);
|
||||
for (int i = 0; i < n; i++) {
|
||||
snprintf(ligne, sizeof(ligne), "%d;%s;%d\n",
|
||||
i + 1, table[i].mot, table[i].occurrences);
|
||||
ajouter(rapport, ligne);
|
||||
ajouter(rapport, ligne, &position);
|
||||
}
|
||||
return rapport;
|
||||
}
|
||||
|
||||
@@ -280,3 +280,89 @@ mkdir -p out/apres_hachage
|
||||
gcc -O0 -pg analyseur.c -o out/apres_hachage/analyseur
|
||||
(cd out/apres_hachage && ./analyseur && gprof -b ./analyseur gmon.out > ../profil_apres_hachage.txt)
|
||||
```
|
||||
|
||||
## Longueurs mémorisées et suppression des parcours répétés
|
||||
|
||||
Le champ `taille` de `Entree` mémorise la longueur du mot à son insertion.
|
||||
La valeur vient directement de `k`, déjà calculé dans `compter_mots_ligne` :
|
||||
aucun parcours supplémentaire n'est nécessaire. La moyenne et la variance
|
||||
lisent désormais ce champ. Le tri déplace l'entrée entière, donc la longueur
|
||||
reste associée au bon mot. Pour un mot tronqué, la taille enregistrée est
|
||||
celle du mot conservé, soit au maximum 31 caractères.
|
||||
|
||||
Deux autres changements éliminent les recalculs sur les chaînes longues :
|
||||
|
||||
- `normaliser_ligne` s'arrête directement sur `ligne[i] == '\0'`. Le parcours
|
||||
d'une ligne de L caractères passe de O(L²) à O(L).
|
||||
- `ajouter` reçoit une position de fin, qu'il avance pendant la copie des
|
||||
caractères ajoutés. Cette position est conservée lors de la construction
|
||||
du rapport et réinitialisée pour chaque mot du vocabulaire. Le préfixe
|
||||
déjà construit n'est plus parcouru à chaque ajout.
|
||||
|
||||
La fonction `longueur`, devenue inutilisée, a été supprimée.
|
||||
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).
|
||||
La version précédente, avec la table de hachage, est décrite dans
|
||||
`out/profil_apres_hachage.txt`.
|
||||
|
||||
| Mesure | Avant | Après |
|
||||
| --- | ---: | ---: |
|
||||
| Appels à `longueur()` depuis les statistiques | 11 732 | 0 |
|
||||
| Appels à `longueur()` depuis `normaliser_ligne` | 1 561 330 | 0 |
|
||||
| Appels à `longueur()` depuis `ajouter` | 26 801 | 0 |
|
||||
| Appels à `longueur()` au total | 1 599 863 | 0 |
|
||||
| Temps réel médian sans profiling (`gcc -O0`, 5 exécutions par version) | 0,832 s | 0,362 s |
|
||||
|
||||
Le temps total baisse de 56,5 %, soit une accélération d'environ 2,30.
|
||||
Cette mesure porte sur l'ensemble des trois changements, et ne doit pas
|
||||
être attribuée uniquement au stockage de la longueur des mots.
|
||||
|
||||
Les cinq mesures, réalisées en alternant les deux versions sur la même
|
||||
machine, sont respectivement : 0,835 / 0,838 / 0,830 / 0,832 / 0,829 s
|
||||
avant, et 0,362 / 0,369 / 0,366 / 0,362 / 0,361 s après.
|
||||
|
||||
Validation : compilation sans avertissement avec `-Wall -Wextra -Wpedantic`,
|
||||
rapport et sortie console identiques octet par octet sur les dix exécutions,
|
||||
avec `-pg` et sous AddressSanitizer et UndefinedBehaviorSanitizer.
|
||||
L'empreinte reste **`1d53de903efd2b7c`**, la moyenne `6.712` et l'écart-type
|
||||
`1.873`. Des tests temporaires ont également vérifié les ajouts vides et
|
||||
successifs jusqu'à la limite d'un tampon, la normalisation, les longueurs
|
||||
avant/après tri, les statistiques, le rapport vide et les mots tronqués.
|
||||
|
||||
Commandes pour reproduire ce profil :
|
||||
|
||||
```bash
|
||||
mkdir -p out/apres_longueurs
|
||||
gcc -O0 -pg analyseur.c -o out/apres_longueurs/analyseur
|
||||
(cd out/apres_longueurs && ./analyseur && gprof -b ./analyseur gmon.out > ../profil_apres_longueurs.txt)
|
||||
```
|
||||
|
||||
```bash
|
||||
[rabot@salle235-06 out]$ time ./analyseur
|
||||
Lignes analysées : 21746
|
||||
Mots au total : 250000
|
||||
Mots distincts : 5866
|
||||
Longueur moyenne : 6.712 (écart-type 1.873)
|
||||
Bigramme le + courant : "me" (17607 fois, souvent suivi de 'n')
|
||||
|
||||
Top 10 :
|
||||
1. rane 287
|
||||
2. fasi 241
|
||||
3. tata 219
|
||||
4. mopo 214
|
||||
5. cofi 180
|
||||
6. vesi 179
|
||||
7. laganomo 177
|
||||
8. boto 172
|
||||
9. nopebo 169
|
||||
10. rotion 165
|
||||
|
||||
Empreinte du rapport : 1d53de903efd2b7c
|
||||
|
||||
real 0m0.751s
|
||||
user 0m0.703s
|
||||
sys 0m0.004s
|
||||
```
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,159 @@
|
||||
Flat profile:
|
||||
|
||||
Each sample counts as 0.01 seconds.
|
||||
% cumulative self self total
|
||||
time seconds seconds calls ms/call ms/call name
|
||||
22.22 0.06 0.06 250000 0.00 0.00 est_mot_vide
|
||||
18.52 0.11 0.05 17202045 0.00 0.00 doit_echanger
|
||||
12.96 0.14 0.04 12172087 0.00 0.00 comparer
|
||||
11.11 0.17 0.03 5297256 0.00 0.00 est_lettre
|
||||
11.11 0.20 0.03 _init
|
||||
9.26 0.23 0.03 12198772 0.00 0.00 egales
|
||||
7.41 0.25 0.02 1 20.00 105.00 trier_entrees
|
||||
3.70 0.26 0.01 21746 0.00 0.00 normaliser_ligne
|
||||
1.85 0.27 0.01 150182 0.00 0.00 chercher_mot
|
||||
1.85 0.27 0.01 150182 0.00 0.00 hacher_mot
|
||||
0.00 0.27 0.00 1266663 0.00 0.00 en_minuscule
|
||||
0.00 0.27 0.00 928117 0.00 0.00 alea
|
||||
0.00 0.27 0.00 150182 0.00 0.00 compter_mot
|
||||
0.00 0.27 0.00 26801 0.00 0.00 ajouter
|
||||
0.00 0.27 0.00 21746 0.00 0.00 compter_mots_ligne
|
||||
0.00 0.27 0.00 5866 0.00 0.00 copier
|
||||
0.00 0.27 0.00 1 0.00 21.28 analyser_bigrammes
|
||||
0.00 0.27 0.00 1 0.00 0.00 construire_rapport
|
||||
0.00 0.27 0.00 1 0.00 0.00 decouper_lignes
|
||||
0.00 0.27 0.00 1 0.00 0.00 ecart_type_longueur
|
||||
0.00 0.27 0.00 1 0.00 0.00 empreinte
|
||||
0.00 0.27 0.00 1 0.00 0.00 generer_texte
|
||||
0.00 0.27 0.00 1 0.00 0.00 generer_vocabulaire
|
||||
0.00 0.27 0.00 1 0.00 0.00 longueur_moyenne
|
||||
0.00 0.27 0.00 1 0.00 0.00 racine
|
||||
|
||||
Call graph
|
||||
|
||||
|
||||
granularity: each sample hit covers 4 byte(s) for 3.70% of 0.27 seconds
|
||||
|
||||
index % time self children called name
|
||||
<spontaneous>
|
||||
[1] 88.9 0.00 0.24 main [1]
|
||||
0.02 0.09 1/1 trier_entrees [2]
|
||||
0.00 0.10 21746/21746 compter_mots_ligne [3]
|
||||
0.00 0.02 1/1 analyser_bigrammes [10]
|
||||
0.01 0.01 21746/21746 normaliser_ligne [11]
|
||||
0.00 0.00 1/1 generer_vocabulaire [24]
|
||||
0.00 0.00 1/1 generer_texte [23]
|
||||
0.00 0.00 1/1 decouper_lignes [20]
|
||||
0.00 0.00 1/1 longueur_moyenne [25]
|
||||
0.00 0.00 1/1 ecart_type_longueur [21]
|
||||
0.00 0.00 1/1 racine [26]
|
||||
0.00 0.00 1/1 construire_rapport [19]
|
||||
0.00 0.00 1/1 empreinte [22]
|
||||
-----------------------------------------------
|
||||
0.02 0.09 1/1 main [1]
|
||||
[2] 38.9 0.02 0.09 1 trier_entrees [2]
|
||||
0.05 0.04 17202045/17202045 doit_echanger [4]
|
||||
-----------------------------------------------
|
||||
0.00 0.10 21746/21746 main [1]
|
||||
[3] 35.2 0.00 0.10 21746 compter_mots_ligne [3]
|
||||
0.06 0.02 250000/250000 est_mot_vide [5]
|
||||
0.00 0.01 150182/150182 compter_mot [13]
|
||||
-----------------------------------------------
|
||||
0.05 0.04 17202045/17202045 trier_entrees [2]
|
||||
[4] 31.5 0.05 0.04 17202045 doit_echanger [4]
|
||||
0.04 0.00 12172087/12172087 comparer [6]
|
||||
-----------------------------------------------
|
||||
0.06 0.02 250000/250000 compter_mots_ligne [3]
|
||||
[5] 31.4 0.06 0.02 250000 est_mot_vide [5]
|
||||
0.02 0.00 12045671/12198772 egales [9]
|
||||
-----------------------------------------------
|
||||
0.04 0.00 12172087/12172087 doit_echanger [4]
|
||||
[6] 13.0 0.04 0.00 12172087 comparer [6]
|
||||
-----------------------------------------------
|
||||
0.01 0.00 1539584/5297256 normaliser_ligne [11]
|
||||
0.02 0.00 3757672/5297256 analyser_bigrammes [10]
|
||||
[7] 11.1 0.03 0.00 5297256 est_lettre [7]
|
||||
-----------------------------------------------
|
||||
<spontaneous>
|
||||
[8] 11.1 0.03 0.00 _init [8]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 153101/12198772 chercher_mot [12]
|
||||
0.02 0.00 12045671/12198772 est_mot_vide [5]
|
||||
[9] 9.3 0.03 0.00 12198772 egales [9]
|
||||
-----------------------------------------------
|
||||
0.00 0.02 1/1 main [1]
|
||||
[10] 7.9 0.00 0.02 1 analyser_bigrammes [10]
|
||||
0.02 0.00 3757672/5297256 est_lettre [7]
|
||||
-----------------------------------------------
|
||||
0.01 0.01 21746/21746 main [1]
|
||||
[11] 6.9 0.01 0.01 21746 normaliser_ligne [11]
|
||||
0.01 0.00 1539584/5297256 est_lettre [7]
|
||||
0.00 0.00 1266663/1266663 en_minuscule [15]
|
||||
-----------------------------------------------
|
||||
0.01 0.01 150182/150182 compter_mot [13]
|
||||
[12] 3.8 0.01 0.01 150182 chercher_mot [12]
|
||||
0.01 0.00 150182/150182 hacher_mot [14]
|
||||
0.00 0.00 153101/12198772 egales [9]
|
||||
-----------------------------------------------
|
||||
0.00 0.01 150182/150182 compter_mots_ligne [3]
|
||||
[13] 3.8 0.00 0.01 150182 compter_mot [13]
|
||||
0.01 0.01 150182/150182 chercher_mot [12]
|
||||
0.00 0.00 5866/5866 copier [18]
|
||||
-----------------------------------------------
|
||||
0.01 0.00 150182/150182 chercher_mot [12]
|
||||
[14] 1.9 0.01 0.00 150182 hacher_mot [14]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1266663/1266663 normaliser_ligne [11]
|
||||
[15] 0.0 0.00 0.00 1266663 en_minuscule [15]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 27934/928117 generer_vocabulaire [24]
|
||||
0.00 0.00 900183/928117 generer_texte [23]
|
||||
[16] 0.0 0.00 0.00 928117 alea [16]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 5867/26801 construire_rapport [19]
|
||||
0.00 0.00 20934/26801 generer_vocabulaire [24]
|
||||
[17] 0.0 0.00 0.00 26801 ajouter [17]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 5866/5866 compter_mot [13]
|
||||
[18] 0.0 0.00 0.00 5866 copier [18]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1/1 main [1]
|
||||
[19] 0.0 0.00 0.00 1 construire_rapport [19]
|
||||
0.00 0.00 5867/26801 ajouter [17]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1/1 main [1]
|
||||
[20] 0.0 0.00 0.00 1 decouper_lignes [20]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1/1 main [1]
|
||||
[21] 0.0 0.00 0.00 1 ecart_type_longueur [21]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1/1 main [1]
|
||||
[22] 0.0 0.00 0.00 1 empreinte [22]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1/1 main [1]
|
||||
[23] 0.0 0.00 0.00 1 generer_texte [23]
|
||||
0.00 0.00 900183/928117 alea [16]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1/1 main [1]
|
||||
[24] 0.0 0.00 0.00 1 generer_vocabulaire [24]
|
||||
0.00 0.00 27934/928117 alea [16]
|
||||
0.00 0.00 20934/26801 ajouter [17]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1/1 main [1]
|
||||
[25] 0.0 0.00 0.00 1 longueur_moyenne [25]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1/1 main [1]
|
||||
[26] 0.0 0.00 0.00 1 racine [26]
|
||||
-----------------------------------------------
|
||||
|
||||
Index by function name
|
||||
|
||||
[8] _init [18] copier [23] generer_texte
|
||||
[17] ajouter [20] decouper_lignes [24] generer_vocabulaire
|
||||
[16] alea [4] doit_echanger [14] hacher_mot
|
||||
[10] analyser_bigrammes [21] ecart_type_longueur [25] longueur_moyenne
|
||||
[12] chercher_mot [9] egales [11] normaliser_ligne
|
||||
[6] comparer [22] empreinte [26] racine
|
||||
[13] compter_mot [15] en_minuscule [2] trier_entrees
|
||||
[3] compter_mots_ligne [7] est_lettre
|
||||
[19] construire_rapport [5] est_mot_vide
|
||||
Reference in New Issue
Block a user