Apostolos Fanakis
6 years ago
6 changed files with 336 additions and 3 deletions
@ -1,7 +1,7 @@ |
|||||
"THE BEER-WARE LICENSE" |
"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. |
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. |
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