Ajouts des différents programmes et ajout des fichiers readme.md

This commit is contained in:
2024-10-04 15:54:19 +02:00
parent f5db552558
commit ef90364a97
12 changed files with 835027 additions and 2 deletions

58
random/README.md Normal file
View File

@@ -0,0 +1,58 @@
# Simulateur de Cache - Version Random
## 📖 Description
Le programme `cache.c` simule le comportement d'un cache de processeur. Il permet de suivre les hits et les misses ainsi que d'analyser les performances du cache en fonction des références mémoire fournies.
## 📦 Compilation
Pour compiler le programme, utilisez la commande suivante :
```bash
gcc -o cache_simulator cache.c -lm
```
## ⚙️ Exécution
Pour exécuter le programme, utilisez la ligne de commande suivante :
```c
./cache_simulator -s <cache_size(KB)> -l <line_size> -a <associativity> [-c] [-W] < <trace_file>
```
## 📝 Arguments
* `-s <cache_size(KB)>` : Taille du cache en kilooctets. (Obligatoire)
Exemple : -s 64 -> taille du cache de 64 KB
* `-l <line_size>` : Taille de la ligne de cache en octets. (Obligatoire)
Exemple : -l 16 -> taille de ligne de 16 octets
* `-a <associativity>` : Associativité du cache (nombre de lignes par ensemble). (Obligatoire)
Exemple : -a 4 -> associativité de 4 lignes
* `-c` : Activer l'écriture en mode Write Back. (Optionnel)
Exemple : -c -> active le mode Write Back
* `-W` : Activer la stratégie d'allocation d'écriture (Write Allocate). (Optionnel)
Exemple : -W -> active l'allocation d'écriture
## 📚 Fonctionnement de la Stratégie Random
La stratégie de remplacement **Random** est une méthode simple pour gérer les lignes de cache lorsque le cache est plein. Contrairement à d'autres méthodes comme LRU, où les décisions sont basées sur l'historique d'accès, Random choisit simplement une ligne à remplacer au hasard parmi celles qui sont présentes dans le cache.
### Principe de Fonctionnement
1. **Choix Aléatoire**: Lorsqu'un nouvel accès à la mémoire doit être effectué et que le cache est plein, une ligne de cache est choisie de manière aléatoire pour être remplacée. Ce choix ne dépend d'aucun critère de fréquence ou de récence.
2. **Remplacement**: La ligne choisie est invalidée et remplacée par la nouvelle ligne de données, qui est ensuite chargée dans le cache.
### Avantages et Inconvénients
- **Avantages**:
- La simplicité de l'algorithme rend son implémentation facile.
- En tant que méthode probabiliste, elle peut parfois donner de bons résultats dans des cas spécifiques, où le comportement d'accès est imprévisible.
- **Inconvénients**:
- Random n'utilise pas d'historique d'accès, ce qui peut entraîner un taux de hit inférieur par rapport à des stratégies comme LRU ou FIFO.
- Dans certains scénarios, elle peut remplacer des lignes de cache qui auraient pu être utilisées à nouveau dans un futur proche, entraînant ainsi des misses fréquentes.
## 🛠️ Auteur
- Moncef STITI

417
random/cache.c Normal file
View File

