From ecd056a3a005a52d4d6f19ff88f5e0cadcd9103c Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sun, 19 Jul 2015 16:17:50 +0200 Subject: [PATCH] added some existing source code for various smaller tasks --- project/hist.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++ project/hist.h | 84 +++++++++++++++++++++++ project/timing.c | 89 ++++++++++++++++++++++++ project/timing.h | 58 ++++++++++++++++ project/utils.c | 77 +++++++++++++++++++++ project/utils.h | 30 ++++++++ 6 files changed, 512 insertions(+) create mode 100644 project/hist.c create mode 100644 project/hist.h create mode 100644 project/timing.c create mode 100644 project/timing.h create mode 100644 project/utils.c create mode 100644 project/utils.h diff --git a/project/hist.c b/project/hist.c new file mode 100644 index 0000000..803f6a6 --- /dev/null +++ b/project/hist.c @@ -0,0 +1,174 @@ +/** Histogram functions. + * + * @author Steffen Vogel + * @copyright 2014-2015, Institute for Automation of Complex Power Systems, EONERC + * This file is part of S2SS. All Rights Reserved. Proprietary and confidential. + * Unauthorized copying of this file, via any medium is strictly prohibited. + *********************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "hist.h" +#include "utils.h" + +#define VAL(h, i) ((h)->low + (i) * (h)->resolution) +#define INDEX(h, v) round((v - (h)->low) / (h)->resolution) + +void hist_create(struct hist *h, double low, double high, double resolution) +{ + h->low = low; + h->high = high; + h->resolution = resolution; + h->length = (high - low) / resolution; + h->data = alloc(h->length * sizeof(unsigned)); + + hist_reset(h); +} + +void hist_destroy(struct hist *h) +{ + free(h->data); +} + +void hist_put(struct hist *h, double value) +{ + int idx = INDEX(h, value); + + /* Update min/max */ + if (value > h->highest) + h->highest = value; + if (value < h->lowest) + h->lowest = value; + + /* Check bounds and increment */ + if (idx >= h->length) + h->higher++; + else if (idx < 0) + h->lower++; + else + h->data[idx]++; + + h->total++; + + /* Online / running calculation of variance and mean + * by Donald Knuth’s Art of Computer Programming, Vol 2, page 232, 3rd edition */ + if (h->total == 1) { + h->_m[1] = h->_m[0] = value; + h->_s[1] = 0.0; + } + else { + h->_m[0] = h->_m[1] + (value - h->_m[1]) / h->total; + h->_s[0] = h->_s[1] + (value - h->_m[1]) * (value - h->_m[0]); + + // set up for next iteration + h->_m[1] = h->_m[0]; + h->_s[1] = h->_s[0]; + } + +} + +void hist_reset(struct hist *h) +{ + h->total = 0; + h->higher = 0; + h->lower = 0; + + h->highest = DBL_MIN; + h->lowest = DBL_MAX; + + memset(h->data, 0, h->length * sizeof(unsigned)); +} + +double hist_mean(struct hist *h) +{ + return (h->total > 0) ? h->_m[0] : 0.0; +} + +double hist_var(struct hist *h) +{ + return (h->total > 1) ? h->_s[0] / (h->total - 1) : 0.0; +} + +double hist_stddev(struct hist *h) +{ + return sqrt(hist_var(h)); +} + +void hist_print(struct hist *h) +{ + printf("Total: %u values\n", h->total); + printf("Highest value: %f\n", h->highest); + printf("Lowest value: %f\n", h->lowest); + printf("Mean: %f\n", hist_mean(h)); + printf("Variance: %f\n", hist_var(h)); + printf("Standard derivation: %f\n", hist_stddev(h)); + if (h->higher > 0) + printf("Missed: %u values above %f\n", h->higher, h->high); + if (h->lower > 0) + printf("Missed: %u values below %f\n", h->lower, h->low); + + if (h->total - h->higher - h->lower > 0) { + hist_plot(h); + + char buf[(h->length + 1) * 8]; + hist_dump(h, buf, sizeof(buf)); + printf(buf); + } +} + +void hist_plot(struct hist *h) +{ + char buf[HIST_HEIGHT]; + memset(buf, '#', sizeof(buf)); + + hist_cnt_t max = 1; + + /* Get highest bar */ + for (int i = 0; i < h->length; i++) { + if (h->data[i] > max) + max = h->data[i]; + } + + /* Print plot */ + printf("%3s | %9s | %5s | %s\n", "#", "Value", "Occur", "Plot"); + printf("--------------------------------------------------------------------------------\n"); + + for (int i = 0; i < h->length; i++) { + int bar = HIST_HEIGHT * ((double) h->data[i] / max); + + printf("%3u | %+5.2e | " "%5u" " | %.*s\n", i, VAL(h, i), h->data[i], bar, buf); + } +} + +void hist_dump(struct hist *h, char *buf, int len) +{ + *buf = 0; + + strap(buf, len, "[ "); + + for (int i = 0; i < h->length; i++) + strap(buf, len, "%u ", h->data[i]); + + strap(buf, len, "]"); +} + +void hist_matlab(struct hist *h, FILE *f) +{ + char buf[h->length * 8]; + hist_dump(h, buf, sizeof(buf)); + + fprintf(f, "%lu = struct( ", time(NULL)); + fprintf(f, "'min', %f, 'max', %f, ", h->low, h->high); + fprintf(f, "'ok', %u, too_high', %u, 'too_low', %u, ", h->total, h->higher, h->lower); + fprintf(f, "'highest', %f, 'lowest', %f, ", h->highest, h->lowest); + fprintf(f, "'mean', %f, ", hist_mean(h)); + fprintf(f, "'var', %f, ", hist_var(h)); + fprintf(f, "'stddev', %f, ", hist_stddev(h)); + fprintf(f, "'hist', %s ", buf); + fprintf(f, "),\n"); +} diff --git a/project/hist.h b/project/hist.h new file mode 100644 index 0000000..6b1541c --- /dev/null +++ b/project/hist.h @@ -0,0 +1,84 @@ +/** Histogram functions. + * + * @file + * @author Steffen Vogel + * @copyright 2014-2015, Steffen Vogel + * @license GPLv3 + *********************************************************************************/ + +#ifndef _HIST_H_ +#define _HIST_H_ + +#include + +#define HIST_HEIGHT 75 +#define HIST_SEQ 17 + +typedef unsigned hist_cnt_t; + +/** Histogram structure used to collect statistics. */ +struct hist { + /** The distance between two adjacent buckets. */ + double resolution; + + /** The value of the highest bucket. */ + double high; + /** The value of the lowest bucket. */ + double low; + + /** The highest value observed (may be higher than #high). */ + double highest; + /** The lowest value observed (may be lower than #low). */ + double lowest; + + /** The number of buckets in #data. */ + int length; + + /** Total number of counted values between #low and #high. */ + hist_cnt_t total; + /** The number of values which are higher than #high. */ + hist_cnt_t higher; + /** The number of values which are lower than #low. */ + hist_cnt_t lower; + + /** Pointer to dynamically allocated array of size length. */ + hist_cnt_t *data; + + /** Private variables for online variance calculation */ + double _m[2], _s[2]; +}; + +/** Initialize struct hist with supplied values and allocate memory for buckets. */ +void hist_create(struct hist *h, double start, double end, double resolution); + +/** Free the dynamically allocated memory. */ +void hist_destroy(struct hist *h); + +/** Reset all counters and values back to zero. */ +void hist_reset(struct hist *h); + +/** Count a value within its corresponding bucket. */ +void hist_put(struct hist *h, double value); + +/** Calcluate the variance of all counted values. */ +double hist_var(struct hist *h); + +/** Calculate the mean average of all counted values. */ +double hist_mean(struct hist *h); + +/** Calculate the standard derivation of all counted values. */ +double hist_stddev(struct hist *h); + +/** Print all statistical properties of distribution including a graphilcal plot of the histogram. */ +void hist_print(struct hist *h); + +/** Print ASCII style plot of histogram */ +void hist_plot(struct hist *h); + +/** Dump histogram data in Matlab format to buf */ +void hist_dump(struct hist *h, char *buf, int len); + +/** Prints Matlab struct containing all infos to file. */ +void hist_matlab(struct hist *h, FILE *f); + +#endif /* _HIST_H_ */ diff --git a/project/timing.c b/project/timing.c new file mode 100644 index 0000000..ea9956d --- /dev/null +++ b/project/timing.c @@ -0,0 +1,89 @@ +/** Time related functions. + * + * @author Steffen Vogel + * @copyright 2014-2015, Steffen Vogel + * @license GPLv3 + *********************************************************************************/ + +#include "timing.h" + +uint64_t timerfd_wait(int fd) +{ + uint64_t runs; + + return read(fd, &runs, sizeof(runs)) < 0 ? 0 : runs; +} + +uint64_t timerfd_wait_until(int fd, struct timespec *until) +{ + struct itimerspec its = { + .it_value = *until + }; + + if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, NULL)) + return 0; + else + return timerfd_wait(fd); +} + +struct timespec time_add(struct timespec *start, struct timespec *end) +{ + struct timespec sum = { + .tv_sec = end->tv_sec + start->tv_sec, + .tv_nsec = end->tv_nsec + start->tv_nsec + }; + + if (sum.tv_nsec > 1000000000) { + sum.tv_sec += 1; + sum.tv_nsec -= 1000000000; + } + + return sum; +} + +struct timespec time_diff(struct timespec *start, struct timespec *end) +{ + struct timespec diff = { + .tv_sec = end->tv_sec - start->tv_sec, + .tv_nsec = end->tv_nsec - start->tv_nsec + }; + + if (diff.tv_nsec < 0) { + diff.tv_sec -= 1; + diff.tv_nsec += 1000000000; + } + + return diff; +} + +struct timespec time_from_double(double secs) +{ + struct timespec ts; + + ts.tv_sec = secs; + ts.tv_nsec = 1.0e9 * (secs - ts.tv_sec); + + return ts; +} + +double time_to_double(struct timespec *ts) +{ + return ts->tv_sec + ts->tv_nsec * 1e-9; +} + +double time_delta(struct timespec *start, struct timespec *end) +{ + struct timespec diff = time_diff(start, end); + + return time_to_double(&diff); +} + +int time_fscan(FILE *f, struct timespec *ts) +{ + return fscanf(f, "%lu.%lu", &ts->tv_sec, &ts->tv_nsec); +} + +int time_fprint(FILE *f, struct timespec *ts) +{ + return fprintf(f, "%lu.%09lu\t", ts->tv_sec, ts->tv_nsec); +} \ No newline at end of file diff --git a/project/timing.h b/project/timing.h new file mode 100644 index 0000000..cd37911 --- /dev/null +++ b/project/timing.h @@ -0,0 +1,58 @@ +/** Time related functions. + * + * @author Steffen Vogel + * @copyright 2014-2015, Steffen Vogel + * @license GPLv3 + *********************************************************************************/ + +#ifndef _TIME_H_ +#define _TIME_H_ + +#define _POSIX_C_SOURCE 199309L + +#include +#include +#include + +#include +#include + +/** Wait until timer elapsed + * + * @param fd A file descriptor which was created by timerfd_create(3). + * @retval 0 An error occured. Maybe the timer was stopped. + * @retval >0 The nummer of runs this timer already fired. + */ +uint64_t timerfd_wait(int fd); + +/** Wait until a fixed time in the future is reached + * + * @param fd A file descriptor which was created by timerfd_create(3). + * @param until A pointer to a time in the future. + * @retval 0 An error occured. Maybe the timer was stopped. + * @retval >0 The nummer of runs this timer already fired. + */ +uint64_t timerfd_wait_until(int fd, struct timespec *until); + +/** Get delta between two timespec structs */ +struct timespec time_diff(struct timespec *start, struct timespec *end); + +/** Get sum of two timespec structs */ +struct timespec time_add(struct timespec *start, struct timespec *end); + +/** Return the diffrence off two timestamps as double value in seconds. */ +double time_delta(struct timespec *start, struct timespec *end); + +/** Convert timespec to double value representing seconds */ +double time_to_double(struct timespec *ts); + +/** Convert double containing seconds after 1970 to timespec. */ +struct timespec time_from_double(double secs); + +/** Read a timestamp from a file with the format: "secs.nanosecs\t" */ +int time_fscan(FILE *f, struct timespec *ts); + +/** Write a timestamp to a file with the format: "secs.nanosecs\t" */ +int time_fprint(FILE *f, struct timespec *ts); + +#endif \ No newline at end of file diff --git a/project/utils.c b/project/utils.c new file mode 100644 index 0000000..e422d66 --- /dev/null +++ b/project/utils.c @@ -0,0 +1,77 @@ +/** Utilities. + * + * @author Steffen Vogel + * @copyright 2014-2015, Steffen Vogel + * @license GPLv3 + *********************************************************************************/ + +#ifndef HEXDUMP_COLS +#define HEXDUMP_COLS 8 +#endif + +#include +#include +#include +#include +#include + +#include "utils.h" + +void hexdump(void *mem, unsigned int len) +{ + unsigned int i, j; + + for (i = 0; i < len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0); i++) { + if (i % HEXDUMP_COLS == 0) + printf("0x%06x: ", i); /* print offset */ + + if (i < len) + printf("%02x ", 0xFF & ((char*)mem)[i]); /* print hex data */ + else + printf(" "); /* end of block, just aligning for ASCII dump */ + + /* print ASCII dump */ + if (i % HEXDUMP_COLS == (HEXDUMP_COLS - 1)) { + for (j = i - (HEXDUMP_COLS - 1); j <= i; j++) { + if (j >= len) /* end of block, not really printing */ + putchar(' '); + else if (isprint(((char*)mem)[j])) /* printable char */ + putchar(0xFF & ((char*)mem)[j]); + else /* other char */ + putchar('.'); + } + + putchar('\n'); + } + } +} + +void * alloc(size_t bytes) +{ + void *p = malloc(bytes); + if (!p) + error(-1, 0, "Failed to allocate memory"); + + memset(p, 0, bytes); + + return p; +} + +int strap(char *dest, size_t size, const char *fmt, ...) +{ + int ret; + + va_list ap; + va_start(ap, fmt); + ret = vstrap(dest, size, fmt, ap); + va_end(ap); + + return ret; +} + +int vstrap(char *dest, size_t size, const char *fmt, va_list ap) +{ + int len = strlen(dest); + + return vsnprintf(dest + len, size - len, fmt, ap); +} \ No newline at end of file diff --git a/project/utils.h b/project/utils.h new file mode 100644 index 0000000..4c937f7 --- /dev/null +++ b/project/utils.h @@ -0,0 +1,30 @@ +/** Utilities. + * + * @author Steffen Vogel + * @copyright 2014-2015, Steffen Vogel + * @license GPLv3 + * @file + *********************************************************************************/ + +#ifndef _UTILS_H_ +#define _UTILS_H_ + +#include + +#define MIN(x, y) ((x < y) ? x : y) +#define MAX(x, y) ((x > y) ? x : y) + +void hexdump(void *mem, unsigned int len); + +void * alloc(size_t bytes); + +/** Safely append a format string to an existing string. + * + * This function is similar to strlcat() from BSD. + */ +int strap(char *dest, size_t size, const char *fmt, ...); + +/** Variadic version of strap() */ +int vstrap(char *dest, size_t size, const char *fmt, va_list va); + +#endif \ No newline at end of file