// disktime.c — tiempo de E/S de un disco duro: aleatorio vs. secuencial.
//
// Uso: ./disktime                       compara los dos discos de la clase
//      ./disktime RPM SEEK_MS MB_S [KB] [MB_SEQ]
//                                       un disco a medida
//
// Modelo: T_E/S = T_búsqueda + T_rotación + T_transferencia
//   T_búsqueda   = búsqueda promedio del fabricante
//   T_rotación   = media vuelta, en promedio
//   T_transfer.  = tamaño / tasa máxima de transferencia
// E/S aleatoria: cada pedido de KB paga búsqueda + rotación.
// E/S secuencial: un solo pedido de MB_SEQ paga búsqueda + rotación una vez.
// Convención: 1 MB = 1000 KB y 1 KB = 1000 bytes (como los fabricantes).
#include <stdio.h>
#include <stdlib.h>

struct disk {
    const char *name;
    double rpm;
    double seek_ms;     // búsqueda promedio
    double rate_mb_s;   // transferencia máxima
};

struct result {
    double rot_ms, xfer_ms, tio_ms, rate_mb_s, iops;
};

// Tiempo y tasa para un pedido de `kb` kilobytes.
static struct result io_time(const struct disk *d, double kb) {
    struct result r;
    double rev_ms = 60.0 * 1000.0 / d->rpm;            // una vuelta
    r.rot_ms = rev_ms / 2.0;                           // media vuelta
    r.xfer_ms = kb / 1000.0 / d->rate_mb_s * 1000.0;   // KB -> MB -> ms
    r.tio_ms = d->seek_ms + r.rot_ms + r.xfer_ms;
    r.rate_mb_s = (kb / 1000.0) / (r.tio_ms / 1000.0);
    r.iops = 1000.0 / r.tio_ms;
    return r;
}

static void report(const struct disk *d, double kb, double seq_mb) {
    struct result rnd = io_time(d, kb);
    struct result seq = io_time(d, seq_mb * 1000.0);
    printf("%s: %.0f RPM, búsqueda %.1f ms, %.0f MB/s\n",
           d->name, d->rpm, d->seek_ms, d->rate_mb_s);
    printf("  vuelta %.2f ms, rotación promedio %.2f ms\n",
           2 * rnd.rot_ms, rnd.rot_ms);
    printf("  aleatorio %.0f KB:  T_E/S = %.1f + %.2f + %.3f = %.2f ms"
           "  -> %.0f E/S por s, %.2f MB/s\n",
           kb, d->seek_ms, rnd.rot_ms, rnd.xfer_ms, rnd.tio_ms, rnd.iops,
           rnd.rate_mb_s);
    printf("  secuencial %.0f MB: T_E/S = %.1f + %.2f + %.1f = %.1f ms"
           "  -> %.1f MB/s\n",
           seq_mb, d->seek_ms, seq.rot_ms, seq.xfer_ms, seq.tio_ms,
           seq.rate_mb_s);
    printf("  secuencial / aleatorio = %.0f veces\n\n",
           seq.rate_mb_s / rnd.rate_mb_s);
}

int main(int argc, char *argv[]) {
    if (argc >= 4) {
        struct disk d = {"disco", atof(argv[1]), atof(argv[2]), atof(argv[3])};
        double kb = argc > 4 ? atof(argv[4]) : 4;
        double mb = argc > 5 ? atof(argv[5]) : 100;
        if (d.rpm <= 0 || d.rate_mb_s <= 0 || kb <= 0 || mb <= 0) {
            fprintf(stderr, "valores inválidos\n");
            return 1;
        }
        report(&d, kb, mb);
        return 0;
    }
    if (argc != 1) {
        fprintf(stderr, "uso: %s [RPM SEEK_MS MB_S [KB] [MB_SEQ]]\n", argv[0]);
        return 1;
    }
    // Dos discos típicos: uno de servidor y uno de escritorio.
    struct disk server = {"Servidor", 10000, 4.5, 150};
    struct disk desktop = {"Escritorio", 7200, 9.0, 105};
    report(&server, 4, 100);
    report(&desktop, 4, 100);
    return 0;
}
