/* main.c
 *
 * Copyright 2023 Marty Míchal
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

#include <fcntl.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/timerfd.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

#define COLLECT_SLEEP_NS 100010 // 9999Hz
//#define COLLECT_SLEEP_NS 10101010 // 99Hz
#define COLLECT_OUTPUT_DIR /tmp/rapl-collector

#define CPUINFO_PATH /proc/cpuinfo
#define NUM_RAPL_DOMAINS 5

#define RAPL_PKG_ENERGY "/sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj"
#define RAPL_CORE_ENERGY "/sys/class/powercap/intel-rapl/intel-rapl:0/intel-rapl:0:0/energy_uj"
#define RAPL_GPU_ENERGY "/sys/class/powercap/intel-rapl/intel-rapl:0/intel-rapl:0:1/energy_uj"
#define RAPL_DRAM_ENERGY "/sys/class/powercap/intel-rapl/intel-rapl:0/intel-rapl:0:2/energy_uj"
#define RAPL_PSYS_ENERGY "/sys/class/powercap/intel-rapl/intel-rapl:1/energy_uj"

static char domains[NUM_RAPL_DOMAINS][70] = {RAPL_PKG_ENERGY, RAPL_CORE_ENERGY, RAPL_GPU_ENERGY, RAPL_DRAM_ENERGY, RAPL_PSYS_ENERGY};

static char collect_output_template[] = "rapl_collector_data_XXXXXX";

static int collect_output_fd;
static int sysfs_fds[NUM_RAPL_DOMAINS];

int init (void) {
    collect_output_fd = mkstemp (collect_output_template);
    if (collect_output_fd == -1)
        return -1;

        // Open all monitored domains
    for (int i = 0; i < NUM_RAPL_DOMAINS; i++) {
        int fd = open (domains[i], O_RDONLY);
        if (fd == -1)
            printf("NOOOO %s\n", domains[i]);

        sysfs_fds[i] = fd;
    }

    return 0;
}

int main (void) {
  init();

  uint64_t exp;

  struct itimerspec timer_spec;

  struct timespec now;
  clock_gettime(CLOCK_MONOTONIC, &now);

  timer_spec.it_value.tv_sec = now.tv_sec;
  timer_spec.it_value.tv_nsec = now.tv_nsec;
  timer_spec.it_interval.tv_sec = 0;
  timer_spec.it_interval.tv_nsec = COLLECT_SLEEP_NS;

  int timer_fd = timerfd_create(CLOCK_MONOTONIC, 0);
  timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &timer_spec, NULL);

  while (1) {
    char buf[50];

    read(timer_fd, &exp, sizeof(uint64_t));

    for (int i = 0; i < NUM_RAPL_DOMAINS; i++) {
        memset(buf, 0, 50);
        pread (sysfs_fds[i], &buf, 50, 0);
        printf("%ld ", atol(buf));
    }
    printf("\n");
  }

  return 0;
}
