diff --git a/src/Makefile.inc b/src/Makefile.inc index 9ae03d6ae..39bb99ca5 100644 --- a/src/Makefile.inc +++ b/src/Makefile.inc @@ -2,7 +2,8 @@ TARGETS = $(BUILDDIR)/villas-node \ $(BUILDDIR)/villas-pipe \ $(BUILDDIR)/villas-signal \ - $(BUILDDIR)/villas-test \ + $(BUILDDIR)/villas-test-rtt \ + $(BUILDDIR)/villas-test-cmp \ $(BUILDDIR)/villas-hook SRC_LDLIBS = $(LDLIBS) -pthread -lm -lvillas @@ -31,7 +32,6 @@ $(TARGETS): $(BUILDDIR)/villas-%: $(BUILDDIR)/src/%.o # Some additional prereqs for individual binaries $(BUILDDIR)/villas-fpga: $(addprefix $(BUILDDIR)/src/,fpga-bench.o $(BENCH_OBJS)) - # Compile executable objects $(BUILDDIR)/src/%.o: src/%.c | $$(dir $$@) $(CC) $(SRC_CFLAGS) -c $< -o $@ diff --git a/src/test-cmp.c b/src/test-cmp.c new file mode 100644 index 000000000..e2c5c10b4 --- /dev/null +++ b/src/test-cmp.c @@ -0,0 +1,201 @@ +/** Compare two data files. + * + * @author Steffen Vogel + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + *********************************************************************************/ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +void usage() +{ + printf("Usage: villas-test-cmp FILE1 FILE2 [OPTIONS]\n"); + printf(" FILE1 first file to compare\n"); + printf(" FILE2 second file to compare against\n"); + printf(" OPTIONS the following optional options:\n"); + printf(" -h print this usage information\n"); + printf(" -d LVL adjust the debug level\n"); + printf(" -j return the results as a JSON object\n"); + printf(" -m return the results as a MATLAB struct\n"); + printf(" -e EPS set epsilon for floating point comparisons to EPS\n"); + printf(" -l LOW smallest value for histogram\n"); + printf(" -H HIGH largest value for histogram\n"); + printf(" -r RES bucket resolution for histogram\n"); + printf("\n"); + + print_copyright(); +} + +int main(int argc, char *argv[]) +{ + int ret = 0; + double epsilon = 1e-9; + + /* Histogram */ + double low = 0; /**< Lowest value in histogram. */ + double high = 1e-1; /**< Highest value in histogram. */ + double res = 1e-3; /**< Histogram resolution. */ + + enum { + OUTPUT_JSON, + OUTPUT_MATLAB, + OUTPUT_HUMAN + } output = OUTPUT_HUMAN; + + struct log log; + struct pool pool = { .state = STATE_DESTROYED }; + struct hist hist; + struct sample *samples[2]; + + struct { + int flags; + char *path; + FILE *handle; + struct sample *sample; + } f1, f2; + + /* Parse Arguments */ + char c, *endptr; + while ((c = getopt (argc, argv, "hjmd:e:l:H:r:")) != -1) { + switch (c) { + case 'd': + log.level = strtoul(optarg, &endptr, 10); + goto check; + case 'e': + epsilon = strtod(optarg, &endptr); + goto check; + case 'j': + output = OUTPUT_JSON; + break; + case 'm': + output = OUTPUT_MATLAB; + break; + case 'l': + low = strtod(optarg, &endptr); + goto check; + case 'H': + high = strtod(optarg, &endptr); + goto check; + case 'r': + res = strtod(optarg, &endptr); + goto check; + case 'h': + case '?': + usage(); + exit(c == '?' ? EXIT_FAILURE : EXIT_SUCCESS); + } + + continue; + +check: if (optarg == endptr) + error("Failed to parse parse option argument '-%c %s'", c, optarg); + } + + if (argc < optind + 2) { + usage(); + exit(EXIT_FAILURE); + } + + f1.path = argv[optind]; + f2.path = argv[optind + 1]; + + log_init(&log, V, LOG_ALL); + log_start(&log); + + hist_init(&hist, low, high, res); + pool_init(&pool, 1024, SAMPLE_LEN(DEFAULT_VALUES), &memtype_heap); + sample_alloc(&pool, samples, 2); + + f1.sample = samples[0]; + f2.sample = samples[1]; + + f1.handle = fopen(f1.path, "r"); + if (!f1.handle) + serror("Failed to open file: %s", f1.path); + + f2.handle = fopen(f2.path, "r"); + if (!f2.handle) + serror("Failed to open file: %s", f2.path); + + while (!feof(f1.handle) && !feof(f2.handle)) { + ret = sample_fscan(f1.handle, f1.sample, &f1.flags); + if (ret < 0) { + if (feof(f1.handle)) + ret = 0; + goto out; + } + + ret = sample_fscan(f2.handle, f2.sample, &f2.flags); + if (ret < 0) { + if (feof(f2.handle)) + ret = 0; + goto out; + } + + /* Compare sequence no */ + if ((f1.flags & SAMPLE_SEQUENCE) && (f2.flags & SAMPLE_SEQUENCE)) { + if (f1.sample->sequence != f2.sample->sequence) { + printf("sequence no: %d != %d\n", f1.sample->sequence, f2.sample->sequence); + ret = -1; + goto out; + } + } + + /* Compare timestamp */ + if (time_delta(&f1.sample->ts.origin, &f2.sample->ts.origin) > epsilon) { + printf("ts.origin: %f != %f\n", time_to_double(&f1.sample->ts.origin), time_to_double(&f2.sample->ts.origin)); + ret = -2; + goto out; + } + + /* Collect historgram info of offset */ + hist_put(&hist, time_delta(&f1.sample->ts.origin, &f2.sample->ts.received)); + + /* Compare data */ + if (f1.sample->length != f2.sample->length) { + printf("length: %d != %d\n", f1.sample->length, f2.sample->length); + ret = -3; + goto out; + } + + for (int i = 0; i < f1.sample->length; i++) { + if (fabs(f1.sample->data[i].f - f2.sample->data[i].f) > epsilon) { + printf("data[%d]: %f != %f\n", i, f1.sample->data[i].f, f2.sample->data[i].f); + ret = -4; + goto out; + } + } + } + +out: sample_free(samples, 2); + + fclose(f1.handle); + fclose(f2.handle); + + switch (output) { + case OUTPUT_MATLAB: + hist_dump_matlab(&hist, stdout); + break; + case OUTPUT_JSON: + hist_dump_json(&hist, stdout); + break; + case OUTPUT_HUMAN: + hist_print(&hist, 1); + break; + } + + hist_destroy(&hist); + pool_destroy(&pool); + + return ret; +} \ No newline at end of file diff --git a/src/test.c b/src/test-rtt.c similarity index 77% rename from src/test.c rename to src/test-rtt.c index 27195121c..af523335f 100644 --- a/src/test.c +++ b/src/test-rtt.c @@ -1,4 +1,4 @@ -/** Some basic tests. +/** Measure round-trip time. * * @author Steffen Vogel * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include @@ -21,7 +21,7 @@ #include "config.h" -struct cfg cfg; /** _vt, argc-3, argv+3, config_root_setting(&cfg.cfg)); + node_type_start(node->_vt, argc-3, argv+3, config_root_setting(&sn.cfg)); node_start(node); /* Parse Arguments */ char c, *endptr; - while ((c = getopt (argc-3, argv+3, "l:h:r:f:c:")) != -1) { + while ((c = getopt (argc-3, argv+3, "l:hH:r:f:c:")) != -1) { switch (c) { case 'c': count = strtoul(optarg, &endptr, 10); @@ -94,12 +104,13 @@ int main(int argc, char *argv[]) case 'l': low = strtod(optarg, &endptr); goto check; - case 'h': + case 'H': high = strtod(optarg, &endptr); goto check; case 'r': res = strtod(optarg, &endptr); goto check; + case 'h': case '?': usage(); exit(c == '?' ? EXIT_FAILURE : EXIT_SUCCESS); @@ -111,15 +122,12 @@ check: if (optarg == endptr) error("Failed to parse parse option argument '-%c %s'", c, optarg); } - if (!strcmp(argv[2], "rtt")) - test_rtt(); - else - error("Unknown test: '%s'", argv[2]); + test_rtt(); node_stop(node); node_type_stop(node->_vt); - cfg_destroy(&cfg); + super_node_destroy(&sn); return 0; } @@ -132,7 +140,7 @@ void test_rtt() { struct sample *smp_send = alloc(SAMPLE_LEN(2)); struct sample *smp_recv = alloc(SAMPLE_LEN(2)); - hist_create(&hist, low, high, res); + hist_init(&hist, low, high, res); /* Print header */ fprintf(stdout, "%17s%5s%10s%10s%10s%10s%10s\n", "timestamp", "seq", "rtt", "min", "max", "mean", "stddev");