/*
 * procrkmonitor.c
 *
 * monitors CPU usage of the /proc/ file system
 *
 * Note: When you create reservation while you are running this program,
 *       the ordering of the reservation in the output file may shift
 *       incorrectly.
 *       That is, when you create reserve-3 after you run this program,
 *       the output may list reserve-3 in the first column.
 *         
 *            row1:   reserv-1   reserv-2     X             
 *                                                        <== create reserve-3
 *            row2:   reserv-3   reserv-1   reserv-2
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/dir.h>
#include <getopt.h>

#include <rk/rk.h>
#include <rk/rk_error.h>
#include <rk/timespec.h>
#include <rk/posix_timers.h>

#define NUMRESERVES 5
#define MAXBUFFERSIZE 5000

static int numreserve;
static int it[3];
static float ft[5];
static float buffer[NUMRESERVES + 1][MAXBUFFERSIZE + 1];
static int numprocbuffer[NUMRESERVES + 1][MAXBUFFERSIZE + 1];
static char output[100];

void print_usage(char *pname)
{
    fprintf(stderr,
	    "\nUsage: %s [--sec n] [--nsec n] [-file filename]\n\n",
	    pname);
    fprintf(stderr, "eg. %s -sec 0 --nsec 500000000 -file output\n",
	    pname);
    fprintf(stderr,
	    "This program monitors CPU usage via /proc/ file system\n");
    fprintf(stderr,
	    "Type Ctrl-C to finish. The log will be in a file named output\n");
    fprintf(stderr,
	    "Output file will list the CPU utilization & the number of processes using that reservation\n\n");
}

void dump(int i)
{
    int j, cnt;
    FILE *fp;

    fp = fopen(output, "w");

    for (j = 0; j < numreserve; j++) {
	fprintf(fp, "cpu\t  numproc\t");
    }
    fprintf(fp, "\n");

    for (cnt = 0; cnt < MAXBUFFERSIZE; cnt++) {
	for (j = 0; j < numreserve; j++) {
	    fprintf(fp, "%.02f\t\t", buffer[j][cnt]);
	    fprintf(fp, "%d\t", numprocbuffer[j][cnt]);
	}
	fprintf(fp, "\n");
    }
    fclose(fp);
    printf("done...result in file %s \n", output);
    exit(1);
}



int main(int argc, char **argv)
{
    int c, counter, reserve, numprocs;
    struct timespec period, start, now;
    DIR *dp;
    FILE *fp;
    rk_resource_set_t rset = NULL;
    struct dirent *dir;
    static char cpu[32];
    long nsec = 500000000;	//default 500ms
    long sec = 0;

    print_usage(argv[0]);

    strcpy(output, "output");

    while (1) {
	int option_index = 0;
	static struct option long_options[] = {
	    {"sec", 1, 0, 0},
	    {"nsec", 1, 0, 0},
	    {"file", 1, 0, 0},
	    {0, 0, 0, 0}
	};

#define OPT_SEC 	0
#define OPT_NSEC 	1
#define OPT_FILE 	2

	c = getopt_long_only(argc, argv, "", long_options, &option_index);

	/* bunch of option handling... */
	if (c == -1)
	    break;
	switch (c) {
	case 0:

	    switch (option_index) {
	    case OPT_SEC:
		sec = atol(optarg);
		break;

	    case OPT_NSEC:
		nsec = atol(optarg);
		break;

	    case OPT_FILE:
		strcpy(output, optarg);
		break;
	    }

	    break;
	case '?':
	    break;
	default:
	    printf("?? getopt returned character code 0%o ??\n", c);
	    //print_usage(argv[0]);
	}
    }
    if (optind < argc) {
	printf("undefined arguments....ignoring   ");
	while (optind < argc)
	    printf("%s ", argv[optind++]);
	printf("\n");
    }




    reserve = counter = 0;
    signal(SIGINT, dump);
    bzero(buffer, sizeof(buffer));

    /* set period for this process */
    period.tv_sec = sec;
    period.tv_nsec = nsec;
    /* start 2 sec from now */
    start.tv_sec = 2;
    start.tv_nsec = 0;

    clock_gettime(CLOCK_REALTIME, &now);

    timespec_add(start, now);

    if (rt_make_periodic(&period, &start) != RK_SUCCESS) {
	perror("rt_make_periodic: period < MIN_PERIOD?\n");
	return 1;
    }

    rt_wait_for_start_time();

    while (1) {

	if ((dp = opendir("/proc/rk")) == NULL) {
	    fprintf(stderr, "cannot open directory\n");
	    exit(1);
	}


	while ((dir = readdir(dp)) != NULL) {
	    if (dir->d_ino == 0)
		continue;
	    if (strncmp(dir->d_name, "c", 1) == 0) {
		bzero(cpu, 32);
		strcat(cpu, "/proc/rk/");
		strcat(cpu, dir->d_name);

		rset = (rk_resource_set_t) strtoul(dir->d_name, NULL, 16);
		numprocs = rk_resource_set_get_num_procs(rset);

		strcat(cpu, "/");
		strcat(cpu, "cpu");
		fp = fopen(cpu, "r");

		//enf_mode, rep_mode
		fscanf(fp, "%d %d", &it[0], &it[1]);
		//printf("%d %d\n", it[0], it[1]);

		// utilization statistics: reseved, previous, average, max, min (%)
		fscanf(fp, "%f %f %f %f %f", &ft[0], &ft[1], &ft[2],
		       &ft[3], &ft[4]);

		// CPU usage: used, available, requested  (usec)
		fscanf(fp, "%d %d %d", &it[0], &it[1], &it[2]);

		//Use the previous utilization value becuase
		//I may be measuring the value in the middle of
		//a period if harmonic...
		if (reserve < NUMRESERVES) {
		    buffer[reserve][counter] = ft[1];
		    numprocbuffer[reserve][counter] = numprocs;
		}
		reserve++;

		// count of replenishment
		fscanf(fp, "%d", &it[0]);
	    }
	}
	closedir(dp);

	counter++;
	if (counter >= MAXBUFFERSIZE) {
	    printf("buffer sliding...\n");
	    counter = 0;
	}
	numreserve = reserve;
	reserve = 0;
	rt_wait_for_next_period();
    }
}
