[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [RFC PATCH] Adding support for coverage informations



From: Frediano Ziglio <frediano.ziglio@xxxxxxxxxx>

This patch introduce coverage support to Xen.
Currently it allows to compile Xen with coverage support but there is no way
to extract them.

The declarations came from Linux source files (as you can see from file
headers).

It also add a new hypercall (can somebody reserve a number for this stuff?).

The idea is to have some operations mainly
- get filename
- get count informations for a file
- reset counter for a specific file
- reset all counters

The op parameter in the hypercall will be the operation.
The idx parameter is the index to the file.
The arg1 is the argument (a buffer pointer for filename or counters).
The arg2 probably will be the size of previous buffer.

Do you think I should pack these parameters and pass a single pointer?

Linux use a file system to export these information. I would use the same
format as Linux use so to make it easy to reuse tools from Linux (like lcov).
That the reason why I split get filename from get counter informations.

These informations cannot be put in a specific section (allowing a safe mapping)
as gcc use .rodata, .data, .text and .ctors sections.

I added code to handle constructors used in this case to initialize a linked
list of files.

Do anybody know why I had to exclude %.init.o files to make it compile?
Are these files used before Xen start?

Signed-off-by: Frediano Ziglio <frediano.ziglio@xxxxxxxxxx>

diff -r 5af4f2ab06f3 Config.mk
--- a/Config.mk Tue Jan 22 09:33:10 2013 +0100
+++ b/Config.mk Mon Jan 28 17:36:14 2013 +0000
@@ -228,3 +228,7 @@ QEMU_TAG ?= 2a1354d655d816feaad7dbdb8364
 # doing and are prepared for some pain.
 
 CONFIG_TESTS       ?= y
+
+# Test coverage support
+TEST_COVERAGE ?= y
+
diff -r 5af4f2ab06f3 xen/Rules.mk
--- a/xen/Rules.mk      Tue Jan 22 09:33:10 2013 +0100
+++ b/xen/Rules.mk      Mon Jan 28 17:36:14 2013 +0000
@@ -103,6 +103,11 @@ subdir-all := $(subdir-y) $(subdir-n)
 
 $(filter %.init.o,$(obj-y) $(obj-bin-y)): CFLAGS += -DINIT_SECTIONS_ONLY
 
+
+ifeq ($(TEST_COVERAGE),y)
+$(filter-out %.init.o,$(obj-y) $(obj-bin-y)): CFLAGS += -fprofile-arcs 
-ftest-coverage -DTEST_COVERAGE
+endif
+
 ifeq ($(lto),y)
 # Would like to handle all object files as bitcode, but objects made from
 # pure asm are in a different format and have to be collected separately.
diff -r 5af4f2ab06f3 xen/arch/x86/setup.c
--- a/xen/arch/x86/setup.c      Tue Jan 22 09:33:10 2013 +0100
+++ b/xen/arch/x86/setup.c      Mon Jan 28 17:36:14 2013 +0000
@@ -46,6 +46,7 @@
 #include <asm/setup.h>
 #include <xen/cpu.h>
 #include <asm/nmi.h>
+#include <xen/gcov.h>
 
 /* opt_nosmp: If true, secondary processors are ignored. */
 static bool_t __initdata opt_nosmp;
@@ -1313,6 +1314,8 @@ void __init __start_xen(unsigned long mb
 
     init_trace_bufs();
 
+    init_coverage();
+
     console_endboot();
 
     /* Hide UART from DOM0 if we're using it */
diff -r 5af4f2ab06f3 xen/arch/x86/x86_64/compat/entry.S
--- a/xen/arch/x86/x86_64/compat/entry.S        Tue Jan 22 09:33:10 2013 +0100
+++ b/xen/arch/x86/x86_64/compat/entry.S        Mon Jan 28 17:36:14 2013 +0000
@@ -413,6 +413,8 @@ ENTRY(compat_hypercall_table)
         .quad do_domctl
         .quad compat_kexec_op
         .quad do_tmem_op
+        .quad compat_ni_hypercall
+        .quad compat_coverage_op
         .rept __HYPERVISOR_arch_0-((.-compat_hypercall_table)/8)
         .quad compat_ni_hypercall
         .endr
@@ -461,6 +463,8 @@ ENTRY(compat_hypercall_args_table)
         .byte 1 /* do_domctl                */
         .byte 2 /* compat_kexec_op          */
         .byte 1 /* do_tmem_op               */
+        .byte 0 /* compat_ni_hypercall      */
+        .byte 4 /* compat_coverage_op       */
         .rept __HYPERVISOR_arch_0-(.-compat_hypercall_args_table)
         .byte 0 /* compat_ni_hypercall      */
         .endr
diff -r 5af4f2ab06f3 xen/arch/x86/x86_64/entry.S
--- a/xen/arch/x86/x86_64/entry.S       Tue Jan 22 09:33:10 2013 +0100
+++ b/xen/arch/x86/x86_64/entry.S       Mon Jan 28 17:36:14 2013 +0000
@@ -738,6 +738,8 @@ ENTRY(hypercall_table)
         .quad do_domctl
         .quad do_kexec_op
         .quad do_tmem_op
+        .quad do_ni_hypercall
+        .quad do_coverage_op
         .rept __HYPERVISOR_arch_0-((.-hypercall_table)/8)
         .quad do_ni_hypercall
         .endr
@@ -786,6 +788,8 @@ ENTRY(hypercall_args_table)
         .byte 1 /* do_domctl            */
         .byte 2 /* do_kexec             */
         .byte 1 /* do_tmem_op           */
+        .byte 0 /* do_ni_hypercall      */
+        .byte 4 /* do_coverage_op       */
         .rept __HYPERVISOR_arch_0-(.-hypercall_args_table)
         .byte 0 /* do_ni_hypercall      */
         .endr
diff -r 5af4f2ab06f3 xen/arch/x86/xen.lds.S
--- a/xen/arch/x86/xen.lds.S    Tue Jan 22 09:33:10 2013 +0100
+++ b/xen/arch/x86/xen.lds.S    Mon Jan 28 17:36:14 2013 +0000
@@ -78,7 +78,23 @@ SECTIONS
        *(.data)
        *(.data.rel)
        *(.data.rel.*)
-       CONSTRUCTORS
+#ifdef __x86_64__
+        . = ALIGN(8);
+        __CTOR_LIST__ = .;
+        QUAD((__CTOR_END__ - __CTOR_LIST__) / 8 - 2)
+        *(.ctors)
+        CONSTRUCTORS
+        QUAD(0)
+        __CTOR_END__ = .;
+#else
+        . = ALIGN(4);
+        __CTOR_LIST__ = .;
+        LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)
+        *(.ctors)
+        CONSTRUCTORS
+        LONG(0)
+        __CTOR_END__ = .;
+#endif
   } :text
 
 #ifdef LOCK_PROFILE
