Apostolos Fanakis
6 years ago
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