6 changed files with 336 additions and 3 deletions
			
			
		@ -1,7 +1,7 @@ | 
				
			|||
"THE BEER-WARE LICENSE" | 
				
			|||
 | 
				
			|||
Copyright (c) 2018 Apostolof, charaldp, tsakonag | 
				
			|||
Copyright (c) 2019 Apostolof | 
				
			|||
 | 
				
			|||
As long as you retain this notice you can do whatever you want with this stuff. | 
				
			|||
If we meet some day, and you think this stuff is worth it, you can buy us a | 
				
			|||
If we meet some day, and you think this stuff is worth it, you can buy me a | 
				
			|||
beer in return. | 
				
			|||
 | 
				
			|||
@ -0,0 +1,38 @@ | 
				
			|||
SHELL := /bin/bash | 
				
			|||
 | 
				
			|||
# ============================================
 | 
				
			|||
# COMMANDS
 | 
				
			|||
 | 
				
			|||
CC = gcc -std=gnu99 | 
				
			|||
RM = rm -f | 
				
			|||
CFLAGS_DEBUG=-O2 -ggdb3 -Wall -Werror -pedantic -D_FORTIFY_SOURCE=2 -fasynchronous-unwind-tables -grecord-gcc-switches -Werror=implicit-function-declaration -I. | 
				
			|||
CFLAGS=-O2 -Wall -Werror -pedantic -I. | 
				
			|||
 | 
				
			|||
OBJ=test_sample.o test_sample_functions.o | 
				
			|||
DEPS=test_sample_functions.h | 
				
			|||
 | 
				
			|||
# ==========================================
 | 
				
			|||
# TARGETS
 | 
				
			|||
 | 
				
			|||
EXECUTABLES = test_sample.out | 
				
			|||
 | 
				
			|||
.PHONY: all clean | 
				
			|||
 | 
				
			|||
all: $(EXECUTABLES) | 
				
			|||
 | 
				
			|||
# ==========================================
 | 
				
			|||
# DEPENDENCIES (HEADERS)
 | 
				
			|||
 | 
				
			|||
%.o: %.c $(DEPS) | 
				
			|||
	$(CC) -c -o $@ $< $(CFLAGS) | 
				
			|||
 | 
				
			|||
.PRECIOUS: $(EXECUTABLES) $(OBJ) | 
				
			|||
 | 
				
			|||
# ==========================================
 | 
				
			|||
# EXECUTABLE (MAIN)
 | 
				
			|||
 | 
				
			|||
$(EXECUTABLES): $(OBJ) | 
				
			|||
	$(CC) -o $@ $^ $(CFLAGS) | 
				
			|||
 | 
				
			|||
clean: | 
				
			|||
	$(RM) *.o *~ $(EXECUTABLES) | 
				
			|||
@ -0,0 +1,43 @@ | 
				
			|||
#include "test_sample_functions.h" | 
				
			|||
 | 
				
			|||
