Semana 3 — Planificación de la CPU

Objetivos

  • Calcular tiempo de retorno (turnaround time) y tiempo de respuesta (response time) para FIFO, SJF, STCF y Round Robin.
  • Explicar las reglas de MLFQ y por qué existen (inanición o starvation, manipulación del planificador, boost).
  • Decidir con la utilización si un conjunto de tareas periódicas es planificable con rate-monotonic o con EDF.

Sesión A — Planificación básica

Lecturas:

Temas:

  • Supuestos sobre la carga de trabajo (workload) y cómo se relajan uno a uno.
  • FIFO y el efecto convoy. SJF, STCF (planificación apropiativa o preemptive).
  • Round Robin: tamaño del quantum (time slice), costo del cambio de contexto.
  • Superposición de E/S con CPU.

Sesión B — Multi-Level Feedback Queue

Lecturas:

Temas:

  • Reglas 1–5 de MLFQ. Aprender del comportamiento pasado sin conocer el futuro.
  • Ataques al planificador (gaming) y contabilidad del tiempo usado.
  • Priority boost. Parámetros (ajuste o tuning) y ejemplos reales (Solaris, BSD, Windows).
  • Planificación de tiempo real: tareas periódicas (C, T, plazo o deadline), tiempo real duro y blando, utilización. Rate-monotonic y su cota (Liu y Layland), EDF. En Linux: SCHED_FIFO, SCHED_RR, SCHED_DEADLINE y chrt.

Lecturas complementarias (tiempo real):

  • Página man sched(7): las políticas de Linux, incluidas SCHED_FIFO, SCHED_RR y SCHED_DEADLINE, y el límite de sched_rt_runtime_us.
  • Página man chrt(1).
  • Documentación del kernel: Deadline Task Scheduling (EDF, CBS y control de admisión) y Real-Time group scheduling.
  • C. L. Liu y J. W. Layland, “Scheduling Algorithms for Multiprogramming in a Hard-Real-Time Environment”, Journal of the ACM 20(1), 1973. El artículo original de RM, EDF y la cota de utilización.
  • Opcional: Tanenbaum y Bos, Modern Operating Systems, 5.ª ed., sec. 2.5.4 Scheduling in Real-Time Systems.

Laboratorio — Simuladores de planificación

  1. scheduler.py: preguntas 1–7 del cap. 7. Resolver primero a mano y verificar con -c.
  2. mlfq.py: preguntas 1–5 del cap. 8.
  3. Construir una carga que haga que MLFQ sin boost produzca inanición.

Entregas

  • P0 entrega.
  • P1 publicado: Shell wish. Entrega en semana 6.

Preguntas de repaso

  1. ¿Bajo qué condiciones SJF y FIFO dan el mismo tiempo de retorno promedio?
  2. ¿Qué compromiso hay entre tiempo de retorno y tiempo de respuesta en Round Robin?
  3. ¿Qué problema resuelve la regla 4 de MLFQ (contabilidad) y cuál la regla 5 (boost)?
  4. ¿Por qué EDF puede cumplir todos los plazos de un conjunto de tareas con el que rate-monotonic pierde alguno? ¿Cuándo garantiza RM los plazos?

Código de la semana

Compilar dentro del contenedor del curso con make o gcc -Wall.

Ejemplos (3)Compilación (1)

Ejemplos

Los programas que usan los apuntes y la clase.

