[Intel-gfx] [i-g-t RFC 1/3] lib: Wrap kcov
Chris Wilson
chris at chris-wilson.co.uk
Wed Jun 8 08:52:03 UTC 2016
A small utility for extracting kernel coverage using
/sys/kernel/debug/kcov.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
lib/Makefile.sources | 2 +
lib/igt_debugfs.c | 20 ++++++
lib/igt_debugfs.h | 1 +
lib/igt_kcov.c | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++
lib/igt_kcov.h | 16 +++++
5 files changed, 227 insertions(+)
create mode 100644 lib/igt_kcov.c
create mode 100644 lib/igt_kcov.h
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index f50ff4d..87bee2b 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -14,6 +14,8 @@ libintel_tools_la_SOURCES = \
igt_edid_template.h \
igt_gt.c \
igt_gt.h \
+ igt_kcov.c \
+ igt_kcov.h \
igt_stats.c \
igt_stats.h \
igt_sysfs.c \
diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
index 5b6ac78..66d2392 100644
--- a/lib/igt_debugfs.c
+++ b/lib/igt_debugfs.c
@@ -138,6 +138,26 @@ static igt_debugfs_t *__igt_debugfs_singleton(void)
}
/**
+ * igt_debugfs_mount:
+ *
+ * This functions detects the mount point for debugfs, or mounts it if
+ * required, then reports the path to the root of debugfs.
+ *
+ * Returns:
+ * The path to find debufs, or NULL on failure.
+ */
+const char *igt_debugfs_mount(void)
+{
+ igt_debugfs_t *debugfs;
+
+ debugfs = __igt_debugfs_singleton();
+ if (!debugfs)
+ return NULL;
+
+ return debugfs->root;
+}
+
+/**
* igt_debugfs_open:
* @filename: name of the debugfs node to open
* @mode: mode bits as used by open()
diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
index 261e31b..cf9d74c 100644
--- a/lib/igt_debugfs.h
+++ b/lib/igt_debugfs.h
@@ -31,6 +31,7 @@
enum pipe;
+const char *igt_debugfs_mount(void);
int igt_debugfs_open(const char *filename, int mode);
FILE *igt_debugfs_fopen(const char *filename,
const char *mode);
diff --git a/lib/igt_kcov.c b/lib/igt_kcov.c
new file mode 100644
index 0000000..dd16c2e
--- /dev/null
+++ b/lib/igt_kcov.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright © 20136Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "igt_kcov.h"
+#include "igt_debugfs.h"
+
+/**
+ * SECTION:igt_kcov
+ * @short_description: Support for kernel basic block coverage
+ * @title: kcov
+ * @include: igt.h
+ *
+ * This facility provides routines to access the reporting of basic block
+ * coverage by the kernel. By enabling kcov around syscalls, we can determine
+ * the path through the kernel that the syscall took. We can use this
+ * information to refine the test or confirm we have sufficient path coverages
+ * in our tests.
+ *
+ * After calling igt_kcov_init() to setup the tracing buffer, use
+ * igt_kcov_enable() and igt_kcov_disable() to enable basic block tracing
+ * around the syscall of interest. The buffer should be constructed per thread,
+ * and allows for thread local basic block tracing.
+ *
+ * This facility is only currently available on recent kernels and x86_64.
+ * The kernel itself must be compiled with gcc-6 and with CONFIG_KCOV.
+ */
+
+#define KCOV_INIT_TRACE _IOR('c', 1, unsigned long)
+#define KCOV_ENABLE _IO('c', 100)
+#define KCOV_DISABLE _IO('c', 101)
+#define COVER_SIZE (64<<10)
+
+/**
+ * igt_kcov_init:
+ * @kcov: the coverage struct
+ *
+ * Setup the tracking buffer.
+ *
+ * Returns:
+ * 0 on success, or a negative error code.
+ */
+int igt_kcov_init(struct igt_kcov *kcov)
+{
+ struct igt_kcov tmp;
+ const char *path;
+ char buf[128];
+ int ret;
+
+ memset(kcov, 0, sizeof(*kcov));
+
+ path = igt_debugfs_mount();
+ if (!path)
+ return -ENOENT;
+
+ snprintf(buf, sizeof(buf), "%s/kcov", path);
+ tmp.fd = open(buf, O_RDWR);
+ if (tmp.fd < 0)
+ return -ENOENT;
+
+ if (ioctl(tmp.fd, KCOV_INIT_TRACE, COVER_SIZE)) {
+ ret = -errno;
+ goto err_fd;
+ }
+
+ tmp.bb = mmap(NULL, COVER_SIZE * sizeof(unsigned long),
+ PROT_READ | PROT_WRITE, MAP_SHARED, tmp.fd, 0);
+ if (tmp.bb == MAP_FAILED) {
+ ret = -errno;
+ goto err_fd;
+ }
+
+ *kcov = tmp;
+ return 0;
+
+err_fd:
+ close(tmp.fd);
+ return ret;
+}
+
+/**
+ * igt_kcov_enable:
+ * @kcov: the coverage struct
+ *
+ * Enable basic block tracing.
+ *
+ * Returns:
+ * 0 on success, or a negative error code.
+ */
+int igt_kcov_enable(struct igt_kcov *kcov)
+{
+ if (!kcov->bb)
+ return 0;
+
+ if (ioctl(kcov->fd, KCOV_ENABLE, 0))
+ return -errno;
+
+ return 0;
+}
+
+/**
+ * igt_kcov_reset:
+ * @kcov: the coverage struct
+ *
+ * Reset the position in the coverage buffer to 0. All subsequent
+ * tracing will then overwrite previous entrie.s
+ */
+void igt_kcov_reset(struct igt_kcov *kcov)
+{
+ if (!kcov->bb)
+ return;
+
+ __atomic_store_n(&kcov->bb[0], 0, __ATOMIC_RELAXED);
+}
+
+/**
+ * igt_kcov_disable:
+ * @kcov: the coverage struct
+ *
+ * Disable basic block tracing.
+ */
+void igt_kcov_disable(struct igt_kcov *kcov)
+{
+ if (!kcov->bb)
+ return;
+
+ ioctl(kcov->fd, KCOV_DISABLE, 0);
+}
+
+void igt_kcov_print(struct igt_kcov *kcov)
+{
+ unsigned long n, i;
+
+ if (!kcov->bb)
+ return;
+
+ n = __atomic_load_n(&kcov->bb[0], __ATOMIC_RELAXED);
+ for (i = 0; i < n; i++)
+ printf("0x%lx\n", kcov->bb[i + 1]);
+}
+
+/**
+ * igt_kcov_fini:
+ * @kcov: the coverage struct
+ *
+ * Release all resources associated with the coverage struct.
+ */
+void igt_kcov_fini(struct igt_kcov *kcov)
+{
+ if (!kcov->bb)
+ return;
+
+ munmap(kcov->bb, COVER_SIZE*sizeof(unsigned long));
+ close(kcov->fd);
+}
diff --git a/lib/igt_kcov.h b/lib/igt_kcov.h
new file mode 100644
index 0000000..dbd3d1e
--- /dev/null
+++ b/lib/igt_kcov.h
@@ -0,0 +1,16 @@
+#ifndef IGT_KCOV_H
+#define IGT_KCOV_H
+
+struct igt_kcov {
+ int fd;
+ unsigned long *bb;
+};
+
+int igt_kcov_init(struct igt_kcov *kcov);
+int igt_kcov_enable(struct igt_kcov *kcov);
+void igt_kcov_reset(struct igt_kcov *kcov);
+void igt_kcov_disable(struct igt_kcov *kcov);
+void igt_kcov_print(struct igt_kcov *kcov);
+void igt_kcov_fini(struct igt_kcov *kcov);
+
+#endif /* IGT_KCOV_H */
--
2.8.1
More information about the Intel-gfx
mailing list