https://hal.archives-ouvertes.fr/hal-03453537
mojitos.c
/*******************************************************
Copyright (C) 2018-2019 Georges Da Costa <georges.da-costa@irit.fr>
This file is part of Mojitos.
Mojitos 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.
Mojitos 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 MojitO/S. If not, see <https://www.gnu.org/licenses/>.
*******************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <signal.h>
#include <inttypes.h>
#include <unistd.h>
#include "counters.h"
#include "rapl.h"
#include "network.h"
#include "infiniband.h"
#include "load.h"
#include "temperature.h"
void usage(char** argv) {
printf("Usage : %s [-t time] [-f freq] [-r] [-p perf_list] [-l] [-u] [-c] [-d network_device] [-i infiniband_path] [-o logfile] [-e command arguments...]\n", argv[0]);
printf("if time==0 then loops infinitively\n");
printf("if -e is present, time and freq are not used\n");
printf("-r activates RAPL\n");
printf("-p activates performance counters\n");
printf(" perf_list is coma separated list of performance counters without space. Ex: instructions,cache_misses\n");
printf("-l lists the possible performance counters and quits\n");
printf("-d activates network monitoring (if network_device is X, tries to detect it automatically)\n");
printf("-i activates infiniband monitoring (if infiniband_path is X, tries to detect it automatically)\n");
printf("-s activates statistics of overhead in nanoseconds\n");
printf("-u activates report of system load\n");
printf("-c activates report of processor temperature\n");
exit(EXIT_SUCCESS);
}
void sighandler(int none) {
}
void flush(int none) {
exit(0);
}
FILE *output;
void flushexit() {
fflush(output);
fclose(output);
}
typedef unsigned int (initializer_t)(char*, void **);
typedef void (labeler_t)(char **, void*);
typedef unsigned int (*getter_t)(uint64_t*, void*);
typedef void (*cleaner_t)(void*);
unsigned int nb_sources=0;
void **states=NULL;
getter_t *getter=NULL;
cleaner_t *cleaner=NULL;
unsigned int nb_sensors=0;
char **labels=NULL;
uint64_t *values=NULL;
void add_source(initializer_t init, char* arg, labeler_t labeler,
getter_t get, cleaner_t clean) {
nb_sources++;
states = realloc(states, nb_sources*sizeof(void*));
getter = realloc(getter, nb_sources*sizeof(void*));
getter[nb_sources-1] = get;
cleaner = realloc(cleaner, nb_sources*sizeof(void*));
cleaner[nb_sources-1] = clean;
int nb = init(arg, &states[nb_sources-1]);
labels = realloc(labels, (nb_sensors+nb)*sizeof(char*));
labeler(labels+nb_sensors, states[nb_sources-1]);
values = realloc(values, (nb_sensors+nb)*sizeof(uint64_t));
nb_sensors += nb;
}
int main(int argc, char **argv) {
int total_time=1;
int delta=0;
int frequency=1;
char **application = NULL;
int stat_mode = -1;
if(argc==1)
usage(argv);
output=stdout;
atexit(flushexit);
signal(15, flush);
int c;
while ((c = getopt (argc, argv, "ilhcftdeoprsu")) != -1 && application==NULL)
switch (c) {
case 'f':
frequency=atoi(argv[optind]);
break;
case 't':
total_time=atoi(argv[optind]);
delta=1;
if(total_time==0) {
total_time=1;
delta=0;
}
break;
case 'd':
add_source(init_network, argv[optind], label_network, get_network, clean_network);
break;
case 'i':
add_source(init_infiniband, argv[optind], label_network, get_network, clean_network);
break;
case 'o':
output = fopen(argv[optind],"wb");
break;
case 'e':
application=&argv[optind];
signal(17,sighandler);
break;
case 'p':
add_source(init_counters, argv[optind], label_counters, get_counters, clean_counters);
break;
case 'r':
add_source(init_rapl, NULL, label_rapl, get_rapl, clean_rapl);
break;
case 'u':
add_source(init_load, NULL, label_load, get_load, clean_load);
break;
case 'c':
add_source(init_temperature, NULL, label_temperature, get_temperature, clean_temperature);
break;
case 's':
stat_mode=0;
break;
case 'l':
show_all_counters();
exit(EXIT_SUCCESS);
default:
usage(argv);
}
struct timespec ts;
struct timespec ts_ref;
fprintf(output, "#timestamp ");
for(int i=0; i<nb_sensors; i++)
fprintf(output, "%s ", labels[i]);
if(stat_mode==0)
fprintf(output, "overhead ");
fprintf(output, "\n");
unsigned long int stat_data=0;
for (int temps = 0; temps <total_time*frequency; temps+=delta) {
clock_gettime(CLOCK_MONOTONIC, &ts_ref);
// Get Data
unsigned int current = 0;
for(int i=0; i<nb_sources; i++)
current += getter[i](&values[current], states[i]);
if(application != NULL) {
if(fork()==0){
execvp(application[0], application);
exit(0);
}
pause();
clock_gettime(CLOCK_MONOTONIC, &ts);
if(ts.tv_nsec >= ts_ref.tv_nsec)
fprintf(output, "%ld.%09ld ", (ts.tv_sec-ts_ref.tv_sec), ts.tv_nsec-ts_ref.tv_nsec);
else
fprintf(output, "%ld.%09ld ", (ts.tv_sec-ts_ref.tv_sec)-1,1000000000+ts.tv_nsec-ts_ref.tv_nsec);
}
else {
#ifdef DEBUG
clock_gettime(CLOCK_MONOTONIC, &ts);
fprintf(stderr, "%ld\n", (ts.tv_nsec-ts_ref.tv_nsec)/1000);
//Indiv: mean: 148 std: 31 % med: 141 std: 28 %
//Group: mean: 309 std: 41 % med: 297 std: 39 %
#endif
if(stat_mode==0) {
clock_gettime(CLOCK_MONOTONIC, &ts);
if(ts.tv_nsec >= ts_ref.tv_nsec)
stat_data = ts.tv_nsec-ts_ref.tv_nsec;
else
stat_data = 1000000000+ts.tv_nsec-ts_ref.tv_nsec;
}
// Treat Data
fprintf(output, "%ld.%09ld ", ts_ref.tv_sec, ts_ref.tv_nsec);
}
for(int i=0; i<nb_sensors; i++)
fprintf(output, "%" PRIu64 " ", values[i]);
if(stat_mode==0)
fprintf(output, "%ld ", stat_data);
fprintf(output, "\n");
if(application != NULL)
break;
clock_gettime(CLOCK_MONOTONIC, &ts);
usleep(1000*1000/frequency-(ts.tv_nsec/1000)%(1000*1000/frequency));
}
for(int i=0; i<nb_sources;i++)
cleaner[i](states[i]);
if(nb_sources > 0) {
free(getter);
free(cleaner);
free(labels);
free(values);
free(states);
}
}