11 - Medición de tiempos reales en C

Medir ejecuciones en C permite validar la teoría de Big-O y detectar cuellos de botella. A diferencia del análisis asintótico, aquí importan constantes, caché y características del hardware.

11.1 Función clock()

clock() entrega el tiempo de CPU consumido por el proceso. Devuelve tics de reloj divididos por CLOCKS_PER_SEC.

#include <stdio.h>
#include <time.h>

double medir_clock(void (*fn)(void)) {
  clock_t inicio = clock();
  fn();
  clock_t fin = clock();
  return (double)(fin - inicio) / CLOCKS_PER_SEC;
}

Si el algoritmo espera I/O o duerme, clock() puede subestimar; en esos casos conviene tiempo de pared.

11.2 Función time.h

time() entrega segundos desde la época y sirve para mediciones gruesas. Para mayor precisión puedes usar clock() o APIs de alta resolución específicas del sistema.

time_t inicio = time(NULL);
ejecutar_trabajo();
time_t fin = time(NULL);
printf("Duracion: %ld s\n", (long)(fin - inicio));

La resolución de time() es de 1 segundo; suficiente para tareas largas, no para loops cortos.

11.3 Crear benchmarks simples

Para reducir ruido:

  • Repite varias veces y promedia.
  • Calienta caches ejecutando una pasada previa.
  • Evita trabajo de E/S dentro del tramo medido.
double benchmark(void (*fn)(int *v, int n), int *v, int n, int repeticiones) {
  double total = 0.0;
  for (int i = 0; i < repeticiones; i++) {
    total += medir_clock(() => fn(v, n)); // pseudocodigo: usar un wrapper real
  }
  return total / repeticiones;
}

En C puro puedes pasar datos precreados y medir dentro de la función sin lambdas: arma una envoltura específica para cada benchmark.

11.4 Comparar tiempos entre algoritmos

Usa las mismas entradas para que la comparación sea justa.

double medir_bubble(int *v, int n) { /* ... */ return 0; }
double medir_quick(int *v, int n) { /* ... */ return 0; }

int main(void) {
  int datos[5000];
  generar(datos, 5000);
  printf("Bubble: %.6f s\\n", medir_bubble(datos, 5000));
  generar(datos, 5000); // reponer datos
  printf("Quick: %.6f s\\n", medir_quick(datos, 5000));
}

Restaura o copia la entrada entre corridas para no medir con datos ya ordenados salvo que sea intencional.

11.5 Variabilidad por hardware

  • CPU, caches y frecuencia turbo alteran el tiempo real sin cambiar Big-O.
  • Otros procesos en el sistema generan ruido; ejecuta en modo aislado o repite varias veces.
  • La memoria y el ancho de banda de disco afectan algoritmos intensivos en E/S.

Reporta la plataforma (CPU, RAM, SO, compilador) junto a los resultados para contexto.

11.6 Graficar resultados (exportar a CSV)

Guardar pares n,tiempo permite graficar en hojas de cálculo o Python.

#include <stdio.h>

void escribir_csv(const char *ruta, const int *ns, const double *tiempos, int m) {
  FILE *f = fopen(ruta, "w");
  if (!f) return;
  fprintf(f, "n,tiempo_s\n");
  for (int i = 0; i < m; i++) {
    fprintf(f, "%d,%.6f\n", ns[i], tiempos[i]);
  }
  fclose(f);
}

Al graficar, observa si la curva crece lineal, logarítmica o cuadrática; contrasta con el Big-O esperado.