commit d87b794e6695b389032d83594da7c57ad67db119 Author: Alexander Nutz Date: Thu Sep 4 01:13:24 2025 +0200 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..be4cc63 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +core +a.out diff --git a/README.md b/README.md new file mode 100644 index 0000000..4a266c5 --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +# test matrix vizualizer + +Visualize test matrix, while tests are running, and then output summary. + +Easy to integrate + +![preview](demo.webm) + +## Input format +```bash +arithmetic x86 1 +arithmetic amd64 1 +arithmetic rv64 1 +# you can put comments anywhere +arithmetic emit-qbe 1 +# empty lines are ignored + + +# omitting entries will mark them as skipped. +# note that you have to keep the order of th elines once you use them in that order +qbe-verify emit-qbe 1 +loops x86 1 +loops amd64 1 +loops rv64 1 +loops emit-qbe 0 +floats x86 0 +floats amd64 1 +floats rv64 0 +floats emit-qbe - + +vectorize-loops-1 amd64 1 +vectorize-loops-1 rv64 0 + +vectorize-loops-2 amd64 1 +vectorize-loops-2 rv64 0 +vectorize-loops-3 amd64 0 +vectorize-loops-3 rv64 1 + +extern-func x86 1 +extern-func amd64 1 +extern-func rv64 1 +extern-func emit-qbe 1 +``` diff --git a/demo.webm b/demo.webm new file mode 100644 index 0000000..0dda1ec Binary files /dev/null and b/demo.webm differ diff --git a/example_input.txt b/example_input.txt new file mode 100644 index 0000000..cf5cd1d --- /dev/null +++ b/example_input.txt @@ -0,0 +1,32 @@ +arithmetic x86 1 +arithmetic amd64 1 +arithmetic rv64 1 +# you can put comments anywhere +arithmetic emit-qbe 1 +# empty lines are ignored + + +# omitting entries will mark them as skipped. +# note that you have to keep the order of th elines once you use them in that order +qbe-verify emit-qbe 1 +loops x86 1 +loops amd64 1 +loops rv64 1 +loops emit-qbe 0 +floats x86 0 +floats amd64 1 +floats rv64 0 +floats emit-qbe - + +vectorize-loops-1 amd64 1 +vectorize-loops-1 rv64 0 + +vectorize-loops-2 amd64 1 +vectorize-loops-2 rv64 0 +vectorize-loops-3 amd64 0 +vectorize-loops-3 rv64 1 + +extern-func x86 1 +extern-func amd64 1 +extern-func rv64 1 +extern-func emit-qbe 1 diff --git a/example_input.txt.sh b/example_input.txt.sh new file mode 100644 index 0000000..ed7153b --- /dev/null +++ b/example_input.txt.sh @@ -0,0 +1,29 @@ +echo arithmetic x86 1 +echo arithmetic amd64 1 +sleep 1 +echo arithmetic rv64 1 +echo arithmetic emit-qbe 1 +echo qbe-verify emit-qbe 1 +echo loops x86 1 +echo loops amd64 1 +echo loops rv64 1 +sleep 1 +echo loops emit-qbe 0 +echo floats x86 0 +echo floats amd64 1 +echo floats rv64 0 +sleep 1 +echo floats emit-qbe - +echo vectorize-loops-1 amd64 1 +echo vectorize-loops-1 rv64 0 +echo vectorize-loops-2 amd64 1 +echo vectorize-loops-2 rv64 0 +sleep 1 +echo vectorize-loops-3 amd64 0 +sleep 1 +echo vectorize-loops-3 rv64 1 +echo extern-func x86 1 +echo extern-func amd64 1 +sleep 1 +echo extern-func rv64 1 +echo extern-func emit-qbe 1 diff --git a/main.c b/main.c new file mode 100644 index 0000000..79e1592 --- /dev/null +++ b/main.c @@ -0,0 +1,199 @@ +#include +#include +#include +#include +#include + +#define lenof(x) (sizeof((x)) / sizeof(*(x))) + +#define MAX_LINE_LEN 256 +#define MAX_RCOL 32 +#define RCOL_LEN 64 + +#define RED "\033[0;31m" +#define GREEN "\033[0;32m" +#define YELLOW "\033[0;33m" + +#define HRED "\033[0;91m" +#define HGREEN "\033[0;92m" +#define HYELLOW "\033[0;93m" + +#define RESET "\033[0m" + +unsigned hash(char const *buf) { + unsigned res = 5381; + for (; *buf; buf++) { + res = (res << 5) + res + *buf; + } + return res; +} + +void err_misfmt_input(char const *reason) { + fprintf(stderr, "error: misformatted input: %s\n", reason); + exit(1); +} + +char buf[MAX_LINE_LEN]; + +struct counters { + unsigned char pfs[3]; +}; + +unsigned num_rcol = 0; +unsigned rcol_hashes[MAX_RCOL] = {0}; +char rcol_values[MAX_RCOL][RCOL_LEN]; +struct counters rcol_ctr[MAX_RCOL] = {0}; + +unsigned rcol_lut(unsigned hash) { + for (unsigned *p = rcol_hashes; *p; p++) + if (*p == hash) + return p - rcol_hashes + 1; + return 0; +} + +void rstrip(char *buf) { + char *sub; + for (; *buf; buf++) { + if (isspace(*buf)) { + for (sub = buf + 1; *sub && isspace(*sub); sub++) + ; + if (!*sub) { + *buf = 0; + break; + } + } + } +} + +void put(int pfs_mode) { + if (pfs_mode == 0) + printf(HGREEN "* " RESET); + else if (pfs_mode == 1) + printf(HRED "X " RESET); + else + printf(HYELLOW "- " RESET); +} + +void finish(int last_lc, unsigned last_rcol_idx) { + if (last_lc == 0) + return; + + for (; last_rcol_idx < num_rcol; last_rcol_idx++) { + put(2); + rcol_ctr[last_rcol_idx - 1].pfs[2] += 1; + } +} + +int main(int argc, char **argv) { + int lcol_width; + int last_lc = 0; + char *p, *lcol, *rcol; + unsigned lcol_hash, rcol_hash, rcol_idx, last_rcol_idx = 0, + actual_last_rcol_idx, i, j, pfs_mode; + struct counters sum = {0}; + + if (argc != 2 || !((lcol_width = atoi(argv[1])))) { + fprintf(stderr, "usage: %s \n", *argv); + return 1; + } + + while (buf == fgets(buf, lenof(buf), stdin)) { + p = buf; + for (; isspace(*p); p++) + ; + if (*p == '#' || !*p) + continue; + + lcol = strtok(p, " \t"); + rcol = strtok(0, " \t"); + p = strtok(0, " \t"); + rstrip(p); + + if (!p || p[1]) + err_misfmt_input("3rd column invalid"); + + if (*p == '0') + pfs_mode = 1; + else if (*p == '1') + pfs_mode = 0; + else if (*p == '-') + pfs_mode = 2; + else + err_misfmt_input("3rd column invalid"); + + lcol_hash = hash(lcol); + rcol_hash = hash(rcol); + + actual_last_rcol_idx = last_rcol_idx; + if (lcol_hash != last_lc) { + last_rcol_idx = 0; + } + + rcol_idx = rcol_lut(rcol_hash); + if (rcol_idx == 0) { + rcol_idx = ++num_rcol; + // TODO: validate length + rcol_hashes[rcol_idx - 1] = rcol_hash; + // TODO: validate length + strcpy(rcol_values[rcol_idx - 1], rcol); + } else if (rcol_idx <= last_rcol_idx && last_rcol_idx != 0) { + err_misfmt_input("ordering different from last time"); + } + + rcol_ctr[rcol_idx - 1].pfs[pfs_mode] += 1; + + if (lcol[0] == '-' && lcol[1] == 0) + continue; + + if (lcol_hash != last_lc) { + finish(last_lc, actual_last_rcol_idx); + if (last_lc != 0) + putchar('\n'); + last_lc = lcol_hash; + last_rcol_idx = 0; + printf("%*s ", lcol_width, lcol); + } + + for (i = last_rcol_idx + 1; i < rcol_idx; i++) { + put(2); + } + + put(pfs_mode); + last_rcol_idx = rcol_idx; + + fflush(stdout); + } + + finish(last_lc, last_rcol_idx); + if (last_lc != 0) + putchar('\n'); + + for (i = 0; i <= num_rcol; i++) { + for (j = 0; j < lcol_width + (num_rcol - i) * 2; j++) + putchar(' '); + if (i != num_rcol) { + putchar('^'); + sum.pfs[0] += rcol_ctr[i].pfs[0]; + sum.pfs[1] += rcol_ctr[i].pfs[1]; + sum.pfs[2] += rcol_ctr[i].pfs[2]; + } else + putchar(' '); + if (i != 0) { + printf(" %s \t(%u/%u passed", rcol_values[num_rcol - i], + rcol_ctr[num_rcol - i].pfs[0], + rcol_ctr[num_rcol - i].pfs[0] + rcol_ctr[num_rcol - i].pfs[1]); + if (rcol_ctr[num_rcol - i].pfs[2]) + printf(", %u skipped", rcol_ctr[num_rcol - i].pfs[2]); + printf(")"); + } + putchar('\n'); + } + + printf("\nSummary:\n"); + if (sum.pfs[0]) + printf(HGREEN " %u passed" RESET "\n", sum.pfs[0]); + if (sum.pfs[1]) + printf(HRED " %u failed" RESET "\n", sum.pfs[1]); + if (sum.pfs[2]) + printf(HYELLOW " %u skipped" RESET "\n", sum.pfs[2]); +}