All of lore.kernel.org
 help / color / mirror / Atom feed
* [igt-dev] [PATCH igt] RFC tools: capture execution pathways
@ 2018-04-20 21:50 Chris Wilson
  2018-04-20 22:03 ` [igt-dev] ✗ Fi.CI.BAT: failure for " Patchwork
                   ` (7 more replies)
  0 siblings, 8 replies; 11+ messages in thread
From: Chris Wilson @ 2018-04-20 21:50 UTC (permalink / raw)
  To: igt-dev

igt_kcov edges -o edges.yaml command-to-trace args
...
igt_kcov sort -o sorted.yaml edges.yaml

Requires CONFIG_KCOV

Use LD_PRELOAD to wrap calls to DRM ioctls and capture the execution
trace of all basic blocks invoked directly from the syscall. (Key
limitation!) From the chain of basic blocks, the "edges" are computed
and the number of times each edge is hit is stored in a vector (modulo a
large hash). The goal then is to select a series of tests that execute
the most unique pathways in the sortest amount of time. To do this we
compare the similarity of the coverage vectors between all commands, and
try to preferentially pick those that are dissimilar from the rest.

* Direct execution pathways from syscall is a huge limitation for
evaluating general testing of driver pathways, but is not so huge when
myopically focusing on the ABI as say used by mesa.

** Caveat lector. Hastily thrown together.
---
 tools/Makefile.am      |  10 +-
 tools/igt_kcov.c       | 905 +++++++++++++++++++++++++++++++++++++++++
 tools/igt_kcov_edges.c | 144 +++++++
 3 files changed, 1058 insertions(+), 1 deletion(-)
 create mode 100644 tools/igt_kcov.c
 create mode 100644 tools/igt_kcov_edges.c

diff --git a/tools/Makefile.am b/tools/Makefile.am
index a0b016ddd..f0c2ef3df 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,6 +1,7 @@
 include Makefile.sources
 
-bin_PROGRAMS = $(tools_prog_lists)
+bin_PROGRAMS = $(tools_prog_lists) igt_kcov
+lib_LTLIBRARIES = igt_kcov_edges.la
 
 if HAVE_LIBDRM_INTEL
 bin_PROGRAMS += $(LIBDRM_INTEL_BIN)
@@ -30,6 +31,13 @@ intel_aubdump_la_LIBADD = $(top_builddir)/lib/libintel_tools.la -ldl
 
 intel_gpu_top_LDADD = $(top_builddir)/lib/libigt_perf.la
 
+igt_kcov_SOURCES = igt_kcov.c
+igt_kcov_LDADD = -lyaml -lz -lrt -lm
+
+igt_kcov_edges_la_SOURCES = igt_kcov_edges.c
+igt_kcov_edges_la_LDFLAGS = -module -no-undefined -avoid-version
+igt_kcov_edges_la_LIBADD = -ldl
+
 bin_SCRIPTS = intel_aubdump
 CLEANFILES = $(bin_SCRIPTS)
 
