#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#ifdef CBLAS
#ifdef USE_MKL
#include <mkl.h>
#else
#include <cblas.h>
#endif
#endif
#include "mymath.h"

#define N 512
#define TAIALS 100

double get_time() {
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return ts.tv_sec + ts.tv_nsec * 1e-9;
}

int main() {
    double *A = malloc(N * N * sizeof(double));
    double *B = malloc(N * N * sizeof(double));
    double *C = malloc(N * N * sizeof(double));

    for (int i = 0; i < N * N; i++) { A[i] = 1.0; B[i] = 2.0; C[i] = 0.0; }

    printf("Benchmarking GEMM (Size: %dx%d, Trials: %d)\n", N, N, TAIALS);
    printf("--------------------------------------------------\n");

    // 1. Warm-up (Ensures CPU is out of power-saving mode)
    manual_gemm(N, A, B, C);
    for (int i = 0; i < N * N; i++) { C[i] = 0.0; }

    double checksum = 0.0;
    // 2. Benchmark Manual GEMM
    double start = get_time();
    for(int t = 0; t < TAIALS; t++) {
        manual_gemm(N, A, B, C);
        checksum += C[t];
    }
    double end = get_time();
    printf("Manual GEMM (Avg): %f seconds, checksum= %f\n", (end - start) / TAIALS, checksum);

#ifdef CBLAS
    // 1. Warm-up (Ensures CPU is out of power-saving mode)
    cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
                    N, N, N, 1.0, A, N, B, N, 0.0, C, N);
    for (int i = 0; i < N * N; i++) { C[i] = 0.0; }

    checksum = 0.0;
    // 2. Benchmark BLAS DGEMM
    start = get_time();
    for(int t = 0; t < TAIALS; t++) {
        cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
                    N, N, N, 1.0, A, N, B, N, 1.0, C, N);
        checksum += C[t];
    }
    end = get_time();
    printf("System BLAS (Avg): %f seconds, checksum= %f\n", (end - start) / TAIALS, checksum);
#endif

    free(A); free(B); free(C);
    return 0;
}
