/* ===== 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. Four 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 interrupts are used. On the fourth interrupts * are combined with sleep to minimize power consumption. */ 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