mlfq.cDescargar mlfq.c
// mlfq.c — simulador de una Multi-Level Feedback Queue con tres colas.
//
// Uso:   ./mlfq [-q quantum] [-a asignación] [-b periodo] [-o] trabajo...
//        trabajo: duración[@llegada][:ráfaga/espera]
//          duración  ticks de CPU que necesita en total
//          llegada   tick en que entra al sistema (0 si se omite)
//          ráfaga    corre esa cantidad de ticks y luego hace E/S...
//          espera    ...que tarda esa cantidad de ticks
//        -q  quantum de cada cola (por defecto 4)
//        -a  asignación (allotment) por nivel (por defecto, igual al quantum)
//        -b  boost: cada cuántos ticks subir todo a la cola más alta (0 = nunca)
//        -o  reglas viejas 4a/4b: quien suelta la CPU antes de agotar su
//            asignación conserva la prioridad y su cuenta vuelve a cero.
//            Sin -o se usa la regla 4: la cuenta se acumula aunque haga E/S.
//
// Ejemplos:
//   ./mlfq 20 6@10                       un trabajo largo y uno corto
//   ./mlfq -o 20 12@8:2/2 12@8:2/2       dos interactivos dejan sin CPU a A
//   ./mlfq -o -b 16 20 12@8:2/2 12@8:2/2 lo mismo, con boost cada 16
//   ./mlfq -o 20 15@8:3/1                B hace trampa con las reglas 4a/4b
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define NLEVELS 3
#define MAXJOBS 26
#define MAXTICKS 600

struct job {
    char name;
    int arrival, length, remaining;
    int burst, io;          // patrón de E/S (burst = 0: solo CPU)
    int level;              // cola actual: NLEVELS-1 es la más alta
    int used;               // ticks usados en este nivel (asignación)
    int slice;              // ticks usados del quantum actual
    int run;                // ticks corridos en la ráfaga actual
    int io_until;           // bloqueado hasta este tick (-1 si no)
    int first_run, finish;
};

static struct job jobs[MAXJOBS];
static int njobs;

// Una cola por nivel: arreglos simples, el primero es el que corre.
static int q[NLEVELS][MAXJOBS];
static int qlen[NLEVELS];

// gantt[nivel][t]: letra del trabajo que corrió en t en ese nivel.
static char gantt[NLEVELS][MAXTICKS];

static void push(int lvl, int j) {
    q[lvl][qlen[lvl]++] = j;
}

static void remove_job(int lvl, int j) {
    int k = 0;
    for (int i = 0; i < qlen[lvl]; i++)
        if (q[lvl][i] != j)
            q[lvl][k++] = q[lvl][i];
    qlen[lvl] = k;
}

// Regla 5: todos los trabajos vuelven a la cola más alta.
static void boost(void) {
    int top = NLEVELS - 1;
    for (int lvl = top - 1; lvl >= 0; lvl--) {
        for (int i = 0; i < qlen[lvl]; i++)
            push(top, q[lvl][i]);
        qlen[lvl] = 0;
    }
    for (int j = 0; j < njobs; j++) {
        jobs[j].level = top;    // los bloqueados también suben
        jobs[j].used = 0;
        jobs[j].slice = 0;
    }
}

static int simulate(int quantum, int allot, int period, int old_rules) {
    int top = NLEVELS - 1, done = 0, t;

    for (t = 0; t < MAXTICKS && done < njobs; t++) {
        for (int j = 0; j < njobs; j++) {
            struct job *p = &jobs[j];
            if (p->arrival == t)            // regla 3: entra arriba
                push(top, j);
            if (p->io_until == t) {         // terminó su E/S
                p->io_until = -1;
                push(p->level, j);
            }
        }
        if (period > 0 && t > 0 && t % period == 0)
            boost();

        int lvl = top;                      // regla 1: la cola más alta
        while (lvl >= 0 && qlen[lvl] == 0)
            lvl--;
        if (lvl < 0)
            continue;                       // CPU ociosa

        int j = q[lvl][0];                  // regla 2: RR dentro de la cola
        struct job *p = &jobs[j];
        if (p->first_run < 0)
            p->first_run = t;
        gantt[lvl][t] = p->name;
        p->remaining--;
        p->used++;
        p->slice++;
        p->run++;

        if (p->remaining == 0) {
            p->finish = t + 1;
            remove_job(lvl, j);
            done++;
            continue;
        }

        int does_io = p->burst > 0 && p->run == p->burst;
        int demote = p->used >= allot;      // agotó su asignación
        if (!demote && does_io && old_rules)
            p->used = 0;                    // regla 4b: soltó la CPU a tiempo

        if (demote || does_io || p->slice >= quantum) {
            remove_job(lvl, j);
            p->slice = 0;
            if (demote) {                   // regla 4 (o 4a): baja un nivel
                p->used = 0;
                if (p->level > 0)
                    p->level--;
            }
            if (does_io) {
                p->run = 0;
                p->io_until = t + 1 + p->io;
            } else {
                push(p->level, j);          // al final de su cola
            }
        }
    }
    return t;
}