diff --git a/tools/igt_kcov.c b/tools/igt_kcov.c
new file mode 100644
index 000000000..9fb522c20
--- /dev/null
+++ b/tools/igt_kcov.c
@@ -0,0 +1,905 @@
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <math.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <yaml.h>
+#include <zlib.h>
+
+#define SZ_8 (1 << 16)
+#define SZ_32 (sizeof(uint32_t) * SZ_8)
+
+static pid_t child = 0;
+
+static void sighandler(int sig)
+{
+	kill(sig, child);
+}
+
+static uint64_t gettime(void)
+{
+	struct timespec ts;
+
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+
+	return ts.tv_sec * 1000000000 + ts.tv_nsec;
+}
+
+static int edges_exec(const char *preload, char **argv, uint64_t *elapsed)
+{
+	char buf[10];
+	int status;
+	int shm;
+	int ret;
+
+	if (access("/sys/kernel/debug/kcov", W_OK)) {
+		fprintf(stderr, "kcov not found in debugfs\n");
+		return -ENOENT;
+	}
+
+	shm = memfd_create("igt_kcov", 0);
+	if (shm == -1)
+		return -errno;
+
+	ftruncate(shm, SZ_32);
+
+	switch ((child = fork())) {
+	case 0: /* child */
+		sprintf(buf, "%d", shm);
+		setenv("IGT_KCOV_FD", buf, 1);
+		setenv("LD_PRELOAD", preload, 1);
+		exit(execvp(argv[0], argv));
+		break;
+
+	case -1:
+		ret = -errno;
+		break;
+
+	default:
+		signal(SIGINT, sighandler);
+
+		*elapsed = -gettime();
+		do {
+			ret = waitpid(child, &status, 0);
+			if (ret == -1)
+				ret = -errno;
+		} while (ret == -EINTR);
+		*elapsed += gettime();
+
+		signal(SIGINT, SIG_DFL);
+		child = 0;
+	}
+
+	if (ret < 0) {
+		close(shm);
+		shm = ret;
+	}
+
+	return shm;
+}
+
+static inline unsigned long __fls(unsigned long word)
+{
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86__) || defined(__x86_64__))
+	asm("bsr %1,%0"
+	    : "=r" (word)
+	    : "rm" (word));
+	return word;
+#else
+	unsigned int v = 0;
+
+	while (word >>= 1)
+		v++;
+
+	return v;
+#endif
+}
+
+static uint8_t lower_u32(uint32_t x)
+{
+	if (x < 16)
+		return x;
+	else
+		return (x >> (__fls(x) - 2)) + ((__fls(x) - 1) << 2);
+}
+
+static uint8_t *lower_edges(int shm)
+{
+	uint8_t *lower;
+	uint32_t *tbl;
+	unsigned int n;
+
+	tbl = mmap(NULL, SZ_32, PROT_READ, MAP_SHARED, shm, 0);
+	if (tbl == MAP_FAILED)
+		return NULL;
+
+	if (tbl[0] == 0) /* empty */
+		goto out;
+
+	lower = malloc(SZ_8);
+	if (!lower)
+		goto out;
+
+	for (n = 0; n < 1 << 16; n++)
+		lower[n] = lower_u32(tbl[n]);
+
+out:
+	munmap(tbl, SZ_32);
+	return lower;
+}
+
+static bool ascii85_encode(uint32_t in, char *out)
+{
+	int i;
+
+	if (in == 0)
+		return false;
+
+	for (i = 5; i--; ) {
+		out[i] = '!' + in % 85;
+		in /= 85;
+	}
+
+	return true;
+}
+
+static char *edges_to_ascii85(uint8_t *tbl)
+{
+	z_stream zs;
+	uint32_t *p;
+	void *out;
+	char *str, *s;
+	int sz;
+
+	sz = SZ_8 * 3 /2;
+	out = malloc(sz);
+	if (!out)
+		return NULL;
+
+	memset(&zs, 0, sizeof(zs));
+	if (deflateInit(&zs, 9)) {
+		free(out);
+		return NULL;
+	}
+
+	zs.next_in = tbl;
+	zs.avail_in = SZ_8;
+	zs.total_in = 0;
+	zs.avail_out = sz;
+	zs.total_out = 0;
+	zs.next_out = out;
+
+	deflate(&zs, Z_FINISH);
+	deflateEnd(&zs);
+
+	if (zs.total_out & 3)
+		memset((char *)out + zs.total_out, 0, 4 - (zs.total_out & 3));
+	zs.total_out = (zs.total_out + 3) / 4;
+
+	str = malloc(zs.total_out * 5 + 1);
+	if (!str) {
+		free(out);
+		return NULL;
+	}
+
+	p = out;
+	s = str;
+	for (int i = 0; i < zs.total_out; i++) {
+		if (ascii85_encode(*p++, s))
+			s += 5;
+		else
+			*s++ = 'z';
+	}
+	*s++ = '\0';
+	free(out);
+
+	return str;
+}
+
+static void edges(int argc, char **argv)
+{
+	static const struct option longopts[] = {
+		{"output", required_argument, 0, 'o'},
+		{"preload", required_argument, 0, 'p'},
+		{ NULL, 0, NULL, 0 }
+	};
+	const char *preload = "/tmp/igt_kcov_edges.so";
+	FILE *out = stdout;
+	uint64_t elapsed;
+	uint8_t *tbl;
+	char *str, *s;
+	int shm, i;
+
+	while ((i = getopt_long(argc, argv,
+				"+o:",
+				longopts, NULL)) != -1) {
+		switch (i) {
+		case 'o':
+			if (strcmp(optarg, "-"))
+				out = fopen(optarg, "a");
+			if (!out) {
+				fprintf(stderr,
+					"Unable to open output file '%s'\n",
+					optarg);
+				exit(1);
+			}
+			break;
+		case 'p':
+			preload = optarg;
+			break;
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 1) {
+		fprintf(stderr,
+			"usage: igt_kcov edges [options] program-to-edges args...\n");
+		exit(1);
+	}
+
+	shm = edges_exec(preload, argv, &elapsed);
+	if (shm < 0) {
+		fprintf(stderr,
+			"Execution of %s failed: err=%d\n",
+			argv[0], shm);
+		exit(1);
+	}
+
+	tbl = lower_edges(shm);
+	close(shm);
+	if (!tbl)
+		exit(1);
+
+	str = edges_to_ascii85(tbl);
+	fprintf(out, "---\n");
+	fprintf(out, "cmd: |  \n");
+	for (i = 0; i < argc; i++) {
+		fprintf(out, " '");
+		for (s = argv[i]; *s; s++) {
+			if (*s == '\'')
+				fprintf(out, "\\\'");
+			else
+				fprintf(out, "%c", *s);
+		}
+		fprintf(out, "'");
+	}
+	fprintf(out, "\n");
+
+	fprintf(out, "elapsed: %"PRIu64" # %.1fms\n", elapsed, 1e-6 * elapsed);
+
+	fprintf(out, "edges: !!asci85.gz |\n");
+	i = strlen(str);
+	s = str;
+	while (i) {
+		int len = i > 70 ? 70 : i;
+		char tmp;
+
+		tmp = s[len];
+		s[len] = '\0';
+		fprintf(out, "  %s\n", s);
+		s[len] = tmp;
+
+		s += len;
+		i -= len;
+	}
+
+	free(str);
+}
+
+static unsigned long zlib_inflate(void *in, unsigned long len,
+				  void *ptr, unsigned long max)
+{
+	struct z_stream_s zstream;
+
+	memset(&zstream, 0, sizeof(zstream));
+
+	zstream.next_in = in;
+	zstream.avail_in = len;
+
+	if (inflateInit(&zstream) != Z_OK)
+		return 0;
+
+	zstream.next_out = ptr;
+	zstream.avail_out = max;
+
+	switch (inflate(&zstream, Z_SYNC_FLUSH)) {
+	case Z_STREAM_END:
+	case Z_OK:
+		break;
+	default:
+		zstream.total_out = 0;
+		break;
+	}
+
+	inflateEnd(&zstream);
+	return zstream.total_out;
+}
+
+static unsigned long ascii85_decode(const char *in,
+				    void *ptr, unsigned long max)
+{
+	unsigned long sz = max / sizeof(uint32_t);
+	unsigned long len = 0;
+	uint32_t *out;
+
+	out = malloc(sz * sizeof(uint32_t));
+	if (out == NULL)
+		return 0;
+
+	while (*in) {
+		uint32_t v = 0;
+
+		if (isspace(*in)) {
+			in++;
+			continue;
+		}
+
+		if (*in < '!' || *in > 'z') {
+			fprintf(stderr, "Invalid value in ascii85 block\n");
+			free(out);
+			return 0;
+		}
+
+		if (len == sz) {
+			sz *= 2;
+			out = realloc(out, sz * sizeof(uint32_t));
+			if (out == NULL)
+				return 0;
+		}
+
+		if (*in == 'z') {
+			in++;
+		} else {
+			v += in[0] - 33; v *= 85;
+			v += in[1] - 33; v *= 85;
+			v += in[2] - 33; v *= 85;
+			v += in[3] - 33; v *= 85;
+			v += in[4] - 33;
+			in += 5;
+		}
+		out[len++] = v;
+	}
+
+	len = zlib_inflate(out, len * sizeof(*out), ptr, max);
+	free(out);
+
+	return len;
+}
+
+static void yaml_print_parser_error(yaml_parser_t *parser, FILE *stream)
+{
+	switch (parser->error) {
+	case YAML_MEMORY_ERROR:
+		fprintf(stderr, "Memory error: Not enough memory for parsing\n");
+		break;
+
+	case YAML_READER_ERROR:
+		if (parser->problem_value != -1) {
+			fprintf(stderr, "Reader error: %s: #%X at %zd\n", parser->problem,
+				parser->problem_value, parser->problem_offset);
+		} else {
+			fprintf(stderr, "Reader error: %s at %zd\n", parser->problem,
+				parser->problem_offset);
+		}
+		break;
+
+	case YAML_SCANNER_ERROR:
+		if (parser->context) {
+			fprintf(stderr, "Scanner error: %s at line %lu, column %lu\n"
+				"%s at line %lu, column %lu\n", parser->context,
+				parser->context_mark.line+1, parser->context_mark.column+1,
+				parser->problem, parser->problem_mark.line+1,
+				parser->problem_mark.column+1);
+		} else {
+			fprintf(stderr, "Scanner error: %s at line %lu, column %lu\n",
+				parser->problem, parser->problem_mark.line+1,
+				parser->problem_mark.column+1);
+		}
+		break;
+
+	case YAML_PARSER_ERROR:
+		if (parser->context) {
+			fprintf(stderr, "Parser error: %s at line %lu, column %lu\n"
+				"%s at line %lu, column %lu\n", parser->context,
+				parser->context_mark.line+1, parser->context_mark.column+1,
+				parser->problem, parser->problem_mark.line+1,
+				parser->problem_mark.column+1);
+		} else {
+			fprintf(stderr, "Parser error: %s at line %lu, column %lu\n",
+				parser->problem, parser->problem_mark.line+1,
+				parser->problem_mark.column+1);
+		}
+		break;
+
+	default:
+		/* Couldn't happen. */
+		fprintf(stderr, "Internal error\n");
+		break;
+	}
+}
+
+struct edges {
+	struct edges *next;
+
+	char *command;
+	uint64_t elapsed;
+
+	unsigned int weight;
+
+	uint8_t tbl[SZ_8];
+};
+
+struct sort {
+	struct edges *edges;
+	unsigned int count;
+
+	unsigned int max_weight;
+	struct edges *best;
+};
+
+static bool sort_parse_command(struct sort *sort,
+			       struct edges *e,
+			       yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+	const char *s;
+	int len;
+
+	if (!yaml_parser_parse(parser, &ev))
+		return false;
+
+	switch (ev.type) {
+	case YAML_SCALAR_EVENT:
+		break;
+
+	default:
+		return false;
+	}
+
+
+	s = (const char *)ev.data.scalar.value;
+	len = strlen(s);
+	while (s[len - 1] == '\n')
+		len--;
+	e->command = malloc(len + 1);
+	if (e->command) {
+		memcpy(e->command, s, len);
+		e->command[len] = '\0';
+	}
+	yaml_event_delete(&ev);
+
+	return true;
+}
+
+static bool sort_parse_elapsed(struct sort *sort,
+			       struct edges *e,
+			       yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+	const char *s;
+
+	if (!yaml_parser_parse(parser, &ev))
+		return false;
+
+	switch (ev.type) {
+	case YAML_SCALAR_EVENT:
+		break;
+
+	default:
+		return false;
+	}
+
+	s = (const char *)ev.data.scalar.value;
+	e->elapsed = strtoull(s, NULL, 0);
+	yaml_event_delete(&ev);
+
+	return true;
+}
+
+static unsigned int bitmap_weight(const void *bitmap, unsigned int bits)
+{
+	const uint32_t *b = bitmap;
+	unsigned int k, lim = bits / 32;
+	unsigned int w = 0;
+
+	for (k = 0; k < lim; k++)
+		w += __builtin_popcount(b[k]);
+
+	if (bits % 32)
+		w += __builtin_popcount(b[k] << (32 - bits % 32));
+
+	return w;
+}
+
+static bool sort_parse_edges(struct sort *sort,
+			     struct edges *e,
+			     yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+	const char *s;
+
+	if (!yaml_parser_parse(parser, &ev))
+		return false;
+
+	switch (ev.type) {
+	case YAML_SCALAR_EVENT:
+		break;
+
+	default:
+		return false;
+	}
+
+	s = (const char *)ev.data.scalar.value;
+	if (ascii85_decode(s, e->tbl, sizeof(e->tbl)))
+		e->weight = bitmap_weight(e->tbl, sizeof(e->tbl) * 8);
+	yaml_event_delete(&ev);
+
+	return true;
+}
+
+static bool edges_valid(const struct edges *e)
+{
+	if (!e->command)
+		return false;
+
+	if (!e->weight)
+		return false;
+
+	if (!e->elapsed)
+		return false;
+
+	return true; /* good enough at least */
+}
+
+static bool sort_add_edges(struct sort *sort, struct edges *e)
+{
+	if (!edges_valid(e))
+		return false;
+
+	e->next = sort->edges;
+	sort->edges = e;
+
+	if (e->weight > sort->max_weight) {
+		sort->max_weight = e->weight;
+		sort->best = e;
+	}
+
+	sort->count++;
+
+	return true;
+}
+
+static bool sort_parse_node(struct sort *sort, yaml_parser_t *parser)
+{
+	struct edges *e;
+	yaml_event_t ev;
+	char *s;
+
+	e = malloc(sizeof(*e));
+	if (!e)
+		return false;
+
+	e->weight = 0;
+
+	do {
+		if (!yaml_parser_parse(parser, &ev))
+			goto err;
+
+		switch (ev.type) {
+		case YAML_MAPPING_END_EVENT:
+			if (!sort_add_edges(sort, e))
+				goto err;
+
+			return true;
+
+		case YAML_SCALAR_EVENT:
+			break;
+
+		default:
+			goto err;
+		}
+
+		s = (char *)ev.data.scalar.value;
+		if (!strcmp(s, "cmd")) {
+			sort_parse_command(sort, e, parser);
+		} else if (!strcmp(s, "elapsed")) {
+			sort_parse_elapsed(sort, e, parser);
+		} else if (!strcmp(s, "edges")) {
+			sort_parse_edges(sort, e, parser);
+		} else {
+			fprintf(stderr,
+				"Unknown element in edges file: %s\n",
+				s);
+		}
+
+		yaml_event_delete(&ev);
+	} while (1);
+
+err:
+	free(e);
+	return false;
+}
+
+static bool sort_parse_doc(struct sort *sort, yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+
+	do {
+		if (!yaml_parser_parse(parser, &ev))
+			return false;
+
+		switch (ev.type) {
+		case YAML_DOCUMENT_END_EVENT:
+			return true;
+
+		case YAML_MAPPING_START_EVENT:
+			break;
+
+		default:
+			return false;
+		}
+		yaml_event_delete(&ev);
+
+		if (!sort_parse_node(sort, parser))
+			return false;
+	} while(1);
+}
+
+static bool sort_add(struct sort *sort, FILE *file)
+{
+	yaml_parser_t parser;
+	bool done = false;
+	yaml_event_t ev;
+
+	yaml_parser_initialize(&parser);
+	yaml_parser_set_input_file(&parser, file);
+
+	memset(&ev, 0, sizeof(ev));
+	yaml_parser_parse(&parser, &ev);
+	if (ev.type != YAML_STREAM_START_EVENT) {
+		fprintf(stderr, "Parser setup failed\n");
+		return false;
+	}
+	yaml_event_delete(&ev);
+
+	do {
+		if (!yaml_parser_parse(&parser, &ev)) {
+			fprintf(stderr, "Invalid yaml\n");
+			yaml_print_parser_error(&parser, stderr);
+			return false;
+		}
+
+		switch (ev.type) {
+		case YAML_DOCUMENT_START_EVENT:
+			break;
+
+		case YAML_STREAM_END_EVENT:
+			done = true;
+			break;
+
+		default:
+			return false;
+		}
+		yaml_event_delete(&ev);
+
+		sort_parse_doc(sort, &parser);
+	} while (!done);
+
+	yaml_parser_delete(&parser);
+	return true;
+}
+
+static double edges_similarity(const struct edges *ta, const struct edges *tb)
+{
+	uint64_t sab, saa, sbb;
+	const uint8_t *a, *b;
+
+	if (ta == tb)
+		return 1;
+
+	a = ta->tbl;
+	b = tb->tbl;
+	sab = 0;
+	saa = 0;
+	sbb = 0;
+
+	for (unsigned int i = 0; i < SZ_8; i++) {
+		sab += (uint32_t)a[i] * b[i];
+		saa += (uint32_t)a[i] * a[i];
+		sbb += (uint32_t)b[i] * b[i];
+	}
+
+	return sab / (sqrt(saa) * sqrt(sbb));
+}
+
+static void rank_by_dissimilarity(struct sort *sort, FILE *out)
+{
+	const unsigned int count = sort->count;
+	double *M, *dis, *sim;
+	struct edges **edges, **t;
+	bool *used;
+	int last = -1;
+
+	t = edges = malloc(count * sizeof(*edges));
+	for (struct edges *e = sort->edges; e; e = e->next)
+		*t++ = e;
+
+	M = malloc(sizeof(double) * count * (count + 2));
+	dis = M + count * count;
+	sim = dis + count;
+	for (int i = 0; i < count; i++) {
+		dis[i] = 0.;
+		sim[i] = 1.;
+		for (int j = 0; j < i; j++)
+			dis[i] += M[j*count + i];
+		for (int j = i + 1; j < count; j++) {
+			double s = edges_similarity(edges[i], edges[j]);
+			s = 1. - s*s;
+			M[i*count + j] = s;
+			dis[i] += s;
+		}
+	}
+
+	fprintf(out, "---\n");
+
+	used = calloc(count, sizeof(bool));
+	for (int rank = 0; rank < count; rank++) {
+		struct edges *e;
+		double best = -HUGE_VAL;
+		int this = -1;
+
+		for (int i = 0; i < count; i++) {
+			double d;
+
+			if (used[i])
+				continue;
+
+			d = dis[i];
+			if (last != -1) {
+				double s;
+
+				if (last < i)
+					s = M[last * count + i];
+				else
+					s = M[i * count + last];
+
+				s *= sim[i];
+				sim[i] = s;
+
+				d *= sqrt(s);
+			}
+			if (d > best) {
+				best = d;
+				this = i;
+			}
+		}
+
+		e = edges[this];
+		used[this] = true;
+		last = this;
+
+		fprintf(out, "- cmd: |\n    %s\n", e->command);
+		fprintf(out, "  elapsed: %"PRIu64" # %.1fms\n",
+			e->elapsed, 1e-6 * e->elapsed);
+		fprintf(out, "  dissimilarity: %f\n",
+			sqrt(best / (count - rank)));
+	}
+
+	free(M);
+	free(edges);
+}
+
+static void sort(int argc, char **argv)
+{
+	static const struct option longopts[] = {
+		{"output", required_argument, 0, 'o'},
+		{ NULL, 0, NULL, 0 }
+	};
+	FILE *out = stdout;
+	struct sort sort;
+	int i;
+
+	while ((i = getopt_long(argc, argv,
+				"+o:",
+				longopts, NULL)) != -1) {
+		switch (i) {
+		case 'o':
+			if (strcmp(optarg, "-"))
+				out = fopen(optarg, "a");
+			if (!out) {
+				fprintf(stderr,
+					"Unable to open output file '%s'\n",
+					optarg);
+				exit(1);
+			}
+			break;
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	memset(&sort, 0, sizeof(sort));
+
+	if (argc == 0) {
+		sort_add(&sort, stdin);
+	} else {
+		for (i = 0; i < argc; i++) {
+			FILE *in;
+
+			fprintf(stderr, "%d: %s\n", i, argv[i]);
+			in = fopen(argv[i], "r");
+			if (!in) {
+				fprintf(stderr, "unable to open input '%s'\n",
+					argv[i]);
+				exit(1);
+			}
+
+			sort_add(&sort, in);
+
+			fclose(in);
+		}
+	}
+
+	if (!sort.count)
+		return;
+
+	printf("%d edges best, : %s, %"PRIu64" ns, weight=%d\n", sort.count, sort.best->command, sort.best->elapsed, sort.best->weight);
+
+	rank_by_dissimilarity(&sort, out);
+}
+
+int main(int argc, char **argv)
+{
+	static const struct option longopts[] = {
+		{"verbose", no_argument, 0, 'v'},
+		{ NULL, 0, NULL, 0 }
+	};
+	int o;
+
+	while ((o = getopt_long(argc, argv,
+				"+v",
+				longopts, NULL)) != -1) {
+		switch (o) {
+		case 'v':
+			printf("Be verbose!\n");
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (optind == argc) {
+		fprintf(stderr, "no subcommand specified\n");
+		exit(1);
+	}
+
+	argc -= optind;
+	argv += optind;
+	optind = 1;
+
+	if (!strcmp(argv[0], "edges")) {
+		edges(argc, argv);
+	} else if (!strcmp(argv[0], "sort")) {
+		sort(argc, argv);
+	} else {
+		fprintf(stderr, "Unknown command '%s'\n", argv[0]);
+		exit(1);
+	}
+
+	return 0;
+}
diff --git a/tools/igt_kcov_edges.c b/tools/igt_kcov_edges.c
new file mode 100644
index 000000000..0f1fef4bd
--- /dev/null
+++ b/tools/igt_kcov_edges.c
@@ -0,0 +1,144 @@
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include <linux/types.h>
+
+static int (*libc_ioctl)(int fd, unsigned long request, void *argp);
+
+static struct kcov {
+	unsigned long *trace;
+	uint32_t *table;
+	int fd;
+} kcov;
+
+#define KCOV_INIT_TRACE                 _IOR('c', 1, unsigned long)
+#define KCOV_ENABLE                     _IO('c', 100)
+#define   KCOV_TRACE_PC  0
+#define   KCOV_TRACE_CMP 1
+#define KCOV_DISABLE                    _IO('c', 101)
+
+#define DRM_IOCTL_BASE 'd'
+
+#define GOLDEN_RATIO_32 0x61C88647
+#define GOLDEN_RATIO_64 0x61C8864680B583EBull
+
+static inline uint32_t hash_32(uint32_t val, unsigned int bits)
+{
+        return val * GOLDEN_RATIO_32 >> (32 - bits);
+}
+
+static inline uint32_t hash_64(uint64_t val, unsigned int bits)
+{
+        return val * GOLDEN_RATIO_64 >> (64 - bits);
+}
+
+#define hash_long(x, y) hash_64(x, y)
+
+static bool kcov_open(struct kcov *kc, unsigned long count)
+{
+	const char *env;
+	int shm;
+
+	env = getenv("IGT_KCOV_FD");
+	if (!env)
+		return false;
+
+	shm = atoi(env);
+	kc->table = mmap(NULL, sizeof(uint32_t) << 16,
+			 PROT_WRITE, MAP_SHARED, shm, 0);
+	close(shm);
+	if (kc->table == (uint32_t *)MAP_FAILED)
+		return false;
+
+	kc->fd = open("/sys/kernel/debug/kcov", O_RDWR);
+	if (kc->fd < 0) 
+		goto err_shm;
+
+	if (libc_ioctl(kc->fd, KCOV_INIT_TRACE, (void *)count))
+		goto err_close;
+
+	kc->trace = mmap(NULL, count * sizeof(unsigned long),
+			 PROT_WRITE, MAP_SHARED, kc->fd, 0);
+	if (kc->trace == MAP_FAILED)
+		goto err_close;
+
+	return true;
+
+err_close:
+	close(kc->fd);
+err_shm:
+	munmap(kc->table, sizeof(uint32_t) << 16);
+	return false;
+}
+
+static void kcov_enable(struct kcov *kc)
+{
+	libc_ioctl(kc->fd, KCOV_ENABLE, KCOV_TRACE_PC);
+	__atomic_store_n(&kc->trace[0], 0, __ATOMIC_RELAXED);
+}
+
+static unsigned long kcov_disable(struct kcov *kc)
+{
+	unsigned long depth;
+
+	depth = __atomic_load_n(&kc->trace[0], __ATOMIC_RELAXED);
+	if (libc_ioctl(kc->fd, KCOV_DISABLE, 0))
+		depth = 0;
+
+	return depth;
+}
+
+int ioctl(int fd, unsigned long request, ...)
+{
+	static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+	unsigned long count, n, prev;
+	va_list args;
+	void *argp;
+	int res;
+
+	va_start(args, request);
+	argp = va_arg(args, void *);
+	va_end(args);
+
+	if (kcov.fd < 0 || _IOC_TYPE(request) != DRM_IOCTL_BASE)
+		return libc_ioctl(fd, request, argp);
+
+	pthread_mutex_lock(&mutex);
+	kcov_enable(&kcov);
+
+	res = libc_ioctl(fd, request, argp);
+
+	count = kcov_disable(&kcov);
+	prev = hash_long(kcov.trace[1], 16);
+	for (n = 2; n <= count; n++) {
+		unsigned long loc = hash_long(kcov.trace[n], 16);
+
+		kcov.table[prev ^ loc]++;
+		prev = loc >> 1;
+	}
+	kcov.table[0] |= 1;
+	pthread_mutex_unlock(&mutex);
+
+	return res;
+}
+
+__attribute__((constructor))
+static void init(void)
+{
+	libc_ioctl = dlsym(RTLD_NEXT, "ioctl");
+
+	if (!kcov_open(&kcov, 64 << 10))
+		kcov.fd = -1;
+}
-- 
2.17.0

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [igt-dev] ✗ Fi.CI.BAT: failure for RFC tools: capture execution pathways
  2018-04-20 21:50 [igt-dev] [PATCH igt] RFC tools: capture execution pathways Chris Wilson
@ 2018-04-20 22:03 ` Patchwork
  2018-04-23 11:29 ` [igt-dev] [PATCH igt] " Joonas Lahtinen
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Patchwork @ 2018-04-20 22:03 UTC (permalink / raw)
  To: Chris Wilson; +Cc: igt-dev

== Series Details ==

Series: RFC tools: capture execution pathways
URL   : https://patchwork.freedesktop.org/series/42056/
State : failure

== Summary ==

Applying: RFC tools: capture execution pathways
Using index info to reconstruct a base tree...
M	tools/Makefile.am
Falling back to patching base and 3-way merge...
Auto-merging tools/Makefile.am
CONFLICT (content): Merge conflict in tools/Makefile.am
Patch failed at 0001 RFC tools: capture execution pathways
The copy of the patch that failed is found in: .git/rebase-apply/patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [igt-dev] [PATCH igt] RFC tools: capture execution pathways
  2018-04-20 21:50 [igt-dev] [PATCH igt] RFC tools: capture execution pathways Chris Wilson
  2018-04-20 22:03 ` [igt-dev] ✗ Fi.CI.BAT: failure for " Patchwork
@ 2018-04-23 11:29 ` Joonas Lahtinen
  2018-04-23 11:53   ` Chris Wilson
  2018-04-23 15:13 ` [igt-dev] ✗ Fi.CI.BAT: failure for RFC tools: capture execution pathways (rev2) Patchwork
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 11+ messages in thread
From: Joonas Lahtinen @ 2018-04-23 11:29 UTC (permalink / raw)
  To: Chris Wilson, igt-dev

Two typos: s/sortest/shortest/, s/asci85/ascii85/

Other than that, makes sense. Did not dive deep into the utility funcs
or validity of the algorithms.

Anything stopping to polish and merge?

Regards, Joonas

Quoting Chris Wilson (2018-04-21 00:50:33)
> igt_kcov edges -o edges.yaml command-to-trace args
> ...
> igt_kcov sort -o sorted.yaml edges.yaml
> 
> Requires CONFIG_KCOV
> 
> Use LD_PRELOAD to wrap calls to DRM ioctls and capture the execution
> trace of all basic blocks invoked directly from the syscall. (Key
> limitation!) From the chain of basic blocks, the "edges" are computed
> and the number of times each edge is hit is stored in a vector (modulo a
> large hash). The goal then is to select a series of tests that execute
> the most unique pathways in the sortest amount of time. To do this we
> compare the similarity of the coverage vectors between all commands, and
> try to preferentially pick those that are dissimilar from the rest.
> 
> * Direct execution pathways from syscall is a huge limitation for
> evaluating general testing of driver pathways, but is not so huge when
> myopically focusing on the ABI as say used by mesa.
> 
> ** Caveat lector. Hastily thrown together.
> ---
>  tools/Makefile.am      |  10 +-
>  tools/igt_kcov.c       | 905 +++++++++++++++++++++++++++++++++++++++++
>  tools/igt_kcov_edges.c | 144 +++++++
>  3 files changed, 1058 insertions(+), 1 deletion(-)
>  create mode 100644 tools/igt_kcov.c
>  create mode 100644 tools/igt_kcov_edges.c
> 
> diff --git a/tools/Makefile.am b/tools/Makefile.am
> index a0b016ddd..f0c2ef3df 100644
> --- a/tools/Makefile.am
> +++ b/tools/Makefile.am
> @@ -1,6 +1,7 @@
>  include Makefile.sources
>  
> -bin_PROGRAMS = $(tools_prog_lists)
> +bin_PROGRAMS = $(tools_prog_lists) igt_kcov
> +lib_LTLIBRARIES = igt_kcov_edges.la
>  
>  if HAVE_LIBDRM_INTEL
>  bin_PROGRAMS += $(LIBDRM_INTEL_BIN)
> @@ -30,6 +31,13 @@ intel_aubdump_la_LIBADD = $(top_builddir)/lib/libintel_tools.la -ldl
>  
>  intel_gpu_top_LDADD = $(top_builddir)/lib/libigt_perf.la
>  
> +igt_kcov_SOURCES = igt_kcov.c
> +igt_kcov_LDADD = -lyaml -lz -lrt -lm
> +
> +igt_kcov_edges_la_SOURCES = igt_kcov_edges.c
> +igt_kcov_edges_la_LDFLAGS = -module -no-undefined -avoid-version
> +igt_kcov_edges_la_LIBADD = -ldl
> +
>  bin_SCRIPTS = intel_aubdump
>  CLEANFILES = $(bin_SCRIPTS)
>  
> diff --git a/tools/igt_kcov.c b/tools/igt_kcov.c
> new file mode 100644
> index 000000000..9fb522c20
> --- /dev/null
> +++ b/tools/igt_kcov.c
> @@ -0,0 +1,905 @@
> +#include <sys/types.h>
> +#include <sys/mman.h>
> +#include <sys/stat.h>
> +#include <sys/wait.h>
> +
> +#include <ctype.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <getopt.h>
> +#include <inttypes.h>
> +#include <math.h>
> +#include <stdbool.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <time.h>
> +#include <unistd.h>
> +
> +#include <yaml.h>
> +#include <zlib.h>
> +
> +#define SZ_8 (1 << 16)
> +#define SZ_32 (sizeof(uint32_t) * SZ_8)
> +
> +static pid_t child = 0;
> +
> +static void sighandler(int sig)
> +{
> +       kill(sig, child);
> +}
> +
> +static uint64_t gettime(void)
> +{
> +       struct timespec ts;
> +
> +       clock_gettime(CLOCK_MONOTONIC, &ts);
> +
> +       return ts.tv_sec * 1000000000 + ts.tv_nsec;
> +}
> +
> +static int edges_exec(const char *preload, char **argv, uint64_t *elapsed)
> +{
> +       char buf[10];
> +       int status;
> +       int shm;
> +       int ret;
> +
> +       if (access("/sys/kernel/debug/kcov", W_OK)) {
> +               fprintf(stderr, "kcov not found in debugfs\n");
> +               return -ENOENT;
> +       }
> +
> +       shm = memfd_create("igt_kcov", 0);
> +       if (shm == -1)
> +               return -errno;
> +
> +       ftruncate(shm, SZ_32);
> +
> +       switch ((child = fork())) {
> +       case 0: /* child */
> +               sprintf(buf, "%d", shm);
> +               setenv("IGT_KCOV_FD", buf, 1);
> +               setenv("LD_PRELOAD", preload, 1);
> +               exit(execvp(argv[0], argv));
> +               break;
> +
> +       case -1:
> +               ret = -errno;
> +               break;
> +
> +       default:
> +               signal(SIGINT, sighandler);
> +
> +               *elapsed = -gettime();
> +               do {
> +                       ret = waitpid(child, &status, 0);
> +                       if (ret == -1)
> +                               ret = -errno;
> +               } while (ret == -EINTR);
> +               *elapsed += gettime();
> +
> +               signal(SIGINT, SIG_DFL);
> +               child = 0;
> +       }
> +
> +       if (ret < 0) {
> +               close(shm);
> +               shm = ret;
> +       }
> +
> +       return shm;
> +}
> +
> +static inline unsigned long __fls(unsigned long word)
> +{
> +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86__) || defined(__x86_64__))
> +       asm("bsr %1,%0"
> +           : "=r" (word)
> +           : "rm" (word));
> +       return word;
> +#else
> +       unsigned int v = 0;
> +
> +       while (word >>= 1)
> +               v++;
> +
> +       return v;
> +#endif
> +}
> +
> +static uint8_t lower_u32(uint32_t x)
> +{
> +       if (x < 16)
> +               return x;
> +       else
> +               return (x >> (__fls(x) - 2)) + ((__fls(x) - 1) << 2);
> +}
> +
> +static uint8_t *lower_edges(int shm)
> +{
> +       uint8_t *lower;
> +       uint32_t *tbl;
> +       unsigned int n;
> +
> +       tbl = mmap(NULL, SZ_32, PROT_READ, MAP_SHARED, shm, 0);
> +       if (tbl == MAP_FAILED)
> +               return NULL;
> +
> +       if (tbl[0] == 0) /* empty */
> +               goto out;
> +
> +       lower = malloc(SZ_8);
> +       if (!lower)
> +               goto out;
> +
> +       for (n = 0; n < 1 << 16; n++)
> +               lower[n] = lower_u32(tbl[n]);
> +
> +out:
> +       munmap(tbl, SZ_32);
> +       return lower;
> +}
> +
> +static bool ascii85_encode(uint32_t in, char *out)
> +{
> +       int i;
> +
> +       if (in == 0)
> +               return false;
> +
> +       for (i = 5; i--; ) {
> +               out[i] = '!' + in % 85;
> +               in /= 85;
> +       }
> +
> +       return true;
> +}
> +
> +static char *edges_to_ascii85(uint8_t *tbl)
> +{
> +       z_stream zs;
> +       uint32_t *p;
> +       void *out;
> +       char *str, *s;
> +       int sz;
> +
> +       sz = SZ_8 * 3 /2;
> +       out = malloc(sz);
> +       if (!out)
> +               return NULL;
> +
> +       memset(&zs, 0, sizeof(zs));
> +       if (deflateInit(&zs, 9)) {
> +               free(out);
> +               return NULL;
> +       }
> +
> +       zs.next_in = tbl;
> +       zs.avail_in = SZ_8;
> +       zs.total_in = 0;
> +       zs.avail_out = sz;
> +       zs.total_out = 0;
> +       zs.next_out = out;
> +
> +       deflate(&zs, Z_FINISH);
> +       deflateEnd(&zs);
> +
> +       if (zs.total_out & 3)
> +               memset((char *)out + zs.total_out, 0, 4 - (zs.total_out & 3));
> +       zs.total_out = (zs.total_out + 3) / 4;
> +
> +       str = malloc(zs.total_out * 5 + 1);
> +       if (!str) {
> +               free(out);
> +               return NULL;
> +       }
> +
> +       p = out;
> +       s = str;
> +       for (int i = 0; i < zs.total_out; i++) {
> +               if (ascii85_encode(*p++, s))
> +                       s += 5;
> +               else
> +                       *s++ = 'z';
> +       }
> +       *s++ = '\0';
> +       free(out);
> +
> +       return str;
> +}
> +
> +static void edges(int argc, char **argv)
> +{
> +       static const struct option longopts[] = {
> +               {"output", required_argument, 0, 'o'},
> +               {"preload", required_argument, 0, 'p'},
> +               { NULL, 0, NULL, 0 }
> +       };
> +       const char *preload = "/tmp/igt_kcov_edges.so";
> +       FILE *out = stdout;
> +       uint64_t elapsed;
> +       uint8_t *tbl;
> +       char *str, *s;
> +       int shm, i;
> +
> +       while ((i = getopt_long(argc, argv,
> +                               "+o:",
> +                               longopts, NULL)) != -1) {
> +               switch (i) {
> +               case 'o':
> +                       if (strcmp(optarg, "-"))
> +                               out = fopen(optarg, "a");
> +                       if (!out) {
> +                               fprintf(stderr,
> +                                       "Unable to open output file '%s'\n",
> +                                       optarg);
> +                               exit(1);
> +                       }
> +                       break;
> +               case 'p':
> +                       preload = optarg;
> +                       break;
> +               }
> +       }
> +       argc -= optind;
> +       argv += optind;
> +
> +       if (argc < 1) {
> +               fprintf(stderr,
> +                       "usage: igt_kcov edges [options] program-to-edges args...\n");
> +               exit(1);
> +       }
> +
> +       shm = edges_exec(preload, argv, &elapsed);
> +       if (shm < 0) {
> +               fprintf(stderr,
> +                       "Execution of %s failed: err=%d\n",
> +                       argv[0], shm);
> +               exit(1);
> +       }
> +
> +       tbl = lower_edges(shm);
> +       close(shm);
> +       if (!tbl)
> +               exit(1);
> +
> +       str = edges_to_ascii85(tbl);
> +       fprintf(out, "---\n");
> +       fprintf(out, "cmd: |  \n");
> +       for (i = 0; i < argc; i++) {
> +               fprintf(out, " '");
> +               for (s = argv[i]; *s; s++) {
> +                       if (*s == '\'')
> +                               fprintf(out, "\\\'");
> +                       else
> +                               fprintf(out, "%c", *s);
> +               }
> +               fprintf(out, "'");
> +       }
> +       fprintf(out, "\n");
> +
> +       fprintf(out, "elapsed: %"PRIu64" # %.1fms\n", elapsed, 1e-6 * elapsed);
> +
> +       fprintf(out, "edges: !!asci85.gz |\n");
> +       i = strlen(str);
> +       s = str;
> +       while (i) {
> +               int len = i > 70 ? 70 : i;
> +               char tmp;
> +
> +               tmp = s[len];
> +               s[len] = '\0';
> +               fprintf(out, "  %s\n", s);
> +               s[len] = tmp;
> +
> +               s += len;
> +               i -= len;
> +       }
> +
> +       free(str);
> +}
> +
> +static unsigned long zlib_inflate(void *in, unsigned long len,
> +                                 void *ptr, unsigned long max)
> +{
> +       struct z_stream_s zstream;
> +
> +       memset(&zstream, 0, sizeof(zstream));
> +
> +       zstream.next_in = in;
> +       zstream.avail_in = len;
> +
> +       if (inflateInit(&zstream) != Z_OK)
> +               return 0;
> +
> +       zstream.next_out = ptr;
> +       zstream.avail_out = max;
> +
> +       switch (inflate(&zstream, Z_SYNC_FLUSH)) {
> +       case Z_STREAM_END:
> +       case Z_OK:
> +               break;
> +       default:
> +               zstream.total_out = 0;
> +               break;
> +       }
> +
> +       inflateEnd(&zstream);
> +       return zstream.total_out;
> +}
> +
> +static unsigned long ascii85_decode(const char *in,
> +                                   void *ptr, unsigned long max)
> +{
> +       unsigned long sz = max / sizeof(uint32_t);
> +       unsigned long len = 0;
> +       uint32_t *out;
> +
> +       out = malloc(sz * sizeof(uint32_t));
> +       if (out == NULL)
> +               return 0;
> +
> +       while (*in) {
> +               uint32_t v = 0;
> +
> +               if (isspace(*in)) {
> +                       in++;
> +                       continue;
> +               }
> +
> +               if (*in < '!' || *in > 'z') {
> +                       fprintf(stderr, "Invalid value in ascii85 block\n");
> +                       free(out);
> +                       return 0;
> +               }
> +
> +               if (len == sz) {
> +                       sz *= 2;
> +                       out = realloc(out, sz * sizeof(uint32_t));
> +                       if (out == NULL)
> +                               return 0;
> +               }
> +
> +               if (*in == 'z') {
> +                       in++;
> +               } else {
> +                       v += in[0] - 33; v *= 85;
> +                       v += in[1] - 33; v *= 85;
> +                       v += in[2] - 33; v *= 85;
> +                       v += in[3] - 33; v *= 85;
> +                       v += in[4] - 33;
> +                       in += 5;
> +               }
> +               out[len++] = v;
> +       }
> +
> +       len = zlib_inflate(out, len * sizeof(*out), ptr, max);
> +       free(out);
> +
> +       return len;
> +}
> +
> +static void yaml_print_parser_error(yaml_parser_t *parser, FILE *stream)
> +{
> +       switch (parser->error) {
> +       case YAML_MEMORY_ERROR:
> +               fprintf(stderr, "Memory error: Not enough memory for parsing\n");
> +               break;
> +
> +       case YAML_READER_ERROR:
> +               if (parser->problem_value != -1) {
> +                       fprintf(stderr, "Reader error: %s: #%X at %zd\n", parser->problem,
> +                               parser->problem_value, parser->problem_offset);
> +               } else {
> +                       fprintf(stderr, "Reader error: %s at %zd\n", parser->problem,
> +                               parser->problem_offset);
> +               }
> +               break;
> +
> +       case YAML_SCANNER_ERROR:
> +               if (parser->context) {
> +                       fprintf(stderr, "Scanner error: %s at line %lu, column %lu\n"
> +                               "%s at line %lu, column %lu\n", parser->context,
> +                               parser->context_mark.line+1, parser->context_mark.column+1,
> +                               parser->problem, parser->problem_mark.line+1,
> +                               parser->problem_mark.column+1);
> +               } else {
> +                       fprintf(stderr, "Scanner error: %s at line %lu, column %lu\n",
> +                               parser->problem, parser->problem_mark.line+1,
> +                               parser->problem_mark.column+1);
> +               }
> +               break;
> +
> +       case YAML_PARSER_ERROR:
> +               if (parser->context) {
> +                       fprintf(stderr, "Parser error: %s at line %lu, column %lu\n"
> +                               "%s at line %lu, column %lu\n", parser->context,
> +                               parser->context_mark.line+1, parser->context_mark.column+1,
> +                               parser->problem, parser->problem_mark.line+1,
> +                               parser->problem_mark.column+1);
> +               } else {
> +                       fprintf(stderr, "Parser error: %s at line %lu, column %lu\n",
> +                               parser->problem, parser->problem_mark.line+1,
> +                               parser->problem_mark.column+1);
> +               }
> +               break;
> +
> +       default:
> +               /* Couldn't happen. */
> +               fprintf(stderr, "Internal error\n");
> +               break;
> +       }
> +}
> +
> +struct edges {
> +       struct edges *next;
> +
> +       char *command;
> +       uint64_t elapsed;
> +
> +       unsigned int weight;
> +
> +       uint8_t tbl[SZ_8];
> +};
> +
> +struct sort {
> +       struct edges *edges;
> +       unsigned int count;
> +
> +       unsigned int max_weight;
> +       struct edges *best;
> +};
> +
> +static bool sort_parse_command(struct sort *sort,
> +                              struct edges *e,
> +                              yaml_parser_t *parser)
> +{
> +       yaml_event_t ev;
> +       const char *s;
> +       int len;
> +
> +       if (!yaml_parser_parse(parser, &ev))
> +               return false;
> +
> +       switch (ev.type) {
> +       case YAML_SCALAR_EVENT:
> +               break;
> +
> +       default:
> +               return false;
> +       }
> +
> +
> +       s = (const char *)ev.data.scalar.value;
> +       len = strlen(s);
> +       while (s[len - 1] == '\n')
> +               len--;
> +       e->command = malloc(len + 1);
> +       if (e->command) {
> +               memcpy(e->command, s, len);
> +               e->command[len] = '\0';
> +       }
> +       yaml_event_delete(&ev);
> +
> +       return true;
> +}
> +
> +static bool sort_parse_elapsed(struct sort *sort,
> +                              struct edges *e,
> +                              yaml_parser_t *parser)
> +{
> +       yaml_event_t ev;
> +       const char *s;
> +
> +       if (!yaml_parser_parse(parser, &ev))
> +               return false;
> +
> +       switch (ev.type) {
> +       case YAML_SCALAR_EVENT:
> +               break;
> +
> +       default:
> +               return false;
> +       }
> +
> +       s = (const char *)ev.data.scalar.value;
> +       e->elapsed = strtoull(s, NULL, 0);
> +       yaml_event_delete(&ev);
> +
> +       return true;
> +}
> +
> +static unsigned int bitmap_weight(const void *bitmap, unsigned int bits)
> +{
> +       const uint32_t *b = bitmap;
> +       unsigned int k, lim = bits / 32;
> +       unsigned int w = 0;
> +
> +       for (k = 0; k < lim; k++)
> +               w += __builtin_popcount(b[k]);
> +
> +       if (bits % 32)
> +               w += __builtin_popcount(b[k] << (32 - bits % 32));
> +
> +       return w;
> +}
> +
> +static bool sort_parse_edges(struct sort *sort,
> +                            struct edges *e,
> +                            yaml_parser_t *parser)
> +{
> +       yaml_event_t ev;
> +       const char *s;
> +
> +       if (!yaml_parser_parse(parser, &ev))
> +               return false;
> +
> +       switch (ev.type) {
> +       case YAML_SCALAR_EVENT:
> +               break;
> +
> +       default:
> +               return false;
> +       }
> +
> +       s = (const char *)ev.data.scalar.value;
> +       if (ascii85_decode(s, e->tbl, sizeof(e->tbl)))
> +               e->weight = bitmap_weight(e->tbl, sizeof(e->tbl) * 8);
> +       yaml_event_delete(&ev);
> +
> +       return true;
> +}
> +
> +static bool edges_valid(const struct edges *e)
> +{
> +       if (!e->command)
> +               return false;
> +
> +       if (!e->weight)
> +               return false;
> +
> +       if (!e->elapsed)
> +               return false;
> +
> +       return true; /* good enough at least */
> +}
> +
> +static bool sort_add_edges(struct sort *sort, struct edges *e)
> +{
> +       if (!edges_valid(e))
> +               return false;
> +
> +       e->next = sort->edges;
> +       sort->edges = e;
> +
> +       if (e->weight > sort->max_weight) {
> +               sort->max_weight = e->weight;
> +               sort->best = e;
> +       }
> +
> +       sort->count++;
> +
> +       return true;
> +}
> +
> +static bool sort_parse_node(struct sort *sort, yaml_parser_t *parser)
> +{
> +       struct edges *e;
> +       yaml_event_t ev;
> +       char *s;
> +
> +       e = malloc(sizeof(*e));
> +       if (!e)
> +               return false;
> +
> +       e->weight = 0;
> +
> +       do {
> +               if (!yaml_parser_parse(parser, &ev))
> +                       goto err;
> +
> +               switch (ev.type) {
> +               case YAML_MAPPING_END_EVENT:
> +                       if (!sort_add_edges(sort, e))
> +                               goto err;
> +
> +                       return true;
> +
> +               case YAML_SCALAR_EVENT:
> +                       break;
> +
> +               default:
> +                       goto err;
> +               }
> +
> +               s = (char *)ev.data.scalar.value;
> +               if (!strcmp(s, "cmd")) {
> +                       sort_parse_command(sort, e, parser);
> +               } else if (!strcmp(s, "elapsed")) {
> +                       sort_parse_elapsed(sort, e, parser);
> +               } else if (!strcmp(s, "edges")) {
> +                       sort_parse_edges(sort, e, parser);
> +               } else {
> +                       fprintf(stderr,
> +                               "Unknown element in edges file: %s\n",
> +                               s);
> +               }
> +
> +               yaml_event_delete(&ev);
> +       } while (1);
> +
> +err:
> +       free(e);
> +       return false;
> +}
> +
> +static bool sort_parse_doc(struct sort *sort, yaml_parser_t *parser)
> +{
> +       yaml_event_t ev;
> +
> +       do {
> +               if (!yaml_parser_parse(parser, &ev))
> +                       return false;
> +
> +               switch (ev.type) {
> +               case YAML_DOCUMENT_END_EVENT:
> +                       return true;
> +
> +               case YAML_MAPPING_START_EVENT:
> +                       break;
> +
> +               default:
> +                       return false;
> +               }
> +               yaml_event_delete(&ev);
> +
> +               if (!sort_parse_node(sort, parser))
> +                       return false;
> +       } while(1);
> +}
> +
> +static bool sort_add(struct sort *sort, FILE *file)
> +{
> +       yaml_parser_t parser;
> +       bool done = false;
> +       yaml_event_t ev;
> +
> +       yaml_parser_initialize(&parser);
> +       yaml_parser_set_input_file(&parser, file);
> +
> +       memset(&ev, 0, sizeof(ev));
> +       yaml_parser_parse(&parser, &ev);
> +       if (ev.type != YAML_STREAM_START_EVENT) {
> +               fprintf(stderr, "Parser setup failed\n");
> +               return false;
> +       }
> +       yaml_event_delete(&ev);
> +
> +       do {
> +               if (!yaml_parser_parse(&parser, &ev)) {
> +                       fprintf(stderr, "Invalid yaml\n");
> +                       yaml_print_parser_error(&parser, stderr);
> +                       return false;
> +               }
> +
> +               switch (ev.type) {
> +               case YAML_DOCUMENT_START_EVENT:
> +                       break;
> +
> +               case YAML_STREAM_END_EVENT:
> +                       done = true;
> +                       break;
> +
> +               default:
> +                       return false;
> +               }
> +               yaml_event_delete(&ev);
> +
> +               sort_parse_doc(sort, &parser);
> +       } while (!done);
> +
> +       yaml_parser_delete(&parser);
> +       return true;
> +}
> +
> +static double edges_similarity(const struct edges *ta, const struct edges *tb)
> +{
> +       uint64_t sab, saa, sbb;
> +       const uint8_t *a, *b;
> +
> +       if (ta == tb)
> +               return 1;
> +
> +       a = ta->tbl;
> +       b = tb->tbl;
> +       sab = 0;
> +       saa = 0;
> +       sbb = 0;
> +
> +       for (unsigned int i = 0; i < SZ_8; i++) {
> +               sab += (uint32_t)a[i] * b[i];
> +               saa += (uint32_t)a[i] * a[i];
> +               sbb += (uint32_t)b[i] * b[i];
> +       }
> +
> +       return sab / (sqrt(saa) * sqrt(sbb));
> +}
> +
> +static void rank_by_dissimilarity(struct sort *sort, FILE *out)
> +{
> +       const unsigned int count = sort->count;
> +       double *M, *dis, *sim;
> +       struct edges **edges, **t;
> +       bool *used;
> +       int last = -1;
> +
> +       t = edges = malloc(count * sizeof(*edges));
> +       for (struct edges *e = sort->edges; e; e = e->next)
> +               *t++ = e;
> +
> +       M = malloc(sizeof(double) * count * (count + 2));
> +       dis = M + count * count;
> +       sim = dis + count;
> +       for (int i = 0; i < count; i++) {
> +               dis[i] = 0.;
> +               sim[i] = 1.;
> +               for (int j = 0; j < i; j++)
> +                       dis[i] += M[j*count + i];
> +               for (int j = i + 1; j < count; j++) {
> +                       double s = edges_similarity(edges[i], edges[j]);
> +                       s = 1. - s*s;
> +                       M[i*count + j] = s;
> +                       dis[i] += s;
> +               }
> +       }
> +
> +       fprintf(out, "---\n");
> +
> +       used = calloc(count, sizeof(bool));
> +       for (int rank = 0; rank < count; rank++) {
> +               struct edges *e;
> +               double best = -HUGE_VAL;
> +               int this = -1;
> +
> +               for (int i = 0; i < count; i++) {
> +                       double d;
> +
> +                       if (used[i])
> +                               continue;
> +
> +                       d = dis[i];
> +                       if (last != -1) {
> +                               double s;
> +
> +                               if (last < i)
> +                                       s = M[last * count + i];
> +                               else
> +                                       s = M[i * count + last];
> +
> +                               s *= sim[i];
> +                               sim[i] = s;
> +
> +                               d *= sqrt(s);
> +                       }
> +                       if (d > best) {
> +                               best = d;
> +                               this = i;
> +                       }
> +               }
> +
> +               e = edges[this];
> +               used[this] = true;
> +               last = this;
> +
> +               fprintf(out, "- cmd: |\n    %s\n", e->command);
> +               fprintf(out, "  elapsed: %"PRIu64" # %.1fms\n",
> +                       e->elapsed, 1e-6 * e->elapsed);
> +               fprintf(out, "  dissimilarity: %f\n",
> +                       sqrt(best / (count - rank)));
> +       }
> +
> +       free(M);
> +       free(edges);
> +}
> +
> +static void sort(int argc, char **argv)
> +{
> +       static const struct option longopts[] = {
> +               {"output", required_argument, 0, 'o'},
> +               { NULL, 0, NULL, 0 }
> +       };
> +       FILE *out = stdout;
> +       struct sort sort;
> +       int i;
> +
> +       while ((i = getopt_long(argc, argv,
> +                               "+o:",
> +                               longopts, NULL)) != -1) {
> +               switch (i) {
> +               case 'o':
> +                       if (strcmp(optarg, "-"))
> +                               out = fopen(optarg, "a");
> +                       if (!out) {
> +                               fprintf(stderr,
> +                                       "Unable to open output file '%s'\n",
> +                                       optarg);
> +                               exit(1);
> +                       }
> +                       break;
> +               }
> +       }
> +       argc -= optind;
> +       argv += optind;
> +
> +       memset(&sort, 0, sizeof(sort));
> +
> +       if (argc == 0) {
> +               sort_add(&sort, stdin);
> +       } else {
> +               for (i = 0; i < argc; i++) {
> +                       FILE *in;
> +
> +                       fprintf(stderr, "%d: %s\n", i, argv[i]);
> +                       in = fopen(argv[i], "r");
> +                       if (!in) {
> +                               fprintf(stderr, "unable to open input '%s'\n",
> +                                       argv[i]);
> +                               exit(1);
> +                       }
> +
> +                       sort_add(&sort, in);
> +
> +                       fclose(in);
> +               }
> +       }
> +
> +       if (!sort.count)
> +               return;
> +
> +       printf("%d edges best, : %s, %"PRIu64" ns, weight=%d\n", sort.count, sort.best->command, sort.best->elapsed, sort.best->weight);
> +
> +       rank_by_dissimilarity(&sort, out);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +       static const struct option longopts[] = {
> +               {"verbose", no_argument, 0, 'v'},
> +               { NULL, 0, NULL, 0 }
> +       };
> +       int o;
> +
> +       while ((o = getopt_long(argc, argv,
> +                               "+v",
> +                               longopts, NULL)) != -1) {
> +               switch (o) {
> +               case 'v':
> +                       printf("Be verbose!\n");
> +                       break;
> +               default:
> +                       break;
> +               }
> +       }
> +
> +       if (optind == argc) {
> +               fprintf(stderr, "no subcommand specified\n");
> +               exit(1);
> +       }
> +
> +       argc -= optind;
> +       argv += optind;
> +       optind = 1;
> +
> +       if (!strcmp(argv[0], "edges")) {
> +               edges(argc, argv);
> +       } else if (!strcmp(argv[0], "sort")) {
> +               sort(argc, argv);
> +       } else {
> +               fprintf(stderr, "Unknown command '%s'\n", argv[0]);
> +               exit(1);
> +       }
> +
> +       return 0;
> +}
> diff --git a/tools/igt_kcov_edges.c b/tools/igt_kcov_edges.c
> new file mode 100644
> index 000000000..0f1fef4bd
> --- /dev/null
> +++ b/tools/igt_kcov_edges.c
> @@ -0,0 +1,144 @@
> +#include <sys/ioctl.h>
> +#include <sys/mman.h>
> +#include <sys/types.h>
> +
> +#include <dlfcn.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdarg.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdint.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <pthread.h>
> +
> +#include <linux/types.h>
> +
> +static int (*libc_ioctl)(int fd, unsigned long request, void *argp);
> +
> +static struct kcov {
> +       unsigned long *trace;
> +       uint32_t *table;
> +       int fd;
> +} kcov;
> +
> +#define KCOV_INIT_TRACE                 _IOR('c', 1, unsigned long)
> +#define KCOV_ENABLE                     _IO('c', 100)
> +#define   KCOV_TRACE_PC  0
> +#define   KCOV_TRACE_CMP 1
> +#define KCOV_DISABLE                    _IO('c', 101)
> +
> +#define DRM_IOCTL_BASE 'd'
> +
> +#define GOLDEN_RATIO_32 0x61C88647
> +#define GOLDEN_RATIO_64 0x61C8864680B583EBull
> +
> +static inline uint32_t hash_32(uint32_t val, unsigned int bits)
> +{
> +        return val * GOLDEN_RATIO_32 >> (32 - bits);
> +}
> +
> +static inline uint32_t hash_64(uint64_t val, unsigned int bits)
> +{
> +        return val * GOLDEN_RATIO_64 >> (64 - bits);
> +}
> +
> +#define hash_long(x, y) hash_64(x, y)
> +
> +static bool kcov_open(struct kcov *kc, unsigned long count)
> +{
> +       const char *env;
> +       int shm;
> +
> +       env = getenv("IGT_KCOV_FD");
> +       if (!env)
> +               return false;
> +
> +       shm = atoi(env);
> +       kc->table = mmap(NULL, sizeof(uint32_t) << 16,
> +                        PROT_WRITE, MAP_SHARED, shm, 0);
> +       close(shm);
> +       if (kc->table == (uint32_t *)MAP_FAILED)
> +               return false;
> +
> +       kc->fd = open("/sys/kernel/debug/kcov", O_RDWR);
> +       if (kc->fd < 0) 
> +               goto err_shm;
> +
> +       if (libc_ioctl(kc->fd, KCOV_INIT_TRACE, (void *)count))
> +               goto err_close;
> +
> +       kc->trace = mmap(NULL, count * sizeof(unsigned long),
> +                        PROT_WRITE, MAP_SHARED, kc->fd, 0);
> +       if (kc->trace == MAP_FAILED)
> +               goto err_close;
> +
> +       return true;
> +
> +err_close:
> +       close(kc->fd);
> +err_shm:
> +       munmap(kc->table, sizeof(uint32_t) << 16);
> +       return false;
> +}
> +
> +static void kcov_enable(struct kcov *kc)
> +{
> +       libc_ioctl(kc->fd, KCOV_ENABLE, KCOV_TRACE_PC);
> +       __atomic_store_n(&kc->trace[0], 0, __ATOMIC_RELAXED);
> +}
> +
> +static unsigned long kcov_disable(struct kcov *kc)
> +{
> +       unsigned long depth;
> +
> +       depth = __atomic_load_n(&kc->trace[0], __ATOMIC_RELAXED);
> +       if (libc_ioctl(kc->fd, KCOV_DISABLE, 0))
> +               depth = 0;
> +
> +       return depth;
> +}
> +
> +int ioctl(int fd, unsigned long request, ...)
> +{
> +       static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
> +       unsigned long count, n, prev;
> +       va_list args;
> +       void *argp;
> +       int res;
> +
> +       va_start(args, request);
> +       argp = va_arg(args, void *);
> +       va_end(args);
> +
> +       if (kcov.fd < 0 || _IOC_TYPE(request) != DRM_IOCTL_BASE)
> +               return libc_ioctl(fd, request, argp);
> +
> +       pthread_mutex_lock(&mutex);
> +       kcov_enable(&kcov);
> +
> +       res = libc_ioctl(fd, request, argp);
> +
> +       count = kcov_disable(&kcov);
> +       prev = hash_long(kcov.trace[1], 16);
> +       for (n = 2; n <= count; n++) {
> +               unsigned long loc = hash_long(kcov.trace[n], 16);
> +
> +               kcov.table[prev ^ loc]++;
> +               prev = loc >> 1;
> +       }
> +       kcov.table[0] |= 1;
> +       pthread_mutex_unlock(&mutex);
> +
> +       return res;
> +}
> +
> +__attribute__((constructor))
> +static void init(void)
> +{
> +       libc_ioctl = dlsym(RTLD_NEXT, "ioctl");
> +
> +       if (!kcov_open(&kcov, 64 << 10))
> +               kcov.fd = -1;
> +}
> -- 
> 2.17.0
> 
> _______________________________________________
> igt-dev mailing list
> igt-dev@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/igt-dev
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [igt-dev] [PATCH igt] RFC tools: capture execution pathways
  2018-04-23 11:29 ` [igt-dev] [PATCH igt] " Joonas Lahtinen
@ 2018-04-23 11:53   ` Chris Wilson
  2018-04-23 13:06     ` [igt-dev] [PATCH i-g-t 1/1] meson'd igt_kcov Petri Latvala
  0 siblings, 1 reply; 11+ messages in thread
From: Chris Wilson @ 2018-04-23 11:53 UTC (permalink / raw)
  To: Joonas Lahtinen, igt-dev

Quoting Joonas Lahtinen (2018-04-23 12:29:21)
> Two typos: s/sortest/shortest/, s/asci85/ascii85/
> 
> Other than that, makes sense. Did not dive deep into the utility funcs
> or validity of the algorithms.
> 
> Anything stopping to polish and merge?

meson. No idea how to go about adding it to that build generator.
-Chris
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [igt-dev] [PATCH i-g-t 1/1] meson'd igt_kcov
  2018-04-23 11:53   ` Chris Wilson
@ 2018-04-23 13:06     ` Petri Latvala
  0 siblings, 0 replies; 11+ messages in thread
From: Petri Latvala @ 2018-04-23 13:06 UTC (permalink / raw)
  To: igt-dev

---

TODO: Figure out how to make meson _not_ force the module name to have
a 'lib' prefix.


meson.build       |  1 +
 tools/meson.build | 12 ++++++++++++
 2 files changed, 13 insertions(+)

diff --git a/meson.build b/meson.build
index 5b783e5d..8cb029ad 100644
--- a/meson.build
+++ b/meson.build
@@ -89,6 +89,7 @@ math = cc.find_library('m')
 realtime = cc.find_library('rt')
 dlsym = cc.find_library('dl')
 zlib = cc.find_library('z')
+yaml = cc.find_library('yaml', required: false)
 
 if cc.has_header('linux/kd.h')
 	config.set('HAVE_LINUX_KD_H', 1)
diff --git a/tools/meson.build b/tools/meson.build
index bd2d313d..757f9c23 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -105,6 +105,18 @@ executable('intel_reg', sources : intel_reg_src,
 	     '-DIGT_DATADIR="@0@"'.format(join_paths(prefix, datadir)),
 	   ])
 
+if yaml.found()
+	igt_kcov_src = [ 'igt_kcov.c' ]
+	executable('igt_kcov', sources : igt_kcov_src,
+		   dependencies : [ igt_deps, zlib, realtime, math, yaml ],
+		   install : true)
+
+	igt_kcov_edges_src = [ 'igt_kcov_edges.c' ]
+	shared_module('igt_kcov_edges', sources : igt_kcov_edges_src,
+		      dependencies : [ dlsym ],
+		      install : true)
+endif
+
 install_data('intel_gpu_abrt', install_dir : bindir)
 
 install_subdir('registers', install_dir : datadir,
-- 
2.14.1

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [igt-dev] ✗ Fi.CI.BAT: failure for RFC tools: capture execution pathways (rev2)
  2018-04-20 21:50 [igt-dev] [PATCH igt] RFC tools: capture execution pathways Chris Wilson
  2018-04-20 22:03 ` [igt-dev] ✗ Fi.CI.BAT: failure for " Patchwork
  2018-04-23 11:29 ` [igt-dev] [PATCH igt] " Joonas Lahtinen
@ 2018-04-23 15:13 ` Patchwork
  2018-04-25 20:22 ` [igt-dev] [PATCH igt] RFC tools: capture execution pathways Chris Wilson
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Patchwork @ 2018-04-23 15:13 UTC (permalink / raw)
  To: Petri Latvala; +Cc: igt-dev

== Series Details ==

Series: RFC tools: capture execution pathways (rev2)
URL   : https://patchwork.freedesktop.org/series/42056/
State : failure

== Summary ==

= CI Bug Log - changes from CI_DRM_4078 -> IGTPW_1291 =

== Summary - FAILURE ==

  Serious unknown changes coming with IGTPW_1291 absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in IGTPW_1291, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/42056/revisions/2/mbox/

== Possible new issues ==

  Here are the unknown changes that may have been introduced in IGTPW_1291:

  === IGT changes ===

    ==== Possible regressions ====

    igt@drv_module_reload@basic-reload:
      fi-glk-j4005:       PASS -> DMESG-WARN

    
== Known issues ==

  Here are the changes found in IGTPW_1291 that come from known issues:

  === IGT changes ===

    ==== Issues hit ====

    igt@kms_chamelium@dp-edid-read:
      fi-kbl-7500u:       PASS -> FAIL (fdo#103841)

    igt@kms_pipe_crc_basic@read-crc-pipe-a-frame-sequence:
      fi-glk-j4005:       PASS -> DMESG-WARN (fdo#106097)

    igt@kms_pipe_crc_basic@suspend-read-crc-pipe-b:
      fi-ivb-3520m:       PASS -> DMESG-WARN (fdo#106084)

    
    ==== Possible fixes ====

    igt@gem_mmap_gtt@basic-small-bo-tiledx:
      fi-gdg-551:         FAIL (fdo#102575) -> PASS

    igt@kms_pipe_crc_basic@suspend-read-crc-pipe-c:
      fi-ivb-3520m:       DMESG-WARN (fdo#106084) -> PASS

    
  fdo#102575 https://bugs.freedesktop.org/show_bug.cgi?id=102575
  fdo#103841 https://bugs.freedesktop.org/show_bug.cgi?id=103841
  fdo#106084 https://bugs.freedesktop.org/show_bug.cgi?id=106084
  fdo#106097 https://bugs.freedesktop.org/show_bug.cgi?id=106097


== Participating hosts (36 -> 31) ==

  Missing    (5): fi-ctg-p8600 fi-cnl-y3 fi-ilk-m540 fi-bxt-dsi fi-skl-6700hq 


== Build changes ==

    * IGT: IGT_4444 -> IGTPW_1291

  CI_DRM_4078: 9391010824b34ec58217f816ba5e314e7312191d @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_1291: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_1291/
  IGT_4444: dcc44347494231feabc588c2a76998cbc9afdf8c @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  piglit_4444: a2f486679f467cd6e82578384f56d4aabaa8cf2e @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_1291/issues.html
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [igt-dev] [PATCH igt] RFC tools: capture execution pathways
  2018-04-20 21:50 [igt-dev] [PATCH igt] RFC tools: capture execution pathways Chris Wilson
                   ` (2 preceding siblings ...)
  2018-04-23 15:13 ` [igt-dev] ✗ Fi.CI.BAT: failure for RFC tools: capture execution pathways (rev2) Patchwork
@ 2018-04-25 20:22 ` Chris Wilson
  2018-04-25 20:42 ` [igt-dev] [PATCH i-g-t] RFCv2 " Chris Wilson
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Chris Wilson @ 2018-04-25 20:22 UTC (permalink / raw)
  To: igt-dev

Quoting Chris Wilson (2018-04-20 22:50:33)
> igt_kcov edges -o edges.yaml command-to-trace args
> ...
> igt_kcov sort -o sorted.yaml edges.yaml
> 
> Requires CONFIG_KCOV
> 
> Use LD_PRELOAD to wrap calls to DRM ioctls and capture the execution
> trace of all basic blocks invoked directly from the syscall. (Key
> limitation!) From the chain of basic blocks, the "edges" are computed
> and the number of times each edge is hit is stored in a vector (modulo a
> large hash). The goal then is to select a series of tests that execute
> the most unique pathways in the sortest amount of time. To do this we
> compare the similarity of the coverage vectors between all commands, and
> try to preferentially pick those that are dissimilar from the rest.
> 
> * Direct execution pathways from syscall is a huge limitation for
> evaluating general testing of driver pathways, but is not so huge when
> myopically focusing on the ABI as say used by mesa.
> 
> ** Caveat lector. Hastily thrown together.

So after some more hacking around, here's the top 30s of "piglit run -p
gdm gpu" on a bxt (try not to overdose on the pinch of salt required):

'bin/draw-sync' '-auto' '-fbo' # 9723.773ms, total 9723.8ms
'bin/fbo-depthstencil' 'drawpixels' 'default_fb' '32F_24_8_REV' '-samples=32' '-auto' # 38.638ms, total 9762.4ms
'bin/gl30basic' '-auto' # 49.098ms, total 9811.5ms
'bin/tex3d-maxsize' '-auto' # 8921.198ms, total 18732.7ms
'bin/copyteximage' 'RECT' '-samples=32' '-auto' # 43.987ms, total 18776.7ms
'bin/copypixels-sync' '-auto' '-fbo' # 2843.007ms, total 21619.7ms
'bin/fbo-sys-sub-blit' '-auto' # 58.708ms, total 21678.4ms
'bin/draw-copypixels-sync' '-auto' '-fbo' # 6022.916ms, total 27701.3ms
'bin/fbo-depthstencil' 'readpixels' 'default_fb' 'FLOAT-and-USHORT' '-samples=32' '-auto' # 32.175ms, total 27733.5ms
'bin/getteximage-depth' '-auto' '-fbo' # 181.520ms, total 27915.0ms
'bin/recursion' '-rlmit' '268435456' 'indirect-complex-separate' '-auto' # 47.082ms, total 27962.1ms
'bin/read-front' 'clear-front-first' '-samples=16' '-auto' # 50.148ms, total 28012.3ms
'bin/texrect-many' '-auto' # 123.456ms, total 28135.7ms
'bin/read-front' '-samples=32' '-auto' # 35.239ms, total 28170.9ms
'bin/fbo-depthstencil' 'clear' 'default_fb' '-samples=32' '-auto' # 39.926ms, total 28210.9ms
'bin/teximage-colors' 'GL_RGBA32F' '-auto' '-fbo' # 164.443ms, total 28375.3ms
'bin/copy_buffer_coherency' '-auto' # 109.981ms, total 28485.3ms
'bin/glsl-explicit-location-04' '-auto' # 66.258ms, total 28551.6ms
'bin/gl-3.2-layered-rendering-clear-color-all-types' 'cube_map_array' 'mipmapped' '-auto' '-fbo' # 121.422ms, total 28673.0ms
'bin/arb_transform_feedback3-ext_interleaved_two_bufs' 'vs' '-auto' # 67.861ms, total 28740.8ms
'bin/copyteximage' 'CUBE' '-samples=32' '-auto' # 30.807ms, total 28771.6ms
'bin/activeprogram-get' '-auto' '-fbo' # 44.429ms, total 28816.1ms
'bin/clear-accum' '-auto' '-fbo' # 35.903ms, total 28852.0ms
'bin/gl-1.3-alpha_to_coverage_nop' '-auto' '-fbo' # 713.298ms, total 29565.3ms
'bin/arb_program_interface_query-getprogramresourceiv' '-auto' # 115.116ms, total 29680.4ms
'bin/max-samplers' 'border' '-auto' '-fbo' # 208.097ms, total 29888.5ms
'bin/masked-clear' '-auto' '-fbo' # 45.091ms, total 29933.6ms
'bin/copyteximage' '2D_ARRAY' '-samples=32' '-auto' # 34.492ms, total 29968.1ms
'bin/fbo-depthstencil' 'drawpixels' 'default_fb' '24_8' '-samples=32' '-auto' # 27.307ms, total 29995.4ms

These are ranked by uniqueness of the basic blocks they execute from
drmIoctls. If we exclude any test that runs longer than 0.5s:

'bin/fbo-depthstencil' 'drawpixels' 'default_fb' '32F_24_8_REV' '-samples=32' '-auto' # 38.638ms, total 38.6ms
'bin/gl30basic' '-auto' # 49.098ms, total 87.7ms
'bin/copyteximage' 'RECT' '-samples=32' '-auto' # 43.987ms, total 131.7ms
'bin/fbo-sys-sub-blit' '-auto' # 58.708ms, total 190.4ms
'bin/fbo-depthstencil' 'readpixels' 'default_fb' 'FLOAT-and-USHORT' '-samples=32' '-auto' # 32.175ms, total 222.6ms
'bin/getteximage-depth' '-auto' '-fbo' # 181.520ms, total 404.1ms
'bin/recursion' '-rlmit' '268435456' 'indirect-complex-separate' '-auto' # 47.082ms, total 451.2ms
'bin/read-front' 'clear-front-first' '-samples=16' '-auto' # 50.148ms, total 501.4ms
'bin/texrect-many' '-auto' # 123.456ms, total 624.8ms
'bin/read-front' '-samples=32' '-auto' # 35.239ms, total 660.1ms
'bin/fbo-depthstencil' 'clear' 'default_fb' '-samples=32' '-auto' # 39.926ms, total 700.0ms
'bin/teximage-colors' 'GL_RGBA32F' '-auto' '-fbo' # 164.443ms, total 864.4ms
'bin/copy_buffer_coherency' '-auto' # 109.981ms, total 974.4ms
'bin/glsl-explicit-location-04' '-auto' # 66.258ms, total 1040.7ms
'bin/gl-3.2-layered-rendering-clear-color-all-types' 'cube_map_array' 'mipmapped' '-auto' '-fbo' # 121.422ms, total 1162.1ms
'bin/arb_transform_feedback3-ext_interleaved_two_bufs' 'vs' '-auto' # 67.861ms, total 1229.9ms
'bin/copyteximage' 'CUBE' '-samples=32' '-auto' # 30.807ms, total 1260.7ms
'bin/activeprogram-get' '-auto' '-fbo' # 44.429ms, total 1305.2ms
'bin/clear-accum' '-auto' '-fbo' # 35.903ms, total 1341.1ms
'bin/arb_program_interface_query-getprogramresourceiv' '-auto' # 115.116ms, total 1456.2ms
'bin/max-samplers' 'border' '-auto' '-fbo' # 208.097ms, total 1664.3ms
'bin/masked-clear' '-auto' '-fbo' # 45.091ms, total 1709.4ms
'bin/gen-nonzero-unit' '-auto' # 98.092ms, total 1807.5ms
'bin/copyteximage' '2D_ARRAY' '-samples=32' '-auto' # 34.492ms, total 1842.0ms
'bin/arb_transform_feedback2-change-objects-while-paused_gles3' '-auto' # 87.031ms, total 1929.0ms
'bin/gl-3.0-required-texture-attachment-formats' '33' '-auto' '-fbo' # 51.791ms, total 1980.8ms
'bin/ext_image_dma_buf_import-invalid_hints' '-auto' # 45.979ms, total 2026.8ms
'bin/read-front' 'clear-front-first' '-samples=8' '-auto' # 71.906ms, total 2098.7ms
'bin/copyteximage' 'CUBE' '-samples=2' '-auto' # 268.906ms, total 2367.6ms
'bin/fbo-depthstencil' 'drawpixels' 'default_fb' '24_8' '-samples=32' '-auto' # 27.307ms, total 2394.9ms
'bin/ext_texture_array-compressed_gles3' 'teximage' '-fbo' '-auto' # 73.392ms, total 2468.3ms
'bin/gl-3.0-required-sized-texture-formats' '31' '-auto' '-fbo' # 52.273ms, total 2520.6ms
'bin/amd_seamless_cubemap_per_texture' '-auto' # 62.070ms, total 2582.6ms
'bin/copyteximage' '1D_ARRAY' '-auto' # 375.446ms, total 2958.1ms
'bin/fcc-front-buffer-distraction' '-auto' # 59.025ms, total 3017.1ms
'bin/read-front' '-samples=16' '-auto' # 104.732ms, total 3121.8ms
'bin/read-front' 'clear-front-first' '-samples=32' '-auto' # 27.369ms, total 3149.2ms
'bin/arb_base_instance-baseinstance-doesnt-affect-gl-instance-id_gles3' '-auto' # 37.624ms, total 3186.8ms
'bin/gl-3.0-bound-resource-limits' '-auto' '-fbo' # 154.116ms, total 3340.9ms
'bin/tex3d' '-auto' '-fbo' # 427.575ms, total 3768.5ms
'bin/fbo-depthstencil' 'readpixels' 'default_fb' '32F_24_8_REV' '-auto' # 82.329ms, total 3850.8ms
'bin/arb_es2_compatibility-getshaderprecisionformat' '-auto' # 53.062ms, total 3903.9ms
'bin/copyteximage' '1D_ARRAY' '-samples=32' '-auto' # 34.307ms, total 3938.2ms
'bin/depthstencil-render-miplevels' '146' 'd=z32f_s8' '-auto' # 66.579ms, total 4004.8ms
'bin/arb_arrays_of_arrays-max-binding' '-auto' # 70.830ms, total 4075.6ms
'bin/copyteximage' 'RECT' '-samples=2' '-auto' # 215.228ms, total 4290.8ms
'bin/gl-1.0-front-invalidate-back' '-auto' # 41.917ms, total 4332.8ms
'bin/fbo-depthstencil' 'readpixels' 'default_fb' '32F_24_8_REV' '-samples=32' '-auto' # 36.760ms, total 4369.5ms
'bin/incomplete-cubemap' 'size' '-auto' '-fbo' # 79.044ms, total 4448.6ms
'bin/arb_sample_shading-builtin-gl-num-samples' '16' '-auto' # 105.381ms, total 4553.9ms
'bin/teximage-errors' '-auto' '-fbo' # 45.772ms, total 4599.7ms
'bin/max-samplers' '-auto' '-fbo' # 208.750ms, total 4808.5ms
'bin/vp-address-06' '-auto' # 49.582ms, total 4858.1ms
'bin/read-front' 'clear-front-first' '-samples=6' '-auto' # 50.643ms, total 4908.7ms
'bin/glsl-explicit-location-02' '-auto' # 41.985ms, total 4950.7ms
'bin/fbo-depthstencil' 'readpixels' 'default_fb' '24_8' '-samples=32' '-auto' # 32.637ms, total 4983.3ms
'bin/copyteximage' '1D_ARRAY' '-samples=4' '-auto' # 316.604ms, total 5299.9ms
'bin/gl-3.0-required-sized-texture-formats' '33' '-auto' '-fbo' # 47.754ms, total 5347.7ms
'bin/arb_transform_feedback2-change-objects-while-paused' '-auto' # 54.757ms, total 5402.4ms
'bin/texture-packed-formats' '-auto' '-fbo' # 395.531ms, total 5798.0ms
'bin/vertex-program-two-side' 'enabled' 'back' 'back2' '-auto' '-fbo' # 53.321ms, total 5851.3ms
'bin/read-front' 'clear-front-first' '-auto' # 51.246ms, total 5902.5ms
'bin/gl-1.0-scissor-many' '-auto' '-fbo' # 338.981ms, total 6241.5ms
'bin/fbo-depthstencil' 'drawpixels' 'default_fb' 'FLOAT-and-USHORT' '-samples=32' '-auto' # 47.502ms, total 6289.0ms
'bin/read-front' '-samples=2' '-auto' # 62.456ms, total 6351.5ms
'bin/arb_sample_shading-builtin-gl-sample-position' '32' '-auto' # 36.846ms, total 6388.3ms
'bin/rg-teximage-01' '-auto' # 80.979ms, total 6469.3ms
'bin/gl-1.0-dlist-bitmap' '-auto' '-fbo' # 195.049ms, total 6664.3ms
'bin/gl-3.0-required-sized-texture-formats' '30' '-auto' '-fbo' # 48.607ms, total 6713.0ms
'bin/cubemap-shader' 'lod' '-auto' # 113.548ms, total 6826.5ms
'bin/fbo-depthstencil' 'copypixels' 'default_fb' '-samples=32' '-auto' # 27.107ms, total 6853.6ms
'bin/fbo-depthstencil' 'readpixels' 'default_fb' 'FLOAT-and-USHORT' '-samples=6' '-auto' # 73.768ms, total 6927.4ms
'bin/read-front' 'clear-front-first' '-samples=4' '-auto' # 73.699ms, total 7001.1ms
'bin/gl-3.2-get-integer-64v' '-auto' '-fbo' # 46.387ms, total 7047.5ms
'bin/ext_image_dma_buf_import-transcode-nv12-as-r8-gr88' '-auto' # 59.923ms, total 7107.4ms
'bin/gl-1.0-drawbuffer-modes' '-auto' # 47.332ms, total 7154.7ms
'bin/ext_texture_array-compressed_gles3' 'texsubimage' '-fbo' '-auto' # 52.964ms, total 7207.7ms
'bin/fbo-depthstencil' 'blit' 'default_fb' '-samples=32' '-auto' # 26.703ms, total 7234.4ms
'bin/gl-1.0-logicop' '-auto' '-fbo' # 109.021ms, total 7343.4ms
'bin/gl-3.0-required-sized-texture-formats' '42' '-auto' '-fbo' # 46.672ms, total 7390.1ms
'bin/primitive-restart-draw-mode' 'lines' '-auto' # 55.387ms, total 7445.5ms
'bin/gl-3.0-required-texture-attachment-formats' '30' '-auto' '-fbo' # 50.314ms, total 7495.8ms
'bin/gen-texsubimage' '-auto' # 90.425ms, total 7586.2ms
'bin/gl-3.2-layered-rendering-clear-color-all-types' 'cube_map' 'mipmapped' '-auto' '-fbo' # 63.288ms, total 7649.5ms
'bin/max-texture-size-level' '-auto' '-fbo' # 168.147ms, total 7817.6ms
'bin/copyteximage' 'CUBE' '-auto' # 254.585ms, total 8072.2ms
'bin/hiz-depth-stencil-test-fbo-d24s8' '-auto' # 70.293ms, total 8142.5ms
'bin/read-front' 'clear-front-first' '-samples=2' '-auto' # 71.141ms, total 8213.7ms
'bin/glsl-vs-raytrace-bug26691' '-auto' '-fbo' # 470.930ms, total 8684.6ms
'bin/teximage-colors' 'GL_RGBA4' '-auto' '-fbo' # 153.488ms, total 8838.1ms
'bin/gl-1.0-long-dlist' '-auto' '-fbo' # 58.517ms, total 8896.6ms
'bin/glsl-fs-fragcoord-zw-ortho' '-auto' '-fbo' # 59.801ms, total 8956.4ms
'bin/copyteximage' '3D' '-auto' '-fbo' # 180.824ms, total 9137.2ms
'bin/gl-1.0-swapbuffers-behavior' '-auto' # 47.067ms, total 9184.3ms
'bin/gl-3.0-required-renderbuffer-attachment-formats' '42' '-auto' '-fbo' # 48.456ms, total 9232.7ms
'bin/cubemap' '-auto' # 272.528ms, total 9505.3ms
'bin/glsl-explicit-location-05' '-auto' # 64.614ms, total 9569.9ms
'bin/copyteximage' '1D_ARRAY' '-samples=8' '-auto' # 324.004ms, total 9893.9ms
'bin/read-front' '-samples=8' '-auto' # 61.458ms, total 9955.3ms
'bin/arb_program_interface_query-getprogramresourceindex' '-auto' # 146.634ms, total 10102.0ms
'bin/arb_enhanced_layouts-transform-feedback-layout-qualifiers' 'gs_max' '-auto' # 100.837ms, total 10202.8ms
'bin/gl-3.2-get-buffer-parameter-i64v' '-auto' '-fbo' # 50.338ms, total 10253.2ms
'bin/ext_transform_feedback-builtin-varyings' 'gl_ClipDistance[6]-no-subscript' '-auto' # 49.990ms, total 10303.1ms
'bin/arb_program_interface_query-resource-location' '-auto' # 75.369ms, total 10378.5ms
'bin/copyteximage' 'RECT' '-samples=4' '-auto' # 148.635ms, total 10527.1ms
'bin/fbo-sys-blit' '-auto' # 65.767ms, total 10592.9ms
'bin/gen-teximage' '-auto' # 77.274ms, total 10670.2ms
'bin/gl-3.2-layered-rendering-framebuffer-layer-count-mismatch' '-auto' '-fbo' # 48.021ms, total 10718.2ms
'bin/arb_sampler_objects-framebufferblit' '-auto' # 70.290ms, total 10788.5ms
'bin/teximage-colors' 'GL_R16F' '-auto' '-fbo' # 147.662ms, total 10936.2ms
'bin/gl-1.2-texture-base-level' '-auto' '-fbo' # 60.154ms, total 10996.3ms
'bin/sized-texture-format-channels' '-auto' '-fbo' # 68.128ms, total 11064.4ms
'bin/texredefine' '-auto' '-fbo' # 77.855ms, total 11142.3ms
'bin/arb_sample_shading-builtin-gl-sample-position' '16' '-auto' # 113.356ms, total 11255.6ms
'bin/copyteximage' '1D_ARRAY' '-samples=2' '-auto' # 366.872ms, total 11622.5ms
'bin/initialized-vbo' '-auto' # 121.142ms, total 11743.7ms
'bin/arb_explicit_uniform_location-use-of-unused-loc' '-auto' # 68.386ms, total 11812.1ms
'bin/gl-1.0-ortho-pos' '-auto' '-fbo' # 87.511ms, total 11899.6ms
'bin/arb_sample_shading-builtin-gl-sample-id' '32' '-auto' # 48.758ms, total 11948.3ms
'bin/teximage-colors' 'GL_ALPHA' '-auto' '-fbo' # 143.929ms, total 12092.2ms
'bin/glsl-vs-mov-after-deref' '-auto' '-fbo' # 52.318ms, total 12144.6ms
'bin/vp-clipdistance-01' '-auto' # 51.502ms, total 12196.1ms
'bin/read-front' '-samples=6' '-auto' # 64.680ms, total 12260.7ms
'bin/copyteximage' 'CUBE' '-samples=16' '-auto' # 249.863ms, total 12510.6ms
'bin/genmipmap-errors' '-auto' '-fbo' # 53.652ms, total 12564.3ms
'bin/fbo-depthstencil' 'blit' 'default_fb' '-auto' # 74.364ms, total 12638.6ms
'bin/arb_vertex_type_10f_11f_11f_rev-api-errors' '-auto' # 76.030ms, total 12714.7ms
'bin/depthstencil-render-miplevels' '585' 's=z24_s8_d=z32f_s8' '-auto' # 164.833ms, total 12879.5ms
'bin/gl-2.0-vertexattribpointer' '-auto' '-fbo' # 104.009ms, total 12983.5ms
'bin/gl-3.1-primitive-restart-xfb' 'generated' '-auto' '-fbo' # 55.630ms, total 13039.1ms
'bin/gl-3.0-required-texture-attachment-formats' '42' '-auto' '-fbo' # 50.500ms, total 13089.6ms
'bin/depthstencil-render-miplevels' '1024' 'd=z32f_s8' '-auto' # 197.145ms, total 13286.8ms
'bin/gl-3.0-texture-integer' '-auto' '-fbo' # 130.958ms, total 13417.7ms
'bin/depthstencil-render-miplevels' '1024' 's=z24_s8' '-auto' # 273.880ms, total 13691.6ms
'bin/gl-1.0-texgen' '-auto' '-fbo' # 76.620ms, total 13768.2ms
'bin/teximage-colors' 'GL_RG8_SNORM' '-auto' '-fbo' # 144.052ms, total 13912.3ms
'bin/ext_image_dma_buf_import-missing_attributes' '-auto' # 40.312ms, total 13952.6ms
'bin/recursion' '-rlmit' '268435456' 'indirect-separate' '-auto' # 69.803ms, total 14022.4ms
'bin/copyteximage' '2D_ARRAY' '-samples=6' '-auto' # 162.608ms, total 14185.0ms
'bin/rg-teximage-02' '-auto' # 115.089ms, total 14300.1ms
'bin/ext_transform_feedback-builtin-varyings' 'gl_ClipDistance[3]-no-subscript' '-auto' # 46.967ms, total 14347.1ms
'bin/gl-3.1-draw-buffers-errors' '-auto' '-fbo' # 45.662ms, total 14392.7ms
'bin/gl-3.2-layered-rendering-framebuffer-layer-complete' '-auto' '-fbo' # 44.793ms, total 14437.5ms
'bin/teximage-colors' 'GL_LUMINANCE12_ALPHA4' '-auto' '-fbo' # 161.042ms, total 14598.6ms
'bin/read-front' '-samples=4' '-auto' # 65.224ms, total 14663.8ms
'bin/copyteximage' '1D_ARRAY' '-samples=6' '-auto' # 364.844ms, total 15028.6ms
'bin/ext_fog_coord-modes' '-auto' # 58.006ms, total 15086.6ms
'bin/map_buffer_range_test' '-auto' # 67.780ms, total 15154.4ms
'bin/vp-clipdistance-03' '-auto' # 39.314ms, total 15193.7ms
'bin/glsl-preprocessor-comments' '-auto' '-fbo' # 53.134ms, total 15246.9ms
'bin/teximage-colors' 'GL_RGBA8_SNORM' '-auto' '-fbo' # 157.683ms, total 15404.5ms
'bin/geterror-invalid-enum' '-auto' '-fbo' # 187.664ms, total 15592.2ms
'bin/arb_enhanced_layouts-transform-feedback-layout-qualifiers' 'vs_struct' '-auto' # 67.596ms, total 15659.8ms
'bin/gl-3.2-layered-rendering-framebuffer-layered-attachments' '-auto' '-fbo' # 42.774ms, total 15702.6ms
'bin/depthstencil-render-miplevels' '292' 'd=s=z32f_s8' '-auto' # 87.815ms, total 15790.4ms
'bin/teximage-colors' 'GL_RED' '-auto' '-fbo' # 186.126ms, total 15976.5ms
'bin/gl-3.0-required-texture-attachment-formats' '31' '-auto' '-fbo' # 53.383ms, total 16029.9ms
'bin/incomplete-cubemap' 'format' '-auto' '-fbo' # 62.008ms, total 16091.9ms
'bin/vp-address-04' '-auto' # 45.814ms, total 16137.7ms
'bin/copyteximage' '2D_ARRAY' '-samples=16' '-auto' # 269.946ms, total 16407.7ms
'bin/glsl-dlist-getattriblocation' '-auto' '-fbo' # 47.843ms, total 16455.5ms
'bin/read-front' '-auto' # 53.942ms, total 16509.5ms
'bin/teximage-colors' 'GL_RGB8' '-auto' '-fbo' # 149.343ms, total 16658.8ms
'bin/fbo-depthstencil' 'drawpixels' 'default_fb' '24_8' '-samples=2' '-auto' # 114.971ms, total 16773.8ms
'bin/cubemap-mismatch' '-auto' # 51.126ms, total 16824.9ms
'bin/arb_transform_feedback3-ext_interleaved_two_bufs' 'gs' '-auto' # 56.760ms, total 16881.7ms
'bin/copyteximage' 'CUBE' '-samples=4' '-auto' # 240.430ms, total 17122.1ms
'bin/depthstencil-render-miplevels' '273' 'd=z32f_s8_s=z24_s8' '-auto' # 78.412ms, total 17200.5ms
'bin/proxy-texture' '-auto' '-fbo' # 46.361ms, total 17246.9ms
'bin/teximage-colors' 'GL_R8' '-auto' '-fbo' # 136.959ms, total 17383.8ms
'bin/depth-tex-modes-glsl' '-auto' '-fbo' # 74.382ms, total 17458.2ms
'bin/primitive-restart' 'VBO_SEPARATE_VERTEX_AND_INDEX' '-auto' # 104.232ms, total 17562.4ms
'bin/roundmode-pixelstore' '-auto' '-fbo' # 51.305ms, total 17613.7ms
'bin/recursion' '-rlmit' '268435456' 'unreachable' '-auto' # 49.374ms, total 17663.1ms
'bin/teximage-colors' 'GL_SRGB8_ALPHA8' '-auto' '-fbo' # 191.689ms, total 17854.8ms
'bin/depthstencil-render-miplevels' '1024' 'd=z32f_s8_s=z24_s8' '-auto' # 389.327ms, total 18244.1ms
'bin/ext_framebuffer_multisample-turn-on-off' '6' '-auto' # 179.773ms, total 18423.9ms
'bin/teximage-colors' 'GL_SLUMINANCE8' '-auto' '-fbo' # 189.052ms, total 18613.0ms
'bin/gl-3.0-required-renderbuffer-attachment-formats' '31' '-auto' '-fbo' # 45.732ms, total 18658.7ms
'bin/arb_sample_shading-api' '-auto' # 53.567ms, total 18712.3ms
'bin/gl-3.2-adj-prims' 'line' 'cull-front' 'pv-first' '-auto' '-fbo' # 63.143ms, total 18775.4ms
'bin/copyteximage' '2D_ARRAY' '-samples=8' '-auto' # 260.001ms, total 19035.4ms
'bin/ext_image_dma_buf_import-sample_yuv' '-fmt=YU12' '-alpha-one' '-auto' # 50.441ms, total 19085.8ms
'bin/arb_program_interface_query-resource-query' '-auto' # 301.738ms, total 19387.6ms
'bin/teximage-colors' 'GL_ALPHA8' '-auto' '-fbo' # 142.210ms, total 19529.8ms
'bin/gl-3.2-adj-prims' 'cull-back' 'pv-first' '-auto' '-fbo' # 54.782ms, total 19584.6ms
'bin/glsl-uniform-out-of-bounds' '-auto' '-fbo' # 77.130ms, total 19661.7ms
'bin/depthstencil-render-miplevels' '273' 'd=s=z32f_s8' '-auto' # 99.332ms, total 19761.0ms
'bin/cubemap' 'npot' '-auto' # 206.273ms, total 19967.3ms
'bin/depthstencil-render-miplevels' '585' 's=z24_s8' '-auto' # 113.819ms, total 20081.1ms
'bin/teximage-colors' 'GL_LUMINANCE12_ALPHA12' '-auto' '-fbo' # 159.678ms, total 20240.8ms
'bin/arb_debug_output-api_error' '-auto' # 55.500ms, total 20296.3ms
'bin/arb_enhanced_layouts-transform-feedback-layout-qualifiers' 'gs' '-auto' # 64.531ms, total 20360.8ms
'bin/arb_texture_cube_map_array-cubemap-lod' '-auto' # 137.990ms, total 20498.8ms
'bin/gl-3.0-required-renderbuffer-attachment-formats' '30' '-auto' '-fbo' # 59.196ms, total 20558.0ms
'bin/copyteximage' '2D_ARRAY' '-auto' # 168.361ms, total 20726.4ms
'bin/ext_image_dma_buf_import-ownership_transfer' '-auto' # 42.445ms, total 20768.8ms
'bin/pbo-teximage-tiling' '-auto' # 87.060ms, total 20855.9ms
'bin/depthstencil-render-miplevels' '585' 'd=s=z32f_s8' '-auto' # 206.428ms, total 21062.3ms
'bin/glsl-resource-not-bound' 'Cube' '-auto' '-fbo' # 67.890ms, total 21130.2ms
'bin/copyteximage' 'RECT' '-auto' # 123.651ms, total 21253.9ms
'bin/arb_transform_feedback3-draw_using_invalid_stream_index' '-auto' # 39.585ms, total 21293.4ms
'bin/glsl-mat-attribute' '-auto' '-fbo' # 63.779ms, total 21357.2ms
'bin/teximage-colors' 'GL_R11F_G11F_B10F' '-auto' '-fbo' # 137.933ms, total 21495.2ms
'bin/depthstencil-render-miplevels' '1024' 'd=z32f' '-auto' # 145.291ms, total 21640.4ms
'bin/sso-uniforms-01' '-auto' '-fbo' # 59.910ms, total 21700.4ms
'bin/rgtc-teximage-02' '-auto' # 350.363ms, total 22050.7ms
'bin/vertex-program-two-side' 'back' 'front2' 'back2' '-auto' '-fbo' # 51.341ms, total 22102.1ms
'bin/teximage-colors' 'GL_ALPHA16' '-auto' '-fbo' # 160.668ms, total 22262.7ms
'bin/integer-errors' '-auto' '-fbo' # 45.788ms, total 22308.5ms
'bin/copyteximage' '2D_ARRAY' '-samples=2' '-auto' # 172.109ms, total 22480.6ms
'bin/ext_texture_array-compressed' 'teximage' 'pbo' '-fbo' '-auto' # 65.308ms, total 22545.9ms
'bin/ext_framebuffer_multisample-turn-on-off' '32' '-auto' # 48.415ms, total 22594.3ms
'bin/gl-1.0-scissor-polygon' '-auto' '-fbo' # 163.852ms, total 22758.2ms
'bin/depthstencil-render-miplevels' '146' 's=d=z32f_s8' '-auto' # 70.495ms, total 22828.7ms
'bin/copyteximage' '2D' '-auto' '-fbo' # 147.559ms, total 22976.3ms
'bin/geterror-inside-begin' '-auto' '-fbo' # 48.789ms, total 23025.0ms
'bin/depthstencil-render-miplevels' '1024' 's=z24_s8_d=z32f_s8' '-auto' # 343.656ms, total 23368.7ms
'bin/fbo-depthstencil' 'clear' 'default_fb' '-samples=6' '-auto' # 79.205ms, total 23447.9ms
'bin/teximage-colors' 'GL_RGBA16_SNORM' '-auto' '-fbo' # 150.670ms, total 23598.6ms
'bin/arb-provoking-vertex-control' '-auto' # 76.680ms, total 23675.2ms
'bin/fbo-depthstencil' 'readpixels' 'default_fb' '24_8' '-samples=8' '-auto' # 76.620ms, total 23751.9ms
'bin/teximage-colors' 'GL_LUMINANCE' '-auto' '-fbo' # 161.753ms, total 23913.6ms
'bin/gl-3.2-layered-rendering-gl-layer-cube-map' '-auto' '-fbo' # 73.565ms, total 23987.2ms
'bin/gl-3.3-minmax' '-auto' '-fbo' # 46.301ms, total 24033.5ms
'bin/copyteximage' 'CUBE' '-samples=8' '-auto' # 271.276ms, total 24304.8ms
'bin/vao-02' '-auto' # 60.266ms, total 24365.0ms
'bin/ext_framebuffer_multisample-turn-on-off' '16' '-auto' # 234.869ms, total 24599.9ms
'bin/depthstencil-render-miplevels' '273' 'd=z16' '-auto' # 67.602ms, total 24667.5ms
'bin/gl-3.0-required-renderbuffer-attachment-formats' '33' '-auto' '-fbo' # 50.558ms, total 24718.1ms
'bin/ext_image_dma_buf_import-sample_yuv' '-fmt=YV12' '-alpha-one' '-auto' # 42.094ms, total 24760.2ms
'bin/teximage-colors' 'GL_R16' '-auto' '-fbo' # 152.071ms, total 24912.2ms
'bin/arb_sample_shading-builtin-gl-sample-mask' '0' '-auto' # 118.550ms, total 25030.8ms
'bin/bindfragdata-link-error' '-auto' '-fbo' # 56.134ms, total 25086.9ms
'bin/arb_robustness_client-mem-bounds' '-auto' # 81.317ms, total 25168.2ms
'bin/vp-clipdistance-02' '-auto' # 55.045ms, total 25223.3ms
'bin/fbo-depthstencil' 'drawpixels' 'default_fb' 'FLOAT-and-USHORT' '-samples=6' '-auto' # 115.834ms, total 25339.1ms
'bin/teximage-colors' 'GL_RGBA' '-auto' '-fbo' # 162.751ms, total 25501.9ms
'bin/copyteximage-clipping' '-auto' '-fbo' # 56.837ms, total 25558.7ms
'bin/quad-invariance' '-auto' '-fbo' # 147.417ms, total 25706.1ms
'bin/teximage-colors' 'GL_SLUMINANCE8_ALPHA8' '-auto' '-fbo' # 211.445ms, total 25917.6ms
'bin/rgtc-teximage-01' '-auto' # 215.997ms, total 26133.6ms
'bin/arb_map_buffer_alignment-sanity_test' '-auto' # 41.860ms, total 26175.4ms
'bin/teximage-colors' 'GL_ALPHA4' '-auto' '-fbo' # 152.335ms, total 26327.7ms
'bin/gl-3.2-layered-rendering-framebuffer-layer-attachment-mismatch' '-auto' '-fbo' # 49.223ms, total 26377.0ms
'bin/ext_texture_array-compressed' 'texsubimage' 'pbo' '-fbo' '-auto' # 74.147ms, total 26451.1ms
'bin/oes_draw_elements_base_vertex-drawrangeelements' '-auto' # 63.079ms, total 26514.2ms
'bin/copyteximage' 'CUBE' '-samples=6' '-auto' # 297.885ms, total 26812.1ms
'bin/arb_vertex_program-getlocal4d-with-error' '-auto' # 43.682ms, total 26855.8ms
'bin/gl-3.2-layered-rendering-clear-color-mismatched-layer-count' '-auto' '-fbo' # 89.791ms, total 26945.6ms
'bin/depthstencil-render-miplevels' '1024' 'd=z32f_s=z24_s8' '-auto' # 349.357ms, total 27294.9ms
'bin/fbo-blit-stretch' '-auto' # 292.928ms, total 27587.8ms
'bin/arb_transform_feedback3-set_varyings_with_invalid_args' '-auto' # 40.395ms, total 27628.2ms
'bin/fbo-depthstencil' 'drawpixels' 'default_fb' '32F_24_8_REV' '-samples=4' '-auto' # 100.551ms, total 27728.8ms
'bin/getuniform-02' '-auto' '-fbo' # 55.287ms, total 27784.1ms
'bin/crossbar' '-auto' # 99.245ms, total 27883.3ms
'bin/teximage-colors' 'GL_RGB16_SNORM' '-auto' '-fbo' # 147.525ms, total 28030.8ms
'bin/depthstencil-render-miplevels' '585' 'd=z24_s=z24_s8' '-auto' # 159.331ms, total 28190.2ms
'bin/ext_framebuffer_multisample-turn-on-off' '8' '-auto' # 174.701ms, total 28364.9ms
'bin/copyteximage' '2D_ARRAY' '-samples=4' '-auto' # 218.974ms, total 28583.8ms
'bin/link-unresolved-function' '-auto' '-fbo' # 48.695ms, total 28632.5ms
'bin/gl-3.0-texparameteri' '-auto' '-fbo' # 44.085ms, total 28676.6ms
'bin/generatemipmap-cubemap' '-auto' '-fbo' # 59.226ms, total 28735.9ms
'bin/teximage-colors' 'GL_RG' '-auto' '-fbo' # 165.208ms, total 28901.1ms
'bin/varying-packing-simple' 'vec2' 'arrays_of_arrays' '-auto' '-fbo' # 384.974ms, total 29286.0ms
'bin/depthstencil-render-miplevels' '585' 'd=z32f' '-auto' # 123.815ms, total 29409.9ms
'bin/gl-3.2-layered-rendering-framebuffertexture' '-auto' '-fbo' # 70.107ms, total 29480.0ms
'bin/gl-3.2-layered-rendering-clear-color-all-types' '2d_array' 'mipmapped' '-auto' '-fbo' # 59.439ms, total 29539.4ms
'bin/built-in-constants_gles2' '/home/ickle/piglit/tests/spec/glsl-es-1.00/minimum-maximums.txt' '-auto' '-fbo' # 90.612ms, total 29630.0ms
'bin/gl-3.0-forward-compatible-bit' 'no' '-auto' '-fbo' # 48.805ms, total 29678.8ms
'bin/copyteximage' 'RECT' '-samples=6' '-auto' # 160.115ms, total 29838.9ms
'bin/gl-3.1-primitive-restart-xfb' 'written' '-auto' '-fbo' # 57.620ms, total 29896.5ms
'bin/vao-01' '-auto' # 47.613ms, total 29944.2ms
'bin/gl-3.2-layered-rendering-clear-color-all-types' '3d' 'mipmapped' '-auto' '-fbo' # 51.769ms, total 29995.9ms

-Chris
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [igt-dev] [PATCH i-g-t] RFCv2 tools: capture execution pathways
  2018-04-20 21:50 [igt-dev] [PATCH igt] RFC tools: capture execution pathways Chris Wilson
                   ` (3 preceding siblings ...)
  2018-04-25 20:22 ` [igt-dev] [PATCH igt] RFC tools: capture execution pathways Chris Wilson
@ 2018-04-25 20:42 ` Chris Wilson
  2018-04-25 20:57 ` Chris Wilson
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Chris Wilson @ 2018-04-25 20:42 UTC (permalink / raw)
  To: igt-dev

igt_kcov edges -o edges.yaml command-to-trace args
...
igt_kcov sort -o sorted.yaml edges.yaml
igt_kcov list --total=30 --single=0.5 sorted.yaml

Requires CONFIG_KCOV

Use LD_PRELOAD to wrap calls to DRM ioctls and capture the execution
trace of all basic blocks invoked directly from the syscall. (Key
limitation!) From the chain of basic blocks, the "edges" are computed
and the number of times each edge is hit is stored in a vector (modulo a
large hash). The goal then is to select a series of tests that execute
the most unique pathways in the sortest amount of time. To do this we
compare the similarity of the coverage vectors between all commands, and
try to preferentially pick those that are dissimilar from the rest.

* Direct execution pathways from syscall is a huge limitation for
evaluating general testing of driver pathways, but is not so huge when
myopically focusing on the ABI as say used by mesa.

** Caveat lector. Hastily thrown together. (Still)
---
 meson.build            |    1 +
 tools/Makefile.am      |   11 +-
 tools/igt_kcov.c       | 1213 ++++++++++++++++++++++++++++++++++++++++
 tools/igt_kcov_edges.c |  145 +++++
 tools/meson.build      |   12 +
 5 files changed, 1381 insertions(+), 1 deletion(-)
 create mode 100644 tools/igt_kcov.c
 create mode 100644 tools/igt_kcov_edges.c

diff --git a/meson.build b/meson.build
index 5b783e5d5..8cb029ad7 100644
--- a/meson.build
+++ b/meson.build
@@ -89,6 +89,7 @@ math = cc.find_library('m')
 realtime = cc.find_library('rt')
 dlsym = cc.find_library('dl')
 zlib = cc.find_library('z')
+yaml = cc.find_library('yaml', required: false)
 
 if cc.has_header('linux/kd.h')
 	config.set('HAVE_LINUX_KD_H', 1)
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 09b6dbcc3..5fd69bdff 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,6 +1,7 @@
 include Makefile.sources
 
-bin_PROGRAMS = $(tools_prog_lists)
+bin_PROGRAMS = $(tools_prog_lists) igt_kcov
+lib_LTLIBRARIES = igt_kcov_edges.la
 
 if HAVE_LIBDRM_INTEL
 bin_PROGRAMS += $(LIBDRM_INTEL_BIN)
@@ -28,6 +29,14 @@ intel_aubdump_la_LDFLAGS = -module -avoid-version -no-undefined
 intel_aubdump_la_SOURCES = aubdump.c
 intel_aubdump_la_LIBADD = $(top_builddir)/lib/libintel_tools.la -ldl
 
+# XXX FIXME
+igt_kcov_SOURCES = igt_kcov.c
+igt_kcov_LDADD = -lyaml -lz -lrt -lm
+
+igt_kcov_edges_la_SOURCES = igt_kcov_edges.c
+igt_kcov_edges_la_LDFLAGS = -module -no-undefined -avoid-version
+igt_kcov_edges_la_LIBADD = -ldl
+
 bin_SCRIPTS = intel_aubdump
 CLEANFILES = $(bin_SCRIPTS)
 
diff --git a/tools/igt_kcov.c b/tools/igt_kcov.c
new file mode 100644
index 000000000..41a0e487d
--- /dev/null
+++ b/tools/igt_kcov.c
@@ -0,0 +1,1213 @@
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <math.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <yaml.h>
+#include <zlib.h>
+
+#define SZ_8 (1 << 16)
+#define SZ_32 (sizeof(uint32_t) * SZ_8)
+
+static pid_t child = 0;
+
+static void sighandler(int sig)
+{
+	kill(sig, child);
+}
+
+static uint64_t gettime(void)
+{
+	struct timespec ts;
+
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+
+	return ts.tv_sec * 1000000000 + ts.tv_nsec;
+}
+
+struct exec {
+	const char *preload;
+	int uid;
+	int gid;
+};
+
+static int edges_exec(const struct exec *args, char **argv, uint64_t *elapsed)
+{
+	char buf[10];
+	int status;
+	int kcov;
+	int shm;
+	int ret;
+
+	kcov = open("/sys/kernel/debug/kcov", O_RDWR);
+	if (kcov < 0)
+		return -errno;
+
+	shm = memfd_create("igt_kcov", 0);
+	if (shm == -1) {
+		close(kcov);
+		return -errno;
+	}
+
+	ftruncate(shm, SZ_32);
+
+	switch ((child = fork())) {
+	case 0: /* child */
+		if (args->gid)
+			setgid(args->gid);
+		if (args->uid)
+			setuid(args->uid);
+
+		sprintf(buf, "%d", shm);
+		setenv("IGT_SHM_FD", buf, 1);
+
+		sprintf(buf, "%d", kcov);
+		setenv("IGT_KCOV_FD", buf, 1);
+
+		setenv("LD_PRELOAD", args->preload, 1);
+		exit(execvp(argv[0], argv));
+		break;
+
+	case -1:
+		ret = -errno;
+		break;
+
+	default:
+		signal(SIGINT, sighandler);
+
+		*elapsed = -gettime();
+		do {
+			ret = waitpid(child, &status, 0);
+			if (ret == -1)
+				ret = -errno;
+		} while (ret == -EINTR);
+		*elapsed += gettime();
+
+		signal(SIGINT, SIG_DFL);
+		child = 0;
+	}
+
+	close(kcov);
+	if (ret < 0) {
+		close(shm);
+		shm = ret;
+	}
+
+	return shm;
+}
+
+static inline unsigned long __fls(unsigned long word)
+{
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86__) || defined(__x86_64__))
+	asm("bsr %1,%0"
+	    : "=r" (word)
+	    : "rm" (word));
+	return word;
+#else
+	unsigned int v = 0;
+
+	while (word >>= 1)
+		v++;
+
+	return v;
+#endif
+}
+
+static uint8_t lower_u32(uint32_t x)
+{
+	if (x < 16)
+		return x;
+	else
+		return (x >> (__fls(x) - 2)) + ((__fls(x) - 1) << 2);
+}
+
+static uint8_t *lower_edges(int shm)
+{
+	uint8_t *lower;
+	uint32_t *tbl;
+	unsigned int n;
+
+	tbl = mmap(NULL, SZ_32, PROT_READ, MAP_SHARED, shm, 0);
+	if (tbl == MAP_FAILED)
+		return NULL;
+
+	if (tbl[0] == 0) /* empty */
+		goto out;
+
+	lower = malloc(SZ_8);
+	if (!lower)
+		goto out;
+
+	for (n = 0; n < 1 << 16; n++)
+		lower[n] = lower_u32(tbl[n]);
+
+out:
+	munmap(tbl, SZ_32);
+	return lower;
+}
+
+static bool ascii85_encode(uint32_t in, char *out)
+{
+	int i;
+
+	if (in == 0)
+		return false;
+
+	for (i = 5; i--; ) {
+		out[i] = '!' + in % 85;
+		in /= 85;
+	}
+
+	return true;
+}
+
+static char *edges_to_ascii85(uint8_t *tbl)
+{
+	z_stream zs;
+	uint32_t *p;
+	void *out;
+	char *str, *s;
+	int sz;
+
+	sz = SZ_8 * 3 /2;
+	out = malloc(sz);
+	if (!out)
+		return NULL;
+
+	memset(&zs, 0, sizeof(zs));
+	if (deflateInit(&zs, 9)) {
+		free(out);
+		return NULL;
+	}
+
+	zs.next_in = tbl;
+	zs.avail_in = SZ_8;
+	zs.total_in = 0;
+	zs.avail_out = sz;
+	zs.total_out = 0;
+	zs.next_out = out;
+
+	deflate(&zs, Z_FINISH);
+	deflateEnd(&zs);
+
+	if (zs.total_out & 3)
+		memset((char *)out + zs.total_out, 0, 4 - (zs.total_out & 3));
+	zs.total_out = (zs.total_out + 3) / 4;
+
+	str = malloc(zs.total_out * 5 + 1);
+	if (!str) {
+		free(out);
+		return NULL;
+	}
+
+	p = out;
+	s = str;
+	for (int i = 0; i < zs.total_out; i++) {
+		if (ascii85_encode(*p++, s))
+			s += 5;
+		else
+			*s++ = 'z';
+	}
+	*s++ = '\0';
+	free(out);
+
+	return str;
+}
+
+static void edges(int argc, char **argv)
+{
+	static const struct option longopts[] = {
+		{"output", required_argument, 0, 'o'},
+		{"preload", required_argument, 0, 'p'},
+		{"user", required_argument, 0, 'u'},
+		{"group", required_argument, 0, 'g'},
+		{ NULL, 0, NULL, 0 }
+	};
+	struct exec args = {
+		.preload = "/tmp/igt_kcov_edges.so",
+	};
+	FILE *out = stdout;
+	uint64_t elapsed;
+	uint8_t *tbl;
+	char *str, *s;
+	int shm, i;
+
+	while ((i = getopt_long(argc, argv,
+				"+o:g:u:",
+				longopts, NULL)) != -1) {
+		switch (i) {
+		case 'o':
+			if (strcmp(optarg, "-"))
+				out = fopen(optarg, "a");
+			if (!out) {
+				fprintf(stderr,
+					"Unable to open output file '%s'\n",
+					optarg);
+				exit(1);
+			}
+			break;
+		case 'p':
+			args.preload = optarg;
+			break;
+		case 'u':
+			args.uid = atoi(optarg);
+			break;
+		case 'g':
+			args.gid = atoi(optarg);
+			break;
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 1) {
+		fprintf(stderr,
+			"usage: igt_kcov edges [options] program-to-edges args...\n");
+		exit(1);
+	}
+
+	shm = edges_exec(&args, argv, &elapsed);
+	if (shm < 0) {
+		fprintf(stderr,
+			"Execution of %s failed: err=%d\n",
+			argv[0], shm);
+		exit(1);
+	}
+
+	tbl = lower_edges(shm);
+	close(shm);
+	if (!tbl)
+		exit(1);
+
+	str = edges_to_ascii85(tbl);
+	fprintf(out, "---\n");
+	fprintf(out, "cmd: |  \n");
+	for (i = 0; i < argc; i++) {
+		fprintf(out, " '");
+		for (s = argv[i]; *s; s++) {
+			if (*s == '\'')
+				fprintf(out, "\\\'");
+			else
+				fprintf(out, "%c", *s);
+		}
+		fprintf(out, "'");
+	}
+	fprintf(out, "\n");
+
+	fprintf(out, "elapsed: %"PRIu64" # %.1fms\n", elapsed, 1e-6 * elapsed);
+
+	fprintf(out, "edges: !!ascii85.gz |\n");
+	i = strlen(str);
+	s = str;
+	while (i) {
+		int len = i > 70 ? 70 : i;
+		char tmp;
+
+		tmp = s[len];
+		s[len] = '\0';
+		fprintf(out, "  %s\n", s);
+		s[len] = tmp;
+
+		s += len;
+		i -= len;
+	}
+
+	free(str);
+}
+
+static unsigned long zlib_inflate(void *in, unsigned long len,
+				  void *ptr, unsigned long max)
+{
+	struct z_stream_s zstream;
+
+	memset(&zstream, 0, sizeof(zstream));
+
+	zstream.next_in = in;
+	zstream.avail_in = len;
+
+	if (inflateInit(&zstream) != Z_OK)
+		return 0;
+
+	zstream.next_out = ptr;
+	zstream.avail_out = max;
+
+	switch (inflate(&zstream, Z_SYNC_FLUSH)) {
+	case Z_STREAM_END:
+	case Z_OK:
+		break;
+	default:
+		zstream.total_out = 0;
+		break;
+	}
+
+	inflateEnd(&zstream);
+	return zstream.total_out;
+}
+
+static unsigned long ascii85_decode(const char *in,
+				    void *ptr, unsigned long max)
+{
+	unsigned long sz = max / sizeof(uint32_t);
+	unsigned long len = 0;
+	uint32_t *out;
+
+	out = malloc(sz * sizeof(uint32_t));
+	if (out == NULL)
+		return 0;
+
+	while (*in) {
+		uint32_t v = 0;
+
+		if (isspace(*in)) {
+			in++;
+			continue;
+		}
+
+		if (*in < '!' || *in > 'z') {
+			fprintf(stderr, "Invalid value in ascii85 block\n");
+			free(out);
+			return 0;
+		}
+
+		if (len == sz) {
+			sz *= 2;
+			out = realloc(out, sz * sizeof(uint32_t));
+			if (out == NULL)
+				return 0;
+		}
+
+		if (*in == 'z') {
+			in++;
+		} else {
+			v += in[0] - 33; v *= 85;
+			v += in[1] - 33; v *= 85;
+			v += in[2] - 33; v *= 85;
+			v += in[3] - 33; v *= 85;
+			v += in[4] - 33;
+			in += 5;
+		}
+		out[len++] = v;
+	}
+
+	len = zlib_inflate(out, len * sizeof(*out), ptr, max);
+	free(out);
+
+	return len;
+}
+
+static void yaml_print_parser_error(yaml_parser_t *parser, FILE *stream)
+{
+	switch (parser->error) {
+	case YAML_MEMORY_ERROR:
+		fprintf(stderr, "Memory error: Not enough memory for parsing\n");
+		break;
+
+	case YAML_READER_ERROR:
+		if (parser->problem_value != -1) {
+			fprintf(stderr, "Reader error: %s: #%X at %zd\n", parser->problem,
+				parser->problem_value, parser->problem_offset);
+		} else {
+			fprintf(stderr, "Reader error: %s at %zd\n", parser->problem,
+				parser->problem_offset);
+		}
+		break;
+
+	case YAML_SCANNER_ERROR:
+		if (parser->context) {
+			fprintf(stderr, "Scanner error: %s at line %lu, column %lu\n"
+				"%s at line %lu, column %lu\n", parser->context,
+				parser->context_mark.line+1, parser->context_mark.column+1,
+				parser->problem, parser->problem_mark.line+1,
+				parser->problem_mark.column+1);
+		} else {
+			fprintf(stderr, "Scanner error: %s at line %lu, column %lu\n",
+				parser->problem, parser->problem_mark.line+1,
+				parser->problem_mark.column+1);
+		}
+		break;
+
+	case YAML_PARSER_ERROR:
+		if (parser->context) {
+			fprintf(stderr, "Parser error: %s at line %lu, column %lu\n"
+				"%s at line %lu, column %lu\n", parser->context,
+				parser->context_mark.line+1, parser->context_mark.column+1,
+				parser->problem, parser->problem_mark.line+1,
+				parser->problem_mark.column+1);
+		} else {
+			fprintf(stderr, "Parser error: %s at line %lu, column %lu\n",
+				parser->problem, parser->problem_mark.line+1,
+				parser->problem_mark.column+1);
+		}
+		break;
+
+	default:
+		/* Couldn't happen. */
+		fprintf(stderr, "Internal error\n");
+		break;
+	}
+}
+
+struct edges {
+	struct edges *next;
+
+	char *command;
+	uint64_t elapsed;
+
+	unsigned int weight;
+
+	uint8_t tbl[SZ_8];
+};
+
+struct sort {
+	struct edges *edges;
+	unsigned int count;
+
+	unsigned int max_weight;
+	struct edges *best;
+};
+
+static bool sort_parse_command(struct sort *sort,
+			       struct edges *e,
+			       yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+	const char *s;
+	int len;
+
+	if (!yaml_parser_parse(parser, &ev))
+		return false;
+
+	switch (ev.type) {
+	case YAML_SCALAR_EVENT:
+		break;
+
+	default:
+		return false;
+	}
+
+
+	s = (const char *)ev.data.scalar.value;
+	len = strlen(s);
+	while (s[len - 1] == '\n')
+		len--;
+	e->command = malloc(len + 1);
+	if (e->command) {
+		memcpy(e->command, s, len);
+		e->command[len] = '\0';
+	}
+	yaml_event_delete(&ev);
+
+	return true;
+}
+
+static bool sort_parse_elapsed(struct sort *sort,
+			       struct edges *e,
+			       yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+	const char *s;
+
+	if (!yaml_parser_parse(parser, &ev))
+		return false;
+
+	switch (ev.type) {
+	case YAML_SCALAR_EVENT:
+		break;
+
+	default:
+		return false;
+	}
+
+	s = (const char *)ev.data.scalar.value;
+	e->elapsed = strtoull(s, NULL, 0);
+	yaml_event_delete(&ev);
+
+	return true;
+}
+
+static unsigned int bitmap_weight(const void *bitmap, unsigned int bits)
+{
+	const uint32_t *b = bitmap;
+	unsigned int k, lim = bits / 32;
+	unsigned int w = 0;
+
+	for (k = 0; k < lim; k++)
+		w += __builtin_popcount(b[k]);
+
+	if (bits % 32)
+		w += __builtin_popcount(b[k] << (32 - bits % 32));
+
+	return w;
+}
+
+static bool sort_parse_edges(struct sort *sort,
+			     struct edges *e,
+			     yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+	const char *s;
+
+	if (!yaml_parser_parse(parser, &ev))
+		return false;
+
+	switch (ev.type) {
+	case YAML_SCALAR_EVENT:
+		break;
+
+	default:
+		return false;
+	}
+
+	s = (const char *)ev.data.scalar.value;
+	if (ascii85_decode(s, e->tbl, sizeof(e->tbl)))
+		e->weight = bitmap_weight(e->tbl, sizeof(e->tbl) * 8);
+	yaml_event_delete(&ev);
+
+	return true;
+}
+
+static bool edges_valid(const struct edges *e)
+{
+	if (!e->command)
+		return false;
+
+	if (!e->weight)
+		return false;
+
+	if (!e->elapsed)
+		return false;
+
+	return true; /* good enough at least */
+}
+
+static bool sort_add_edges(struct sort *sort, struct edges *e)
+{
+	if (!edges_valid(e))
+		return false;
+
+	e->next = sort->edges;
+	sort->edges = e;
+
+	if (e->weight > sort->max_weight) {
+		sort->max_weight = e->weight;
+		sort->best = e;
+	}
+
+	sort->count++;
+
+	return true;
+}
+
+static bool sort_parse_node(struct sort *sort, yaml_parser_t *parser)
+{
+	struct edges *e;
+	yaml_event_t ev;
+	char *s;
+
+	e = malloc(sizeof(*e));
+	if (!e)
+		return false;
+
+	e->weight = 0;
+
+	do {
+		if (!yaml_parser_parse(parser, &ev))
+			goto err;
+
+		switch (ev.type) {
+		case YAML_MAPPING_END_EVENT:
+			if (!sort_add_edges(sort, e))
+				goto err;
+
+			return true;
+
+		case YAML_SCALAR_EVENT:
+			break;
+
+		default:
+			goto err;
+		}
+
+		s = (char *)ev.data.scalar.value;
+		if (!strcmp(s, "cmd")) {
+			sort_parse_command(sort, e, parser);
+		} else if (!strcmp(s, "elapsed")) {
+			sort_parse_elapsed(sort, e, parser);
+		} else if (!strcmp(s, "edges")) {
+			sort_parse_edges(sort, e, parser);
+		} else {
+			fprintf(stderr,
+				"Unknown element in edges file: %s\n",
+				s);
+		}
+
+		yaml_event_delete(&ev);
+	} while (1);
+
+err:
+	free(e);
+	return false;
+}
+
+static bool sort_parse_doc(struct sort *sort, yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+
+	do {
+		if (!yaml_parser_parse(parser, &ev))
+			return false;
+
+		switch (ev.type) {
+		case YAML_DOCUMENT_END_EVENT:
+			return true;
+
+		case YAML_MAPPING_START_EVENT:
+			break;
+
+		default:
+			return false;
+		}
+		yaml_event_delete(&ev);
+
+		if (!sort_parse_node(sort, parser))
+			return false;
+	} while(1);
+}
+
+static bool sort_add(struct sort *sort, FILE *file)
+{
+	yaml_parser_t parser;
+	bool done = false;
+	yaml_event_t ev;
+
+	yaml_parser_initialize(&parser);
+	yaml_parser_set_input_file(&parser, file);
+
+	memset(&ev, 0, sizeof(ev));
+	yaml_parser_parse(&parser, &ev);
+	if (ev.type != YAML_STREAM_START_EVENT) {
+		fprintf(stderr, "Parser setup failed\n");
+		return false;
+	}
+	yaml_event_delete(&ev);
+
+	do {
+		if (!yaml_parser_parse(&parser, &ev)) {
+			fprintf(stderr, "Invalid yaml\n");
+			yaml_print_parser_error(&parser, stderr);
+			return false;
+		}
+
+		switch (ev.type) {
+		case YAML_DOCUMENT_START_EVENT:
+			break;
+
+		case YAML_STREAM_END_EVENT:
+			done = true;
+			break;
+
+		default:
+			return false;
+		}
+		yaml_event_delete(&ev);
+
+		sort_parse_doc(sort, &parser);
+	} while (!done);
+
+	yaml_parser_delete(&parser);
+	return true;
+}
+
+static double edges_similarity(const struct edges *ta, const struct edges *tb)
+{
+	uint64_t sab, saa, sbb;
+	const uint8_t *a, *b;
+
+	if (ta == tb)
+		return 1;
+
+	a = ta->tbl;
+	b = tb->tbl;
+	sab = 0;
+	saa = 0;
+	sbb = 0;
+
+	for (unsigned int i = 0; i < SZ_8; i++) {
+		sab += (uint32_t)a[i] * b[i];
+		saa += (uint32_t)a[i] * a[i];
+		sbb += (uint32_t)b[i] * b[i];
+	}
+
+	return sab / (sqrt(saa) * sqrt(sbb));
+}
+
+static void rank_by_dissimilarity(struct sort *sort, FILE *out)
+{
+	const unsigned int count = sort->count;
+	double *M, *dis, *sim;
+	struct edges **edges, **t;
+	bool *used;
+	int last = -1;
+
+	t = edges = malloc(count * sizeof(*edges));
+	for (struct edges *e = sort->edges; e; e = e->next)
+		*t++ = e;
+
+	M = malloc(sizeof(double) * count * (count + 2));
+	dis = M + count * count;
+	sim = dis + count;
+	for (int i = 0; i < count; i++) {
+		dis[i] = 0.;
+		sim[i] = 1.;
+		for (int j = 0; j < i; j++)
+			dis[i] += M[j*count + i];
+		for (int j = i + 1; j < count; j++) {
+			double s = edges_similarity(edges[i], edges[j]);
+			s = 1. - s*s;
+			M[i*count + j] = s;
+			dis[i] += s;
+		}
+	}
+
+	fprintf(out, "---\n");
+
+	used = calloc(count, sizeof(bool));
+	for (int rank = 0; rank < count; rank++) {
+		struct edges *e;
+		double best = -HUGE_VAL;
+		int this = -1;
+
+		for (int i = 0; i < count; i++) {
+			double d;
+
+			if (used[i])
+				continue;
+
+			d = dis[i];
+			if (last != -1) {
+				double s;
+
+				if (last < i)
+					s = M[last * count + i];
+				else
+					s = M[i * count + last];
+
+				s *= sim[i];
+				sim[i] = s;
+
+				d *= sqrt(s);
+			}
+			if (d > best) {
+				best = d;
+				this = i;
+			}
+		}
+
+		e = edges[this];
+		used[this] = true;
+		last = this;
+
+		fprintf(out, "- cmd: |\n    %s\n", e->command);
+		fprintf(out, "  elapsed: %"PRIu64" # %.1fms\n",
+			e->elapsed, 1e-6 * e->elapsed);
+		fprintf(out, "  dissimilarity: %f\n",
+			sqrt(best / (count - rank)));
+	}
+
+	free(M);
+	free(edges);
+}
+
+static void sort(int argc, char **argv)
+{
+	static const struct option longopts[] = {
+		{"output", required_argument, 0, 'o'},
+		{ NULL, 0, NULL, 0 }
+	};
+	FILE *out = stdout;
+	struct sort sort;
+	int i;
+
+	while ((i = getopt_long(argc, argv,
+				"+o:",
+				longopts, NULL)) != -1) {
+		switch (i) {
+		case 'o':
+			if (strcmp(optarg, "-"))
+				out = fopen(optarg, "a");
+			if (!out) {
+				fprintf(stderr,
+					"Unable to open output file '%s'\n",
+					optarg);
+				exit(1);
+			}
+			break;
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	memset(&sort, 0, sizeof(sort));
+
+	if (argc == 0) {
+		sort_add(&sort, stdin);
+	} else {
+		for (i = 0; i < argc; i++) {
+			FILE *in;
+
+			in = fopen(argv[i], "r");
+			if (!in) {
+				fprintf(stderr, "unable to open input '%s'\n",
+					argv[i]);
+				exit(1);
+			}
+
+			sort_add(&sort, in);
+
+			fclose(in);
+		}
+	}
+
+	if (!sort.count)
+		return;
+
+	rank_by_dissimilarity(&sort, out);
+}
+
+struct list {
+	struct {
+		double single;
+		double total;
+	} limit;
+	double total;
+	FILE *out;
+};
+
+struct list_node {
+	char *cmd;
+	uint64_t elapsed;
+};
+
+static bool list_parse_command(struct list *list,
+			       struct list_node *node,
+			       yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+	const char *s;
+	int len;
+
+	if (!yaml_parser_parse(parser, &ev))
+		return false;
+
+	switch (ev.type) {
+	case YAML_SCALAR_EVENT:
+		break;
+
+	default:
+		return false;
+	}
+
+
+	s = (const char *)ev.data.scalar.value;
+	len = strlen(s);
+	while (len > 0 && isspace(s[len - 1]))
+		len--;
+
+	node->cmd = strndup(s, len);
+	yaml_event_delete(&ev);
+
+	return true;
+}
+
+static bool list_parse_elapsed(struct list *list,
+			       struct list_node *node,
+			       yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+	const char *s;
+
+	if (!yaml_parser_parse(parser, &ev))
+		return false;
+
+	switch (ev.type) {
+	case YAML_SCALAR_EVENT:
+		break;
+
+	default:
+		return false;
+	}
+
+	s = (const char *)ev.data.scalar.value;
+	node->elapsed = strtoull(s, NULL, 0);
+	yaml_event_delete(&ev);
+
+	return true;
+}
+
+static bool list_parse_node(struct list *list, yaml_parser_t *parser)
+{
+	struct list_node node = {};
+	yaml_event_t ev;
+	char *s;
+
+	do {
+		if (!yaml_parser_parse(parser, &ev))
+			return false;
+
+		switch (ev.type) {
+		case YAML_MAPPING_END_EVENT:
+			if (list->limit.single &&
+			    1e-9 * node.elapsed > list->limit.single) {
+				free(node.cmd);
+				return true;
+			}
+
+			if (list->limit.total &&
+			    list->total + 1e-9 * node.elapsed > list->limit.total) {
+				free(node.cmd);
+				return true;
+			}
+
+			if (node.cmd) {
+				list->total += 1e-9 * node.elapsed;
+				fprintf(list->out,
+					"%s # %.3fms, total %.1fms\n",
+					node.cmd,
+					1e-6 * node.elapsed,
+					1e3 * list->total);
+				free(node.cmd);
+			}
+			return true;
+
+		case YAML_SCALAR_EVENT:
+			break;
+
+		default:
+			return false;
+		}
+
+		s = (char *)ev.data.scalar.value;
+		if (!strcmp(s, "cmd")) {
+			list_parse_command(list, &node, parser);
+		} else if (!strcmp(s, "elapsed")) {
+			if (!list_parse_elapsed(list, &node,parser))
+				return false;
+		}
+		yaml_event_delete(&ev);
+	} while (1);
+}
+
+static bool list_parse_sequence(struct list *list, yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+
+	do {
+		if (!yaml_parser_parse(parser, &ev))
+			return false;
+
+		switch (ev.type) {
+		case YAML_SEQUENCE_END_EVENT:
+			return true;
+
+		case YAML_MAPPING_START_EVENT:
+			if (!list_parse_node(list, parser))
+				return false;
+			break;
+
+		default:
+			return false;
+		}
+		yaml_event_delete(&ev);
+	} while(1);
+}
+
+static bool list_parse_doc(struct list *list, yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+
+	do {
+		if (!yaml_parser_parse(parser, &ev))
+			return false;
+
+		switch (ev.type) {
+		case YAML_DOCUMENT_END_EVENT:
+			return true;
+
+		case YAML_MAPPING_START_EVENT:
+			if (!list_parse_node(list, parser))
+				return false;
+			break;
+
+		case YAML_SEQUENCE_START_EVENT:
+			if (!list_parse_sequence(list, parser))
+				return false;
+			break;
+
+		default:
+			return false;
+		}
+		yaml_event_delete(&ev);
+	} while(1);
+}
+
+static bool list_show(struct list *list, FILE *file)
+{
+	yaml_parser_t parser;
+	bool done = false;
+	yaml_event_t ev;
+
+	yaml_parser_initialize(&parser);
+	yaml_parser_set_input_file(&parser, file);
+
+	memset(&ev, 0, sizeof(ev));
+	yaml_parser_parse(&parser, &ev);
+	if (ev.type != YAML_STREAM_START_EVENT) {
+		fprintf(stderr, "Parser setup failed\n");
+		return false;
+	}
+	yaml_event_delete(&ev);
+
+	do {
+		if (!yaml_parser_parse(&parser, &ev)) {
+			fprintf(stderr, "Invalid yaml\n");
+			yaml_print_parser_error(&parser, stderr);
+			return false;
+		}
+
+		switch (ev.type) {
+		case YAML_DOCUMENT_START_EVENT:
+			break;
+
+		case YAML_STREAM_END_EVENT:
+			done = true;
+			break;
+
+		default:
+			return false;
+		}
+		yaml_event_delete(&ev);
+
+		list_parse_doc(list, &parser);
+	} while (!done);
+
+	yaml_parser_delete(&parser);
+	return true;
+}
+
+static void list(int argc, char **argv)
+{
+	static const struct option longopts[] = {
+		{"output", required_argument, 0, 'o'},
+		{"total", required_argument, 0, 't'},
+		{"single", required_argument, 0, 's'},
+		{ NULL, 0, NULL, 0 }
+	};
+	struct list list;
+	int i;
+
+	memset(&list, 0, sizeof(list));
+	list.out = stdout;
+
+	while ((i = getopt_long(argc, argv,
+				"+o:t:",
+				longopts, NULL)) != -1) {
+		switch (i) {
+		case 'o':
+			if (strcmp(optarg, "-"))
+				list.out = fopen(optarg, "a");
+			if (!list.out) {
+				fprintf(stderr,
+					"Unable to open output file '%s'\n",
+					optarg);
+				exit(1);
+			}
+			break;
+		case 's':
+			list.limit.single = atof(optarg);
+			break;
+		case 't':
+			list.limit.total = atof(optarg);
+			break;
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc == 0) {
+		list_show(&list, stdin);
+	} else {
+		for (i = 0; i < argc; i++) {
+			FILE *in;
+
+			in = fopen(argv[i], "r");
+			if (!in) {
+				fprintf(stderr, "unable to open input '%s'\n",
+					argv[i]);
+				exit(1);
+			}
+
+			fprintf(stderr, "%s\n", argv[i]);
+
+			if (!list_show(&list, in))
+				i = argc;
+
+			fclose(in);
+		}
+	}
+}
+
+int main(int argc, char **argv)
+{
+	static const struct option longopts[] = {
+		{"verbose", no_argument, 0, 'v'},
+		{ NULL, 0, NULL, 0 }
+	};
+	int o;
+
+	while ((o = getopt_long(argc, argv,
+				"+v",
+				longopts, NULL)) != -1) {
+		switch (o) {
+		case 'v':
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (optind == argc) {
+		fprintf(stderr, "no subcommand specified\n");
+		exit(1);
+	}
+
+	argc -= optind;
+	argv += optind;
+	optind = 1;
+
+	if (!strcmp(argv[0], "edges")) {
+		edges(argc, argv);
+	} else if (!strcmp(argv[0], "sort")) {
+		sort(argc, argv);
+	} else if (!strcmp(argv[0], "list")) {
+		list(argc, argv);
+	} else {
+		fprintf(stderr, "Unknown command '%s'\n", argv[0]);
+		exit(1);
+	}
+
+	return 0;
+}
diff --git a/tools/igt_kcov_edges.c b/tools/igt_kcov_edges.c
new file mode 100644
index 000000000..750d4f8b5
--- /dev/null
+++ b/tools/igt_kcov_edges.c
@@ -0,0 +1,145 @@
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include <linux/types.h>
+
+static int (*libc_ioctl)(int fd, unsigned long request, void *argp);
+
+static struct kcov {
+	unsigned long *trace;
+	uint32_t *table;
+	int fd;
+} kcov;
+
+#define KCOV_INIT_TRACE                 _IOR('c', 1, unsigned long)
+#define KCOV_ENABLE                     _IO('c', 100)
+#define   KCOV_TRACE_PC  0
+#define   KCOV_TRACE_CMP 1
+#define KCOV_DISABLE                    _IO('c', 101)
+
+#define DRM_IOCTL_BASE 'd'
+
+#define GOLDEN_RATIO_32 0x61C88647
+#define GOLDEN_RATIO_64 0x61C8864680B583EBull
+
+static inline uint32_t hash_32(uint32_t val, unsigned int bits)
+{
+        return val * GOLDEN_RATIO_32 >> (32 - bits);
+}
+
+static inline uint32_t hash_64(uint64_t val, unsigned int bits)
+{
+        return val * GOLDEN_RATIO_64 >> (64 - bits);
+}
+
+#define hash_long(x, y) hash_64(x, y)
+
+static bool kcov_open(struct kcov *kc, unsigned long count)
+{
+	const char *env;
+	int shm;
+
+	env = getenv("IGT_SHM_FD");
+	if (!env)
+		return false;
+
+	shm = atoi(env);
+	kc->table = mmap(NULL, sizeof(uint32_t) << 16,
+			 PROT_WRITE, MAP_SHARED, shm, 0);
+	close(shm);
+	if (kc->table == (uint32_t *)MAP_FAILED)
+		return false;
+
+	env = getenv("IGT_KCOV_FD");
+	if (!env)
+		goto err_shm;
+
+	kc->fd = atoi(env);
+	if (libc_ioctl(kc->fd, KCOV_INIT_TRACE, (void *)count))
+		goto err_close;
+
+	kc->trace = mmap(NULL, count * sizeof(unsigned long),
+			 PROT_WRITE, MAP_SHARED, kc->fd, 0);
+	if (kc->trace == MAP_FAILED)
+		goto err_close;
+
+	return true;
+
+err_close:
+	close(kc->fd);
+err_shm:
+	munmap(kc->table, sizeof(uint32_t) << 16);
+	return false;
+}
+
+static void kcov_enable(struct kcov *kc)
+{
+	libc_ioctl(kc->fd, KCOV_ENABLE, KCOV_TRACE_PC);
+	__atomic_store_n(&kc->trace[0], 0, __ATOMIC_RELAXED);
+}
+
+static unsigned long kcov_disable(struct kcov *kc)
+{
+	unsigned long depth;
+
+	depth = __atomic_load_n(&kc->trace[0], __ATOMIC_RELAXED);
+	if (libc_ioctl(kc->fd, KCOV_DISABLE, 0))
+		depth = 0;
+
+	return depth;
+}
+
+int ioctl(int fd, unsigned long request, ...)
+{
+	static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+	unsigned long count, n, prev;
+	va_list args;
+	void *argp;
+	int res;
+
+	va_start(args, request);
+	argp = va_arg(args, void *);
+	va_end(args);
+
+	if (kcov.fd < 0 || _IOC_TYPE(request) != DRM_IOCTL_BASE)
+		return libc_ioctl(fd, request, argp);
+
+	pthread_mutex_lock(&mutex);
+	kcov_enable(&kcov);
+
+	res = libc_ioctl(fd, request, argp);
+
+	count = kcov_disable(&kcov);
+	prev = hash_long(kcov.trace[1], 16);
+	for (n = 2; n <= count; n++) {
+		unsigned long loc = hash_long(kcov.trace[n], 16);
+
+		kcov.table[prev ^ loc]++;
+		prev = loc >> 1;
+	}
+	kcov.table[0] |= 1;
+	pthread_mutex_unlock(&mutex);
+
+	return res;
+}
+
+__attribute__((constructor))
+static void init(void)
+{
+	libc_ioctl = dlsym(RTLD_NEXT, "ioctl");
+
+	if (!kcov_open(&kcov, 64 << 10))
+		kcov.fd = -1;
+}
diff --git a/tools/meson.build b/tools/meson.build
index bd2d313d5..a5ea108ff 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -105,6 +105,18 @@ executable('intel_reg', sources : intel_reg_src,
 	     '-DIGT_DATADIR="@0@"'.format(join_paths(prefix, datadir)),
 	   ])
 
+if yaml.found()
+	executable('igt_kcov',
+		   sources: [ 'igt_kcov.c' ],
+		   dependencies: [ zlib, realtime, math, yaml ],
+		   install: true) # setuid me!
+
+	shared_module('igt_kcov_edges',
+		      sources: [ 'igt_kcov_edges.c' ],
+		      dependences: [ 'dlsym' ],
+		      install: true) # strip version, lib prefix, -Dlibdir
+endif
+
 install_data('intel_gpu_abrt', install_dir : bindir)
 
 install_subdir('registers', install_dir : datadir,
-- 
2.17.0

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [igt-dev] [PATCH i-g-t] RFCv2 tools: capture execution pathways
  2018-04-20 21:50 [igt-dev] [PATCH igt] RFC tools: capture execution pathways Chris Wilson
                   ` (4 preceding siblings ...)
  2018-04-25 20:42 ` [igt-dev] [PATCH i-g-t] RFCv2 " Chris Wilson
@ 2018-04-25 20:57 ` Chris Wilson
  2018-04-25 23:09 ` [igt-dev] ✓ Fi.CI.BAT: success for RFC tools: capture execution pathways (rev4) Patchwork
  2018-04-26  2:47 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
  7 siblings, 0 replies; 11+ messages in thread
From: Chris Wilson @ 2018-04-25 20:57 UTC (permalink / raw)
  To: igt-dev

igt_kcov edges -o edges.yaml command-to-trace args
...
igt_kcov sort -o sorted.yaml edges.yaml
igt_kcov list --total=30 --single=0.5 sorted.yaml

Requires CONFIG_KCOV

Use LD_PRELOAD to wrap calls to DRM ioctls and capture the execution
trace of all basic blocks invoked directly from the syscall. (Key
limitation!) From the chain of basic blocks, the "edges" are computed
and the number of times each edge is hit is stored in a vector (modulo a
large hash). The goal then is to select a series of tests that execute
the most unique pathways in the sortest amount of time. To do this we
compare the similarity of the coverage vectors between all commands, and
try to preferentially pick those that are dissimilar from the rest.

* Direct execution pathways from syscall is a huge limitation for
evaluating general testing of driver pathways, but is not so huge when
myopically focusing on the ABI as say used by mesa.

** Caveat lector. Hastily thrown together. (Still)
---
Fewer meson fumbles.
---
 meson.build            |    1 +
 tools/Makefile.am      |   11 +-
 tools/igt_kcov.c       | 1215 ++++++++++++++++++++++++++++++++++++++++
 tools/igt_kcov_edges.c |  145 +++++
 tools/meson.build      |   13 +
 5 files changed, 1384 insertions(+), 1 deletion(-)
 create mode 100644 tools/igt_kcov.c
 create mode 100644 tools/igt_kcov_edges.c

diff --git a/meson.build b/meson.build
index 5b783e5d5..8cb029ad7 100644
--- a/meson.build
+++ b/meson.build
@@ -89,6 +89,7 @@ math = cc.find_library('m')
 realtime = cc.find_library('rt')
 dlsym = cc.find_library('dl')
 zlib = cc.find_library('z')
+yaml = cc.find_library('yaml', required: false)
 
 if cc.has_header('linux/kd.h')
 	config.set('HAVE_LINUX_KD_H', 1)
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 09b6dbcc3..5fd69bdff 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,6 +1,7 @@
 include Makefile.sources
 
-bin_PROGRAMS = $(tools_prog_lists)
+bin_PROGRAMS = $(tools_prog_lists) igt_kcov
+lib_LTLIBRARIES = igt_kcov_edges.la
 
 if HAVE_LIBDRM_INTEL
 bin_PROGRAMS += $(LIBDRM_INTEL_BIN)
@@ -28,6 +29,14 @@ intel_aubdump_la_LDFLAGS = -module -avoid-version -no-undefined
 intel_aubdump_la_SOURCES = aubdump.c
 intel_aubdump_la_LIBADD = $(top_builddir)/lib/libintel_tools.la -ldl
 
+# XXX FIXME
+igt_kcov_SOURCES = igt_kcov.c
+igt_kcov_LDADD = -lyaml -lz -lrt -lm
+
+igt_kcov_edges_la_SOURCES = igt_kcov_edges.c
+igt_kcov_edges_la_LDFLAGS = -module -no-undefined -avoid-version
+igt_kcov_edges_la_LIBADD = -ldl
+
 bin_SCRIPTS = intel_aubdump
 CLEANFILES = $(bin_SCRIPTS)
 
diff --git a/tools/igt_kcov.c b/tools/igt_kcov.c
new file mode 100644
index 000000000..70ae2b2de
--- /dev/null
+++ b/tools/igt_kcov.c
@@ -0,0 +1,1215 @@
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <math.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <yaml.h>
+#include <zlib.h>
+
+#define SZ_8 (1 << 16)
+#define SZ_32 (sizeof(uint32_t) * SZ_8)
+
+static pid_t child = 0;
+
+static void sighandler(int sig)
+{
+	kill(sig, child);
+}
+
+static uint64_t gettime(void)
+{
+	struct timespec ts;
+
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+
+	return ts.tv_sec * 1000000000 + ts.tv_nsec;
+}
+
+struct exec {
+	const char *preload;
+	int uid;
+	int gid;
+};
+
+static int edges_exec(const struct exec *args, char **argv, uint64_t *elapsed)
+{
+	char buf[10];
+	int status;
+	int kcov;
+	int shm;
+	int ret;
+
+	kcov = open("/sys/kernel/debug/kcov", O_RDWR);
+	if (kcov < 0)
+		return -errno;
+
+	shm = memfd_create("igt_kcov", 0);
+	if (shm == -1) {
+		close(kcov);
+		return -errno;
+	}
+
+	ftruncate(shm, SZ_32);
+
+	switch ((child = fork())) {
+	case 0: /* child */
+		if (args->gid)
+			setgid(args->gid);
+		if (args->uid)
+			setuid(args->uid);
+
+		sprintf(buf, "%d", shm);
+		setenv("IGT_SHM_FD", buf, 1);
+
+		sprintf(buf, "%d", kcov);
+		setenv("IGT_KCOV_FD", buf, 1);
+
+		setenv("LD_PRELOAD", args->preload, 1);
+		exit(execvp(argv[0], argv));
+		break;
+
+	case -1:
+		ret = -errno;
+		break;
+
+	default:
+		signal(SIGINT, sighandler);
+
+		*elapsed = -gettime();
+		do {
+			ret = waitpid(child, &status, 0);
+			if (ret == -1)
+				ret = -errno;
+		} while (ret == -EINTR);
+		*elapsed += gettime();
+
+		signal(SIGINT, SIG_DFL);
+		child = 0;
+	}
+
+	close(kcov);
+	if (ret < 0) {
+		close(shm);
+		shm = ret;
+	}
+
+	return shm;
+}
+
+static inline unsigned long __fls(unsigned long word)
+{
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86__) || defined(__x86_64__))
+	asm("bsr %1,%0"
+	    : "=r" (word)
+	    : "rm" (word));
+	return word;
+#else
+	unsigned int v = 0;
+
+	while (word >>= 1)
+		v++;
+
+	return v;
+#endif
+}
+
+static uint8_t lower_u32(uint32_t x)
+{
+	if (x < 16)
+		return x;
+	else
+		return (x >> (__fls(x) - 2)) + ((__fls(x) - 1) << 2);
+}
+
+static uint8_t *lower_edges(int shm)
+{
+	uint8_t *lower;
+	uint32_t *tbl;
+	unsigned int n;
+
+	tbl = mmap(NULL, SZ_32, PROT_READ, MAP_SHARED, shm, 0);
+	if (tbl == MAP_FAILED)
+		return NULL;
+
+	if (tbl[0] == 0) /* empty */
+		goto out;
+
+	lower = malloc(SZ_8);
+	if (!lower)
+		goto out;
+
+	for (n = 0; n < 1 << 16; n++)
+		lower[n] = lower_u32(tbl[n]);
+
+out:
+	munmap(tbl, SZ_32);
+	return lower;
+}
+
+static bool ascii85_encode(uint32_t in, char *out)
+{
+	int i;
+
+	if (in == 0)
+		return false;
+
+	for (i = 5; i--; ) {
+		out[i] = '!' + in % 85;
+		in /= 85;
+	}
+
+	return true;
+}
+
+static char *edges_to_ascii85(uint8_t *tbl)
+{
+	z_stream zs;
+	uint32_t *p;
+	void *out;
+	char *str, *s;
+	int sz;
+
+	sz = SZ_8 * 3 /2;
+	out = malloc(sz);
+	if (!out)
+		return NULL;
+
+	memset(&zs, 0, sizeof(zs));
+	if (deflateInit(&zs, 9)) {
+		free(out);
+		return NULL;
+	}
+
+	zs.next_in = tbl;
+	zs.avail_in = SZ_8;
+	zs.total_in = 0;
+	zs.avail_out = sz;
+	zs.total_out = 0;
+	zs.next_out = out;
+
+	deflate(&zs, Z_FINISH);
+	deflateEnd(&zs);
+
+	if (zs.total_out & 3)
+		memset((char *)out + zs.total_out, 0, 4 - (zs.total_out & 3));
+	zs.total_out = (zs.total_out + 3) / 4;
+
+	str = malloc(zs.total_out * 5 + 1);
+	if (!str) {
+		free(out);
+		return NULL;
+	}
+
+	p = out;
+	s = str;
+	for (int i = 0; i < zs.total_out; i++) {
+		if (ascii85_encode(*p++, s))
+			s += 5;
+		else
+			*s++ = 'z';
+	}
+	*s++ = '\0';
+	free(out);
+
+	return str;
+}
+
+static void edges(int argc, char **argv)
+{
+	static const struct option longopts[] = {
+		{"output", required_argument, 0, 'o'},
+		{"preload", required_argument, 0, 'p'},
+		{"user", required_argument, 0, 'u'},
+		{"group", required_argument, 0, 'g'},
+		{ NULL, 0, NULL, 0 }
+	};
+	struct exec args = {
+		.preload = "/tmp/igt_kcov_edges.so",
+	};
+	FILE *out = stdout;
+	uint64_t elapsed;
+	uint8_t *tbl;
+	char *str, *s;
+	int shm, i;
+
+	while ((i = getopt_long(argc, argv,
+				"+o:g:u:",
+				longopts, NULL)) != -1) {
+		switch (i) {
+		case 'o':
+			if (strcmp(optarg, "-"))
+				out = fopen(optarg, "a");
+			if (!out) {
+				fprintf(stderr,
+					"Unable to open output file '%s'\n",
+					optarg);
+				exit(1);
+			}
+			break;
+		case 'p':
+			args.preload = optarg;
+			break;
+		case 'u':
+			args.uid = atoi(optarg);
+			break;
+		case 'g':
+			args.gid = atoi(optarg);
+			break;
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 1) {
+		fprintf(stderr,
+			"usage: igt_kcov edges [options] program-to-edges args...\n");
+		exit(1);
+	}
+
+	shm = edges_exec(&args, argv, &elapsed);
+	if (shm < 0) {
+		fprintf(stderr,
+			"Execution of %s failed: err=%d\n",
+			argv[0], shm);
+		exit(1);
+	}
+
+	tbl = lower_edges(shm);
+	close(shm);
+	if (!tbl)
+		exit(1);
+
+	str = edges_to_ascii85(tbl);
+	fprintf(out, "---\n");
+	fprintf(out, "cmd: |  \n");
+	for (i = 0; i < argc; i++) {
+		fprintf(out, " '");
+		for (s = argv[i]; *s; s++) {
+			if (*s == '\'')
+				fprintf(out, "\\\'");
+			else
+				fprintf(out, "%c", *s);
+		}
+		fprintf(out, "'");
+	}
+	fprintf(out, "\n");
+
+	fprintf(out, "elapsed: %"PRIu64" # %.1fms\n", elapsed, 1e-6 * elapsed);
+
+	fprintf(out, "edges: !!ascii85.gz |\n");
+	i = strlen(str);
+	s = str;
+	while (i) {
+		int len = i > 70 ? 70 : i;
+		char tmp;
+
+		tmp = s[len];
+		s[len] = '\0';
+		fprintf(out, "  %s\n", s);
+		s[len] = tmp;
+
+		s += len;
+		i -= len;
+	}
+
+	free(str);
+}
+
+static unsigned long zlib_inflate(void *in, unsigned long len,
+				  void *ptr, unsigned long max)
+{
+	struct z_stream_s zstream;
+
+	memset(&zstream, 0, sizeof(zstream));
+
+	zstream.next_in = in;
+	zstream.avail_in = len;
+
+	if (inflateInit(&zstream) != Z_OK)
+		return 0;
+
+	zstream.next_out = ptr;
+	zstream.avail_out = max;
+
+	switch (inflate(&zstream, Z_SYNC_FLUSH)) {
+	case Z_STREAM_END:
+	case Z_OK:
+		break;
+	default:
+		zstream.total_out = 0;
+		break;
+	}
+
+	inflateEnd(&zstream);
+	return zstream.total_out;
+}
+
+static unsigned long ascii85_decode(const char *in,
+				    void *ptr, unsigned long max)
+{
+	unsigned long sz = max / sizeof(uint32_t);
+	unsigned long len = 0;
+	uint32_t *out;
+
+	out = malloc(sz * sizeof(uint32_t));
+	if (out == NULL)
+		return 0;
+
+	while (*in) {
+		uint32_t v = 0;
+
+		if (isspace(*in)) {
+			in++;
+			continue;
+		}
+
+		if (*in < '!' || *in > 'z') {
+			fprintf(stderr, "Invalid value in ascii85 block\n");
+			free(out);
+			return 0;
+		}
+
+		if (len == sz) {
+			sz *= 2;
+			out = realloc(out, sz * sizeof(uint32_t));
+			if (out == NULL)
+				return 0;
+		}
+
+		if (*in == 'z') {
+			in++;
+		} else {
+			v += in[0] - 33; v *= 85;
+			v += in[1] - 33; v *= 85;
+			v += in[2] - 33; v *= 85;
+			v += in[3] - 33; v *= 85;
+			v += in[4] - 33;
+			in += 5;
+		}
+		out[len++] = v;
+	}
+
+	len = zlib_inflate(out, len * sizeof(*out), ptr, max);
+	free(out);
+
+	return len;
+}
+
+static void yaml_print_parser_error(yaml_parser_t *parser, FILE *stream)
+{
+	switch (parser->error) {
+	case YAML_MEMORY_ERROR:
+		fprintf(stderr, "Memory error: Not enough memory for parsing\n");
+		break;
+
+	case YAML_READER_ERROR:
+		if (parser->problem_value != -1) {
+			fprintf(stderr, "Reader error: %s: #%X at %zd\n", parser->problem,
+				parser->problem_value, parser->problem_offset);
+		} else {
+			fprintf(stderr, "Reader error: %s at %zd\n", parser->problem,
+				parser->problem_offset);
+		}
+		break;
+
+	case YAML_SCANNER_ERROR:
+		if (parser->context) {
+			fprintf(stderr, "Scanner error: %s at line %lu, column %lu\n"
+				"%s at line %lu, column %lu\n", parser->context,
+				parser->context_mark.line+1, parser->context_mark.column+1,
+				parser->problem, parser->problem_mark.line+1,
+				parser->problem_mark.column+1);
+		} else {
+			fprintf(stderr, "Scanner error: %s at line %lu, column %lu\n",
+				parser->problem, parser->problem_mark.line+1,
+				parser->problem_mark.column+1);
+		}
+		break;
+
+	case YAML_PARSER_ERROR:
+		if (parser->context) {
+			fprintf(stderr, "Parser error: %s at line %lu, column %lu\n"
+				"%s at line %lu, column %lu\n", parser->context,
+				parser->context_mark.line+1, parser->context_mark.column+1,
+				parser->problem, parser->problem_mark.line+1,
+				parser->problem_mark.column+1);
+		} else {
+			fprintf(stderr, "Parser error: %s at line %lu, column %lu\n",
+				parser->problem, parser->problem_mark.line+1,
+				parser->problem_mark.column+1);
+		}
+		break;
+
+	default:
+		/* Couldn't happen. */
+		fprintf(stderr, "Internal error\n");
+		break;
+	}
+}
+
+struct edges {
+	struct edges *next;
+
+	char *command;
+	uint64_t elapsed;
+
+	unsigned int weight;
+
+	uint8_t tbl[SZ_8];
+};
+
+struct sort {
+	struct edges *edges;
+	unsigned int count;
+
+	unsigned int max_weight;
+	struct edges *best;
+};
+
+static bool sort_parse_command(struct sort *sort,
+			       struct edges *e,
+			       yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+	const char *s;
+	int len;
+
+	if (!yaml_parser_parse(parser, &ev))
+		return false;
+
+	switch (ev.type) {
+	case YAML_SCALAR_EVENT:
+		break;
+
+	default:
+		return false;
+	}
+
+
+	s = (const char *)ev.data.scalar.value;
+	len = strlen(s);
+	while (s[len - 1] == '\n')
+		len--;
+	e->command = malloc(len + 1);
+	if (e->command) {
+		memcpy(e->command, s, len);
+		e->command[len] = '\0';
+	}
+	yaml_event_delete(&ev);
+
+	return true;
+}
+
+static bool sort_parse_elapsed(struct sort *sort,
+			       struct edges *e,
+			       yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+	const char *s;
+
+	if (!yaml_parser_parse(parser, &ev))
+		return false;
+
+	switch (ev.type) {
+	case YAML_SCALAR_EVENT:
+		break;
+
+	default:
+		return false;
+	}
+
+	s = (const char *)ev.data.scalar.value;
+	e->elapsed = strtoull(s, NULL, 0);
+	yaml_event_delete(&ev);
+
+	return true;
+}
+
+static unsigned int bitmap_weight(const void *bitmap, unsigned int bits)
+{
+	const uint32_t *b = bitmap;
+	unsigned int k, lim = bits / 32;
+	unsigned int w = 0;
+
+	for (k = 0; k < lim; k++)
+		w += __builtin_popcount(b[k]);
+
+	if (bits % 32)
+		w += __builtin_popcount(b[k] << (32 - bits % 32));
+
+	return w;
+}
+
+static bool sort_parse_edges(struct sort *sort,
+			     struct edges *e,
+			     yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+	const char *s;
+
+	if (!yaml_parser_parse(parser, &ev))
+		return false;
+
+	switch (ev.type) {
+	case YAML_SCALAR_EVENT:
+		break;
+
+	default:
+		return false;
+	}
+
+	s = (const char *)ev.data.scalar.value;
+	if (ascii85_decode(s, e->tbl, sizeof(e->tbl)))
+		e->weight = bitmap_weight(e->tbl, sizeof(e->tbl) * 8);
+	yaml_event_delete(&ev);
+
+	return true;
+}
+
+static bool edges_valid(const struct edges *e)
+{
+	if (!e->command)
+		return false;
+
+	if (!e->weight)
+		return false;
+
+	if (!e->elapsed)
+		return false;
+
+	return true; /* good enough at least */
+}
+
+static bool sort_add_edges(struct sort *sort, struct edges *e)
+{
+	if (!edges_valid(e))
+		return false;
+
+	e->next = sort->edges;
+	sort->edges = e;
+
+	if (e->weight > sort->max_weight) {
+		sort->max_weight = e->weight;
+		sort->best = e;
+	}
+
+	sort->count++;
+
+	return true;
+}
+
+static bool sort_parse_node(struct sort *sort, yaml_parser_t *parser)
+{
+	struct edges *e;
+	yaml_event_t ev;
+	char *s;
+
+	e = malloc(sizeof(*e));
+	if (!e)
+		return false;
+
+	e->weight = 0;
+
+	do {
+		if (!yaml_parser_parse(parser, &ev))
+			goto err;
+
+		switch (ev.type) {
+		case YAML_MAPPING_END_EVENT:
+			if (!sort_add_edges(sort, e))
+				goto err;
+
+			return true;
+
+		case YAML_SCALAR_EVENT:
+			break;
+
+		default:
+			goto err;
+		}
+
+		s = (char *)ev.data.scalar.value;
+		if (!strcmp(s, "cmd")) {
+			sort_parse_command(sort, e, parser);
+		} else if (!strcmp(s, "elapsed")) {
+			sort_parse_elapsed(sort, e, parser);
+		} else if (!strcmp(s, "edges")) {
+			sort_parse_edges(sort, e, parser);
+		} else {
+			fprintf(stderr,
+				"Unknown element in edges file: %s\n",
+				s);
+		}
+
+		yaml_event_delete(&ev);
+	} while (1);
+
+err:
+	free(e);
+	return false;
+}
+
+static bool sort_parse_doc(struct sort *sort, yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+
+	do {
+		if (!yaml_parser_parse(parser, &ev))
+			return false;
+
+		switch (ev.type) {
+		case YAML_DOCUMENT_END_EVENT:
+			return true;
+
+		case YAML_MAPPING_START_EVENT:
+			break;
+
+		default:
+			return false;
+		}
+		yaml_event_delete(&ev);
+
+		if (!sort_parse_node(sort, parser))
+			return false;
+	} while(1);
+}
+
+static bool sort_add(struct sort *sort, FILE *file)
+{
+	yaml_parser_t parser;
+	bool done = false;
+	yaml_event_t ev;
+
+	yaml_parser_initialize(&parser);
+	yaml_parser_set_input_file(&parser, file);
+
+	memset(&ev, 0, sizeof(ev));
+	yaml_parser_parse(&parser, &ev);
+	if (ev.type != YAML_STREAM_START_EVENT) {
+		fprintf(stderr, "Parser setup failed\n");
+		return false;
+	}
+	yaml_event_delete(&ev);
+
+	do {
+		if (!yaml_parser_parse(&parser, &ev)) {
+			fprintf(stderr, "Invalid yaml\n");
+			yaml_print_parser_error(&parser, stderr);
+			return false;
+		}
+
+		switch (ev.type) {
+		case YAML_DOCUMENT_START_EVENT:
+			break;
+
+		case YAML_STREAM_END_EVENT:
+			done = true;
+			break;
+
+		default:
+			return false;
+		}
+		yaml_event_delete(&ev);
+
+		sort_parse_doc(sort, &parser);
+	} while (!done);
+
+	yaml_parser_delete(&parser);
+	return true;
+}
+
+static double edges_similarity(const struct edges *ta, const struct edges *tb)
+{
+	uint64_t sab, saa, sbb;
+	const uint8_t *a, *b;
+
+	if (ta == tb)
+		return 1;
+
+	a = ta->tbl;
+	b = tb->tbl;
+	sab = 0;
+	saa = 0;
+	sbb = 0;
+
+	for (unsigned int i = 0; i < SZ_8; i++) {
+		sab += (uint32_t)a[i] * b[i];
+		saa += (uint32_t)a[i] * a[i];
+		sbb += (uint32_t)b[i] * b[i];
+	}
+
+	return ((long double)sab * sab) / ((long double)saa * sbb);
+}
+
+static void rank_by_dissimilarity(struct sort *sort, FILE *out)
+{
+	const unsigned int count = sort->count;
+	double *M, *dis, *sim;
+	struct edges **edges, **t;
+	bool *used;
+	int last = -1;
+
+	t = edges = malloc(count * sizeof(*edges));
+	for (struct edges *e = sort->edges; e; e = e->next)
+		*t++ = e;
+
+	M = malloc(sizeof(double) * count * (count + 2));
+	dis = M + count * count;
+	sim = dis + count;
+	for (int i = 0; i < count; i++) {
+		dis[i] = 0.;
+		sim[i] = 1.;
+		for (int j = 0; j < i; j++)
+			dis[i] += M[j*count + i];
+		for (int j = i + 1; j < count; j++) {
+			double d = 1. - edges_similarity(edges[i], edges[j]);
+			M[i*count + j] = d;
+			dis[i] += d;
+		}
+	}
+
+	fprintf(out, "---\n");
+
+	used = calloc(count, sizeof(bool));
+	for (int rank = 0; rank < count; rank++) {
+		struct edges *e;
+		double best = -HUGE_VAL;
+		int this = -1;
+
+		for (int i = 0; i < count; i++) {
+			double d;
+
+			if (used[i])
+				continue;
+
+			d = dis[i];
+			if (last != -1) {
+				double s;
+
+				if (last < i)
+					s = M[last * count + i];
+				else
+					s = M[i * count + last];
+
+				s *= sim[i];
+				sim[i] = s;
+
+				d *= sqrt(s);
+			}
+			if (d > best) {
+				best = d;
+				this = i;
+			}
+		}
+
+		if (this < 0)
+			break;
+
+		e = edges[this];
+		used[this] = true;
+		last = this;
+
+		fprintf(out, "- cmd: |\n    %s\n", e->command);
+		fprintf(out, "  elapsed: %"PRIu64" # %.1fms\n",
+			e->elapsed, 1e-6 * e->elapsed);
+		fprintf(out, "  dissimilarity: %f\n",
+			sqrt(best / (count - rank)));
+	}
+
+	free(M);
+	free(edges);
+}
+
+static void sort(int argc, char **argv)
+{
+	static const struct option longopts[] = {
+		{"output", required_argument, 0, 'o'},
+		{ NULL, 0, NULL, 0 }
+	};
+	FILE *out = stdout;
+	struct sort sort;
+	int i;
+
+	while ((i = getopt_long(argc, argv,
+				"+o:",
+				longopts, NULL)) != -1) {
+		switch (i) {
+		case 'o':
+			if (strcmp(optarg, "-"))
+				out = fopen(optarg, "a");
+			if (!out) {
+				fprintf(stderr,
+					"Unable to open output file '%s'\n",
+					optarg);
+				exit(1);
+			}
+			break;
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	memset(&sort, 0, sizeof(sort));
+
+	if (argc == 0) {
+		sort_add(&sort, stdin);
+	} else {
+		for (i = 0; i < argc; i++) {
+			FILE *in;
+
+			in = fopen(argv[i], "r");
+			if (!in) {
+				fprintf(stderr, "unable to open input '%s'\n",
+					argv[i]);
+				exit(1);
+			}
+
+			sort_add(&sort, in);
+
+			fclose(in);
+		}
+	}
+
+	if (!sort.count)
+		return;
+
+	rank_by_dissimilarity(&sort, out);
+}
+
+struct list {
+	struct {
+		double single;
+		double total;
+	} limit;
+	double total;
+	FILE *out;
+};
+
+struct list_node {
+	char *cmd;
+	uint64_t elapsed;
+};
+
+static bool list_parse_command(struct list *list,
+			       struct list_node *node,
+			       yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+	const char *s;
+	int len;
+
+	if (!yaml_parser_parse(parser, &ev))
+		return false;
+
+	switch (ev.type) {
+	case YAML_SCALAR_EVENT:
+		break;
+
+	default:
+		return false;
+	}
+
+
+	s = (const char *)ev.data.scalar.value;
+	len = strlen(s);
+	while (len > 0 && isspace(s[len - 1]))
+		len--;
+
+	node->cmd = strndup(s, len);
+	yaml_event_delete(&ev);
+
+	return true;
+}
+
+static bool list_parse_elapsed(struct list *list,
+			       struct list_node *node,
+			       yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+	const char *s;
+
+	if (!yaml_parser_parse(parser, &ev))
+		return false;
+
+	switch (ev.type) {
+	case YAML_SCALAR_EVENT:
+		break;
+
+	default:
+		return false;
+	}
+
+	s = (const char *)ev.data.scalar.value;
+	node->elapsed = strtoull(s, NULL, 0);
+	yaml_event_delete(&ev);
+
+	return true;
+}
+
+static bool list_parse_node(struct list *list, yaml_parser_t *parser)
+{
+	struct list_node node = {};
+	yaml_event_t ev;
+	char *s;
+
+	do {
+		if (!yaml_parser_parse(parser, &ev))
+			return false;
+
+		switch (ev.type) {
+		case YAML_MAPPING_END_EVENT:
+			if (list->limit.single &&
+			    1e-9 * node.elapsed > list->limit.single) {
+				free(node.cmd);
+				return true;
+			}
+
+			if (list->limit.total &&
+			    list->total + 1e-9 * node.elapsed > list->limit.total) {
+				free(node.cmd);
+				return true;
+			}
+
+			if (node.cmd) {
+				list->total += 1e-9 * node.elapsed;
+				fprintf(list->out,
+					"%s # %.3fms, total %.1fms\n",
+					node.cmd,
+					1e-6 * node.elapsed,
+					1e3 * list->total);
+				free(node.cmd);
+			}
+			return true;
+
+		case YAML_SCALAR_EVENT:
+			break;
+
+		default:
+			return false;
+		}
+
+		s = (char *)ev.data.scalar.value;
+		if (!strcmp(s, "cmd")) {
+			list_parse_command(list, &node, parser);
+		} else if (!strcmp(s, "elapsed")) {
+			if (!list_parse_elapsed(list, &node,parser))
+				return false;
+		}
+		yaml_event_delete(&ev);
+	} while (1);
+}
+
+static bool list_parse_sequence(struct list *list, yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+
+	do {
+		if (!yaml_parser_parse(parser, &ev))
+			return false;
+
+		switch (ev.type) {
+		case YAML_SEQUENCE_END_EVENT:
+			return true;
+
+		case YAML_MAPPING_START_EVENT:
+			if (!list_parse_node(list, parser))
+				return false;
+			break;
+
+		default:
+			return false;
+		}
+		yaml_event_delete(&ev);
+	} while(1);
+}
+
+static bool list_parse_doc(struct list *list, yaml_parser_t *parser)
+{
+	yaml_event_t ev;
+
+	do {
+		if (!yaml_parser_parse(parser, &ev))
+			return false;
+
+		switch (ev.type) {
+		case YAML_DOCUMENT_END_EVENT:
+			return true;
+
+		case YAML_MAPPING_START_EVENT:
+			if (!list_parse_node(list, parser))
+				return false;
+			break;
+
+		case YAML_SEQUENCE_START_EVENT:
+			if (!list_parse_sequence(list, parser))
+				return false;
+			break;
+
+		default:
+			return false;
+		}
+		yaml_event_delete(&ev);
+	} while(1);
+}
+
+static bool list_show(struct list *list, FILE *file)
+{
+	yaml_parser_t parser;
+	bool done = false;
+	yaml_event_t ev;
+
+	yaml_parser_initialize(&parser);
+	yaml_parser_set_input_file(&parser, file);
+
+	memset(&ev, 0, sizeof(ev));
+	yaml_parser_parse(&parser, &ev);
+	if (ev.type != YAML_STREAM_START_EVENT) {
+		fprintf(stderr, "Parser setup failed\n");
+		return false;
+	}
+	yaml_event_delete(&ev);
+
+	do {
+		if (!yaml_parser_parse(&parser, &ev)) {
+			fprintf(stderr, "Invalid yaml\n");
+			yaml_print_parser_error(&parser, stderr);
+			return false;
+		}
+
+		switch (ev.type) {
+		case YAML_DOCUMENT_START_EVENT:
+			break;
+
+		case YAML_STREAM_END_EVENT:
+			done = true;
+			break;
+
+		default:
+			return false;
+		}
+		yaml_event_delete(&ev);
+
+		list_parse_doc(list, &parser);
+	} while (!done);
+
+	yaml_parser_delete(&parser);
+	return true;
+}
+
+static void list(int argc, char **argv)
+{
+	static const struct option longopts[] = {
+		{"output", required_argument, 0, 'o'},
+		{"total", required_argument, 0, 't'},
+		{"single", required_argument, 0, 's'},
+		{ NULL, 0, NULL, 0 }
+	};
+	struct list list;
+	int i;
+
+	memset(&list, 0, sizeof(list));
+	list.out = stdout;
+
+	while ((i = getopt_long(argc, argv,
+				"+o:t:",
+				longopts, NULL)) != -1) {
+		switch (i) {
+		case 'o':
+			if (strcmp(optarg, "-"))
+				list.out = fopen(optarg, "a");
+			if (!list.out) {
+				fprintf(stderr,
+					"Unable to open output file '%s'\n",
+					optarg);
+				exit(1);
+			}
+			break;
+		case 's':
+			list.limit.single = atof(optarg);
+			break;
+		case 't':
+			list.limit.total = atof(optarg);
+			break;
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc == 0) {
+		list_show(&list, stdin);
+	} else {
+		for (i = 0; i < argc; i++) {
+			FILE *in;
+
+			in = fopen(argv[i], "r");
+			if (!in) {
+				fprintf(stderr, "unable to open input '%s'\n",
+					argv[i]);
+				exit(1);
+			}
+
+			fprintf(stderr, "%s\n", argv[i]);
+
+			if (!list_show(&list, in))
+				i = argc;
+
+			fclose(in);
+		}
+	}
+}
+
+int main(int argc, char **argv)
+{
+	static const struct option longopts[] = {
+		{"verbose", no_argument, 0, 'v'},
+		{ NULL, 0, NULL, 0 }
+	};
+	int o;
+
+	while ((o = getopt_long(argc, argv,
+				"+v",
+				longopts, NULL)) != -1) {
+		switch (o) {
+		case 'v':
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (optind == argc) {
+		fprintf(stderr, "no subcommand specified\n");
+		exit(1);
+	}
+
+	argc -= optind;
+	argv += optind;
+	optind = 1;
+
+	if (!strcmp(argv[0], "edges")) {
+		edges(argc, argv);
+	} else if (!strcmp(argv[0], "sort")) {
+		sort(argc, argv);
+	} else if (!strcmp(argv[0], "list")) {
+		list(argc, argv);
+	} else {
+		fprintf(stderr, "Unknown command '%s'\n", argv[0]);
+		exit(1);
+	}
+
+	return 0;
+}
diff --git a/tools/igt_kcov_edges.c b/tools/igt_kcov_edges.c
new file mode 100644
index 000000000..750d4f8b5
--- /dev/null
+++ b/tools/igt_kcov_edges.c
@@ -0,0 +1,145 @@
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include <linux/types.h>
+
+static int (*libc_ioctl)(int fd, unsigned long request, void *argp);
+
+static struct kcov {
+	unsigned long *trace;
+	uint32_t *table;
+	int fd;
+} kcov;
+
+#define KCOV_INIT_TRACE                 _IOR('c', 1, unsigned long)
+#define KCOV_ENABLE                     _IO('c', 100)
+#define   KCOV_TRACE_PC  0
+#define   KCOV_TRACE_CMP 1
+#define KCOV_DISABLE                    _IO('c', 101)
+
+#define DRM_IOCTL_BASE 'd'
+
+#define GOLDEN_RATIO_32 0x61C88647
+#define GOLDEN_RATIO_64 0x61C8864680B583EBull
+
+static inline uint32_t hash_32(uint32_t val, unsigned int bits)
+{
+        return val * GOLDEN_RATIO_32 >> (32 - bits);
+}
+
+static inline uint32_t hash_64(uint64_t val, unsigned int bits)
+{
+        return val * GOLDEN_RATIO_64 >> (64 - bits);
+}
+
+#define hash_long(x, y) hash_64(x, y)
+
+static bool kcov_open(struct kcov *kc, unsigned long count)
+{
+	const char *env;
+	int shm;
+
+	env = getenv("IGT_SHM_FD");
+	if (!env)
+		return false;
+
+	shm = atoi(env);
+	kc->table = mmap(NULL, sizeof(uint32_t) << 16,
+			 PROT_WRITE, MAP_SHARED, shm, 0);
+	close(shm);
+	if (kc->table == (uint32_t *)MAP_FAILED)
+		return false;
+
+	env = getenv("IGT_KCOV_FD");
+	if (!env)
+		goto err_shm;
+
+	kc->fd = atoi(env);
+	if (libc_ioctl(kc->fd, KCOV_INIT_TRACE, (void *)count))
+		goto err_close;
+
+	kc->trace = mmap(NULL, count * sizeof(unsigned long),
+			 PROT_WRITE, MAP_SHARED, kc->fd, 0);
+	if (kc->trace == MAP_FAILED)
+		goto err_close;
+
+	return true;
+
+err_close:
+	close(kc->fd);
+err_shm:
+	munmap(kc->table, sizeof(uint32_t) << 16);
+	return false;
+}
+
+static void kcov_enable(struct kcov *kc)
+{
+	libc_ioctl(kc->fd, KCOV_ENABLE, KCOV_TRACE_PC);
+	__atomic_store_n(&kc->trace[0], 0, __ATOMIC_RELAXED);
+}
+
+static unsigned long kcov_disable(struct kcov *kc)
+{
+	unsigned long depth;
+
+	depth = __atomic_load_n(&kc->trace[0], __ATOMIC_RELAXED);
+	if (libc_ioctl(kc->fd, KCOV_DISABLE, 0))
+		depth = 0;
+
+	return depth;
+}
+
+int ioctl(int fd, unsigned long request, ...)
+{
+	static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+	unsigned long count, n, prev;
+	va_list args;
+	void *argp;
+	int res;
+
+	va_start(args, request);
+	argp = va_arg(args, void *);
+	va_end(args);
+
+	if (kcov.fd < 0 || _IOC_TYPE(request) != DRM_IOCTL_BASE)
+		return libc_ioctl(fd, request, argp);
+
+	pthread_mutex_lock(&mutex);
+	kcov_enable(&kcov);
+
+	res = libc_ioctl(fd, request, argp);
+
+	count = kcov_disable(&kcov);
+	prev = hash_long(kcov.trace[1], 16);
+	for (n = 2; n <= count; n++) {
+		unsigned long loc = hash_long(kcov.trace[n], 16);
+
+		kcov.table[prev ^ loc]++;
+		prev = loc >> 1;
+	}
+	kcov.table[0] |= 1;
+	pthread_mutex_unlock(&mutex);
+
+	return res;
+}
+
+__attribute__((constructor))
+static void init(void)
+{
+	libc_ioctl = dlsym(RTLD_NEXT, "ioctl");
+
+	if (!kcov_open(&kcov, 64 << 10))
+		kcov.fd = -1;
+}
diff --git a/tools/meson.build b/tools/meson.build
index bd2d313d5..48adedfa4 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -105,6 +105,19 @@ executable('intel_reg', sources : intel_reg_src,
 	     '-DIGT_DATADIR="@0@"'.format(join_paths(prefix, datadir)),
 	   ])
 
+if yaml.found()
+	executable('igt_kcov',
+		   sources: [ 'igt_kcov.c' ],
+		   dependencies: [ zlib, realtime, math, yaml ],
+		   install: true) # setuid me!
+
+	shared_module('igt_kcov_edges',
+		      sources: [ 'igt_kcov_edges.c' ],
+		      name_prefix: '',
+		      dependencies: [ dlsym ],
+		      install: true) # -version, -Dlibdir
+endif
+
 install_data('intel_gpu_abrt', install_dir : bindir)
 
 install_subdir('registers', install_dir : datadir,
-- 
2.17.0

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [igt-dev] ✓ Fi.CI.BAT: success for RFC tools: capture execution pathways (rev4)
  2018-04-20 21:50 [igt-dev] [PATCH igt] RFC tools: capture execution pathways Chris Wilson
                   ` (5 preceding siblings ...)
  2018-04-25 20:57 ` Chris Wilson
@ 2018-04-25 23:09 ` Patchwork
  2018-04-26  2:47 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
  7 siblings, 0 replies; 11+ messages in thread
From: Patchwork @ 2018-04-25 23:09 UTC (permalink / raw)
  To: Chris Wilson; +Cc: igt-dev

== Series Details ==

Series: RFC tools: capture execution pathways (rev4)
URL   : https://patchwork.freedesktop.org/series/42056/
State : success

== Summary ==

= CI Bug Log - changes from CI_DRM_4099 -> IGTPW_1303 =

== Summary - SUCCESS ==

  No regressions found.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/42056/revisions/4/mbox/

== Known issues ==

  Here are the changes found in IGTPW_1303 that come from known issues:

  === IGT changes ===

    ==== Issues hit ====

    igt@gem_mmap_gtt@basic-small-bo-tiledx:
      fi-gdg-551:         PASS -> FAIL (fdo#102575)

    igt@kms_flip@basic-flip-vs-modeset:
      fi-cnl-y3:          PASS -> INCOMPLETE (fdo#105086)

    igt@kms_flip@basic-flip-vs-wf_vblank:
      fi-cfl-s3:          PASS -> FAIL (fdo#100368, fdo#103928)

    igt@kms_frontbuffer_tracking@basic:
      {fi-hsw-4200u}:     PASS -> DMESG-FAIL (fdo#106103)

    igt@kms_pipe_crc_basic@suspend-read-crc-pipe-c:
      fi-ivb-3520m:       PASS -> DMESG-WARN (fdo#106084)

    igt@prime_vgem@basic-fence-flip:
      fi-ilk-650:         PASS -> FAIL (fdo#104008)

    
    ==== Possible fixes ====

    igt@kms_pipe_crc_basic@suspend-read-crc-pipe-b:
      fi-snb-2520m:       INCOMPLETE (fdo#103713) -> PASS

    
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  fdo#100368 https://bugs.freedesktop.org/show_bug.cgi?id=100368
  fdo#102575 https://bugs.freedesktop.org/show_bug.cgi?id=102575
  fdo#103713 https://bugs.freedesktop.org/show_bug.cgi?id=103713
  fdo#103928 https://bugs.freedesktop.org/show_bug.cgi?id=103928
  fdo#104008 https://bugs.freedesktop.org/show_bug.cgi?id=104008
  fdo#105086 https://bugs.freedesktop.org/show_bug.cgi?id=105086
  fdo#106084 https://bugs.freedesktop.org/show_bug.cgi?id=106084
  fdo#106103 https://bugs.freedesktop.org/show_bug.cgi?id=106103


== Participating hosts (38 -> 36) ==

  Missing    (2): fi-ilk-m540 fi-skl-6700hq 


== Build changes ==

    * IGT: IGT_4449 -> IGTPW_1303

  CI_DRM_4099: 92a39635c2eca4dfe1c8c1673e0c606a720746e5 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_1303: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_1303/
  IGT_4449: 0350f0e7f6a0e07281445fc3082aa70419f4aac7 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  piglit_4449: ad8992d3fb27fd604b9ab15e7963c42421ced85c @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_1303/issues.html
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [igt-dev] ✓ Fi.CI.IGT: success for RFC tools: capture execution pathways (rev4)
  2018-04-20 21:50 [igt-dev] [PATCH igt] RFC tools: capture execution pathways Chris Wilson
                   ` (6 preceding siblings ...)
  2018-04-25 23:09 ` [igt-dev] ✓ Fi.CI.BAT: success for RFC tools: capture execution pathways (rev4) Patchwork
@ 2018-04-26  2:47 ` Patchwork
  7 siblings, 0 replies; 11+ messages in thread
From: Patchwork @ 2018-04-26  2:47 UTC (permalink / raw)
  To: Chris Wilson; +Cc: igt-dev

== Series Details ==

Series: RFC tools: capture execution pathways (rev4)
URL   : https://patchwork.freedesktop.org/series/42056/
State : success

== Summary ==

= CI Bug Log - changes from IGT_4449_full -> IGTPW_1303_full =

== Summary - WARNING ==

  Minor unknown changes coming with IGTPW_1303_full need to be verified
  manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in IGTPW_1303_full, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/42056/revisions/4/mbox/

== Possible new issues ==

  Here are the unknown changes that may have been introduced in IGTPW_1303_full:

  === IGT changes ===

    ==== Warnings ====

    igt@gem_exec_schedule@deep-bsd1:
      shard-kbl:          PASS -> SKIP

    igt@kms_chv_cursor_fail@pipe-b-128x128-top-edge:
      shard-snb:          SKIP -> PASS +1

    
== Known issues ==

  Here are the changes found in IGTPW_1303_full that come from known issues:

  === IGT changes ===

    ==== Issues hit ====

    igt@gem_ctx_isolation@vecs0-s3:
      shard-kbl:          PASS -> INCOMPLETE (fdo#103665) +1

    igt@kms_flip@2x-flip-vs-expired-vblank-interruptible:
      shard-hsw:          PASS -> FAIL (fdo#102887)

    igt@kms_flip@wf_vblank-ts-check-interruptible:
      shard-snb:          PASS -> FAIL (fdo#100368)

    igt@kms_rotation_crc@primary-rotation-180:
      shard-snb:          PASS -> FAIL (fdo#103925)

    igt@kms_rotation_crc@sprite-rotation-180:
      shard-hsw:          PASS -> FAIL (fdo#103925)

    
    ==== Possible fixes ====

    igt@gem_ppgtt@blt-vs-render-ctxn:
      shard-kbl:          INCOMPLETE (fdo#103665, fdo#106023) -> PASS

    igt@gem_render_copy_redux@interruptible:
      shard-kbl:          INCOMPLETE (fdo#103665) -> PASS

    igt@kms_flip@2x-dpms-vs-vblank-race-interruptible:
      shard-hsw:          FAIL (fdo#103060) -> PASS +1

    igt@kms_flip@2x-plain-flip-ts-check-interruptible:
      shard-hsw:          FAIL (fdo#100368) -> PASS +1

    
  fdo#100368 https://bugs.freedesktop.org/show_bug.cgi?id=100368
  fdo#102887 https://bugs.freedesktop.org/show_bug.cgi?id=102887
  fdo#103060 https://bugs.freedesktop.org/show_bug.cgi?id=103060
  fdo#103665 https://bugs.freedesktop.org/show_bug.cgi?id=103665
  fdo#103925 https://bugs.freedesktop.org/show_bug.cgi?id=103925
  fdo#106023 https://bugs.freedesktop.org/show_bug.cgi?id=106023


== Participating hosts (5 -> 4) ==

  Missing    (1): shard-glkb 


== Build changes ==

    * IGT: IGT_4449 -> IGTPW_1303
    * Linux: CI_DRM_4096 -> CI_DRM_4099

  CI_DRM_4096: d561357bb1537ba454f462db0bb044dac644aeec @ git://anongit.freedesktop.org/gfx-ci/linux
  CI_DRM_4099: 92a39635c2eca4dfe1c8c1673e0c606a720746e5 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_1303: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_1303/
  IGT_4449: 0350f0e7f6a0e07281445fc3082aa70419f4aac7 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  piglit_4449: ad8992d3fb27fd604b9ab15e7963c42421ced85c @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_1303/shards.html
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2018-04-26  2:47 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-20 21:50 [igt-dev] [PATCH igt] RFC tools: capture execution pathways Chris Wilson
2018-04-20 22:03 ` [igt-dev] ✗ Fi.CI.BAT: failure for " Patchwork
2018-04-23 11:29 ` [igt-dev] [PATCH igt] " Joonas Lahtinen
2018-04-23 11:53   ` Chris Wilson
2018-04-23 13:06     ` [igt-dev] [PATCH i-g-t 1/1] meson'd igt_kcov Petri Latvala
2018-04-23 15:13 ` [igt-dev] ✗ Fi.CI.BAT: failure for RFC tools: capture execution pathways (rev2) Patchwork
2018-04-25 20:22 ` [igt-dev] [PATCH igt] RFC tools: capture execution pathways Chris Wilson
2018-04-25 20:42 ` [igt-dev] [PATCH i-g-t] RFCv2 " Chris Wilson
2018-04-25 20:57 ` Chris Wilson
2018-04-25 23:09 ` [igt-dev] ✓ Fi.CI.BAT: success for RFC tools: capture execution pathways (rev4) Patchwork
2018-04-26  2:47 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.