@@ -0,0 +1,417 @@
/*
* Fichier : cache.c
* Auteur : Moncef STITI
* Date : 02/11/2024
* Version : 1.0
* Description : Ce programme permet de simuler une mémoire cache avec comme algorithme d'éviction d'une ligne "Random" (Aléatoire).
* Compilation : Pour compiler le programme, on utilise la commande suivante : gcc cache.c -o simulateur_cache -lm -Wall
*/
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h> // Pour les options en argument
#include <time.h> // Pour les mesures de temps
// Différentes couleurs pour l'affichage des résultats
#define RESET "\x1b[0m" // Couleur de base du terminal
#define GREEN "\x1b[32m" // Vert
#define YELLOW "\x1b[33m" // Jaune
#define RED "\x1b[31m" // Rouge
#define CYAN "\033[36m" // Cyan
#define MAGENTA "\x1b[35m" // Violet/Magenta
#define WHITE "\x1b[37m" // Blanc
#define COULEUR_BORDURE CYAN // Cyan
// Structure représentant une ligne de cache.
struct line
{
unsigned int valid; // Indicateur de validité
unsigned int dirty; // Indicateur de "saleté" (dirty)
unsigned int tag; // Tag de la ligne de cache
}; typedef struct line line;
// Structure représentant un ensemble de lignes de cache.
struct Set
{
struct line *lines;
}; typedef struct Set Set;
// Structure représentant le cache lui-même.
struct Cache
{
struct Set *sets;
}; typedef struct Cache Cache;
/*
* Fonction : ecrire_ligne_en_memoire
* Description : Cette fonction simule l'écriture d'une ligne de cache évincée
* dans la mémoire principale. Dans le contexte de la simulation,
* la fonction n'effectue pas d'écriture réelle, mais elle peut
* être utilisée pour afficher des informations de débogage concernant
* l'éviction d'une ligne "dirty" (modifiée).
*
* Paramètre :
* - line *evictedLine : Pointeur vers la ligne de cache qui a été évincée.
*
* Retour :
* - void : Cette fonction ne retourne rien, car elle est conçue pour
* effectuer une action (écriture dans la mémoire) plutôt que de
* fournir une valeur de retour.
*/
void ecrire_ligne_en_memoire(line *evictedLine)
{
// Comme il s'agit d'une simulation, nous ne faisons pas d'écriture réelle ici.
// Mais voici comment afficher la ligne :
// printf("Ecriture de la ligne %d dans la mémoire centrale\n", evictedLine->tag);
}
/*
* Fonction : creer_struct_cache
* Description : Cette fonction initialise une structure de cache en allouant
* dynamiquement la mémoire pour les ensembles et les lignes de cache.
* Chaque ligne est initialisée avec des valeurs par défaut pour
* les indicateurs de validité, de saleté (dirty) et le tag.
*
* Paramètres :
* - Cache *cache : Pointeur vers la structure de cache à initialiser.
* - int numSets : Nombre d'ensembles dans la cache. C'est le nombre total
* de groupes de lignes de cache.
* - int associativite : Le degré d'associativité de la mémoire cache.
*
* Retour :
* - void : Cette fonction ne retourne rien, car elle modifie directement
* la structure de cache passée en paramètre.
*/
void creer_struct_cache(Cache *cache, int numSets, int associativite)
{
cache->sets = (Set *)malloc(numSets * sizeof(Set));
for (int i = 0; i < numSets; i++) {
cache->sets[i].lines = (line *)malloc(associativite * sizeof(line));
for (int j = 0; j < associativite; j++) {
cache->sets[i].lines[j].valid = 0;
cache->sets[i].lines[j].dirty = 0;
cache->sets[i].lines[j].tag = -1;
}
}
}
/*
* Fonction : acceder_cache
* Description : Cette fonction simule l'accès à un cache à partir d'une
* adresse mémoire donnée. Elle détermine si l'accès est un hit ou
* un miss, met à jour les statistiques en conséquence, et gère
* l'éviction de lignes de cache si nécessaire.
*
* Paramètres :
* - Cache *cache : Pointeur vers la structure de cache dans laquelle l'accès
* est effectué.
* - int adresse : Adresse mémoire à laquelle on souhaite accéder.
* - int associativite : Degré d'associativité de la mémoire cache.
* - int writeBack : Indicateur de la politique d'écriture (Write Back ou Write Through).
* - int writeAllocate : Indicateur de la stratégie d'allocation lors des écritures
* (Write Allocate ou No Write Allocate).
* - int numSets : Nombre d'ensembles dans la mémoire cache.
* - int accessType : Type d'accès (0 pour lecture, 1 pour écriture).
* - int* memoryAccesses : Pointeur vers un entier qui suit le nombre total
* d'accès mémoire effectués.
* - int* hitsLecture : Pointeur vers un entier qui suit le nombre de hits en lecture.
* - int* missesLecture : Pointeur vers un entier qui suit le nombre de misses en lecture.
* - int* hitsEcriture : Pointeur vers un entier qui suit le nombre de hits en écriture.
* - int* missesEcriture : Pointeur vers un entier qui suit le nombre de misses en écriture.
*
* Retour :
* - void : Cette fonction ne retourne rien, mais met à jour les statistiques de cache
* en fonction de l'accès effectué.
*/
void acceder_cache(Cache *cache, int adresse, int associativite, int writeBack, int writeAllocate, int numSets, int accessType, int* memoryAccesses, int* hitsLecture, int* missesLecture, int* hitsEcriture, int* missesEcriture)
{
int setIndex = adresse % numSets;
// Recherche de l'adresse dans le set correspondant
int found = 0;
for (int i = 0; i < associativite; i++) {
line *currentLine = &cache->sets[setIndex].lines[i];
if (currentLine->valid && currentLine->tag == (adresse / numSets)) {
found = 1;
if (accessType == 0 || accessType == 2) {
// C'est un hit en lecture
(*hitsLecture)++;
} else {
// C'est un hit en écriture
(*hitsEcriture)++;
if (writeBack) {
currentLine->dirty = 1;
}
}
// Marquer la ligne comme valide
currentLine->valid = 1;
}
}
if (!found) {
// C'est un miss, mettre à jour les statistiques
if (accessType == 0 || accessType == 2) {
// C'est un miss en lecture
(*missesLecture)++;
} else {
// C'est un miss en écriture
(*missesEcriture)++;
}
// Choisir aléatoirement une ligne pour l'éviction
int evictionIndex = rand() % associativite;
line *evictedLine = &cache->sets[setIndex].lines[evictionIndex];
// Si la ligne évincée est "dirty" et si la stratégie = write-back, alors écrire dans la mémoire centrale
if (writeBack && evictedLine->dirty) {
ecrire_ligne_en_memoire(evictedLine);
}
// Mettez à jour la ligne évincée avec la nouvelle adresse
evictedLine->tag = adresse / numSets;
evictedLine->valid = 1;
if (accessType == 1) {
evictedLine->dirty = 1;
}
(*memoryAccesses)++;
}
}
/*
* Fonction : get_hits_color
* Description : Cette fonction détermine la couleur d'affichage basée sur le pourcentage
* de hits pour une performance de cache donnée. Elle renvoie une constante
* représentant une couleur en fonction du niveau de performance.
*
* Paramètre :
* - float percentage : Pourcentage de hits, exprimé en tant que valeur
* flottante. Ce pourcentage est utilisé pour évaluer
* la performance de la mémoire cache.
*
* Retour :
* - const char* : Retourne une constante de chaîne de caractères représentant
* la couleur correspondant à la performance de la mémoire cache :
* - GREEN pour une bonne performance (≥ 80 %)
* - YELLOW pour une performance moyenne (≥ 50 % et < 80 %)
* - RED pour une mauvaise performance (< 50 %)
*
* Potentiel erreur :
* - La fonction ne gère pas les valeurs de pourcentage en dehors de la
* plage normale (0 à 100). Les entrées négatives ou supérieures à 100
* pourraient donner des résultats inattendus.
*/
const char* get_hits_color(float percentage)
{
if (percentage >= 80.0) {
return GREEN; // Bonne performance
} else if (percentage >= 50.0) {
return YELLOW; // Moyenne performance
} else {
return RED; // Mauvais performance
}
}
/*
* Fonction : get_misses_color
* Description : Cette fonction détermine la couleur d'affichage basée sur le pourcentage
* de misses pour une performance de cache donnée. Elle renvoie une constante
* représentant une couleur en fonction du niveau de performance.
*
* Paramètre :
* - float percentage : Pourcentage de misses, exprimé en tant que valeur
* flottante. Ce pourcentage est utilisé pour évaluer
* la performance de la mémoire cache.
*
* Retour :
* - const char* : Retourne une constante de chaîne de caractères représentant
* la couleur correspondant à la performance de la mémoire cache :
* - GREEN pour une bonne performance (< 8 % de misses)
* - YELLOW pour une performance acceptable (≥ 8 % et < 16 %)
* - RED pour une mauvaise performance (≥ 16 % de misses)
*
* Potentiel erreur :
* - La fonction ne gère pas les valeurs de pourcentage en dehors de la
* plage normale (0 à 100). Les entrées négatives ou supérieures à 100
* pourraient donner des résultats inattendus.
*/
const char* get_misses_color(float percentage)
{
if (percentage < 8.0) {
return GREEN; // Bonne performance
} else if (percentage < 16.0) {
return YELLOW; // Acceptable
} else {
return RED; // Mauvais performance
}
}
void afficher_hits_miss(int nbTotalAcces, int nbAccesLecture, int nbAccesEcriture, int memoryAccesses, int hitsLecture, int hitsEcriture, int missesLecture, int missesEcriture, double cpu_time_used) {
// Calculs des pourcentages
float pourcentAccLecture = (double) nbAccesLecture / nbTotalAcces * 100;
float pourcentAccEcriture = (double) nbAccesEcriture / nbTotalAcces * 100;
int totalHits = hitsLecture + hitsEcriture;
float pourcentHits = (double) totalHits / nbTotalAcces * 100;
float pourcentHitsLecture = (double) hitsLecture / nbAccesLecture * 100;
float pourcentHitsEcriture = (double) hitsEcriture / nbAccesEcriture * 100;
int totalMisses = missesLecture + missesEcriture;
float pourcentMisses = (double) totalMisses / nbTotalAcces * 100;
float pourcentMissesLecture = (double) missesLecture / nbAccesLecture * 100;
float pourcentMissesEcriture = (double) missesEcriture / nbAccesEcriture * 100;
// Affichage avec bordures et couleurs
printf("%s----------------------------------------------------\n", COULEUR_BORDURE);
printf("| %sStatistiques de Cache%s |\n", WHITE, COULEUR_BORDURE);
printf("----------------------------------------------------\n");
printf("| %sTotal Accès%s | %s%6d %s|\n", MAGENTA, COULEUR_BORDURE, WHITE, nbTotalAcces, COULEUR_BORDURE);
printf("----------------------------------------------------\n");
printf("| %sAccès en Lecture%s | %s%6d (%.2f%%)%s |\n", WHITE, COULEUR_BORDURE, WHITE, nbAccesLecture, pourcentAccLecture, COULEUR_BORDURE);
printf("| %sAccès en Écriture%s | %s%6d (%.2f%%)%s |\n", WHITE, COULEUR_BORDURE, WHITE, nbAccesEcriture, pourcentAccEcriture, COULEUR_BORDURE);
printf("----------------------------------------------------\n");
printf("| %sTotal Hits :%s | %s%6d (%.2f%%) %s|\n", MAGENTA, COULEUR_BORDURE, get_hits_color(pourcentHits), totalHits, pourcentHits, COULEUR_BORDURE);
printf("|%s - Hits en Lecture %s | %s%6d (%.2f%%)%s |\n", WHITE, COULEUR_BORDURE, get_hits_color(pourcentHits), hitsLecture, pourcentHitsLecture, COULEUR_BORDURE);
printf("|%s - Hits en Écriture %s | %s%6d (%.2f%%)%s |\n", WHITE, COULEUR_BORDURE, get_hits_color(pourcentHits), hitsEcriture, pourcentHitsEcriture, COULEUR_BORDURE);
printf("----------------------------------------------------\n");
printf("| %sTotal Misses :%s | %s%6d (%.2f%%) %s|\n", MAGENTA, COULEUR_BORDURE, get_misses_color(pourcentMisses), totalMisses, pourcentMisses, COULEUR_BORDURE);
printf("|%s - Misses en Lecture%s | %s%6d (%.2f%%) %s|\n", WHITE, COULEUR_BORDURE, get_misses_color(pourcentMisses), missesLecture, pourcentMissesLecture, COULEUR_BORDURE);
printf("|%s - Misses en Écriture%s | %s%6d (%.2f%%) %s|\n", WHITE, COULEUR_BORDURE, get_misses_color(pourcentMisses), missesEcriture, pourcentMissesEcriture, COULEUR_BORDURE);
printf("----------------------------------------------------\n");
printf("|%s Accès Mémoire%s | %s%6d %s|\n", WHITE, COULEUR_BORDURE, WHITE, memoryAccesses, COULEUR_BORDURE);
printf("----------------------------------------------------\n");
printf("| %sTemps total d'accès au cache : %.6f secondes%s |\n", MAGENTA, cpu_time_used, COULEUR_BORDURE);
printf("----------------------------------------------------%s\n", RESET);
}
/*
* Fonction : afficher_aide
* Description : Cette fonction affiche un message d'aide détaillant comment utiliser le programme
* de simulation de cache. Elle fournit des informations sur les options disponibles
* et la syntaxe correcte pour exécuter le programme.
*
* Fonctionnalités :
* - Indique l'utilisation générale du programme.
* - Liste les options possibles avec des descriptions pour chacune, y compris
* les paramètres de taille de cache, de taille de ligne, d'associativité,
* et les options de politique d'écriture.
* - Fournit un exemple de ligne de commande illustrant l'utilisation des options.
*
* Comportement :
* - Appelle `printf` pour afficher chaque ligne d'information à l'utilisateur.
* - Utilise `exit(EXIT_SUCCESS)` pour quitter le programme après l'affichage de l'aide,
* garantissant que le programme ne continue pas à s'exécuter après avoir fourni
* les informations nécessaires.
*/
void afficher_aide()
{
printf("Usage: ./cache [options] < fichier\n");
printf("Options :\n");
printf(" -h : Affiche cette aide et quitte le programme\n");
printf(" -s <taille_cache> : Spécifie la taille du cache en Ko\n");
printf(" -l <taille_ligne> : Spécifie la taille d'une ligne de cache en octets\n");
printf(" -a <associativite>: Spécifie l'associativité de la mémoire cache (ex: 1, 2, 4, 8...)\n");
printf(" -c : Active le Write Back (par défaut, Write Through est activé)\n");
printf(" -W : Active le Write Allocate (par défaut, No Write Allocate est activé)\n");
printf("\nExemple :\n");
printf(" ./cache -s 1 -l 8 -W -c -a 1 < sample\n");
printf("\n");
exit(EXIT_SUCCESS);
}
int main(int argc, char *argv[])
{
if (argc < 7 || argc > 9)
{
afficher_aide();
}
Cache cache;
// def Arguments
int tailleCache;
int tailleLigne;
int associativite;
int writeBack = 0;
int writeAllocate = 0;
// Suivi des statistiques
int nbTotalAcces = 0;
int nbAccesLecture = 0;
int nbAccesEcriture = 0;
int memoryAccesses = 0;
int hitsLecture = 0;
int hitsEcriture = 0;
int missesLecture = 0;
int missesEcriture = 0;
int numSets;
int accessType;
int adresse;
// Variables pour le temps
clock_t start_time, end_time;
double cpu_time_used;
// Arguments
int opt;
while ((opt = getopt(argc, argv, "s:l:a:Wch:")) != -1) {
switch (opt) {
case 's':
tailleCache = atoi(optarg);
break;
case 'l':
tailleLigne = atoi(optarg);
break;
case 'a':
associativite = atoi(optarg);
break;
case 'W':
writeAllocate = 1;
break;
case 'c':
writeBack = 1;
break;
case 'h':
afficher_aide();
break;
default:
printf("Usage: %s -s <cache_size> -l <line_size> -a <associativite> -[W] -[c] < fichier_trace\n", argv[0]);
exit(1);
}
}
numSets = tailleCache * 1024 / (tailleLigne * associativite);
// Initialiser le générateur aléatoire une seule fois
srand(time(NULL));
// Initialiser le cache
creer_struct_cache(&cache, numSets, associativite);
// Démarrer le chrono
start_time = clock();
// Boucle de simulation d'accès au cache
while (scanf("%d %x", &accessType, &adresse) != EOF) {
nbTotalAcces++;
if (accessType == 0 || accessType == 2) {
nbAccesLecture++;
} else {
nbAccesEcriture++;
}
acceder_cache(&cache, adresse, associativite, writeBack, writeAllocate, numSets, accessType, &memoryAccesses, &hitsLecture, &hitsEcriture, &missesLecture, &missesEcriture);
}
// Arrêter le chronomètre
end_time = clock();
cpu_time_used = ((double) (end_time - start_time)) / CLOCKS_PER_SEC; // Calcule le temps écoulé
// Afficher les statistiques du cache
afficher_hits_miss(nbTotalAcces, nbAccesLecture, nbAccesEcriture, memoryAccesses, hitsLecture, hitsEcriture, missesLecture, missesEcriture, cpu_time_used);
// Libérer la mémoire allouée
for (int i = 0; i < numSets; i++) {
free(cache.sets[i].lines);
}
free(cache.sets);
return 0;
}