aboutsummaryrefslogtreecommitdiff
path: root/fuzz
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2020-07-25 10:37:23 +0200
committerMarc André Tanner <mat@brain-dump.org>2020-07-25 11:57:53 +0200
commite83cc6536f2b536693fe424c080ce635a65993f7 (patch)
tree93a72eaf76677e8e7d428777b3d51b83b65089de /fuzz
parentee0edf4e662c588075b53185987183343f27621c (diff)
downloadvis-e83cc6536f2b536693fe424c080ce635a65993f7.tar.gz
vis-e83cc6536f2b536693fe424c080ce635a65993f7.tar.xz
Add basic text benchmarking infrastructure
This adds a new bench command to the interactive shell initially used for fuzzing with AFL. The syntax is: > b op pos [count] where op is either: i (insert) d (delete) r (replace) m (set/get mark) and pos is one of: ^ (start) | (middle) $ (end) % (random) - (consecutively from end to start) + (consecutively from start to end) ~ (stripes with fixed distance) Hence the following would perform 100 insertions at random positions: > b i % 100 Note however, that the used pseudo-random number generator is currently not seeded, meaning multiple execution will start with the same state, making them comparable. Timing is currently performed using monotonic clock_gettime(2).
Diffstat (limited to 'fuzz')
-rw-r--r--fuzz/text-fuzzer.c128
1 files changed, 128 insertions, 0 deletions
diff --git a/fuzz/text-fuzzer.c b/fuzz/text-fuzzer.c
index c09d7be..956c44b 100644
--- a/fuzz/text-fuzzer.c
+++ b/fuzz/text-fuzzer.c
@@ -5,6 +5,7 @@
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
+#include <inttypes.h>
#include "fuzzer.h"
#include "text.h"
#include "text-util.h"
@@ -18,6 +19,132 @@ typedef enum CmdStatus (*Cmd)(Text *txt, const char *cmd);
static Mark mark = EMARK;
+static char data[BUFSIZ];
+
+static uint64_t bench(void) {
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
+ return (uint64_t)(ts.tv_sec * 1000000 + ts.tv_nsec / 1000);
+ else
+ return 0;
+}
+
+static size_t pos_start(Text *txt) {
+ return 0;
+}
+
+static size_t pos_middle(Text *txt) {
+ return text_size(txt) / 2;
+}
+
+static size_t pos_end(Text *txt) {
+ return text_size(txt);
+}
+
+static size_t pos_random(Text *txt) {
+ return rand() % (text_size(txt) + 1);
+}
+
+static size_t pos_prev(Text *txt) {
+ static size_t pos = EPOS;
+ size_t max = text_size(txt);
+ if (pos > max)
+ pos = max;
+ return pos-- % (max + 1);
+}
+
+static size_t pos_next(Text *txt) {
+ static size_t pos = 0;
+ return pos++ % (text_size(txt) + 1);
+}
+
+static size_t pos_stripe(Text *txt) {
+ static size_t pos = 0;
+ return pos+=1024 % (text_size(txt) + 1);
+}
+
+static enum CmdStatus bench_insert(Text *txt, size_t pos, const char *cmd) {
+ return text_insert(txt, pos, data, sizeof data);
+}
+
+static enum CmdStatus bench_delete(Text *txt, size_t pos, const char *cmd) {
+ return text_delete(txt, pos, 1);
+}
+
+static enum CmdStatus bench_replace(Text *txt, size_t pos, const char *cmd) {
+ text_delete(txt, pos, 1);
+ text_insert(txt, pos, "-", 1);
+ return CMD_OK;
+}
+
+static enum CmdStatus bench_mark(Text *txt, size_t pos, const char *cmd) {
+ Mark mark = text_mark_set(txt, pos);
+ if (mark == EMARK)
+ return CMD_FAIL;
+ if (text_mark_get(txt, mark) != pos)
+ return CMD_FAIL;
+ return CMD_OK;
+}
+
+static enum CmdStatus cmd_bench(Text *txt, const char *cmd) {
+
+ static enum CmdStatus (*bench_cmd[])(Text*, size_t, const char*) = {
+ ['i'] = bench_insert,
+ ['d'] = bench_delete,
+ ['r'] = bench_replace,
+ ['m'] = bench_mark,
+ };
+
+ static size_t (*bench_pos[])(Text*) = {
+ ['^'] = pos_start,
+ ['|'] = pos_middle,
+ ['$'] = pos_end,
+ ['%'] = pos_random,
+ ['-'] = pos_prev,
+ ['+'] = pos_next,
+ ['~'] = pos_stripe,
+ };
+
+ if (!data[0]) {
+ // make `p` command output more readable
+ int len = snprintf(data, sizeof data, "[ ... %zu bytes ... ]\n", sizeof data);
+ memset(data+len, '\r', sizeof(data) - len);
+ }
+
+ const char *params = cmd;
+ while (*params == ' ')
+ params++;
+
+ size_t idx_cmd = params[0];
+ if (idx_cmd >= LENGTH(bench_cmd) || !bench_cmd[idx_cmd]) {
+ puts("Invalid bench command");
+ return CMD_ERR;
+ }
+
+ for (params++; *params == ' '; params++);
+
+ size_t idx_pos = params[0];
+ if (idx_pos >= LENGTH(bench_pos) || !bench_pos[idx_pos]) {
+ puts("Invalid bench position");
+ return CMD_ERR;
+ }
+
+ size_t iter = 1;
+ sscanf(params+1, "%zu\n", &iter);
+
+ for (size_t i = 1; i <= iter; i++) {
+ size_t pos = bench_pos[idx_pos](txt);
+ uint64_t s = bench();
+ enum CmdStatus ret = bench_cmd[idx_cmd](txt, pos, NULL);
+ uint64_t e = bench();
+ if (ret != CMD_OK)
+ return ret;
+ printf("%zu: %" PRIu64 "us\n", i, e-s);
+ }
+ return CMD_OK;
+}
+
static enum CmdStatus cmd_insert(Text *txt, const char *cmd) {
char data[BUFSIZ];
size_t pos;
@@ -104,6 +231,7 @@ static Cmd commands[] = {
['?'] = cmd_mark_get,
['='] = cmd_mark_set,
['#'] = cmd_size,
+ ['b'] = cmd_bench,
['d'] = cmd_delete,
['i'] = cmd_insert,
['p'] = cmd_print,