Browse Source

Init commit in new repo

Joachim M. Giæver 7 years ago
parent
commit
e33a91e301
7 changed files with 505 additions and 3 deletions
  1. 0 3
      README.md
  2. 32 0
      READ_ME.md
  3. 26 0
      example/Makefile
  4. 28 0
      example/READ_ME.md
  5. 133 0
      example/main.c
  6. 229 0
      log.c
  7. 57 0
      log.h

+ 0 - 3
README.md

@@ -1,3 +0,0 @@
-# c-logging
-
-Log your c programs and plot data into graphs. Supports custom log functions, if you dont want to use a timer to log with.

+ 32 - 0
READ_ME.md

@@ -0,0 +1,32 @@
+LOGGING 
+===
+# About
+
+Do logging (in the manner of benchmarking etc) with this application. The application is easy to use and strive to use an ADT that is flexible in many ways. For example, you can easily implement your own functions if you're not looking for an alternative solution, e.g count stuff. Just do like this:
+
+```c
+void numeric(unsigned long long *t, ...) {
+    va_list vargs;
+    va_start(vargs, t);
+
+    int num = va_arg(vargs, int);
+    
+    if (num % 2)
+        num += 10;
+
+    *t = num;
+
+    va_end(vargs);
+}
+```
+
+and pass it on as the third argument to the ```log_init```-function. Data collected between logent_start and logent_end can again be passed on to the function by adding them after the third argument to ```logent_end```.
+
+## How to
+--- more info here
+
+### Initialize one or several logs
+--- it will come
+
+## Todo:
+Comment out and clean up code in ```log.c``` and ```log.h```.

+ 26 - 0
example/Makefile