static void print_gantt(int total) {
    for (int start = 0; start < total; start += 60) {
        int end = start + 60 < total ? start + 60 : total;
        printf("    ");
        for (int i = start; i < end; i++) {
            if (i % 5 == 0)
                i += printf("%d", i) - 1;
            else
                putchar(' ');
        }
        printf("\n");
        for (int lvl = NLEVELS - 1; lvl >= 0; lvl--) {
            printf("Q%d  ", lvl);
            for (int i = start; i < end; i++)
                putchar(gantt[lvl][i] ? gantt[lvl][i] : '.');
            printf("\n");
        }
    }
    printf("\n");
}

static void print_table(int total) {
    printf("trabajo llegada duración  fin  retorno  respuesta\n");
    for (int j = 0; j < njobs; j++) {
        struct job *p = &jobs[j];
        printf("   %c    %5d   %6d", p->name, p->arrival, p->length);
        if (p->remaining > 0)
            printf("    -        -");
        else
            printf(" %4d  %7d", p->finish, p->finish - p->arrival);
        if (p->first_run >= 0)
            printf("  %9d\n", p->first_run - p->arrival);
        else
            printf("          -\n");
    }
    printf("ticks simulados: %d\n", total);
}

static void usage(const char *prog) {
    fprintf(stderr, "uso: %s [-q quantum] [-a asignación] [-b periodo] [-o] "
                    "duración[@llegada][:ráfaga/espera]...\n", prog);
    exit(1);
}

int main(int argc, char *argv[]) {
    int quantum = 4, allot = 0, period = 0, old_rules = 0, opt;
    while ((opt = getopt(argc, argv, "q:a:b:o")) != -1) {
        switch (opt) {
        case 'q': quantum = atoi(optarg); break;
        case 'a': allot = atoi(optarg); break;
        case 'b': period = atoi(optarg); break;
        case 'o': old_rules = 1; break;
        default: usage(argv[0]);
        }
    }
    if (allot == 0)
        allot = quantum;
    if (optind >= argc || quantum < 1 || allot < 1 || period < 0)
        usage(argv[0]);

    for (int i = optind; i < argc && njobs < MAXJOBS; i++) {
        struct job *p = &jobs[njobs];
        p->name = 'A' + njobs;
        const char *s = argv[i];
        int n;
        if (sscanf(s, "%d%n", &p->length, &n) != 1 || p->length < 1)
            usage(argv[0]);
        s += n;
        if (*s == '@') {
            if (sscanf(s + 1, "%d%n", &p->arrival, &n) != 1)
                usage(argv[0]);
            s += 1 + n;
        }
        if (*s == ':' && (sscanf(s + 1, "%d/%d", &p->burst, &p->io) != 2 ||
                          p->burst < 1 || p->io < 1))
            usage(argv[0]);
        p->remaining = p->length;
        p->level = NLEVELS - 1;
        p->io_until = -1;
        p->first_run = -1;
        njobs++;
    }

    printf("MLFQ: %d colas, quantum %d, asignación %d, boost %s, regla %s\n",
           NLEVELS, quantum, allot, period ? "sí" : "no",
           old_rules ? "4a/4b" : "4");
    if (period)
        printf("boost cada %d ticks\n", period);

    int total = simulate(quantum, allot, period, old_rules);
    print_gantt(total);
    print_table(total);
    return 0;
}
rtsched.cDescargar rtsched.c
// rtsched.c — simulador de planificación de tiempo real: rate-monotonic (RM)
// y earliest deadline first (EDF) con tareas periódicas.
//
// Uso:   ./rtsched tarea...
//        tarea: C/T   (cómputo por periodo / periodo; las tareas se llaman A, B, C...)
//
// Ejemplo:
//   ./rtsched 3/6 4/9     A necesita 3 ticks cada 6; B, 4 cada 9
//
// Modelo: cada tarea suelta una instancia en t = 0, T, 2T, ... y el plazo
// (deadline) de cada instancia es el inicio de la siguiente (D = T). Simula
// las dos políticas hasta el hiperperiodo (el mcm de los periodos).
//
// En cada tick t, en este orden:
//   1. Plazos: si una instancia llega a su plazo sin terminar, es un plazo
//      perdido. Se anota y se descarta lo que le faltaba.
//   2. Llegadas: las tareas con t múltiplo de T sueltan una instancia nueva.
//   3. Elegir: RM, la de menor periodo (empate: el orden de la línea de
//      comandos). EDF, la de plazo más cercano (empate: sigue la que ya
//      corría; si no, el orden de la línea de comandos).
//   4. Correr un tick. '.' en el diagrama = CPU ociosa.
#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#define MAXTASKS 8
#define MAXTICKS 1000

