Skip to main content

Overview

The Timeline class provides chronological event logging for the simulation. Each UI module creates its own timeline instance to display execution events as they happen.

Class: Timeline

Location

source/js/ui/timeline.js

Constructor

timeline.js
export class Timeline {
  constructor(container) {
    this.container = container;
  }
}
Parameters:
  • container - DOM element where timeline events will be rendered

Example Instantiation

ui.js
import { Timeline } from "./timeline.js";
import { $ } from "../utils/dom.js";

const timeline = new Timeline($("timeline"));

Methods

addEvent(text)

Adds a new event to the timeline with a timestamp. Parameters:
  • text - String describing the event
Behavior:
  • Creates a timestamped log entry
  • Prepends (adds to top) so newest events appear first
  • Uses HH:MM:SS format in 24-hour time
Example:
timeline.addEvent("๐Ÿ”‘ Cliente-1 entro en Seccion Critica");
timeline.addEvent("๐Ÿ’ธ Cliente-2 modifico el saldo: -$100");
timeline.addEvent("๐Ÿ”“ Cliente-1 salio y libero el Mutex");
Implementation:
timeline.js
addEvent(text) {
  const log = create("div");
  log.className = "text-[11px] font-mono py-1.5 border-b border-gray-800";
  
  const now = new Date();
  const timeStr = now.toLocaleTimeString([], {
    hour12: false,
    minute: "2-digit",
    second: "2-digit",
  });
  
  log.innerHTML = `<span class="text-green-500">[${timeStr}]</span> <span class="text-gray-200">${text}</span>`;
  
  // Inserta arriba para mostrar primero lo mas reciente.
  this.container.prepend(log);
}
Rendered Output:
<div class="text-[11px] font-mono py-1.5 border-b border-gray-800">
  <span class="text-green-500">[14:23:15]</span> 
  <span class="text-gray-200">๐Ÿ”‘ Cliente-1 entro en Seccion Critica</span>
</div>

clear()

Removes all events from the timeline. Example:
timeline.clear();
Implementation:
timeline.js
clear() {
  this.container.innerHTML = "";
}
Usage: Typically called when generating a new scenario to start fresh:
ui.js
$("generateScenario").onclick = () => {
  // ... setup code
  timeline.clear();
  timeline.addEvent(`Sistema listo: ${num} hilos creados.`);
  // ... more setup
};

Event Flow

The timeline integrates with the simulation execution cycle:
// 1. Engine executes a step and returns events
const events = engine.step(context);
// events = ["๐Ÿ”‘ Cliente-1 entro en Seccion Critica", "๐Ÿ’ธ Cliente-2 modifico el saldo: -$100"]

// 2. UI logs each event to timeline
if (events.length === 0) {
  if (active) {
    timeline.addEvent("Planificador: Sin tareas pendientes.");
  } else if (!this.simulationFinished) {
    timeline.addEvent("Simulacion terminada satisfactoriamente.");
    this.simulationFinished = true;
  }
} else {
  events.forEach((e) => timeline.addEvent(e));
}

Event Types by Scenario

Mutex (Bank Scenario)

"๐Ÿ”‘ Cliente-1 entro en Seccion Critica"
"๐Ÿ’ธ Cliente-1 modifico el saldo: -$100"
"๐Ÿ’ต Cliente-2 ingreso al saldo: +$50"
"๐Ÿ”“ Cliente-1 salio y libero el Mutex"
"๐Ÿ”’ Cliente-3 esta esperando el Mutex"
"โš ๏ธ Cliente-2 pidio retirar $500, pero solo se retiro $100 (saldo insuficiente)"

Semaphore (Printer Scenario)

"๐ŸŸข Trabajo-1 obtuvo Impresora-1"
"โณ Trabajo-2 espera una impresora libre"
"๐Ÿ–จ๏ธ Trabajo-1 imprime 5 paginas en Impresora-1"
"๐Ÿ” Trabajo-1 libera Impresora-1 y la pasa a Trabajo-2"
"โœ… Trabajo-3 libera Impresora-2"

Condition Variables (Restaurant Scenario)

"๐Ÿ‘จโ€๐Ÿณ Chef preparo un plato (1/5)"
"๐Ÿ”” Chef llamo a Cliente-1: comida lista"
"๐Ÿฝ๏ธ Cliente-1 recibio un plato y pasa a comer"
"๐Ÿช‘ Cliente-2 espera comida en el restaurante"
"๐Ÿด Cliente-1 comio su plato"
"๐Ÿ“ฃ Chef anuncio comida, pero no habia clientes esperando"

Barrier (Race Scenario)

"๐Ÿƒ Corredor-1 llego al checkpoint"
"๐Ÿงฑ Corredor-1 espera en el checkpoint (1/2 en cola)"
"๐Ÿƒ Corredor-2 llego al checkpoint"
"๐Ÿšฆ Corredor-2 abrio barrera y libero a: Corredor-1"
"โœ… Corredor-1 cruza el checkpoint tras apertura de barrera"
"๐Ÿ Corredor-1 llego a la meta"

Monitor (Library Scenario)

"๐Ÿ“– Lector-1 entro a la biblioteca como lector"
"๐Ÿ‘ฉโ€๐ŸŽ“ Lector-1 esta leyendo Libro (catalogo v1)"
"๐Ÿšช Lector-1 salio de lectura"
"๐Ÿง‘โ€๐Ÿ’ผ Bibliotecario entro al monitor en modo escritura"
"๐Ÿ—‚๏ธ Bibliotecario actualizo catalogo a version 2"
"โœ… Bibliotecario libero monitor y desperto a: Lector-2, Lector-3"