@@ -0,0 +1,26 @@
+CC = gcc
+CFLAGS = -p -Wall
+COPT = -O0
+SRCS = main.c
+
+all: main
+
+LOG_DIR=./logs
+LOG_PLT=$(LOG_DIR)/*.plot
+LOG_CMP=$(LOG_DIR)/*.ps
+
+main: $(SRCS) Makefile
+	$(CC) $(CFLAGS) $(COPT) -o $@ $<  
+
+cmp:
+	gnuplot $(LOG_DIR)/*.plot
+	find $(LOG_DIR) -name *.ps -exec ps2pdf {} {}.pdf \;
+
+cmpl:
+	find $(LOG_DIR) -name *.pdf -exec evince {} \;
+
+cmpc:
+	rm -rf $(LOG_DIR)
+
+clean: cmpc
+	rm -f *~ *.o *.exe *.s *.out main

+ 28 - 0
example/READ_ME.md

@@ -0,0 +1,28 @@
+Example program
+===
+
+Compile the program (you may alter it as well if you'd like) with the following:
+```bash
+$ make              # make program
+$ ./main            # run the program, and wait....
+$ make cmp          # make compare files (from data to plots)
+```
+
+If you like, you can have evince (must be installed) to view your graph(s), one by one:
+
+```bash
+$ make cmpl         # launche pdf in evince
+```
+
+TO CLEAN UP:
+
+```bash
+$ make clean        # Note! Will remove logs as well!
+```
+or
+```bash
+$ make cmpl         # to clean up only the logs
+```
+
+### Todo:
+Comment ```main.c```.

+ 133 - 0
example/main.c

@@ -0,0 +1,133 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include "../log.c"
+
+#define LSIZE       100000
+#define LSTEP       10000
+
+static int *mk_array(int len) {
+    int *arr = (int *)malloc(sizeof(int) * len), i;
+
+    srand(time(NULL));
+    for (i = 0; i < len; i++)
+        arr[i] = (rand() % (len * 10));
+
+    return arr;
+}
+
+static void *cp_array(int *arr, int len) {
+    int *narr = (int *)malloc(sizeof(int) * len), i;
+
+    for (i = 0; i < len; i++)
+        narr[i] = arr[i];
+    
+    return narr;
+}
+
+static void bubble_sort(int *arr, int len) {
+    int c, d, swp;
+
+    for (c = 0; c < (len - 1); c++) {
+        for (d = 0; d < (len - c - 1); d++) {
+            if (arr[d] > arr[d+1]) {
+                swp = arr[d];
+                arr[d] = arr[d+1];
+                arr[d+1] = swp;
+            }
+        }
+    }
+}
+
+static void merge(int *arr, int min, int mid, int max) {
+    int l1, l2, i,
+        *buf = (int *)malloc(sizeof(int) * (max + 1));
+
+    for (l1 = min, l2 = mid + 1, i = min; l1 <= mid && l2 <= max; i++)
+        if (arr[l1] <= arr[l2]) buf[i] = arr[l1++];
+        else buf[i] = arr[l2++];
+
+    while (l1 <= mid)
+        buf[i++] = arr[l1++];
+
+    while (l2 <= max)
+        buf[i++] = arr[l2++];
+
+    for (i = min; i <= max; i++)
+        arr[i] = buf[i];
+
+    free(buf);
+}
+
+static void merge_sort(int *arr, int min, int max) {
+    int mid;
+    if (min < max) {
+        mid = (min + max) / 2;
+        merge_sort(arr, min, mid);
+        merge_sort(arr, mid+1, max);
+        merge(arr, min, mid, max);
+    }
+}
+
+int main(int argc, char const *argv[]) {
+    /**
+     * set first argument to
+     * a+:  Append results to current log. Typically if you'd 
+     *      make changes to the programs algorithms for each run, and
+     *      each execution should be compared.
+     * w+:  Each execution does several logging, and create a new log for
+     *      this for each run.
+     */
+    log_t *lt = log_init("actual", "w+", "Elements to sort", "Processing time", (logfunc_t)(gettime)),
+          *la = log_init("average", "w+", "Elements to sort", "Avg. processing time", (logfunc_t)(gettime));
+
+    logent_t *le_bt = logent_init(lt, "bubble sort total", "bubble"),
+             *le_ba = logent_init(la, "bubble sort avg.", "bubble");
+
+    logent_t *le_mt = logent_init(lt, "merge sort total", "merge"),
+             *le_ma = logent_init(la, "merge sort avg.", "merge");
+
+    int k = LSTEP, *arr, *bsort_arr_t, *bsort_arr_a, *msort_arr_t, *msort_arr_a;
+
+    while (k <= LSIZE) {
+        arr = mk_array(k);
+
+        bsort_arr_t = cp_array(arr, k);
+        bsort_arr_a = cp_array(arr, k);
+        msort_arr_t = cp_array(arr, k);
+        msort_arr_a = cp_array(arr, k);
+
+        logent_start(le_bt);
+        bubble_sort(bsort_arr_t, k);
+        logent_end(le_bt, k, 1);
+
+        logent_start(le_ba);
+        bubble_sort(bsort_arr_a, k);
+        logent_end(le_ba, k, k);
+
+        logent_start(le_mt);
+        merge_sort(msort_arr_t, 0, k-1);
+        logent_end(le_mt, k, 1);
+
+        logent_start(le_ma);
+        merge_sort(msort_arr_a, 0, k-1);
+        logent_end(le_ma, k, k);
+
+        k += LSTEP;
+    }
+
+    // Closes log-entries
+    log_destroy(lt);
+    log_destroy(la);
+
+    /*
+    Now missing: (will probably be added)
+	logfile_avg( log_for );
+	logfile_avg( log_while );
+
+	logfile_destroy( log_for );
+	logfile_destroy( log_while );
+    */
+
+	return 0;
+}

+ 229 - 0
log.c

