/// <summary> /// Constructor para crear los bloques por defecto de la cache /// </summary> /// <param name="controlador">Controlador de la simulacion</param> /// <param name="solicitante">Cache dueña del bloqueMemoria</param> public BloqueCacheDatos(Controlador controlador, CacheDatos cache) : base(-1, -1, -1) { this.controlador = controlador; this.cache = cache; this.estado = EstadosB.Invalido; }
public void ModificarBloque(CacheDatos solicitante, BloqueCacheDatos bloque) { Esperar(solicitante); Debug.Assert(EstaBloqueado()); Debug.Assert(usuarios[bloque.IndiceMemoriaPrincipal].Count == 1); Estados[bloque.IndiceMemoriaPrincipal] = EstadosD.Modificado; }
/// <summary> /// Obtiene la informacion necesaria con respecto a la operacion que se quiere leer /// </summary> /// <param name="controlador"></param> /// <param name="solicitante"></param> /// <param name="direccionPalabra"></param> public InformacionPalabra(Controlador controlador, CacheDatos solicitante, int direccionPalabra) { this.controlador = controlador; this.solicitante = solicitante; this.id = direccionPalabra / BytesPorMemoria; int direccionPalabraLocal = direccionPalabra % BytesPorMemoria; this.indiceBloqueMemoria = direccionPalabraLocal / BytesPorBloque; this.indicePalabra = (direccionPalabraLocal % BytesPorBloque) / BytesPorPalabra; ActualizarBloque(); }
/// <summary> /// Cantidad de ciclos a esperar en caso de que se trate de una operación local o remota /// </summary> /// <param name="solicitante">Cache de Datos solicitante</param> private void Esperar(CacheDatos solicitante) { if (id == solicitante.ID) { controlador.Esperar(EsperaOperacionDirectorioLocal); } else { controlador.Esperar(EsperaOperacionDirectorioRemoto); } }
/// <summary> /// Crea todas las condiciones necesarias para la simulacion y /// posteriormente la inicia simplemente diciendole a cada procesador /// que se ejecute /// /// Este metodo esta pensado en que se va a envolver en un hilo cuando se /// cree desde la vista! /// </summary> public void EjecutarSimulacion() { Debug.WriteLine("Simulador: Iniciando..."); Debug.Flush(); // Modificar aqui la cantidad de procesadores deseados! int numeroProcesadores = cantidadProgramas > 2 ? 3 : cantidadProgramas; //para ajustar la cantidad según necesidad // Se crean vectores para todos los objetos necesarios Controlador controlador = new Controlador(); Procesador[] procesadores = new Procesador[numeroProcesadores]; CacheInstrucciones cacheInstrucciones = new CacheInstrucciones(numeroProcesadores, instrucciones, iniciosProgramas, cantidadProgramas, nombresProgramas); CacheDatos[] cachesDatos = new CacheDatos[numeroProcesadores]; Directorio[] directorios = new Directorio[numeroProcesadores]; MemoriaPrincipal[] memoriasPrincipales = new MemoriaPrincipal[numeroProcesadores]; // Se inicializan todos los objetos relacionados a los procesadores for (int i = 0; i < numeroProcesadores; ++i) { directorios[i] = new Directorio(controlador, i); memoriasPrincipales[i] = new MemoriaPrincipal(controlador, i); cachesDatos[i] = new CacheDatos(controlador, i); procesadores[i] = new Procesador(controlador, i); } // Se agrega la interfaz como listener del controlador/modelo controlador.AddListener(interfaz); // Se inicializa el controlador que hasta el momento no conocia a nadie controlador.Inicializar(procesadores, cachesDatos, cacheInstrucciones, directorios, memoriasPrincipales); // Se crean los hilos necesarios Thread[] hilosProcesadores = new Thread[numeroProcesadores]; for (int i = 0; i < numeroProcesadores; ++i) { // Se crea un hilo para cada procesador y se manda a ejectuar instrucciones hilosProcesadores[i] = new Thread(procesadores[i].Procesar); hilosProcesadores[i].Start(); } // Cuando todos los procesadores comienzan, se empiezan a sincronizar // solos con ayuda del objeto controlador porque ahi esta la barrera // Se espera que cada procesador termine for (int i = 0; i < numeroProcesadores; ++i) { hilosProcesadores[i].Join(); } // El hilo del simulador termina en el momento que todos los procesadores terminan! }
/// <summary> /// Método que devuelve cuantos usuarios comparten un bloque menos yo /// </summary> /// <param name="bloqueMemoria">Bloque para obtener el índice de memoria principal</param> /// <returns>Lista de Caches que comparten el bloqueMemoria</returns> public int CountUsuariosQueComparten(CacheDatos solicitante, Bloque bloque) { Esperar(solicitante); Debug.Assert(EstaBloqueado()); List <int> tmp = new List <int>(usuarios[bloque.IndiceMemoriaPrincipal]); tmp.Remove(solicitante.ID); return(tmp.Count); }
/// <summary> /// Se elimina cache de la lista respectiva /// </summary> /// <param name="solicitante">Cache de datos que ya no es usuaria del bloqueMemoria</param> /// <param name="bloqueMemoria">Bloque ya no utilizado</param> public void EliminarUsuarioBloque(CacheDatos solicitante, BloqueCacheDatos bloque) { Esperar(solicitante); Debug.Assert(EstaBloqueado()); Debug.Assert(usuarios[bloque.IndiceMemoriaPrincipal].Contains(solicitante.ID)); Debug.Assert(bloque.ID == this.id); usuarios[bloque.IndiceMemoriaPrincipal].Remove(solicitante.ID); if (usuarios[bloque.IndiceMemoriaPrincipal].Count == 0) { estados[bloque.IndiceMemoriaPrincipal] = EstadosD.Uncached; } }
/// <summary> /// Método que devuelve la cache que modificó un bloqueMemoria. /// Devuelve null si nadie ha modificado el bloqueMemoria. /// </summary> /// <param name="solicitante">Solicitante del cambio</param> /// <param name="bloqueMemoria">Bloque para obtener el id</param> /// <returns>Cache que modificó una palabra del bloqueMemoria</returns> public CacheDatos GetUsuarioQueModifica(CacheDatos solicitante, Bloque bloque) { Esperar(solicitante); Debug.Assert(EstaBloqueado()); CacheDatos cache = null; int indice = bloque.IndiceMemoriaPrincipal; if (estados[indice] == EstadosD.Modificado && usuarios[indice].Count == 1) { cache = controlador.CachesDatos[usuarios[indice][0]]; } return(cache); }
/// <summary> /// Agrega una cache como usuaria de un bloque. Siempre se agregan los bloques en C. /// </summary> /// <param name="solicitante">Cache de datos usuaria del bloqueMemoria</param> /// <param name="bloqueMemoria">Bloque siendo utilizado</param> public void AgregarUsuarioBloque(CacheDatos solicitante, BloqueCacheDatos bloque) { Esperar(solicitante); // Debido a la implementación los bloques siempre se agregan como compartidos al directorio // Si la cache los modifica, luego llama al método de ModificarBloque del directorio Debug.Assert(EstaBloqueado()); Debug.Assert(estados[bloque.IndiceMemoriaPrincipal] != EstadosD.Modificado); Debug.Assert(bloque.Estado != EstadosB.Modificado); Debug.Assert(!usuarios[bloque.IndiceMemoriaPrincipal].Contains(solicitante.ID)); Debug.Assert(bloque.ID == this.id); Debug.Assert(solicitante[bloque.IndiceCache].Direccion == bloque.Direccion); usuarios[bloque.IndiceMemoriaPrincipal].Add(solicitante.ID); estados[bloque.IndiceMemoriaPrincipal] = EstadosD.Compartido; }
/// <summary> /// Se invalida el bloqueMemoria en todas las cachés que lo usen /// </summary> /// <param name="solicitante">Cache de Datos solicitante</param> /// <param name="bloqueMemoria">Bloque para obtener la dirección</param> public void InvalidarBloque(CacheDatos solicitante, Bloque bloque) { Esperar(solicitante); // Solo se puede invalidar un bloqueMemoria si alguien lo está compartiendo Debug.Assert(EstaBloqueado()); Debug.Assert(estados[bloque.IndiceMemoriaPrincipal] == EstadosD.Compartido); Debug.WriteLine("Cache " + solicitante.ID + ": Invalidando a quienes comparten el bloque " + bloque.Direccion); //Obtengo quienes son las caches que tienen bloqueN compartido List <int> lectores = usuarios[bloque.IndiceMemoriaPrincipal]; // Creo una copia de la lista de lectores sin la cache solicitante // Si es que se encuentra List <int> tmp = new List <int>(lectores); tmp.Remove(solicitante.ID); // TODO Mejorar este código para que reintente sobre las caches // Mientras no falle consecutivamente en todas foreach (int id in tmp) { CacheDatos cache = controlador.CachesDatos[id]; // Bloqueo la cache cache.Bloquear(this.Nombre); BloqueCacheDatos bloqueCache = cache[bloque.IndiceCache]; Debug.Assert(bloqueCache.Direccion == bloque.Direccion); // Invalido el bloque bloqueCache.Invalidar(); // Debloqueo la cache cache.Desbloquear(this.Nombre); } // O no hay nadie compartiendo el bloque o la solicitante es la unica que lo comparte Debug.Assert(lectores.Count == 0 || lectores[0] == solicitante.ID && lectores.Count == 1); }
/// <summary> /// Método que realmente se encarga de ejecutar la lógica de leer una palabra. /// Si no puede bloquear algo, tira una excepción del tipo RebootNeededException. /// </summary> /// <param name="info">Información de la palabra que se quiere leer</param> /// <returns>Palabra que se quiere leer</returns> private int Leer(InformacionPalabra info) { int palabraLeida = -1; // Se bloquea la cache this.Bloquear(this.Nombre); bloqueados.Add(this); // Se pregunta si es Hit if (!info.EsHit()) { // Se envia el bloqueV a memoria si está modificado EnviarAMemoriaBloqueVSiModificado(this[info.IndiceCache]); // Bloqueo el directorio que contiene la palabra que busco info.Directorio.Bloquear(this.Nombre); bloqueados.Add(info.Directorio); // Consulto el directorio del bloqueMemoria que contiene la palabra que busco // para ver si alguna cache lo tiene modificado CacheDatos modificante = info.Directorio.GetUsuarioQueModifica(this, info.Bloque); if (modificante == null) { // Traigo el bloqueMemoria de memoria BloqueCacheDatos.TraerBloqueCacheDatos(info.Bloque, controlador, this, true); } else { // Bloqueo la cache que modificó el dato modificante.Bloquear(this.Nombre); bloqueados.Add(modificante); // Se envía el bloque en la cache modificante a memoria modificante[info.IndiceCache].EnviarAMemoria(); // Se actualiza la información del bloque con lo último de memoria info.ActualizarBloque(); // Traigo el dato de la cache modificante BloqueCacheDatos.TraerBloqueCacheDatos(info.Bloque, controlador, this, false); // Desbloqueo la cache que modificó el dato modificante.Desbloquear(this.Nombre); bloqueados.Remove(modificante); } // Desbloqueo el directorio info.Directorio.Desbloquear(this.Nombre); bloqueados.Remove(info.Directorio); } // Leo la palabra palabraLeida = this[info.IndiceCache][info.IndicePalabra]; // Desbloqueo la cache this.Desbloquear(this.Nombre); bloqueados.Remove(this); // Devuelvo la palabra leída return(palabraLeida); }
/// <summary> /// Método que escribe una palabra en una dirección de memoria /// </summary> /// <param name="info">Guarda información de donde debe escribirse la palabra</param> /// <param name="palabra">Palabra que se quiere escribir</param> public void Escribir(InformacionPalabra info, int palabra) { //Se bloquea mi cache this.Bloquear(this.Nombre); bloqueados.Add(this); // Si es hit if (info.EsHit()) { BloqueCacheDatos bloqueN = this[info.IndiceCache]; if (bloqueN.Estado == EstadosB.Modificado) { // Si está en mi cache modificado nada más lo escribo bloqueN[info.IndicePalabra] = palabra; bloqueN.Estado = EstadosB.Modificado; } else { // Si lo tengo compartido, bloqueo el directorio correspondiente info.Directorio.Bloquear(this.Nombre); bloqueados.Add(info.Directorio); // Invalido a todos quienes compartan el bloque info.Directorio.InvalidarBloque(this, info.Bloque); // Escribo la palabra bloqueN[info.IndicePalabra] = palabra; bloqueN.Estado = EstadosB.Modificado; info.Directorio.ModificarBloque(this, bloqueN); // Desbloqueo el directorio info.Directorio.Desbloquear(this.Nombre); bloqueados.Remove(info.Directorio); } } else { // Se envia el bloqueV a memoria si está modificado EnviarAMemoriaBloqueVSiModificado(this[info.IndiceCache]); // Bloqueo el directorio que contiene la palabra que busco info.Directorio.Bloquear(this.Nombre); bloqueados.Add(info.Directorio); // Consulto el directorio del bloqueMemoria que contiene la palabra que busco // para ver si alguna cache lo tiene modificado CacheDatos modificante = info.Directorio.GetUsuarioQueModifica(this, info.Bloque); if (modificante == null) //Si no hay nadie que esté modificando en bloque { if (info.Directorio.CountUsuariosQueComparten(this, info.Bloque) > 0) { //Se les invalida el BloqueN a todas las caches que lo tengan compartido info.Directorio.InvalidarBloque(this, info.Bloque); } // Traigo el bloqueMemoria de memoria // El constructor pone el bloque en la cache BloqueCacheDatos.TraerBloqueCacheDatos(info.Bloque, controlador, this, true); } else { // Bloqueo la cache que modificó el dato modificante.Bloquear(this.Nombre); bloqueados.Add(modificante); // Se envía el bloque en la cache modificante a memoria modificante[info.IndiceCache].EnviarAMemoria(); // Se actualiza la información del bloque info.ActualizarBloque(); // Traigo el dato desde la cache modificante BloqueCacheDatos.TraerBloqueCacheDatos(info.Bloque, controlador, this, false); // Desbloqueo la cache que modificó el dato modificante.Desbloquear(this.Nombre); bloqueados.Remove(modificante); } // Escribo la palabra this[info.IndiceCache][info.IndicePalabra] = palabra; this[info.IndiceCache].Estado = EstadosB.Modificado; this[info.IndiceCache].Directorio.ModificarBloque(this, this[info.IndiceCache]); // Desbloqueo el directorio info.Directorio.Desbloquear(this.Nombre); bloqueados.Remove(info.Directorio); } // Desbloqueo mi cache this.Desbloquear(this.Nombre); bloqueados.Remove(this); }
/// <summary> /// Trae un bloque de memoria o desde otra cache /// </summary> /// <param name="bloque">Bloque</param> /// <param name="controlador">Controlador</param> /// <param name="cache">Cache dueña del bloque</param> /// <param name="vieneDeMemoria">Indica si viene de memoria (true) o de otra cache (false)</param> public static BloqueCacheDatos TraerBloqueCacheDatos(Bloque bloque, Controlador controlador, CacheDatos cache, bool vieneDeMemoria) { // Se copian los datos del bloque BloqueCacheDatos bloqueCache = new BloqueCacheDatos(controlador, cache); bloqueCache.id = bloque.ID; bloqueCache.direccionInicial = bloque.Direccion; bloqueCache.indiceMemoriaPrincipal = bloque.IndiceMemoriaPrincipal; for (int i = 0; i < PalabrasPorBloque; ++i) { bloqueCache.palabras[i] = bloque[i]; } // Asigna el controlador y la cache bloqueCache.controlador = controlador; bloqueCache.cache = cache; Debug.Assert(cache.EstaBloqueado()); Debug.Assert(bloqueCache.Directorio.EstaBloqueado()); // Se espera que el bloque venga de memoria bloqueCache.EsperarTraida(vieneDeMemoria); // Se pone el bloque como compartido bloqueCache.estado = EstadosB.Compartido; // Me pongo en la cache cache[bloqueCache.IndiceCache] = bloqueCache; // Se refleja el cambio en el directorio // Se pone como compartido en el directorio bloqueCache.Directorio.AgregarUsuarioBloque(cache, bloqueCache); return(bloqueCache); }