Join/Await (House Construction Scenario)

"๐Ÿงฑ Albaรฑil construye Cimientos (1/3)"
"๐Ÿงฑ Albaรฑil construye Cimientos (2/3)"
"๐Ÿ—๏ธ Albaรฑil termino Cimientos"
"โ›“๏ธ Techador espera join de Albaรฑil"
"โœ… Techador join cumplido con Albaรฑil"
"๐Ÿ•’ Supervisor espera await de: Albaรฑil, Techador, Electricista"
"โœ… Supervisor await cumplido: Albaรฑil, Techador, Electricista"
"๐Ÿ  Supervisor entrego la casa terminada"

Petersonโ€™s Algorithm (Robot Station Scenario)

"๐Ÿ” Robot-1 entro a estacion compartida"
"๐Ÿค– Robot-2 espera turno en estacion (turn=1)"
"โš™๏ธ Robot-1 usa estacion (uso 1)"
"๐Ÿ”“ Robot-1 libero estacion y desperto a Robot-2"

Timeline Styling

The timeline uses a monospace font and consistent styling:
text-[11px]        /* Small text size */
font-mono          /* Monospace font for alignment */
py-1.5             /* Vertical padding */
border-b           /* Bottom border separator */
border-gray-800    /* Dark border color */
text-green-500     /* Green timestamps */
text-gray-200      /* Light gray event text */

Event Ordering

Events are displayed in reverse chronological order (newest first):
[14:23:18] ๐Ÿ”“ Cliente-1 salio y libero el Mutex
[14:23:17] ๐Ÿ’ธ Cliente-1 modifico el saldo: -$100
[14:23:16] ๐Ÿ”‘ Cliente-1 entro en Seccion Critica
[14:23:15] Sistema listo: 3 hilos creados.
This is achieved by using prepend() instead of append():
this.container.prepend(log);  // Adds to top

Integration with UI Modules

Each UI module creates its own timeline:
// Mutex scenario
const timeline = new Timeline($("timeline"));

// Semaphore scenario  
const timeline = new Timeline($("semTimeline"));

// Condition scenario
const timeline = new Timeline($("condTimeline"));

// Barrier scenario
const timeline = new Timeline($("barTimeline"));

// Monitor scenario
const timeline = new Timeline($("monTimeline"));

// Join scenario
const timeline = new Timeline($("joinTimeline"));

// Peterson scenario
const timeline = new Timeline($("petTimeline"));
This ensures events from different scenarios donโ€™t mix.

Typical Usage Pattern

ui.js
init(engine) {
  const timeline = new Timeline($("timeline"));
  let context = null;
  
  // Generate scenario
  $("generateScenario").onclick = () => {
    // ... setup
    timeline.clear();
    timeline.addEvent("Sistema listo: 3 hilos creados.");
    // ... more setup
  };
  
  // Execute step
  const runTick = (engine, context, timeline) => {
    const events = engine.step(context);
    
    if (events.length === 0) {
      if (active) {
        timeline.addEvent("Planificador: Sin tareas pendientes.");
      } else {
        timeline.addEvent("Simulacion terminada satisfactoriamente.");
      }
    } else {
      events.forEach(e => timeline.addEvent(e));
    }
  };
}

Event Sources

Timeline events come from:
  1. Engine Execution - engine.step() returns event strings
  2. UI Messages - Status updates from UI module
  3. Scenario Initialization - Setup messages when creating scenarios

Engine Events

Generated in engine.js by the execute() method:
engine.js
execute(thread, inst, ctx) {
  switch (inst.type) {
    case Instructions.ACQUIRE:
      if (mutex.acquire(thread)) {
        thread.nextInstruction();
        return `๐Ÿ”‘ ${thread.name} entro en Seccion Critica`;
      }
      return `๐Ÿ”’ ${thread.name} esta esperando el Mutex`;
    
    case Instructions.WITHDRAW:
      // ... logic
      return `๐Ÿ’ธ ${thread.name} modifico el saldo: -$${allowed}`;
    
    // ... more cases
  }
}

UI Status Messages

ui.js
if (events.length === 0) {
  if (active) {
    timeline.addEvent("Planificador: Sin tareas pendientes.");
  } else if (!this.simulationFinished) {
    timeline.addEvent("Simulacion terminada satisfactoriamente.");
    this.simulationFinished = true;
  }
}

Scenario Setup Messages

ui.js
timeline.clear();
timeline.addEvent(`Sistema listo: ${num} hilos creados.`);
operations.forEach((op, i) => {
  const action = op.type === Instructions.DEPOSIT ? "ingresar" : "retirar";
  timeline.addEvent(`Cliente-${i + 1} va a ${action} $${op.amount}.`);
});

Best Practices

  1. Clear on New Scenario - Always clear the timeline when starting fresh
  2. Use Emojis - Visual icons help distinguish event types quickly
  3. Be Descriptive - Include relevant details (thread names, amounts, etc.)
  4. Handle Empty Events - Check events.length before iterating
  5. Prevent Duplicates - Use simulationFinished flag for final messages

Timeline Container Requirements

The container should:
  • Be scrollable if events overflow
  • Have a dark background for readability
  • Support monospace font rendering
Example HTML:
<div id="timeline" class="h-64 overflow-y-auto bg-slate-950 rounded-lg p-2"></div>

Next Steps

Build docs developers (and LLMs) love