enum policy { RM, EDF };

struct task {
    char name;
    int c, t;        // cómputo y periodo
    int remaining;   // lo que le falta a la instancia actual
    int deadline;    // plazo absoluto de la instancia actual
};

static struct task tasks[MAXTASKS];
static int ntasks;
static char gantt[MAXTICKS + 1];
static char misses[MAXTICKS + 2];   // '!' en el instante de un plazo perdido

// Plazos perdidos, para imprimirlos después del diagrama.
static struct { char name; int t, left; } lost[MAXTASKS * (MAXTICKS + 1)];
static int nlost;

static long long gcd(long long a, long long b) {
    return b == 0 ? a : gcd(b, a % b);
}

static int pick(enum policy pol, int cur) {
    int best = -1;
    for (int i = 0; i < ntasks; i++) {
        if (tasks[i].remaining == 0)
            continue;
        if (best < 0 ||
            (pol == RM && tasks[i].t < tasks[best].t) ||
            (pol == EDF && tasks[i].deadline < tasks[best].deadline))
            best = i;
    }
    // EDF: ante un empate de plazos, no desalojar a la que está corriendo.
    if (pol == EDF && cur >= 0 && tasks[cur].remaining > 0 &&
        tasks[cur].deadline == tasks[best].deadline)
        best = cur;
    return best;
}

static void simulate(enum policy pol, int end) {
    int cur = -1;
    nlost = 0;
    for (int i = 0; i < ntasks; i++)
        tasks[i].remaining = 0;

    for (int t = 0; t <= end; t++) {
        misses[t] = ' ';
        for (int i = 0; i < ntasks; i++) {
            struct task *p = &tasks[i];
            if (p->remaining > 0 && p->deadline == t) {   // 1. plazo perdido
                lost[nlost].name = p->name;
                lost[nlost].t = t;
                lost[nlost++].left = p->remaining;
                misses[t] = '!';
                p->remaining = 0;
            }
            if (t % p->t == 0 && t < end) {               // 2. llegada
                p->remaining = p->c;
                p->deadline = t + p->t;
            }
        }
        if (t == end)
            break;
        cur = pick(pol, cur);                             // 3. elegir
        if (cur < 0) {
            gantt[t] = '.';
            continue;
        }
        gantt[t] = tasks[cur].name;                       // 4. correr
        tasks[cur].remaining--;
    }
    gantt[end] = misses[end + 1] = '\0';
}