int main(int argc, char **argv) { | 
				
			|||
	Parameters parameters; | 
				
			|||
	parseArguments(argc, argv, ¶meters); | 
				
			|||
	//parameters.numberOfSamples = (parameters.time + parameters.delta - 1) / parameters.delta;
 | 
				
			|||
	parameters.numberOfSamples = 1 + ((parameters.time - 1) / parameters.delta); | 
				
			|||
 | 
				
			|||
	// Initialize a matrix to store the sample values
 | 
				
			|||
	double **samplesMatrix = (double **) malloc(parameters.numberOfSamples * sizeof(double *)); | 
				
			|||
	for (int i=0; i<parameters.numberOfSamples; ++i) { | 
				
			|||
		samplesMatrix[i] = (double *) malloc(3 * sizeof(double)); | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
	// Saves information about the experiment to the output file
 | 
				
			|||
	{ | 
				
			|||
		FILE *outputFile; | 
				
			|||
		outputFile = fopen(parameters.outputFilename, "w"); | 
				
			|||
 | 
				
			|||
		if (outputFile == NULL) { | 
				
			|||
			printf("Error while opening the output file.\n"); | 
				
			|||
			exit(EXIT_FAILURE); | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		fprintf(outputFile, "Sampling experiment will run for %f seconds\n"\ | 
				
			|||
			"Sampling period is set to %f seconds.\n"\ | 
				
			|||
			"Number of samples should be %d.\n\n", | 
				
			|||
			parameters.time, parameters.delta, parameters.numberOfSamples); | 
				
			|||
 | 
				
			|||
		fclose(outputFile); | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
	printf(ANSI_COLOR_BLUE "\n----- STARTING EXPERIMENT -----\n" ANSI_COLOR_RESET); | 
				
			|||
 | 
				
			|||
	testSampling(&samplesMatrix, parameters); | 
				
			|||
 | 
				
			|||
	printf(ANSI_COLOR_YELLOW "\n----- WRITING RESULTS TO OUTPUT FILE -----\n" ANSI_COLOR_RESET); | 
				
			|||
 | 
				
			|||
	// Saves results to the output file
 | 
				
			|||
	saveSamplesToFile(parameters.outputFilename, samplesMatrix, parameters.numberOfSamples); | 
				
			|||
 | 
				
			|||
	printf(ANSI_COLOR_GREEN "\n----- DONE -----\n" ANSI_COLOR_RESET); | 
				
			|||
} | 
				
			|||
@ -0,0 +1,187 @@ | 
				
			|||
/* ===== 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 "\n----- 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 "\n----- 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 "\n----- 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); Is this needed?
 | 
				
			|||
} | 
				
			|||
 | 
				
			|||
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("%s [-t time] [-d delta] [-o output]" \ | 
				
			|||
		"\n-t time" \ | 
				
			|||
		"\n\ttotal duration of the sampling in seconds" \ | 
				
			|||
		"\n-d delta" \ | 
				
			|||
		"\n\tsampling period in seconds" \ | 
				
			|||
		"\n-o output" \ | 
				
			|||
		"\n\tfilename and path for the 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\n", | 
				
			|||
			samplesMatrix[i][0], samplesMatrix[i][1], samplesMatrix[i][2]); | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
	fclose(outputFile); | 
				
			|||
} | 
				
			|||
@ -0,0 +1,65 @@ | 
				
			|||
#ifndef TEST_SAMPLE_FUNCTIONS_H	/* Include guard */ | 
				
			|||
#define TEST_SAMPLE_FUNCTIONS_H | 
				
			|||
 | 
				
			|||
/* ===== INCLUDES ===== */ | 
				
			|||
 | 
				
			|||
#include <sys/time.h> | 
				
			|||
#include <stdio.h> | 
				
			|||
#include <stdlib.h> | 
				
			|||
#include <string.h> | 
				
			|||
#include <unistd.h> | 
				
			|||
#include <signal.h> | 
				
			|||
#include <stdbool.h> | 
				
			|||
 | 
				
			|||
/* ===== DEFINITIONS ===== */ | 
				
			|||
 | 
				
			|||
//Colors used for better console output formating.
 | 
				
			|||
#define ANSI_COLOR_RED     "\x1B[31m" | 
				
			|||
#define ANSI_COLOR_GREEN   "\x1B[32m" | 
				
			|||
#define ANSI_COLOR_YELLOW  "\x1B[33m" | 
				
			|||
#define ANSI_COLOR_BLUE    "\x1B[34m" | 
				
			|||
#define ANSI_COLOR_CYAN    "\x1B[36m" | 
				
			|||
#define ANSI_COLOR_RESET   "\x1B[0m" | 
				
			|||
 | 
				
			|||
/* ===== CONSTANTS DEFINITION ===== */ | 
				
			|||
 | 
				
			|||
// Constant strings that store the command line options available.
 | 
				
			|||
extern const char *ARGUMENT_TIME; | 
				
			|||
extern const char *ARGUMENT_DELTA; | 
				
			|||
extern const char *ARGUMENT_OUTPUT_FILENAME; | 
				
			|||
// Default filename used for the output.
 | 
				
			|||
extern char *DEFAULT_OUTPUT_FILENAME; | 
				
			|||
 | 
				
			|||
/* ===== STRUCTURES ===== */ | 
				
			|||
 | 
				
			|||
// Structures used in gettimeofday
 | 
				
			|||
extern struct timeval startwtime, endwtime; | 
				
			|||
 | 
				
			|||
// A data structure to conveniently hold the algorithm's parameters.
 | 
				
			|||
typedef struct parameters { | 
				
			|||
	double time, delta; | 
				
			|||
	char *outputFilename; | 
				
			|||
	int numberOfSamples; | 
				
			|||
} Parameters; | 
				
			|||
 | 
				
			|||
/* ===== FUNCTION DEFINITIONS ===== */ | 
				
			|||
 | 
				
			|||
// Function that implements the sampling experiment.
 | 
				
			|||
void testSampling(double ***samplesMatrix, Parameters parameters); | 
				
			|||
 | 
				
			|||
void handle_alarm(int sig); | 
				
			|||
 | 
				
			|||
// Function validUsage outputs the correct way to use the program with command line arguments.
 | 
				
			|||
void validUsage(char *programName); | 
				
			|||
 | 
				
			|||
// Function checkIncrement is a helper function used in parseArguments (see bellow).
 | 
				
			|||
int checkIncrement(int previousIndex, int maxIndex, char *programName); | 
				
			|||
 | 
				
			|||
// Function parseArguments parses command line arguments.
 | 
				
			|||
void parseArguments(int argumentCount, char **argumentVector, Parameters *parameters); | 
				
			|||
 | 
				
			|||
// Function saveSamplesToFile appends the sample matrix "samplesMatrix" to the file with the
 | 
				
			|||
// filename supplied in the arguments.
 | 
				
			|||
void saveSamplesToFile(char *filename, double **samplesMatrix, int matrixRows); | 
				
			|||
 | 
				
			|||
#endif	// TEST_SAMPLE_FUNCTIONS_H
 | 
				
			|||
					Loading…
					
					
				
		Reference in new issue