@@ -0,0 +1,229 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include "log.h"
+
+#define PLOT_LINES      6
+
+static void log_add_ent(log_t *l, logent_t *le);
+static void logent_destroy(logent_t *le);
+static void fatal_error(const char *format, ...);
+static f_t *finit(char *name, const char *mode);
+static void fend(f_t *f);
+
+/**
+ * Get the time: function to use as logfunc_t
+ **/
+void gettime(unsigned long long *t) {
+    struct timeval tp;
+    unsigned long long ctime;
+
+    gettimeofday( &tp, NULL );
+    ctime = tp.tv_sec;
+    ctime *= 1000000;
+    ctime += tp.tv_usec;
+
+    *t = ctime;
+}
+
+log_t *log_init(char *fn, const char *mode, char *xlabel, char *ylabel, logfunc_t func) {
+    char buf[256];
+
+    stat_t  st;
+    log_t   *l = (log_t *) malloc(sizeof(log_t));
+    
+    if (l == NULL)
+        fatal_error("Could not allocate memory for the new log [%s].", fn);
+
+    if (stat(LOG_DIR, &st) != 0)
+        if (mkdir(LOG_DIR, 0777))
+            fatal_error("Could not create directory: %s", LOG_DIR);
+
+    sprintf(buf, "%s/%s-%s", LOG_DIR, fn, LOG_PLT);
+    l->file = finit(buf, mode);
+
+    if (l->file->lines == 0)
+        l->file->lines = PLOT_LINES;
+    
+    l->entries = 0;
+    l->entry = NULL;
+    l->xlabel = strdup(xlabel);
+    l->ylabel = strdup(ylabel);
+    l->func = func;
+
+    return l;
+}
+
+logent_t *logent_init(log_t *l, char *desc, ...) {
+    char buf[256];
+    char *id;
+    va_list vargs;
+    logent_t *le = (logent_t *)malloc(sizeof(logent_t));
+
+    if (l == NULL)
+        fatal_error("Log is NULL\n");
+
+    if (le == NULL)
+        fatal_error("Could not allocate memory for log entry: %s:%s\n", l->file->fn, desc);
+
+    le->desc = strdup(desc);
+
+    va_start(vargs, desc);
+    id = va_arg(vargs, char*);
+    va_end(vargs);
+
+    if (id != NULL)
+        sprintf(buf, "%s-%d.data", l->file->fn, l->file->lines - PLOT_LINES + l->entries);
+    else
+        sprintf(buf, "%s-%s.data", l->file->fn, id);
+
+    printf("FN: %s\n", buf);
+    le->file = finit(buf, l->file->mode);
+
+    log_add_ent(l, le);
+
+    return le;
+}
+
+void logent_start(logent_t *le, ...) {
+    va_list vargs;
+
+    if (le == NULL)
+        fatal_error("Log entry is NULL\n");
+
+    va_start(vargs, le);
+    le->log->func(&le->t1);
+    va_end(vargs);
+}
+
+void logent_end(logent_t *le, int idx, int ent, ...) {
+    int res;
+    va_list vargs;
+    
+    if (le == NULL)
+        fatal_error("Logentry is NULL\n");
+    
+    va_start(vargs, ent);
+    le->log->func(&le->t2, vargs);
+    va_end(vargs);
+
+    if (ent <= 0)
+        ent = 1;
+
+    res = (int)(le->t2 - le->t1) / ent;
+
+    fprintf(le->file->f, "%d %d\n", idx, res);
+    fflush(le->file->f);
+}
+
+void log_destroy(log_t *l) {
+    int i;
+
+    if (ftell(l->file->f) == 0) {
+        fprintf(l->file->f, "set terminal postscript color\n");
+        fprintf(l->file->f, "set output \"%s-%s\"\n", l->file->fn, LOG_CMP);
+        fprintf(l->file->f, "set autoscale\n");
+        fprintf(l->file->f, "set xlabel \"%s\"\nset ylabel \"%s\"\n", l->xlabel, l->ylabel);
+        fprintf(l->file->f, "set key right\nplot");
+    }
+
+    for (i = 0; i < l->entries; i++) {
+        if (l->entry[i]->file->lines == 0) {
+            fprintf(l->file->f, " \\\n\"%s\" w linespoints lw 2 t \"%s\",",
+                l->entry[i]->file->fn, l->entry[i]->desc
+            );
+        }
+        logent_destroy(l->entry[i]);
+    }
+
+    fflush(l->file->f);
+    fend(l->file);
+    free(l->xlabel);
+    free(l->ylabel);
+
+    if (l->entry != NULL)
+        free(l->entry);
+}
+
+/** 
+ * When something bad happens.... we end!
+ **/
+static void fatal_error(const char *format, ...) {
+    va_list vargs;
+    fprintf(stdout, "[FATAL] ");
+    va_start(vargs, format);
+    vfprintf(stdout, format, vargs);
+    va_end(vargs);
+	exit(EXIT_FAILURE);
+}
+
+static f_t *finit(char *name, const char *mode) {
+
+    char c;
+
+    f_t *f = (f_t *)malloc(sizeof(f_t));
+
+    if (f == NULL)
+        fatal_error("Could not allocate memory for %s\n", name);
+
+    f->fn = strdup(name);
+    f->f = fopen(f->fn, mode);
+    f->lines = 0;
+    f->mode = mode;
+
+    if (f->f == NULL)
+        fatal_error("Coult not open %s[%s]\n", name, mode);
+
+    while ((c = fgetc(f->f)) != EOF)
+        if (c == '\n')
+            f->lines++;
+
+    fseek(f->f, 0, SEEK_END);
+
+    return f;
+}
+
+static void fend(f_t *f) {
+    if (f == NULL)
+        fatal_error("Cant close NULL-file\n");
+
+    if (f->f == NULL)
+        return;
+
+    printf("[FILE] stored in: %s\n", f->fn);
+    free(f->fn);
+    fclose(f->f);
+}
+
+static void log_add_ent(log_t *l, logent_t *le) {
+    int i;
+
+    logent_t **entry = (logent_t **)malloc(sizeof(logent_t*) * (l->entries + 1));
+
+    for (i = 0; i < l->entries; i++)
+        entry[i] = l->entry[i];
+
+    entry[l->entries++] = le;
+    
+    if (l->entry != NULL)
+        free(l->entry);
+    
+    l->entry = entry;
+    le->log = l;
+}
+
+static void logent_destroy(logent_t *le) {
+    
+    if (le == NULL)
+        fatal_error("Cant close log entry 0x%p\n", le);
+
+    if (le->file->f != NULL)
+        fend(le->file);
+
+    le->file->f = NULL;
+
+    free(le->desc);
+    free(le);
+}