static void print_gantt(int total) {
    for (int start = 0; start < total; start += 60) {
        int end = start + 60 < total ? start + 60 : total;
        printf("       ");
        for (int i = start; i < end; i++) {
            if (i % 5 == 0) {
                int n = printf("%d", i);
                i += n - 1;
            } else {
                putchar(' ');
            }
        }
        printf("\ngantt  %.*s\n", end - start, gantt + start);
        // los plazos perdidos caen en el borde izquierdo del tick t
        int last = -1;
        int lim = end == total ? end : end - 1;   // t = 60 va en la fila siguiente
        for (int i = start; i <= lim; i++)
            if (misses[i] == '!')
                last = i;
        if (last >= 0)
            printf("plazo  %.*s\n", last - start + 1, misses + start);
    }

    printf("tramos ");
    for (int i = 0; i < total;) {
        int k = i;
        while (k < total && gantt[k] == gantt[i])
            k++;
        printf("%c[%d,%d) ", gantt[i], i, k);
        i = k;
    }
    printf("\n");
}

static void run(enum policy pol, int end) {
    if (pol == RM)
        printf("\nRM (prioridad fija: menor periodo primero)\n");
    else
        printf("\nEDF (prioridad dinámica: plazo más cercano primero)\n");
    simulate(pol, end);
    print_gantt(end);
    printf("plazos perdidos: %d\n", nlost);
    for (int i = 0; i < nlost; i++)
        printf("  %c en t = %d (le faltaba%s %d)\n", lost[i].name, lost[i].t,
               lost[i].left > 1 ? "n" : "", lost[i].left);
}

static void usage(const char *prog) {
    fprintf(stderr, "uso: %s C/T...   (1 <= C <= T, hasta %d tareas)\n",
            prog, MAXTASKS);
    exit(1);
}

int main(int argc, char *argv[]) {
    if (argc < 2 || argc - 1 > MAXTASKS)
        usage(argv[0]);

    long long hyper = 1;
    double u = 0;
    for (int i = 1; i < argc; i++) {
        struct task *p = &tasks[ntasks];
        p->name = 'A' + ntasks;
        if (sscanf(argv[i], "%d/%d", &p->c, &p->t) != 2 ||
            p->c < 1 || p->c > p->t)
            usage(argv[0]);
        if (hyper <= MAXTICKS)   // más allá no hace falta el valor exacto
            hyper = hyper / gcd(hyper, p->t) * p->t;
        u += (double)p->c / p->t;
        ntasks++;
    }

    int n = ntasks;
    double bound = n * (pow(2.0, 1.0 / n) - 1);   // cota de Liu y Layland
    printf("tarea   C   T   C/T\n");
    for (int i = 0; i < n; i++)
        printf("  %c   %3d %3d  %.3f\n", tasks[i].name, tasks[i].c, tasks[i].t,
               (double)tasks[i].c / tasks[i].t);
    printf("U = %.3f   cota de RM para n = %d: %.3f   hiperperiodo: ", u, n, bound);
    if (hyper <= MAXTICKS)
        printf("%lld\n", hyper);
    else
        printf("más de %d (se simulan solo los primeros %d ticks)\n",
               MAXTICKS, MAXTICKS);
    if (u <= bound + 1e-9)
        printf("U <= cota: RM y EDF cumplen todos los plazos\n");
    else if (u <= 1 + 1e-9)
        printf("cota < U <= 1: EDF cumple; RM no está garantizado (hay que simular)\n");
    else
        printf("U > 1: ninguna política puede cumplir todos los plazos\n");

    int end = hyper <= MAXTICKS ? (int)hyper : MAXTICKS;
    run(RM, end);
    run(EDF, end);
    return 0;
}
sched.cDescargar sched.c
// sched.c — simulador de planificación: FIFO, SJF, STCF y Round Robin.
//
// Uso:   ./sched [-q quantum] [-c costo] política trabajo...
//        política: fifo | sjf | stcf | rr
//        trabajo:  duración[@llegada]   (los trabajos se llaman A, B, C...)
//
// Ejemplos:
//   ./sched fifo 12 3 3          tres trabajos que llegan en t = 0
//   ./sched stcf 12 3@2 3@2      B y C llegan en t = 2
//   ./sched -q 2 -c 1 rr 6 6 6   Round Robin, quantum 2, cambio de contexto 1
//
// El tiempo avanza en ticks enteros. Reglas de desempate:
//   - FIFO: menor llegada; si empatan, el orden de la línea de comandos.
//   - SJF:  menor duración; luego menor llegada; luego el orden.
//   - STCF: menor tiempo restante; si empatan, sigue el que ya corría.
//   - RR:   los que llegan en t entran a la cola ANTES que el que fue
//           desalojado en t.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define MAXJOBS 26
#define MAXTICKS 10000