diff -r 5af4f2ab06f3 xen/common/Makefile
--- a/xen/common/Makefile       Tue Jan 22 09:33:10 2013 +0100
+++ b/xen/common/Makefile       Mon Jan 28 17:36:14 2013 +0000
@@ -59,5 +59,7 @@ subdir-$(CONFIG_COMPAT) += compat
 
 subdir-$(x86_64) += hvm
 
+subdir-$(TEST_COVERAGE) += gcov
+
 subdir-y += libelf
 subdir-$(HAS_DEVICE_TREE) += libfdt
diff -r 5af4f2ab06f3 xen/common/gcov/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/common/gcov/Makefile  Mon Jan 28 17:36:14 2013 +0000
@@ -0,0 +1,1 @@
+obj-y += gcov.o
diff -r 5af4f2ab06f3 xen/common/gcov/gcov.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/common/gcov/gcov.c    Mon Jan 28 17:36:14 2013 +0000
@@ -0,0 +1,97 @@
+/*
+ *  This code maintains a list of active profiling data structures.
+ *
+ *    Copyright IBM Corp. 2009
+ *    Author(s): Peter Oberparleiter <oberpar@xxxxxxxxxxxxxxxxxx>
+ *
+ *    Uses gcc-internal data definitions.
+ *    Based on the gcov-kernel patch by:
+ *       Hubertus Franke <frankeh@xxxxxxxxxx>
+ *       Nigel Hinds <nhinds@xxxxxxxxxx>
+ *       Rajan Ravindran <rajancr@xxxxxxxxxx>
+ *       Peter Oberparleiter <oberpar@xxxxxxxxxxxxxxxxxx>
+ *       Paul Larson
+ */
+
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/gcov.h>
+#include <xen/errno.h>
+#include <public/xen.h>
+
+static struct gcov_info *info_list;
+static unsigned num_info = 0;
+
+/*
+ * __gcov_init is called by gcc-generated constructor code for each object
+ * file compiled with -fprofile-arcs.
+ * 
+ * Although this function is called only during initialization is called from
+ * a .text section which is still present after initialization so not declare
+ * as __init.
+ */
+void __gcov_init(struct gcov_info *info)
+{
+    /* add new profiling data structure to list */
+    info->next = info_list;
+    info_list = info;
+    ++num_info;
+}
+
+/*
+ * These functions may be referenced by gcc-generated profiling code but serve
+ * no function for Xen.
+ */
+void __gcov_flush(void)
+{
+    /* Unused. */
+}
+
+void __gcov_merge_add(gcov_type *counters, unsigned int n_counters)
+{
+    /* Unused. */
+}
+
+void __gcov_merge_single(gcov_type *counters, unsigned int n_counters)
+{
+    /* Unused. */
+}
+
+void __gcov_merge_delta(gcov_type *counters, unsigned int n_counters)
+{
+    /* Unused. */
+}
+
+typedef void (*ctor_func_t)(void);
+extern struct {
+    unsigned long count;
+    ctor_func_t funcs[1];
+} __CTOR_LIST__;
+
+void __init init_coverage(void)
+{
+    unsigned long n;
+    for (n = 0; n < __CTOR_LIST__.count; ++n)
+        __CTOR_LIST__.funcs[n]();
+
+#ifndef NDEBUG
+    printk(XENLOG_INFO "Initialized %u coverage strucures\n", num_info);
+    if (info_list)
+        printk(XENLOG_INFO "First coverage file %s\n", info_list->filename);
+#endif
+}
+
+long do_coverage_op(int op, int idx, XEN_GUEST_HANDLE_PARAM(void) uarg, int 
arg2)
+{
+    return -EINVAL;
+}
+
+#ifdef CONFIG_COMPAT
+int compat_coverage_op(int op, int idx, XEN_GUEST_HANDLE_PARAM(void) uarg, int 
arg2)
+{
+    return -EINVAL;
+}
+#endif
+
+
diff -r 5af4f2ab06f3 xen/include/public/xen.h
--- a/xen/include/public/xen.h  Tue Jan 22 09:33:10 2013 +0100
+++ b/xen/include/public/xen.h  Mon Jan 28 17:36:14 2013 +0000
@@ -101,6 +101,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_ulong_t);
 #define __HYPERVISOR_kexec_op             37
 #define __HYPERVISOR_tmem_op              38
 #define __HYPERVISOR_xc_reserved_op       39 /* reserved for XenClient */