+ 57 - 0
log.h

@@ -0,0 +1,57 @@
+#ifndef LOG_H
+#define LOG_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+
+#ifndef LOG_DIR
+#define LOG_DIR     "./logs"
+#endif
+#ifndef LOG_CMP
+#define LOG_CMP     "cmpr.ps"
+#endif
+#ifndef LOG_PLT
+#define LOG_PLT     "cmpr.plot"
+#endif
+
+typedef void (*logfunc_t)(void *, ...);
+
+typedef struct stat stat_t;
+typedef struct log log_t;
+typedef struct logent logent_t;
+
+typedef struct {
+    FILE        *f;
+    char        *fn;
+    int         lines;
+    const char  *mode;
+} f_t;
+
+struct log {
+    f_t         *file;
+    char        *xlabel,
+                *ylabel;
+    logfunc_t   func;
+    logent_t    **entry;
+    int         entries;
+};
+
+struct logent {
+    char                *desc;
+    f_t                 *file;
+    unsigned long long  t1, 
+                        t2;
+    log_t               *log;
+};
+
+
+void gettime(unsigned long long *t);
+log_t *log_init(char *name, const char *mode, char *xlabel, char *ylabel, logfunc_t f);
+logent_t *logent_init(log_t *l, char *desc, ...);
+void logent_start(logent_t *le, ...);
+void logent_end(logent_t *le, int idx, int ent, ...);
+void log_destroy(log_t *l);
+#endif