enum policy { FIFO, SJF, STCF, RR };

struct job {
    char name;
    int arrival;
    int length;
    int remaining;
    int first_run;   // -1 mientras no haya corrido nunca
    int finish;
};

static struct job jobs[MAXJOBS];
static int njobs;
static char gantt[MAXTICKS];   // una letra por tick: trabajo, '-' ocioso, '*' cambio

// Cola circular para Round Robin.
static int queue[MAXJOBS + 1];
static int qhead, qtail;

static void enqueue(int j) {
    queue[qtail] = j;
    qtail = (qtail + 1) % (MAXJOBS + 1);
}

static int dequeue(void) {
    if (qhead == qtail)
        return -1;
    int j = queue[qhead];
    qhead = (qhead + 1) % (MAXJOBS + 1);
    return j;
}

static int ready(int j, int t) {
    return jobs[j].arrival <= t && jobs[j].remaining > 0;
}

// FIFO, SJF y STCF: elegir entre los trabajos listos en t.
static int pick(enum policy pol, int t, int cur) {
    int best = -1;
    for (int j = 0; j < njobs; j++) {
        if (!ready(j, t))
            continue;
        if (best < 0) {
            best = j;
            continue;
        }
        struct job *a = &jobs[j], *b = &jobs[best];
        if (pol == FIFO && a->arrival < b->arrival)
            best = j;
        if (pol == SJF && (a->length < b->length ||
                           (a->length == b->length && a->arrival < b->arrival)))
            best = j;
        if (pol == STCF && a->remaining < b->remaining)
            best = j;
    }
    // STCF: ante un empate, no desalojar al que está corriendo.
    if (pol == STCF && cur >= 0 && ready(cur, t) &&
        jobs[cur].remaining == jobs[best].remaining)
        best = cur;
    return best;
}

static int simulate(enum policy pol, int quantum, int cost) {
    int t = 0, done = 0;
    int cur = -1;        // trabajo elegido
    int last = -1;       // último trabajo que usó la CPU
    int slice = 0;       // ticks usados del quantum actual
    int overhead = 0;    // ticks de cambio de contexto pendientes

    while (done < njobs && t < MAXTICKS) {
        if (pol == RR)
            for (int j = 0; j < njobs; j++)
                if (jobs[j].arrival == t)
                    enqueue(j);

        if (overhead > 0) {          // el kernel está cambiando de contexto
            gantt[t++] = '*';
            overhead--;
            continue;
        }

        int prev = cur;
        if (pol == RR) {
            if (cur >= 0 && slice == quantum) {   // se acabó el quantum
                enqueue(cur);
                cur = -1;
            }
            if (cur < 0) {
                cur = dequeue();
                slice = 0;
            }
        } else if (pol == STCF || cur < 0) {      // FIFO y SJF no desalojan
            cur = pick(pol, t, cur);
        }

        if (cur < 0) {               // nadie listo: CPU ociosa
            gantt[t++] = '-';
            continue;
        }
        if (cur != prev && last >= 0 && cur != last && cost > 0) {
            gantt[t++] = '*';        // cobrar el cambio antes de correr
            overhead = cost - 1;
            continue;
        }

        struct job *p = &jobs[cur];
        if (p->first_run < 0)
            p->first_run = t;
        gantt[t++] = p->name;
        p->remaining--;
        slice++;
        last = cur;
        if (p->remaining == 0) {
            p->finish = t;
            done++;
            cur = -1;
        }
    }
    return t;
}