+#define __HYPERVISOR_coverage             40 /* reserved to get coverage 
information */
 
 /* Architecture-specific hypercall definitions. */
 #define __HYPERVISOR_arch_0               48
diff -r 5af4f2ab06f3 xen/include/xen/gcov.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/xen/gcov.h    Mon Jan 28 17:36:14 2013 +0000
@@ -0,0 +1,141 @@
+/*
+ *  Profiling infrastructure declarations.
+ *
+ *  This file is based on gcc-internal definitions. Data structures are
+ *  defined to be compatible with gcc counterparts. For a better
+ *  understanding, refer to gcc source: gcc/gcov-io.h.
+ *
+ *    Copyright IBM Corp. 2009
+ *    Author(s): Peter Oberparleiter <oberpar@xxxxxxxxxxxxxxxxxx>
+ *
+ *    Uses gcc-internal data definitions.
+ */
+
+#ifndef GCOV_H
+#define GCOV_H GCOV_H
+
+/*
+ * Profiling data types used for gcc 3.4 and above - these are defined by
+ * gcc and need to be kept as close to the original definition as possible to
+ * remain compatible.
+ */
+#define GCOV_COUNTERS         5
+#define GCOV_DATA_MAGIC       ((unsigned int) 0x67636461)
+#define GCOV_TAG_FUNCTION     ((unsigned int) 0x01000000)
+#define GCOV_TAG_COUNTER_BASE ((unsigned int) 0x01a10000)
+#define GCOV_TAG_FOR_COUNTER(count) \
+    (GCOV_TAG_COUNTER_BASE + ((unsigned int) (count) << 17))
+
+#if BITS_PER_LONG >= 64
+typedef long gcov_type;
+#else
+typedef long long gcov_type;
+#endif
+
+/**
+ * struct gcov_fn_info - profiling meta data per function
+ * @ident: object file-unique function identifier
+ * @checksum: function checksum
+ * @n_ctrs: number of values per counter type belonging to this function
+ *
+ * This data is generated by gcc during compilation and doesn't change
+ * at run-time.
+ */
+struct gcov_fn_info {
+    unsigned int ident;
+    unsigned int checksum;
+    unsigned int n_ctrs[0];
+};
+
+/**
+ * struct gcov_ctr_info - profiling data per counter type
+ * @num: number of counter values for this type
+ * @values: array of counter values for this type
+ * @merge: merge function for counter values of this type (unused)
+ *
+ * This data is generated by gcc during compilation and doesn't change
+ * at run-time with the exception of the values array.
+ */
+struct gcov_ctr_info {
+    unsigned int num;
+    gcov_type *values;
+    void (*merge)(gcov_type *, unsigned int);
+};
+
+/**
+ * struct gcov_info - profiling data per object file
+ * @version: gcov version magic indicating the gcc version used for compilation
+ * @next: list head for a singly-linked list
+ * @stamp: time stamp
+ * @filename: name of the associated gcov data file
+ * @n_functions: number of instrumented functions
+ * @functions: function data
+ * @ctr_mask: mask specifying which counter types are active
+ * @counts: counter data per counter type
+ *
+ * This data is generated by gcc during compilation and doesn't change
+ * at run-time with the exception of the next pointer.
+ */
+struct gcov_info {
+    unsigned int              version;
+    struct gcov_info          *next;
+    unsigned int              stamp;
+    const char                *filename;
+    unsigned int              n_functions;
+    const struct gcov_fn_info *functions;
+    unsigned int              ctr_mask;
+    struct gcov_ctr_info      counts[0];
+};
+
+#if 0
+/* Base interface. */
+enum gcov_action {
+    GCOV_ADD,
+    GCOV_REMOVE,
+};
+
+void gcov_event(enum gcov_action action, struct gcov_info *info);
+void gcov_enable_events(void);
+
+/* Iterator control. */
+struct seq_file;
+struct gcov_iterator;
+
+struct gcov_iterator *gcov_iter_new(struct gcov_info *info);
+void gcov_iter_free(struct gcov_iterator *iter);
+void gcov_iter_start(struct gcov_iterator *iter);
+int gcov_iter_next(struct gcov_iterator *iter);
+int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq);
+struct gcov_info *gcov_iter_get_info(struct gcov_iterator *iter);
+
+/* gcov_info control. */
+void gcov_info_reset(struct gcov_info *info);
+int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2);
+void gcov_info_add(struct gcov_info *dest, struct gcov_info *source);
+struct gcov_info *gcov_info_dup(struct gcov_info *info);
+void gcov_info_free(struct gcov_info *info);
+
+struct gcov_link {
+    enum {
+        OBJ_TREE,
+        SRC_TREE,
+    } dir;
+    const char *ext;
+};
+extern const struct gcov_link gcov_link[];
+#endif
+
+/**
+ * Initialize coverage informations
+ * Currently create a linked list of all files compiled in with
+ * coverage informations.
+ */
+#ifdef TEST_COVERAGE
+void __init init_coverage(void);
+#else
+static inline void init_coverage(void) {
+}
+#endif
+
+
+#endif /* GCOV_H */
diff -r 5af4f2ab06f3 xen/include/xen/hypercall.h
--- a/xen/include/xen/hypercall.h       Tue Jan 22 09:33:10 2013 +0100
+++ b/xen/include/xen/hypercall.h       Mon Jan 28 17:36:14 2013 +0000
@@ -140,6 +140,12 @@ do_tmem_op(
 extern long
 do_xenoprof_op(int op, XEN_GUEST_HANDLE_PARAM(void) arg);
 
+extern long
+do_coverage_op(int op,
+    int idx,
+    XEN_GUEST_HANDLE_PARAM(void) arg1,
+    int arg2);
+
 #ifdef CONFIG_COMPAT
 
 extern int
@@ -162,6 +168,12 @@ compat_vcpu_op(
 extern int
 compat_xenoprof_op(int op, XEN_GUEST_HANDLE_PARAM(void) arg);
 
+extern long
+compat_coverage_op(int op,
+    int idx,
+    XEN_GUEST_HANDLE_PARAM(void) arg1,
+    int arg2);
+
 extern int
 compat_xen_version(
     int cmd,


Regards,
  Frediano Ziglio




_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.