|
|
|
/* ===== INCLUDES ===== */
|
|
|
|
|
|
|
|
#include "test_sample_functions.h"
|
|
|
|
|
|
|
|
/* ===== CONSTANTS ===== */
|
|
|
|
|
|
|
|
const char *ARGUMENT_TIME = "-t";
|
|
|
|
const char *ARGUMENT_DELTA = "-d";
|
|
|
|
const char *ARGUMENT_OUTPUT_FILENAME = "-o";
|
|
|
|
|
|
|
|
char *DEFAULT_OUTPUT_FILENAME = "sample_test_output";
|
|
|
|
|
|
|
|
/* ===== STRUCTURES ===== */
|
|
|
|
|
|
|
|
struct timeval startwtime, endwtime;
|
|
|
|
|
|
|
|
/* ===== OTHER ===== */
|
|
|
|
|
|
|
|
volatile sig_atomic_t sample_flag = false;
|
|
|
|
|
|
|
|
/* ===== FUNCTIONS ===== */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* testSampling implements the sampling experiment. Three different ways of sampling are
|
|
|
|
* implemented. On the first one sleep is used. On the second sleep is used and the sleep times are
|
|
|
|
* corrected based on the previous error. On the third alarms are used.
|
|
|
|
*/
|
|
|
|
void testSampling(double ***samplesMatrix, Parameters parameters) {
|
|
|
|
printf(ANSI_COLOR_CYAN "----- RUNNING FIRST EXPERIMENT\n" ANSI_COLOR_RESET);
|
|
|
|
for (int i = 0; i < parameters.numberOfSamples; ++i) {
|
|
|
|
gettimeofday (&startwtime, NULL);
|
|
|
|
|
|
|
|
usleep(parameters.delta * 1000000);
|
|
|
|
|
|
|
|
gettimeofday (&endwtime, NULL);
|
|
|
|
(*samplesMatrix)[i][0] = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6 +
|
|
|
|
endwtime.tv_sec - startwtime.tv_sec);
|
|
|
|
}
|
|
|
|
|
|
|
|
printf(ANSI_COLOR_CYAN "----- RUNNING SECOND EXPERIMENT\n" ANSI_COLOR_RESET);
|
|
|
|
double totalError = 0;
|
|
|
|
for (int i = 0; i < parameters.numberOfSamples; ++i) {
|
|
|
|
gettimeofday (&startwtime, NULL);
|
|
|
|
|
|
|
|
usleep((parameters.delta - (totalError / (i + 1))) * 1000000);
|
|
|
|
|
|
|
|
gettimeofday (&endwtime, NULL);
|
|
|
|
(*samplesMatrix)[i][1] = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6 +
|
|
|
|
endwtime.tv_sec - startwtime.tv_sec);
|
|
|
|
|
|
|
|
totalError += (*samplesMatrix)[i][1] - parameters.delta;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf(ANSI_COLOR_CYAN "----- RUNNING THIRD EXPERIMENT\n" ANSI_COLOR_RESET);
|
|
|
|
signal(SIGALRM, handle_alarm);
|
|
|
|
|
|
|
|
struct itimerval new;
|
|
|
|
|
|
|
|
new.it_interval.tv_usec = (int) ((parameters.delta - ((int) parameters.delta)) * 1000000);
|
|
|
|
new.it_interval.tv_sec = ((int) parameters.delta);
|
|
|
|
new.it_value.tv_usec = (int) ((parameters.delta - ((int) parameters.delta)) * 1000000);
|
|
|
|
new.it_value.tv_sec = ((int) parameters.delta);
|
|
|
|
|
|
|
|
if (setitimer (ITIMER_REAL, &new, NULL) == -1) {
|
|
|
|
perror("setitimer");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
gettimeofday (&startwtime, NULL);
|
|
|
|
|
|
|
|
int i = 0 ;
|
|
|
|
while(i < parameters.numberOfSamples) {
|
|
|
|
if (sample_flag) {
|
|
|
|
sample_flag = false;
|
|
|
|
gettimeofday (&endwtime, NULL);
|
|
|
|
(*samplesMatrix)[i][2] = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6 +
|
|
|
|
endwtime.tv_sec - startwtime.tv_sec);
|
|
|
|
|
|
|
|
++i;
|
|
|
|
gettimeofday (&startwtime, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
alarm(0);
|
|
|
|
printf(ANSI_COLOR_CYAN "----- RUNNING FOURTH EXPERIMENT\n" ANSI_COLOR_RESET);
|
|
|
|
if (setitimer (ITIMER_REAL, &new, NULL) == -1) {
|
|
|
|
perror("setitimer");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < parameters.numberOfSamples; ++i){
|
|
|
|
gettimeofday (&startwtime, NULL);
|
|
|
|
// Sleeps until a signal wakes up the process.
|
|
|
|
sleep(parameters.time + 420);
|
|
|
|
|
|
|
|
while (!sample_flag) {
|
|
|
|
// Does nothing.
|
|
|
|
// Makes sure signal was indeed triggered.
|
|
|
|
}
|
|
|
|
|
|
|
|
sample_flag = false;
|
|
|
|
gettimeofday (&endwtime, NULL);
|
|
|
|
(*samplesMatrix)[i][3] = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6 +
|
|
|
|
endwtime.tv_sec - startwtime.tv_sec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void handle_alarm(int sig) {
|
|
|
|
sample_flag = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== PROGRAM INPUT AND OUTPUT UTILS ====================
|
|
|
|
|
|
|
|
/*
|
|
|
|
* parseArguments parses the command line arguments given by the user.
|
|
|
|
*/
|
|
|
|
void parseArguments(int argumentCount, char **argumentVector, Parameters *parameters) {
|
|
|
|
if (argumentCount > 7) {
|
|
|
|
validUsage(argumentVector[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
(*parameters).time = 7200;
|
|
|
|
(*parameters).delta = 0.1;
|
|
|
|
(*parameters).outputFilename = DEFAULT_OUTPUT_FILENAME;
|
|
|
|
|
|
|
|
char *endPointer;
|
|
|
|
int argumentIndex = 1;
|
|
|
|
|
|
|
|
while (argumentIndex < argumentCount) {
|
|
|
|
if (!strcmp(argumentVector[argumentIndex], ARGUMENT_TIME)) {
|
|
|
|
argumentIndex = checkIncrement(argumentIndex, argumentCount, argumentVector[0]);
|
|
|
|
|
|
|
|
double timeInput = strtod(argumentVector[argumentIndex], &endPointer);
|
|
|
|
if ((timeInput <= 0) && endPointer) {
|
|
|
|
printf("Invalid time argument\n");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
(*parameters).time = timeInput;
|
|
|
|
} else if (!strcmp(argumentVector[argumentIndex], ARGUMENT_DELTA)) {
|
|
|
|
argumentIndex = checkIncrement(argumentIndex, argumentCount, argumentVector[0]);
|
|
|
|
|
|
|
|
double deltaInput = strtod(argumentVector[argumentIndex], &endPointer);
|
|
|
|
if ((deltaInput <= 0) && endPointer) {
|
|
|
|
printf("Invalid time argument\n");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
(*parameters).delta = deltaInput;
|
|
|
|
} else if (!strcmp(argumentVector[argumentIndex], ARGUMENT_OUTPUT_FILENAME)) {
|
|
|
|
argumentIndex = checkIncrement(argumentIndex, argumentCount, argumentVector[0]);
|
|
|
|
|
|
|
|
if (fopen(argumentVector[argumentIndex], "w") == NULL) {
|
|
|
|
printf("Invalid output filename. Reverting to default.\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
(*parameters).outputFilename = argumentVector[argumentIndex];
|
|
|
|
} else {
|
|
|
|
validUsage(argumentVector[0]);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
++argumentIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* validUsage outputs a message to the console that informs the user of the
|
|
|
|
* correct (valid) way to use the program.
|
|
|
|
*/
|
|
|
|
void validUsage(char *programName) {
|
|
|
|
printf("Usage:\t%s [-t time] [-d delta] [-o output]" \
|
|
|
|
"\n-t time" \
|
|
|
|
"\n\ttotal duration of the sampling in seconds, default value is 7200" \
|
|
|
|
"\n-d delta" \
|
|
|
|
"\n\tsampling period in seconds, default value is 0.1" \
|
|
|
|
"\n-o output" \
|
|
|
|
"\n\tfilename and path for the output, default filename is 'sample_test_output'" \
|
|
|
|
"\n", programName);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* checkIncrement is a helper function for parseArguments function.
|
|
|
|
*/
|
|
|
|
int checkIncrement(int previousIndex, int maxIndex, char *programName) {
|
|
|
|
if (previousIndex == maxIndex) {
|
|
|
|
validUsage(programName);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
return ++previousIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
void saveSamplesToFile(char *filename, double **samplesMatrix, int matrixRows) {
|
|
|
|
FILE *outputFile;
|
|
|
|
|
|
|
|
outputFile = fopen(filename, "a");
|
|
|
|
|
|
|
|
if (outputFile == NULL) {
|
|
|
|
printf("Error while opening the output file.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Saves the samples matrix
|
|
|
|
for (int i=0; i<matrixRows; ++i) {
|
|
|
|
fprintf(outputFile, "%.10g\t%.10g\t%.10g\t%.10g\n",
|
|
|
|
samplesMatrix[i][0], samplesMatrix[i][1], samplesMatrix[i][2], samplesMatrix[i][3]);
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(outputFile);
|
|
|
|
}
|