static void print_gantt(int total) {
    for (int start = 0; start < total; start += 60) {
        int end = start + 60 < total ? start + 60 : total;
        printf("       ");
        for (int i = start; i < end; i++) {
            if (i % 5 == 0) {
                int n = printf("%d", i);
                i += n - 1;
            } else {
                putchar(' ');
            }
        }
        printf("\ngantt  %.*s\n", end - start, gantt + start);
    }

    printf("tramos ");
    for (int i = 0; i < total;) {
        int k = i;
        while (k < total && gantt[k] == gantt[i])
            k++;
        printf("%c[%d,%d) ", gantt[i], i, k);
        i = k;
    }
    printf("\n\n");
}

static void print_table(int total) {
    double sum_ta = 0, sum_resp = 0;
    int switching = 0;

    printf("trabajo llegada duración  inicio  fin  retorno  respuesta\n");
    for (int j = 0; j < njobs; j++) {
        struct job *p = &jobs[j];
        int ta = p->finish - p->arrival;       // tiempo de retorno
        int resp = p->first_run - p->arrival;  // tiempo de respuesta
        sum_ta += ta;
        sum_resp += resp;
        printf("   %c    %5d   %6d  %6d %5d  %7d  %9d\n",
               p->name, p->arrival, p->length, p->first_run, p->finish, ta, resp);
    }
    printf("promedio                              %7.2f  %9.2f\n",
           sum_ta / njobs, sum_resp / njobs);

    for (int i = 0; i < total; i++)
        switching += gantt[i] == '*';
    if (switching > 0)
        printf("cambios de contexto: %d ticks de %d (%.0f%% de la CPU)\n",
               switching, total, 100.0 * switching / total);
}

static void usage(const char *prog) {
    fprintf(stderr, "uso: %s [-q quantum] [-c costo] fifo|sjf|stcf|rr "
                    "duración[@llegada]...\n", prog);
    exit(1);
}

int main(int argc, char *argv[]) {
    int quantum = 1, cost = 0, opt;
    while ((opt = getopt(argc, argv, "q:c:")) != -1) {
        if (opt == 'q')
            quantum = atoi(optarg);
        else if (opt == 'c')
            cost = atoi(optarg);
        else
            usage(argv[0]);
    }
    if (argc - optind < 2 || quantum < 1 || cost < 0)
        usage(argv[0]);

    const char *names[] = {"fifo", "sjf", "stcf", "rr"};
    const char *titles[] = {"FIFO", "SJF", "STCF", "Round Robin"};
    int pol = -1;
    for (int i = 0; i < 4; i++)
        if (strcmp(argv[optind], names[i]) == 0)
            pol = i;
    if (pol < 0)
        usage(argv[0]);

    for (int i = optind + 1; i < argc && njobs < MAXJOBS; i++) {
        struct job *p = &jobs[njobs];
        p->name = 'A' + njobs;
        p->arrival = 0;
        if (sscanf(argv[i], "%d@%d", &p->length, &p->arrival) < 1 ||
            p->length < 1 || p->arrival < 0)
            usage(argv[0]);
        p->remaining = p->length;
        p->first_run = -1;
        njobs++;
    }

    printf("política: %s", titles[pol]);
    if (pol == RR)
        printf(" (quantum %d)", quantum);
    if (cost > 0)
        printf(", cambio de contexto: %d", cost);
    printf("\n");

    int total = simulate(pol, quantum, cost);
    print_gantt(total);
    print_table(total);
    return 0;
}

Compilación

Cómo se compilan y ejecutan los ejemplos.

MakefileDescargar Makefile
# Semana 3: simuladores de planificación.
#   make         compila todo
#   make test    corre los ejemplos de los apuntes
#   make clean   borra los binarios
CFLAGS = -Wall -Wextra -g
LDLIBS = -lm
PROGS  = sched mlfq rtsched

all: $(PROGS)

test: $(PROGS)
	./sched fifo 12 3 3
	./sched stcf 12 3@2 3@2
	./sched -q 3 -c 1 rr 6 6 6
	./mlfq 20 6@10
	./mlfq -o 20 15@8:3/1
	./mlfq 20 15@8:3/1
	./rtsched 3/6 4/9

clean:
	rm -f $(PROGS)

.PHONY: all test clean