From: Tej <bewith.tej@gmail.com>
To: George Dunlap <george.dunlap@eu.citrix.com>
Cc: xen-devel@lists.xensource.com,
xen-users <xen-users@lists.xensource.com>,
parkash.tej@gmail.com
Subject: Xen GCOV Patches for latest Xen Unbstable and linux 2.6.18.8 kernel(32/64bit)
Date: Sat, 8 May 2010 01:31:01 +0530 [thread overview]
Message-ID: <o2jf1c9d251005071301jfd33f723gc49e4013ae4a3d47@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 1528 bytes --]
All,
Here are the latest patches to expreiment with gcov profiler for xen
hypervisor. I have tested current patches on Intel i686.
System Details:
gcc version 4.3.3 (Ubuntu 4.3.3-5ubuntu4)
gcov (Ubuntu 4.3.3-5ubuntu4) 4.3.3
Kernel 2.6.28-11-generic
Distribution: Ubuntu jaunty 9.04
There are some design issue which i would like to highlight here:
1. To create gcov proc dir user /proc/xen, we are explicitly exported
xen_base symbol. I want to know your thoughts.
2. XEN_GCOV_PROC config is set as not selected. So someone has to be
configured manually as M/Y
Known Issues:
File vmac.c throw some fault while using with lcov/gcov. This is due
to some raw count copy between xen and kernel. I could not able to
reproduce it many times, may be someone can try on 64 bit m/c.
"My take on this is that zero length array element in gcov_info
structure has to be copied separately between xen and kernel. How? I
dont know."
I am still debugging this issue.
If you get fault and fail to proceed please apply the above patch in
linux-wa-v1.patch in Linux 2.6.18.8 and recompile. This time vmac.gcda
file wont appear in /proc/xen/gcov/crypto
HOWTO Test using lcov
1. install lcov from repo
# sudo apt-get install lcov
2. vi /etc/lcovrc
Change line: lcov_gcov_dir = /proc/gcov to lcov_gcov_dir = /proc/xen/gcov
3. # cd /tmp; lcov -c -o kernel.info
4. # genhtml kernel.info
5, # firefox index.html
lcov README and screenshot is attached.
HTH
Note:
For any other detail required please CC me to parkash.tej@gmail.com
[-- Attachment #2: linux-2.6.18-gcov-v1.patch --]
[-- Type: text/x-patch, Size: 44147 bytes --]
diff -r 86d6c6417cf9 drivers/xen/Kconfig
--- a/drivers/xen/Kconfig Thu Feb 04 13:08:27 2010 +0000
+++ b/drivers/xen/Kconfig Sun Feb 07 00:13:40 2010 +0530
@@ -311,6 +311,13 @@
help
Xen hypervisor attributes will show up under /sys/hypervisor/.
+config XEN_GCOV_PROC
+ tristate "Code covarage for hypervisor"
+ help
+ Select to profile Xen Hypervisor only. Create /proc/xen/gcov entry
+ which provides access to the current code coverage state of xen hypervisor
+
+
choice
prompt "Xen version compatibility"
default XEN_COMPAT_030002_AND_LATER
diff -r 86d6c6417cf9 drivers/xen/Makefile
--- a/drivers/xen/Makefile Thu Feb 04 13:08:27 2010 +0000
+++ b/drivers/xen/Makefile Sun Feb 07 00:13:40 2010 +0530
@@ -3,6 +3,7 @@
obj-y += evtchn/
obj-y += xenbus/
obj-y += char/
+obj-y += gcov/
obj-y += util.o
obj-$(CONFIG_XEN_BALLOON) += balloon/
diff -r 86d6c6417cf9 drivers/xen/core/xen_proc.c
--- a/drivers/xen/core/xen_proc.c Thu Feb 04 13:08:27 2010 +0000
+++ b/drivers/xen/core/xen_proc.c Sun Feb 07 00:13:40 2010 +0530
@@ -3,7 +3,7 @@
#include <linux/proc_fs.h>
#include <xen/xen_proc.h>
-static struct proc_dir_entry *xen_base;
+struct proc_dir_entry *xen_base;
struct proc_dir_entry *create_xen_proc_entry(const char *name, mode_t mode)
{
@@ -20,4 +20,5 @@
remove_proc_entry(name, xen_base);
}
+EXPORT_SYMBOL(xen_base);
EXPORT_SYMBOL_GPL(remove_xen_proc_entry);
diff -r 86d6c6417cf9 drivers/xen/gcov/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/gcov/Makefile Sun Feb 07 00:13:40 2010 +0530
@@ -0,0 +1,1 @@
+obj-$(CONFIG_XEN_GCOV_PROC) := xen-gcov-proc.o
diff -r 86d6c6417cf9 drivers/xen/gcov/xen-gcov-proc.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/gcov/xen-gcov-proc.c Sun Feb 07 00:13:40 2010 +0530
@@ -0,0 +1,1235 @@
+/**
+ * @file xen-gcov-proc.c
+ *
+ * @Author: Hubertus Franke <frankeh@us.ibm.com>
+ * Rajan Ravindran <rajancr@us.ibm.com>
+ * Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
+ * Paul Larson
+ *
+ * Modified by tej parkash and team for Xen (tej.parkash@hcl.in)
+ *
+ */
+/***************************************************************************/
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/sysctl.h>
+#include <linux/spinlock.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/xen-gcov.h>
+#include <xen/evtchn.h>
+#include <xen/xen_proc.h>
+#include <linux/proc_fs.h>
+#include <linux/workqueue.h>
+
+MODULE_LICENSE("GPL");
+
+#define GCOV_PROC_HEADER "xen-gcov-proc: "
+#define GCOV_PROC_ROOT "gcov"
+#define GCOV_PROC_VMLINUX "vmlinux"
+#define PAD8(x) (((x) + 7) & ~7)
+
+#define FILE_LENGTH 100
+
+/*
+ * If set to non-zero, create links to additional files(.c and .gcno) in proc
+ * filesystem entries.
+ */
+static int xen_gcov_link = 1;
+
+/* Count update frequency */
+static int xen_gcov_update = 5;
+
+#ifdef MODULE
+/* Parameter handling. */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+/* module_param is a 2.6 thing (though there are compat macros since 2.4.25) */
+MODULE_PARM(xen_gcov_link, "i");
+MODULE_PARM(xen_gcov_update, "i");
+#else
+module_param(xen_gcov_link, int, 0400);
+module_param(xen_gcov_update, int, 0400);
+#endif /* LINUX_VERSION_CODE */
+
+MODULE_PARM_DESC(xen_gcov_link, "If set to non-zero, create links to additional "
+ "files in proc filesystem entries");
+MODULE_PARM_DESC(xen_gcov_update, "decides the frequency of hypervisor count"
+ "update and default value is 5sec.");
+#else /* MODULE */
+/* Called when 'xen_gcov_link' is specified on the kernel command line. */
+static int __init xen_gcov_link_setup(char *str)
+{
+ xen_gcov_link = (int)simple_strtol(str, NULL, 10);
+ return 1;
+}
+
+__setup("xen_gcov_link=", xen_gcov_link_setup);
+
+static int __init xen_gcov_update_setup(char *str)
+{
+ xen_gcov_update = (int)simple_strtol(str, NULL, 10);
+ return 1;
+}
+
+__setup("xen_gcov_update=", xen_gcov_update_setup);
+
+#endif /* MODULE */
+
+/*
+ * create sysclt entry @/proc/sys/xen
+ * accomplish the count update frequency
+ * perform: echo <num> >/proc/sys/xen/xen_gcov_update
+ */
+#ifdef CONFIG_SYSCTL
+static ctl_table gcov_table[] = {
+ {
+ .ctl_name = 4,
+ .procname = "xen_gcov_update",
+ .data = &xen_gcov_update,
+ .maxlen = sizeof(xen_gcov_update),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ }
+ ,
+ {.ctl_name = 0}
+};
+
+static ctl_table gcov_root_table[] = {
+ {
+ .ctl_name = 123,
+ .procname = "xen",
+ .mode = 0555,
+ .child = gcov_table},
+ {.ctl_name = 0}
+};
+
+/*sysclt table specific declaration*/
+static struct ctl_table_header *gcov_table_header;
+
+#endif /* CONFIG_SYSCTL */
+
+/* Protect global variables from concurrent access. */
+static DEFINE_MUTEX(read_mutex);
+static DEFINE_MUTEX(write_mutex);
+
+/* workqueue function */
+static void xeno_prof(void *);
+
+/* workqueue for the calling hypervisor count head */
+static DECLARE_WORK(work, xeno_prof, NULL);
+
+/* Filesystem entry for /proc/gcov/vmlinux */
+static struct proc_dir_entry *proc_vmlinux = NULL;
+
+/* First leaf node. */
+static struct gcov_ftree_node *leaf_nodes = NULL;
+
+/* Cached node used to speed up sequential reads in /proc/vmlinux. */
+static struct gcov_ftree_node *cached_node = NULL;
+
+/* Root node for internal data tree. */
+static struct gcov_ftree_node tree_root;
+
+struct node_info *node_info = NULL;
+
+/* Filename extension for data files. */
+static const char *da_ending = "gcda";
+
+/* Array of filename endings to use when creating links. */
+static const char *endings[] = { "gcno", "c" };
+
+/* Info which keeps no if file in xen info to be profile */
+unsigned int xen_file_nos;
+
+/* head of xen-gcov-info linked list */
+struct gcov_info *list_head = NULL;
+
+/* xen_sourcepath length */
+static int sourcepath_len;
+
+/* gcov version no */
+unsigned long xen_gcov_version;
+
+
+/* Determine whether counter TYPE is active in BB. */
+static inline int
+counter_active(struct gcov_info *bb, unsigned int type)
+{
+ return (1 << type) & bb->ctr_mask;
+}
+
+/* Return the number of active counter types for BB. */
+static inline unsigned int
+num_counter_active(struct gcov_info *bb)
+{
+ unsigned int i;
+ unsigned int result;
+
+ result = 0;
+ for (i=0; i < GCOV_COUNTERS; i++)
+ if (counter_active(bb, i))
+ result++;
+ return result;
+}
+
+/*
+ * Get number of bytes used for one entry in the gcov_fn_info array pointed to
+ * by BB->functions.
+ */
+static inline unsigned int
+get_fn_stride(struct gcov_info *bb)
+{
+ unsigned int stride;
+
+ stride = sizeof(struct gcov_fn_info) + num_counter_active(bb) *
+ sizeof(unsigned int);
+ if (__alignof__(struct gcov_fn_info) > sizeof(unsigned int))
+ {
+ stride += __alignof__(struct gcov_fn_info) - 1;
+ stride &= ~(__alignof__(struct gcov_fn_info) - 1);
+ }
+ return stride;
+}
+
+/* Get the address of gcov_fn_info for function FUNC of BB. */
+static inline struct gcov_fn_info *
+get_fn_info(struct gcov_info *bb, unsigned int func)
+{
+ return (struct gcov_fn_info *)
+ ((char *)bb->functions + func * get_fn_stride(bb));
+}
+
+/*
+ * Create xen_gcov_info linked list by creating nodes for all gcda files
+ * based on n_files value
+ */
+static inline int create_bb_list(void)
+{
+ struct gcov_info *node = NULL, *tmp_node = NULL;
+ int i, j, len=0, active;
+
+ for (i = 0; i < node_info->n_files; i++)
+ {
+ /* Allocate memory for struct gcov_info */
+ active = node_info->active_counters[i];
+ len = sizeof(struct gcov_info) + sizeof(struct gcov_ctr_info)*active;
+ node = (struct gcov_info *) kmalloc(len, GFP_KERNEL);
+ for (j=0; j < active; j++) {
+ len =sizeof(gcov_type) * node_info->ctr_num[i][j];
+ node->counts[j].values = kmalloc(len, GFP_KERNEL);
+ }
+
+ /* Allocate memory for array of struct gcov_fn_info */
+ len = (sizeof(struct gcov_fn_info) + active*sizeof(unsigned int)) *
+ node_info->n_funcs[i];
+ node->functions = (struct gcov_fn_info *) kmalloc(len,GFP_KERNEL);
+ node->filename = (char *) kmalloc(FILE_SIZE*sizeof(char),GFP_KERNEL);
+ node->next = NULL;
+
+ if (list_head == NULL)
+ {
+ list_head = node;
+ tmp_node = node;
+ }
+ else
+ {
+ tmp_node->next = node;
+ tmp_node = node;
+ }
+ }
+ return 0;
+}
+
+/* free memory allocated for gcov_info list */
+static inline int free_bb_list(void)
+{
+ struct gcov_info *node = NULL;
+ struct gcov_info *temp = list_head;
+ int active,i;
+
+ for (;temp!=NULL;temp = temp->next)
+ {
+ node = temp;
+ active=num_counter_active(node);
+ for(i=0; i < active; i++)
+ kfree(node->counts[i].values);
+ kfree(node->functions);
+ kfree(node);
+ }
+
+ return 0;
+}
+
+/*
+ * Store a portable representation of VALUE in DEST using BYTES*8-1 bits.
+ * Return a non-zero value if VALUE requires more than BYTES*8-1 bits
+ * to store (adapted from gcc/gcov-io.h).
+ */
+static int store_gcov_type(gcov_type value, char *dest, size_t bytes)
+{
+ int upper_bit = (value < 0 ? 128 : 0);
+ size_t i;
+ if (value < 0)
+ {
+ gcov_type oldvalue = value;
+ value = -value;
+ if (oldvalue != -value)
+ return 1;
+ }
+
+ for (i = 0; i < (sizeof(value) < bytes ? sizeof(value) : bytes); i++)
+ {
+ dest[i] = value & (i == (bytes - 1) ? 127 : 255);
+ value = value / 256;
+ }
+
+ if (value && value != -1)
+ return 1;
+
+ for (; i < bytes; i++)
+ dest[i] = 0;
+ dest[bytes - 1] |= upper_bit;
+
+ return 0;
+}
+
+/* Return size of .gcda counter section. */
+static size_t
+sizeof_counter_data(struct gcov_info *bb, unsigned int row,
+ unsigned int col)
+{
+
+ struct gcov_fn_info *func = get_fn_info(bb,row);
+
+ if (counter_active(bb, col))
+ {
+ return /* tag */ 4 + /* length */ 4 +
+ /* counters */ func->n_ctrs[col] * 8;
+ }
+ else
+ return 0;
+}
+
+/* Return size of .gcda data section associated with FUNC. */
+static size_t sizeof_func_data(struct gcov_info *bb, unsigned int row)
+{
+ size_t result;
+ unsigned int type;
+
+ result =
+ /* tag */ 4 + /* length */ 4 + /* ident */ 4 + /* checksum */ 4;
+ for (type = 0; type < GCOV_COUNTERS; type++)
+ result += sizeof_counter_data(bb, row, type);
+ return result;
+}
+
+/* Get size of .gcda file associated with BB. */
+static size_t sizeof_da_file(struct gcov_info *bb)
+{
+ size_t result;
+ unsigned int i;
+
+ result = /* magic */ 4 + /* version */ 4 + /* stamp */ 4;
+ for (i = 0; i < bb->n_functions; i++)
+ result += sizeof_func_data(bb, i);
+ return result;
+}
+
+/*
+ * Store a 32 bit unsigned integer value in GCOV format to memory at address
+ * BUF.
+ */
+static void store_int32(uint32_t i, char *buf)
+{
+ uint32_t *p;
+ p = (int *)buf;
+ *p = i;
+
+}
+
+/*
+ * Store a 64 bit unsigned integer value in GCOV format to memory at address
+ * BUF.
+ */
+static void store_int64(uint64_t i, char *buf)
+{
+ store_int32((uint32_t) (i & 0xffff), buf);
+ store_int32((uint32_t) (i >> 32), buf + 4);
+}
+
+/*
+ * Store a gcov counter in GCOV format to memory at address BUF. The counter is
+ * identified by BB, FUNC, TYPE and COUNTER.
+ */
+static void
+store_counter(struct gcov_info *bb, unsigned int func, unsigned int type,
+ unsigned int counter, char *buf)
+{
+ unsigned int counter_off;
+ unsigned int type_off;
+ unsigned int i;
+ struct gcov_fn_info *func_ptr;
+ /* Get offset into counts array */
+ type_off = 0;
+ for (i = 0; i < type; i++)
+ if (counter_active(bb, i))
+ type_off++;
+ /* Get offset into values array. */
+ counter_off = counter;
+ for (i = 0; i < func; i++)
+ {
+ func_ptr = get_fn_info(bb,i);
+ counter_off += func_ptr->n_ctrs[type];
+ }
+ /* Create in temporary storage */
+ store_int64(bb->counts[type_off].values[counter_off], buf);
+}
+
+/*
+ * Store a counter section in userspace memory. The counter section is
+ * identified by BB, FUNC and TYPE. The destination address is BUF. Store at
+ * most COUNT bytes beginning at OFFSET. Return the number of bytes stored or a
+ * negative value on error.
+ */
+static ssize_t
+store_counter_data(struct gcov_info *bb, unsigned int func,
+ unsigned int type, char *buf, size_t count, loff_t offset)
+{
+ struct gcov_fn_info *func_ptr;
+ char data[8];
+ char *from;
+ size_t len;
+ ssize_t result;
+ unsigned int i;
+
+ func_ptr = get_fn_info(bb,func);
+ result = 0;
+ while (count > 0)
+ {
+ if (offset < 4)
+ {
+ /* Tag ID */
+ store_int32((uint32_t) GCOV_TAG_FOR_COUNTER(type),
+ data);
+ len = 4 - offset;
+ from = data + offset;
+ }
+ else if (offset < 8)
+ {
+ /* Tag length in groups of 4 bytes */
+ store_int32((uint32_t)
+ func_ptr->n_ctrs[type] * 2, data);
+ len = 4 - (offset - 4);
+ from = data + (offset - 4);
+ }
+ else
+ {
+ /* Actual counter data */
+ i = (offset - 8) / 8;
+ /* Check for EOF */
+ if (i >= func_ptr->n_ctrs[type])
+ break;
+ store_counter(bb, func, type, i, data);
+ len = 8 - (offset - 8) % 8;
+ from = data + (offset - 8) % 8;
+ }
+ if (len > count)
+ len = count;
+ if (copy_to_user(buf, from, len))
+ return -EFAULT;
+ count -= len;
+ buf += len;
+ offset += len;
+ result += len;
+ }
+
+ return result;
+}
+
+/*
+ * Store a function section and associated counter sections in userspace memory.
+ * The function section is identified by BB and FUNC. The destination address is
+ * BUF. Store at most COUNT bytes beginning at OFFSET. Return the number of
+ * bytes stored or a negative value on error.
+ */
+static ssize_t
+store_func_data(struct gcov_info *bb, unsigned int func, char *buf,
+ size_t count, loff_t offset)
+{
+ struct gcov_fn_info *func_ptr;
+ char data[4];
+ char *from;
+ size_t len;
+ unsigned int i;
+ loff_t off;
+ size_t size;
+ ssize_t result;
+ ssize_t rc;
+
+ func_ptr = get_fn_info(bb, func);
+ result = 0;
+ while (count > 0)
+ {
+ if (offset < 16)
+ {
+ if (offset < 4)
+ {
+ /* Tag ID */
+ store_int32((uint32_t) GCOV_TAG_FUNCTION, data);
+ len = 4 - offset;
+ from = data + offset;
+ }
+ else if (offset < 8)
+ {
+ /* Tag length */
+ store_int32(2, data);
+ len = 4 - (offset - 4);
+ from = data + (offset - 4);
+ }
+ else if (offset < 12)
+ {
+ /* Function ident */
+ store_int32((uint32_t) func_ptr->ident ,data);
+
+ len = 4 - (offset - 8);
+ from = data + (offset - 8);
+ }
+ else
+ {
+ /* Function checksum */
+ store_int32((uint32_t) func_ptr->checksum,data);
+ len = 4 - (offset - 12);
+ from = data + (offset - 12);
+ }
+ /* Do the actual store */
+ if (len > count)
+ len = count;
+ if (copy_to_user(buf, from, len))
+ return -EFAULT;
+ }
+ else
+ {
+ off = 16;
+ len = 0;
+ for (i = 0; i < GCOV_COUNTERS; i++)
+ {
+ size = sizeof_counter_data(bb, func, i);
+ if (offset < off + size)
+ {
+ rc = store_counter_data(bb, func, i,
+ buf, count,
+ offset - off);
+ if (rc < 0)
+ return rc;
+ len = rc;
+ break;
+ }
+ off += size;
+ }
+ /* Check for EOF */
+ if (i == GCOV_COUNTERS)
+ break;
+ }
+ count -= len;
+ buf += len;
+ offset += len;
+ result += len;
+ }
+
+ return result;
+}
+
+/*
+ * Store data of .gcda file associated with NODE to userspace memory at BUF.
+ * OFFSET specifies the offset inside the .da file. COUNT is the maximum
+ * number of bytes to store. Return the number of bytes stored, zero for
+ * EOF or a negative number in case of error.
+ */
+static ssize_t
+store_da_file(struct gcov_ftree_node *node, char *buf, size_t count,
+ loff_t offset)
+{
+
+ struct gcov_info *bb;
+ char data[4];
+ char *from;
+ size_t len;
+ unsigned int i;
+ loff_t off;
+ size_t size;
+ ssize_t result;
+ ssize_t rc;
+
+ bb = node->bb;
+ result = 0;
+ while (count > 0)
+ {
+ if (offset < 12)
+ {
+ if (offset < 4)
+ {
+ /* File magic */
+ store_int32((uint32_t) GCOV_DATA_MAGIC, data);
+ len = 4 - offset;
+ from = data + offset;
+ }
+ else if (offset < 8)
+ {
+ /* File format/GCC version */
+ store_int32(xen_gcov_version, data);
+ len = 4 - (offset - 4);
+ from = data + (offset - 4);
+ }
+ else
+ {
+ /* Time stamp */
+ store_int32((uint32_t) bb->stamp, data);
+ len = 4 - (offset - 8);
+ from = data + (offset - 8);
+ }
+ /* Do the actual store */
+ if (len > count)
+ len = count;
+ if (copy_to_user(buf, from, len))
+ return -EFAULT;
+ }
+ else
+ {
+ off = 12;
+ len = 0;
+ for (i = 0; i < bb->n_functions; i++)
+ {
+
+ size = sizeof_func_data(bb, i);
+ if (offset < off + size)
+ {
+ rc = store_func_data(bb, i, buf, count,
+ offset - off);
+
+ if (rc < 0)
+ return rc;
+ len = rc;
+ break;
+ }
+ off += size;
+
+ }
+ /* Check for EOF */
+ if (i == bb->n_functions)
+ break;
+ }
+ count -= len;
+ buf += len;
+ offset += len;
+ result += len;
+ }
+
+ return result;
+}
+
+/*
+ * Return size of header which precedes .da file entry associated with BB
+ * in the vmlinux file.
+ */
+static size_t sizeof_vmlinux_header(struct gcov_info *bb)
+{
+ return 8 + PAD8(strlen(bb->filename) + 1);
+}
+
+/*
+ * Store data of header which precedes .da file entry associated with NODE
+ * in the vmlinux file to userspace memory at BUF. OFFSET specifies the offset
+ * inside the header file. COUNT is the maximum number of bytes to store.
+ * Return the number of bytes stored, zero for EOF or a negative number in
+ * case of error.
+ */
+static ssize_t
+store_vmlinux_header(struct gcov_ftree_node *node, char *buf, size_t count,
+ loff_t offset)
+{
+ char data[8];
+ char *from;
+ size_t namelen;
+ ssize_t stored;
+ size_t len;
+
+ namelen = strlen(node->bb->filename);
+ stored = 0;
+ while (count > 0)
+ {
+ if (offset < 8)
+ {
+ /* Filename length */
+ if (store_gcov_type(PAD8(namelen + 1), data, 8))
+ return -EINVAL;
+ from = data + offset;
+ len = 8 - offset;
+ }
+ else if (offset < 8 + namelen)
+ {
+ /* Filename */
+ from = (char *)node->bb->filename + offset - 8;
+ len = namelen - (offset - 8);
+ }
+ else if (offset < node->header_size)
+ {
+ /* Nil byte padding */
+ memset(data, 0, 8);
+ from = data;
+ len = PAD8(namelen + 1) - (offset - 8);
+ }
+ else
+ break;
+ if (len > count)
+ len = count;
+ if (copy_to_user(buf, from, len))
+ return -EFAULT;
+
+ stored += len;
+ count -= len;
+ offset += len;
+ buf += len;
+ }
+
+ return stored;
+}
+
+/* Update data related to vmlinux file. */
+static void update_vmlinux_data(void)
+{
+ struct gcov_ftree_node *node;
+ loff_t offset;
+
+ offset = 0;
+ for (node = leaf_nodes; node; node = node->next)
+ {
+ node->offset = offset;
+ node->da_size = sizeof_da_file(node->bb);
+ node->header_size = sizeof_vmlinux_header(node->bb);
+ offset += node->header_size + node->da_size;
+ }
+ proc_vmlinux->size = offset;
+ cached_node = NULL;
+}
+
+/* Read .da or vmlinux file. */
+static ssize_t
+read_gcov(struct file *file, char *buf, size_t count, loff_t * pos)
+{
+ struct gcov_ftree_node *node;
+ struct proc_dir_entry *dir_entry;
+ ssize_t rc;
+
+ mutex_lock(&read_mutex);
+ dir_entry = PDE(file->f_dentry->d_inode);
+ rc = 0;
+ if (dir_entry == proc_vmlinux)
+ {
+ /* Are we in a sequential read? */
+ if (cached_node && (*pos >= cached_node->offset))
+ node = cached_node;
+ else
+ node = leaf_nodes;
+ /* Find node corresponding to offset */
+ while (node && node->next && (*pos >= node->next->offset))
+ node = node->next;
+ cached_node = node;
+ if (node)
+ {
+ if (*pos - node->offset < node->header_size)
+ rc = store_vmlinux_header(node, buf, count,
+ *pos - node->offset);
+ else
+ {
+ rc = store_da_file(node, buf, count,
+ *pos - node->offset -
+ node->header_size);
+ }
+ }
+ }
+ else
+ {
+ node = (struct gcov_ftree_node *)dir_entry->data;
+ if (node)
+ {
+ rc = store_da_file(node, buf, count, *pos);
+ }
+ }
+ if (rc > 0)
+ *pos += rc;
+ mutex_unlock(&read_mutex);
+ return rc;
+}
+
+/* Reset counters on write request. */
+static ssize_t
+write_gcov(struct file *file, const char *buf, size_t count, loff_t * ppos)
+{
+ struct gcov_ftree_node *node;
+ struct proc_dir_entry *dir_entry;
+
+ mutex_lock(&write_mutex);
+ dir_entry = PDE(file->f_dentry->d_inode);
+ if (dir_entry == proc_vmlinux)
+ {
+ /* Reset all nodes */
+ node = leaf_nodes;
+ if (HYPERVISOR_gcovprof_op(GCOVPROF_reset, NULL, !RESET_GCDA))
+ {
+ printk(KERN_ERR GCOV_PROC_HEADER
+ "Failed to reset the vmlinux\n");
+ mutex_unlock(&write_mutex);
+ return EIO;
+ }
+ }
+ else
+ {
+ node = (struct gcov_ftree_node *)dir_entry->data;
+ if (HYPERVISOR_gcovprof_op
+ (GCOVPROF_reset, node->bb->filename, RESET_GCDA))
+ {
+ printk(KERN_ERR GCOV_PROC_HEADER
+ "Failed to reset file %s\n", node->bb->filename);
+ mutex_unlock(&write_mutex);
+ return EIO;
+ }
+ }
+ mutex_unlock(&write_mutex);
+ return count;
+}
+
+/* Return a newly allocated copy of STRING. */
+static char *strdup(const char *string)
+{
+ char *result;
+
+ result = (char *)kmalloc(strlen(string) + 1, GFP_KERNEL);
+ if (result)
+ strcpy(result, string);
+ return result;
+}
+
+/* Allocate a new node and fill in NAME and BB. */
+static struct gcov_ftree_node *alloc_node(const char *name,
+ struct gcov_info *bb)
+{
+ struct gcov_ftree_node *node;
+
+ node = (struct gcov_ftree_node *)
+ kmalloc(sizeof(struct gcov_ftree_node), GFP_KERNEL);
+ if (!node)
+ return NULL;
+ memset(node, 0, sizeof(struct gcov_ftree_node));
+ node->fname = strdup(name);
+ if (!node->fname)
+ {
+ kfree(node);
+ return NULL;
+ }
+ node->bb = bb;
+ return node;
+}
+
+/* Free memory allocated for NODE. */
+static void free_node(struct gcov_ftree_node *node)
+{
+ if (node == &tree_root)
+ return;
+ if (node->fname)
+ kfree(node->fname);
+ kfree(node);
+}
+
+/* Remove proc filesystem entries associated with NODE. */
+static void delete_from_proc(struct gcov_ftree_node *node)
+{
+ struct proc_dir_entry *parent;
+ int i;
+
+ if (node->parent)
+ parent = node->parent->proc[0];
+ else
+ parent = xen_base;
+ for (i = 0; i < sizeof(node->proc) / sizeof(node->proc[0]); i++)
+ if (node->proc[i])
+ remove_proc_entry(node->proc[i]->name, parent);
+}
+
+/*
+ * Release all resources associated with NODE. If NODE is a directory node,
+ * also clean up all children.
+ */
+static void cleanup_node(struct gcov_ftree_node *node)
+{
+ struct gcov_ftree_node *curr;
+ struct gcov_ftree_node *next;
+ struct gcov_ftree_node *prev;
+
+ next = node;
+ do
+ {
+ /* Depth first traversal of all children */
+ curr = next;
+ while (curr->files)
+ curr = curr->files;
+ if (curr->sibling)
+ next = curr->sibling;
+ else
+ next = curr->parent;
+ /* Remove from tree */
+ if (curr->parent)
+ {
+ if (curr->parent->files == curr)
+ curr->parent->files = curr->sibling;
+ else
+ {
+ for (prev = curr->parent->files;
+ prev->sibling != curr;
+ prev = prev->sibling) ;
+ prev->sibling = curr->sibling;
+ }
+ }
+ /* Remove from leaf node list if necessary */
+ if (curr->bb)
+ {
+ if (leaf_nodes == curr)
+ leaf_nodes = curr->next;
+ else
+ {
+ for (prev = leaf_nodes;
+ prev && (prev->next != curr);
+ prev = prev->next) ;
+ if (prev)
+ prev->next = curr->next;
+ }
+ }
+ /* Delete node */
+ delete_from_proc(curr);
+ free_node(curr);
+ } while (node != curr);
+}
+
+/* Clean up NODE and containing path in case it would be left empty. */
+static void cleanup_node_and_path(struct gcov_ftree_node *node)
+{
+ while (node->parent &&
+ node->parent != &tree_root && !node->parent->files->sibling)
+ node = node->parent;
+ cleanup_node(node);
+}
+
+/*
+ * Create a new directory node named NAME under PARENT. Upon success return
+ * zero and update RESULT to point to the newly created node. Return non-zero
+ * otherwise.
+ */
+static int
+create_dir_node(struct gcov_ftree_node *parent, char *name,
+ struct gcov_ftree_node **result)
+{
+ struct gcov_ftree_node *node;
+
+ /* Initialize new node */
+ node = alloc_node(name, NULL);
+ if (!node)
+ return -ENOMEM;
+ /* Create proc filesystem entry */
+ node->proc[0] = proc_mkdir(name, parent->proc[0]);
+ if (!node->proc[0])
+ {
+ free_node(node);
+ return -EIO;
+ }
+ /* Insert node into tree */
+ node->parent = parent;
+ node->sibling = parent->files;
+ parent->files = node;
+ *result = node;
+ return 0;
+}
+
+static struct file_operations proc_gcov_operations = {
+ .owner = THIS_MODULE,
+ .read = read_gcov,
+ .write = write_gcov,
+};
+
+/*
+ * Create a new file node named NAME under PARENT. Associate node with BB.
+ * Return zero upon success, non-zero otherwise.
+ */
+static int
+create_file_node(struct gcov_ftree_node *parent, char *name,
+ struct gcov_info *bb)
+{
+ struct gcov_ftree_node *node;
+ char *link_target;
+ char *link_name;
+ int i;
+ /* Initialize new node */
+ node = alloc_node(name, bb);
+ if (!node)
+ return -ENOMEM;
+ /* Create proc filesystem entry */
+ node->proc[0] = create_proc_entry(name, S_IWUSR | S_IRUGO,
+ parent->proc[0]);
+ if (!node->proc[0])
+ {
+ free_node(node);
+ return -EIO;
+ }
+ node->proc[0]->data = node;
+ node->proc[0]->proc_fops = &proc_gcov_operations;
+ node->proc[0]->size = sizeof_da_file(bb);
+ /* Create symbolic links */
+ if (xen_gcov_link)
+ {
+ /* Note: temp string length is calculated as upper limit */
+ link_target = (char *)kmalloc(strlen(bb->filename) +
+ strlen(da_ending) +
+ strlen(node_info->src_path),
+ GFP_KERNEL);
+ if (!link_target)
+ {
+ delete_from_proc(node);
+ free_node(node);
+ return -ENOMEM;
+ }
+ for (i = 0; i < sizeof(endings) / sizeof(endings[0]); i++)
+ {
+
+ strcpy(link_target, bb->filename);
+ link_target[strlen(link_target) -
+ strlen(da_ending)] = 0;
+ strcat(link_target, endings[i]);
+ link_name = strrchr(link_target, '/') + 1;
+ node->proc[i + 1] = proc_symlink(link_name,
+ parent->proc[0],
+ link_target);
+ if (!node->proc[i + 1])
+ {
+ kfree(link_target);
+ delete_from_proc(node);
+ free_node(node);
+ return -EIO;
+ }
+ }
+ kfree(link_target);
+ }
+ /* Insert node into tree */
+ node->parent = parent;
+ node->sibling = parent->files;
+ parent->files = node;
+ node->next = leaf_nodes;
+ leaf_nodes = node;
+ return 0;
+}
+
+/* Return proc filesystem entry name for FILENAME. */
+static inline char *get_proc_filename(const char *filename)
+{
+ char *result;
+
+ result = strdup(filename + sourcepath_len + 1);
+ return result;
+}
+
+/*
+ * Create tree node and proc filesystem entry for BB. Create subdirectories as
+ * necessary. Return zero upon success, non-zero otherwise.
+ */
+static int create_node(struct gcov_info *bb)
+{
+ struct gcov_ftree_node *parent;
+ struct gcov_ftree_node *node;
+ char *filename;
+ char *curr;
+ char *next;
+ int rc;
+
+ filename = get_proc_filename(bb->filename);
+ if (!filename)
+ return -ENOMEM;
+ /* Recreate directory path in proc filesystem */
+ parent = &tree_root;
+ for (curr = filename; (next = strchr(curr, '/')); curr = next + 1)
+ {
+ /* Skip empty path components */
+ if (curr == next)
+ continue;
+ *next = 0;
+ /* Check whether directory already exists */
+ for (node = parent->files;
+ node && (strcmp(node->fname, curr) != 0);
+ node = node->sibling) ;
+ if (!node)
+ {
+ /* Create directory node */
+ rc = create_dir_node(parent, curr, &node);
+ if (rc)
+ {
+ if (parent != &tree_root)
+ cleanup_node_and_path(parent);
+ kfree(filename);
+ return rc;
+ }
+ }
+ parent = node;
+ }
+ rc = create_file_node(parent, curr, bb);
+ kfree(filename);
+ return rc;
+}
+
+static void xeno_prof(void *data)
+{
+ /*update linked list with profiling info and line counts */
+ WARN_ON(HYPERVISOR_gcovprof_op(GCOVPROF_start, list_head, 0));
+
+ /*again schedule work */
+ schedule_delayed_work(&work, xen_gcov_update * HZ);
+
+}
+
+/*
+ * Invokes hypercall to get all the necessary gcov information to construct
+ * gcov linked list in Kernel
+ */
+static inline int get_list_info(void)
+{
+
+ int ret,i;
+ node_info = kmalloc(sizeof(struct node_info), GFP_KERNEL);
+ if ((ret =
+ HYPERVISOR_gcovprof_op(GCOVPROF_get_info, node_info, 0)) != 0)
+ return ret;
+
+ xen_gcov_version = node_info->g_version;
+
+ node_info->ctr_num =
+ kmalloc(node_info->n_files * sizeof(gcov_unsigned_t *), GFP_KERNEL);
+ for(i=0;i<node_info->n_files;i++){
+ node_info->ctr_num[i] =
+ kmalloc(GCOV_COUNTERS * sizeof(gcov_unsigned_t), GFP_KERNEL);
+ }
+
+ node_info->n_funcs =
+ kmalloc(node_info->n_files * sizeof(gcov_unsigned_t), GFP_KERNEL);
+
+ node_info->active_counters =
+ kmalloc(node_info->n_files * sizeof(unsigned int), GFP_KERNEL);
+
+ if ((ret =
+ HYPERVISOR_gcovprof_op(GCOVPROF_get_info, node_info, 1)) != 0)
+ return ret;
+
+ sourcepath_len = strlen(node_info->src_path);
+ return ret;
+}
+
+static int __init xen_gcov_init(void)
+{
+ struct gcov_info *bb;
+ int ret,rc = 0;
+
+ /* seek gcov core variable information & construct the gcov_info list */
+ ret = get_list_info();
+ if (ret) {
+ printk(KERN_ERR GCOV_PROC_HEADER
+ "No Core variable, Check if GCOV core is compiled in or not\n");
+ return -ENOENT;
+ }
+
+ /*add sys entry in /proc/sys/xen for count update tuning*/
+#ifdef CONFIG_SYSCTL
+ gcov_table_header = register_sysctl_table(gcov_root_table, 0);
+ if (!gcov_table_header)
+ printk(KERN_INFO GCOV_PROC_HEADER
+ "no /proc/sys/xen added\n");
+#endif
+ printk(KERN_INFO GCOV_PROC_HEADER "xen_gcov_link=%d xen_gcov_update=%d\n",
+ xen_gcov_link, xen_gcov_update);
+
+
+ /* Create gcov_info linked list */
+ create_bb_list();
+
+ /*populate the linked list with profiling info and line counts */
+ ret = HYPERVISOR_gcovprof_op(GCOVPROF_start, list_head, 0);
+ if (ret) {
+ printk(KERN_ERR GCOV_PROC_HEADER
+ "Failed to retrive hypervisor profiling info\n");
+ return ret;
+ }
+
+ /* Initializing root node and /proc/gcov entry */
+ tree_root.fname = GCOV_PROC_ROOT;
+ tree_root.proc[0] = proc_mkdir(tree_root.fname, xen_base);
+ if (!tree_root.proc[0]) {
+ printk(KERN_ERR GCOV_PROC_HEADER "init failed: could not "
+ "create root proc filesystem entry\n");
+ return -EIO;
+ }
+ /* Create /proc/gcov/vmlinux entry */
+ proc_vmlinux = create_proc_entry(GCOV_PROC_VMLINUX, S_IWUSR | S_IRUGO,
+ tree_root.proc[0]);
+ if (!proc_vmlinux)
+ {
+ printk(KERN_ERR GCOV_PROC_HEADER "init failed: could not "
+ "create proc filesystem entry %s\n", GCOV_PROC_VMLINUX);
+ cleanup_node(&tree_root);
+ return -EIO;
+ }
+ proc_vmlinux->proc_fops = &proc_gcov_operations;
+
+ /*populate /proc/xen/gcov entry with data files*/
+ for (bb = list_head; bb != NULL; bb = bb->next)
+ {
+ rc = create_node(bb);
+ if (rc)
+ {
+ printk(KERN_ERR GCOV_PROC_HEADER
+ "init failed: could not create node for %s (err=%d)\n",
+ bb->filename, rc);
+ remove_proc_entry(proc_vmlinux->name,
+ tree_root.proc[0]);
+ cleanup_node(&tree_root);
+ return rc;
+ }
+ } /*done*/
+
+ update_vmlinux_data();
+
+ /*schedule for profiling update after <xen_gcov_update> secs*/
+ schedule_delayed_work(&work, xen_gcov_update * HZ);
+ printk(KERN_INFO GCOV_PROC_HEADER "init done\n");
+ kfree(node_info);
+ return 0;
+}
+
+/* Clean up module data. */
+static void __exit xen_gcov_cleanup(void)
+{
+ cancel_delayed_work(&work);
+ flush_scheduled_work();
+#ifdef CONFIG_SYSCTL
+ unregister_sysctl_table(gcov_table_header);
+#endif
+ remove_proc_entry(proc_vmlinux->name, tree_root.proc[0]);
+ cleanup_node(&tree_root);
+ free_bb_list();
+ printk(KERN_INFO GCOV_PROC_HEADER "Module is now unloaded\n");
+}
+
+module_init(xen_gcov_init);
+module_exit(xen_gcov_cleanup);
diff -r 86d6c6417cf9 include/asm-i386/mach-xen/asm/hypercall.h
--- a/include/asm-i386/mach-xen/asm/hypercall.h Thu Feb 04 13:08:27 2010 +0000
+++ b/include/asm-i386/mach-xen/asm/hypercall.h Sun Feb 07 00:13:40 2010 +0530
@@ -411,5 +411,12 @@
return _hypercall1(int, tmem_op, op);
}
+static inline int __must_check
+HYPERVISOR_gcovprof_op(
+ int cmd, void *arg, int val)
+{
+ return _hypercall3(int, gcovprof_op, cmd, arg, val);
+}
+
#endif /* __HYPERCALL_H__ */
diff -r 86d6c6417cf9 include/asm-x86_64/mach-xen/asm/hypercall.h
--- a/include/asm-x86_64/mach-xen/asm/hypercall.h Thu Feb 04 13:08:27 2010 +0000
+++ b/include/asm-x86_64/mach-xen/asm/hypercall.h Sun Feb 07 00:13:40 2010 +0530
@@ -419,4 +419,12 @@
return _hypercall1(int, tmem_op, op);
}
+static inline int __must_check
+HYPERVISOR_gcovprof_op(
+ int cmd, void *arg, int val)
+{
+ return _hypercall3(int, gcovprof_op, cmd, arg, val);
+}
+
+
#endif /* __HYPERCALL_H__ */
diff -r 86d6c6417cf9 include/xen/interface/xen-gcov.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/include/xen/interface/xen-gcov.h Sun Feb 07 00:13:40 2010 +0530
@@ -0,0 +1,126 @@
+/******************************************************************************
+ * xen-gcov.h
+ *
+ * Interface for populating hypervisor profiling info under /proc/xen
+ *
+ * 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 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.
+ *
+ * Author: tej parkash <tej.parkash@hcl.in>
+ * Written by tej parkash and team
+ *
+ */
+/******************************************************************************/
+
+#ifndef __XEN_PUBLIC_GCOVPROF_H__
+#define __XEN_PUBLIC_GCOVPROF_H__
+
+#include "xen.h"
+
+/*
+ * Commands to HYPERVISOR_gcovprof_op()
+ */
+#define GCOVPROF_get_info 0
+#define GCOVPROF_start 1
+#define GCOVPROF_reset 2
+#define GCOVPROF_last_op 3
+
+
+/*gcc specific macros*/
+#define GCOV_COUNTERS 5
+#define GCOV_DATA_MAGIC ((gcov_unsigned_t) 0x67636461)
+#define GCOV_TAG_FUNCTION ((gcov_unsigned_t) 0x01000000)
+#define GCOV_TAG_COUNTER_BASE ((gcov_unsigned_t) 0x01a10000)
+#define GCOV_TAG_FOR_COUNTER(COUNT) \
+ (GCOV_TAG_COUNTER_BASE + ((gcov_unsigned_t) (COUNT) << 17))
+
+/*xen-gcov-proc specific macros*/
+#define RESET_GCDA 0
+
+#define FILE_SIZE 100
+
+typedef unsigned gcov_unsigned_t __attribute__ ((mode (SI)));
+typedef signed gcov_type __attribute__ ((mode (DI)));
+typedef void (*gcov_merge_fn) (gcov_type *, gcov_unsigned_t);
+
+
+struct gcov_ftree_node
+{
+ char *fname; /* Hierarchy-relative name */
+ struct gcov_ftree_node *sibling; /* First sibling of this node */
+ struct gcov_ftree_node *files; /* First child of this node */
+ struct gcov_ftree_node *parent; /* Parent of this node */
+ struct proc_dir_entry *proc[4]; /* Entries for .da, .bb, .bbg, .c */
+ struct gcov_info *bb; /* Associated struct bb */
+ loff_t offset; /* Offset in vmlinux file */
+ size_t da_size; /* Size of associated .da file */
+ size_t header_size; /* Size of associated file header */
+ struct gcov_ftree_node *next; /* Next leaf node */
+};
+
+
+struct gcov_fn_info
+{
+ gcov_unsigned_t ident; /* unique ident of function */
+ gcov_unsigned_t checksum; /* function checksum */
+ unsigned int n_ctrs[0]; /* instrumented counters */
+};
+typedef struct gcov_fn_info gcov_fn_info_t;
+DEFINE_XEN_GUEST_HANDLE(gcov_fn_info_t);
+
+struct gcov_ctr_info
+{
+ gcov_unsigned_t num; /* number of counters. */
+ gcov_type *values; /* thier values. */
+ gcov_merge_fn merge; /* merge function */
+};
+typedef struct gcov_ctr_info gcov_ctr_info_t;
+DEFINE_XEN_GUEST_HANDLE(gcov_ctr_info_t);
+
+/* Information about a single object file. */
+struct gcov_info
+{
+ gcov_unsigned_t version; /* expected version number */
+ struct gcov_info *next; /* link to next, used by libgcov */
+
+ gcov_unsigned_t stamp; /* uniquifying time stamp */
+ char *filename;
+
+ unsigned int n_functions; /* number of functions */
+ struct gcov_fn_info *functions; /* table of functions */
+
+ unsigned int ctr_mask; /* mask of counters instrumented. */
+ struct gcov_ctr_info counts[0]; /* count data */
+};
+typedef struct gcov_info gcov_info_t;
+DEFINE_XEN_GUEST_HANDLE(gcov_info_t);
+
+struct node_info
+{
+ char src_path[100]; /* source path */
+ unsigned long g_version; /* gcov version */
+ unsigned int n_files; /* num of file in hypervisor code */
+ gcov_unsigned_t **ctr_num; /* count variables */
+ unsigned int *n_funcs; /* num of funcs per bb struct */
+ unsigned int *active_counters; /* No of gcov counters */
+
+};
+typedef struct node_info node_info_t;
+DEFINE_XEN_GUEST_HANDLE(node_info_t);
+
+#endif /* __XEN_PUBLIC_GCOVPROF_H__ */
diff -r 86d6c6417cf9 include/xen/interface/xen.h
--- a/include/xen/interface/xen.h Thu Feb 04 13:08:27 2010 +0000
+++ b/include/xen/interface/xen.h Sun Feb 07 00:13:40 2010 +0530
@@ -93,6 +93,7 @@
#define __HYPERVISOR_domctl 36
#define __HYPERVISOR_kexec_op 37
#define __HYPERVISOR_tmem_op 38
+#define __HYPERVISOR_gcovprof_op 39
/* Architecture-specific hypercall definitions. */
#define __HYPERVISOR_arch_0 48
diff -r 86d6c6417cf9 include/xen/xen_proc.h
--- a/include/xen/xen_proc.h Thu Feb 04 13:08:27 2010 +0000
+++ b/include/xen/xen_proc.h Sun Feb 07 00:13:40 2010 +0530
@@ -4,6 +4,7 @@
#include <linux/proc_fs.h>
+extern struct proc_dir_entry *xen_base;
extern struct proc_dir_entry *create_xen_proc_entry(
const char *name, mode_t mode);
extern void remove_xen_proc_entry(
[-- Attachment #3: linux-wa-v1.patch --]
[-- Type: text/x-patch, Size: 497 bytes --]
diff -r b0a497fd3322 drivers/xen/gcov/xen-gcov-proc.c
--- a/drivers/xen/gcov/xen-gcov-proc.c Thu May 06 06:55:42 2010 +0530
+++ b/drivers/xen/gcov/xen-gcov-proc.c Thu May 06 06:57:08 2010 +0530
@@ -1193,7 +1193,7 @@
proc_vmlinux->proc_fops = &proc_gcov_operations;
/*populate /proc/xen/gcov entry with data files*/
- for (bb = list_head; bb != NULL; bb = bb->next)
+ for (bb = list_head->next; bb != NULL; bb = bb->next)
{
rc = create_node(bb);
if (rc)
[-- Attachment #4: xen-unstable-gcov-v1.patch --]
[-- Type: text/x-patch, Size: 21400 bytes --]
diff -r efa1b905d893 xen/Rules.mk
--- a/xen/Rules.mk Tue May 04 13:59:55 2010 +0100
+++ b/xen/Rules.mk Thu May 06 06:53:09 2010 +0530
@@ -10,6 +10,14 @@
crash_debug ?= n
gdbsx ?= n
frame_pointer ?= n
+# gcov profiler build for xen hypervisor only
+gcov ?= n
+
+# xen source path to get update in .gcno files
+ifeq ($(gcov),y)
+xen_src := $(CURDIR)
+xentree := $(if $(xen_src),$(xen_src),$(CURDIR))
+endif
XEN_ROOT=$(BASEDIR)/..
include $(XEN_ROOT)/Config.mk
@@ -43,6 +51,7 @@
ALL_OBJS-$(x86) += $(BASEDIR)/crypto/built_in.o
CFLAGS-y += -g -D__XEN__
+CFLAGS-$(gcov) += -fprofile-arcs -ftest-coverage -DCONFIG_XEN_GCOV
CFLAGS-$(XSM_ENABLE) += -DXSM_ENABLE
CFLAGS-$(FLASK_ENABLE) += -DFLASK_ENABLE -DXSM_MAGIC=0xf97cff8c
CFLAGS-$(FLASK_ENABLE) += -DFLASK_DEVELOP -DFLASK_BOOTPARAM -DFLASK_AVC_STATS
@@ -107,12 +116,17 @@
.PHONY: clean
clean:: $(addprefix _clean_, $(subdir-all))
- rm -f *.o *~ core $(DEPS)
+ rm -f *.o *.gcno *~ core $(DEPS)
_clean_%/: FORCE
$(MAKE) -f $(BASEDIR)/Rules.mk -C $* clean
%.o: %.c Makefile
+ifeq ($(gcov),y)
+ $(CC) $(CFLAGS) -c -o $@ \
+ $(if $(filter-out /%,$<),$(xentree)/$<,$<)
+else
$(CC) $(CFLAGS) -c $< -o $@
+endif
%.o: %.S Makefile
$(CC) $(AFLAGS) -c $< -o $@
diff -r efa1b905d893 xen/arch/x86/mm/Makefile
--- a/xen/arch/x86/mm/Makefile Tue May 04 13:59:55 2010 +0100
+++ b/xen/arch/x86/mm/Makefile Thu May 06 06:53:09 2010 +0530
@@ -10,5 +10,18 @@
obj-y += mem_paging.o
obj-y += mem_sharing.o
+LN = /bin/ln
+num=$*.c
+
guest_walk_%.o: guest_walk.c Makefile
+ifeq ($(gcov),y)
+ $(CC) $(CFLAGS) -DGUEST_PAGING_LEVELS=$* -c -o $@ \
+ $(if $(filter-out /%,$<),$(xentree)/$<,$<)
+ $(LN) -f -s guest_walk.c guest_walk_$(num)
+else
$(CC) $(CFLAGS) -DGUEST_PAGING_LEVELS=$* -c $< -o $@
+endif
+
+.PHONY: clean
+clean::
+ rm -f guest_walk_*.c
diff -r efa1b905d893 xen/arch/x86/mm/hap/Makefile
--- a/xen/arch/x86/mm/hap/Makefile Tue May 04 13:59:55 2010 +0100
+++ b/xen/arch/x86/mm/hap/Makefile Thu May 06 06:53:09 2010 +0530
@@ -4,8 +4,22 @@
obj-y += guest_walk_4level.o
obj-y += p2m-ept.o
+LN = /bin/ln
+
guest_levels = $(subst level,,$(filter %level,$(subst ., ,$(subst _, ,$(1)))))
guest_walk_defns = -DGUEST_PAGING_LEVELS=$(call guest_levels,$(1))
+num = $(call guest_levels,$(@F))level.c
+
guest_walk_%level.o: guest_walk.c Makefile
+ifeq ($(gcov),y)
+ $(CC) $(CFLAGS) $(call guest_walk_defns,$(@F)) -c -o $@ \
+ $(if $(filter-out /%,$<),$(xentree)/$<,$<)
+ $(LN) -f -s guest_walk.c guest_walk_$(num)
+else
$(CC) $(CFLAGS) $(call guest_walk_defns,$(@F)) -c $< -o $@
+endif
+
+.PHONY: clean
+clean::
+ rm -f guest_walk_*.c
diff -r efa1b905d893 xen/arch/x86/mm/shadow/Makefile
--- a/xen/arch/x86/mm/shadow/Makefile Tue May 04 13:59:55 2010 +0100
+++ b/xen/arch/x86/mm/shadow/Makefile Thu May 06 06:53:09 2010 +0530
@@ -1,5 +1,18 @@
obj-$(x86_32) += common.o guest_2.o guest_3.o
obj-$(x86_64) += common.o guest_2.o guest_3.o guest_4.o
+LN = /bin/ln
+num=$*.c
+
guest_%.o: multi.c Makefile
+ifeq ($(gcov),y)
+ $(CC) $(CFLAGS) -DGUEST_PAGING_LEVELS=$* -c -o $@ \
+ $(if $(filter-out /%,$<),$(xentree)/$<,$<)
+ $(LN) -f -s multi.c guest_$(num)
+else
$(CC) $(CFLAGS) -DGUEST_PAGING_LEVELS=$* -c $< -o $@
+endif
+
+.PHONY: clean
+clean::
+ rm -f guest_*.c
diff -r efa1b905d893 xen/arch/x86/x86_32/entry.S
--- a/xen/arch/x86/x86_32/entry.S Tue May 04 13:59:55 2010 +0100
+++ b/xen/arch/x86/x86_32/entry.S Thu May 06 06:53:09 2010 +0530
@@ -706,6 +706,9 @@
.long do_domctl
.long do_kexec_op
.long do_tmem_op
+#ifdef CONFIG_XEN_GCOV
+ .long do_gcovprof_op
+#endif
.rept __HYPERVISOR_arch_0-((.-hypercall_table)/4)
.long do_ni_hypercall
.endr
@@ -754,6 +757,9 @@
.byte 1 /* do_domctl */
.byte 2 /* do_kexec_op */
.byte 1 /* do_tmem_op */
+#ifdef CONFIG_XEN_GCOV
+ .byte 3 /* do_gcovprof_op */
+#endif
.rept __HYPERVISOR_arch_0-(.-hypercall_args_table)
.byte 0 /* do_ni_hypercall */
.endr
diff -r efa1b905d893 xen/arch/x86/x86_64/entry.S
--- a/xen/arch/x86/x86_64/entry.S Tue May 04 13:59:55 2010 +0100
+++ b/xen/arch/x86/x86_64/entry.S Thu May 06 06:53:09 2010 +0530
@@ -695,6 +695,9 @@
.quad do_domctl
.quad do_kexec_op
.quad do_tmem_op
+#ifdef CONFIG_XEN_GCOV
+ .quad do_gcovprof_op
+#endif
.rept __HYPERVISOR_arch_0-((.-hypercall_table)/8)
.quad do_ni_hypercall
.endr
@@ -743,6 +746,9 @@
.byte 1 /* do_domctl */
.byte 2 /* do_kexec */
.byte 1 /* do_tmem_op */
+#ifdef CONFIG_XEN_GCOV
+ .byte 3 /* do_gcovprof_op */
+#endif
.rept __HYPERVISOR_arch_0-(.-hypercall_args_table)
.byte 0 /* do_ni_hypercall */
.endr
diff -r efa1b905d893 xen/common/Makefile
--- a/xen/common/Makefile Tue May 04 13:59:55 2010 +0100
+++ b/xen/common/Makefile Thu May 06 06:53:09 2010 +0530
@@ -40,6 +40,7 @@
obj-$(CONFIG_X86) += decompress.o bunzip2.o unlzma.o
+obj-$(gcov) += xen-gcov-core.o
obj-$(perfc) += perfc.o
obj-$(crash_debug) += gdbstub.o
obj-$(xenoprof) += xenoprof.o
@@ -53,3 +54,6 @@
subdir-$(ia64) += hvm
subdir-y += libelf
+
+CFLAGS += -DSRC_PATH='"$(BASEDIR)"'
+
diff -r efa1b905d893 xen/common/xen-gcov-core.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/common/xen-gcov-core.c Thu May 06 06:53:09 2010 +0530
@@ -0,0 +1,389 @@
+/**
+ * xen-gcov-core.c: arch dependent code for hypervisor profiling
+ *
+ * Written by tej parkash and team(tej.parkash@hcl.in)
+ *
+ */
+/***************************************************************************/
+#include <xen/init.h>
+#include <xen/kernel.h>
+#include <xen/guest_access.h>
+#include <xen/sched.h>
+#include <xen/event.h>
+#include <xen/string.h>
+#include <public/xen-gcov.h>
+#include <xen/paging.h>
+#include <xsm/xsm.h>
+#include <xen/config.h>
+#include <xen/lib.h>
+
+
+#define XEN_GCOV_CORE "xen-gcov-core:"
+#define FILE_SIZE 100
+
+/* No of XEN source files to profile */
+static int num_xen_files;
+
+gcov_unsigned_t gcov_version = 0;
+
+/* List head for gcov_info structure list */
+struct gcov_info *bb_head;
+
+/* head of xen-gcov-info linked list */
+struct gcov_info *bb_list_head = NULL;
+
+
+/* global constructor list */
+struct ctor_list
+{
+ unsigned long num;
+ ctor_t ctor[];
+};
+
+/* Start of global constructor list. */
+extern struct ctor_list __CTOR_LIST__;
+
+/*
+ * Determine whether counter TYPE is active in list node
+ * For gcc 3.4 to 4.3 only counter 0 will be active
+ *
+ */
+static inline int
+counter_active(struct gcov_info *bb, unsigned int type)
+{
+ return (1 << type) & bb->ctr_mask;
+}
+
+/* Return the number of active counter types for BB. */
+static inline unsigned int
+num_counter_active(struct gcov_info *bb)
+{
+ unsigned int i;
+ unsigned int result;
+
+ result = 0;
+ for (i=0; i < GCOV_COUNTERS; i++)
+ if (counter_active(bb, i))
+ result++;
+ return result;
+}
+
+/*
+ * Get number of bytes used for one entry in the gcov_fn_info array pointed to
+ * by BB->functions.
+ */
+static inline unsigned int
+get_fn_stride(struct gcov_info *bb)
+{
+ unsigned int stride;
+
+ stride = sizeof(struct gcov_fn_info) + num_counter_active(bb)*
+ sizeof(unsigned int);
+ if (__alignof__(struct gcov_fn_info) > sizeof(unsigned int))
+ {
+ stride += __alignof__(struct gcov_fn_info) - 1;
+ stride &= ~(__alignof__(struct gcov_fn_info) - 1);
+ }
+ return stride;
+}
+
+/* Get the address of gcov_fn_info for function FUNC of BB. */
+static inline struct gcov_fn_info *
+get_fn_info(struct gcov_info *bb, unsigned int func)
+{
+ return (struct gcov_fn_info *)
+ ((char *)bb->functions + func * get_fn_stride(bb));
+}
+
+/* Reset the execution count values on each list node */
+static void reset(struct gcov_info *bb)
+{
+
+ unsigned int i;
+ struct gcov_ctr_info *ctr;
+ ctr = bb->counts;
+ for (i=0; i < GCOV_COUNTERS; i++)
+ {
+ if (counter_active(bb, i))
+ {
+ memset(ctr->values, 0, ctr->num * sizeof(gcov_type));
+ ctr++;
+ }
+ }
+}
+
+
+/*
+ * Create xen_gcov_info linked list by accessing kernel nodes
+ * based on num of xen file to be profiled, This list act
+ * as temporary variable between Xen bb_head and kernel list_head
+ */
+
+static inline int create_bb_list(void)
+{
+ struct gcov_info *node = NULL, *tmp_node = NULL, *bb = bb_head;
+ int i, j, len=0, active, len1=0;
+
+ for (i = 0; i < num_xen_files; i++)
+ {
+ /* Allocate memory for struct gcov_info */
+ active = num_counter_active(bb);
+ len = sizeof(struct gcov_info) + sizeof(struct gcov_ctr_info)*active;
+ node = (struct gcov_info *) xmalloc_bytes(len);
+ for (j=0; j < active; j++)
+ {
+ len1 = sizeof(gcov_type) *bb->counts[j].num;
+ node->counts[j].values = xmalloc_bytes(len1);
+ memset(node->counts[j].values, 0, len1);
+ }
+
+ /* Allocate memory for array of struct gcov_fn_info */
+ len = (sizeof(struct gcov_fn_info) + active*sizeof(unsigned int)) *
+ bb->n_functions;
+ node->functions = (struct gcov_fn_info *) xmalloc_bytes(len);
+ node->filename = (char *) xmalloc_bytes(FILE_SIZE*sizeof(char));
+ node->next = NULL;
+
+ if (bb_list_head == NULL)
+ {
+ bb_list_head = node;
+ tmp_node = node;
+ }
+ else
+ {
+ tmp_node->next = node;
+ tmp_node = node;
+ }
+ bb = bb->next;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Func to reset the execution counts. Reset all nodes count
+ * if mul defined else reset single file count specified in arg.
+ */
+
+static int reset_counts(XEN_GUEST_HANDLE(void) arg, int mul)
+{
+ struct gcov_info *tmp=bb_head;
+ char bb_file[100];
+
+ if (!mul)
+ {
+ /* reset single data file */
+ if ( copy_from_guest(&bb_file, arg, 1) )
+ return -EFAULT;
+ for(;tmp!=NULL;tmp=tmp->next)
+ {
+ if(!strcmp(tmp->filename, bb_file))
+ {
+ reset(tmp);
+ break;
+ }
+ else
+ continue;
+ }
+ }
+ else
+ {
+ /* reset all data files */
+ for(;tmp!=NULL;tmp=tmp->next)
+ reset(tmp);
+ }
+ return 0;
+}
+
+/*
+ * Func copies metadata in each gcov_info list nodes to guest.
+ * with this metadeta, guest populates and update the /proc
+ * with gcov data files (*.gcda)
+ */
+
+static int ret_profiled_data(XEN_GUEST_HANDLE(void) arg, int val)
+{
+ struct gcov_info *bb, *tmp = bb_head;
+ struct gcov_fn_info *func,*fn_ptr;
+ int i, j, active,len;
+
+ bb = bb_list_head;
+ if (copy_from_guest(bb_list_head, arg, 1))
+ return -EFAULT;
+
+ /* iterate through list nodes to copy metadata in Guest nodes*/
+ for(;tmp!=NULL, bb!=NULL; tmp = tmp->next)
+ {
+
+ bb->version = tmp->version;
+ bb->stamp = tmp->stamp;
+ len=strlen(tmp->filename)+1;
+ memcpy(bb->filename, tmp->filename,sizeof(char)*len);
+ bb->ctr_mask = tmp->ctr_mask;
+ bb->n_functions = tmp->n_functions;
+
+
+ active= num_counter_active(tmp);
+ /* Copy functions data */
+ for(i=0;i<tmp->n_functions;i++)
+ {
+ fn_ptr= get_fn_info(bb,i);
+ func = get_fn_info(tmp,i);
+ fn_ptr->ident=func->ident;
+ fn_ptr->checksum=func->checksum;
+ for (j=0;j< active;j++)
+ fn_ptr->n_ctrs[j]=func->n_ctrs[j];
+ }
+
+ /* Copy count data */
+ for (i=0; i < active; i++) {
+ bb->counts[i].num = tmp->counts[i].num;
+ bb->counts[i].merge = tmp->counts[i].merge;
+ len = sizeof(gcov_type)*tmp->counts[i].num;
+ memcpy(bb->counts[i].values, tmp->counts[i].values, len);
+ }
+ /*increment the bb_head pointers*/
+ bb=bb->next;
+ }
+
+ if ( copy_to_guest(arg, bb_list_head, 1) )
+ return -EFAULT;
+
+ return 0;
+}
+
+/*
+ * Func to retrieve the inital gcov core information
+ * by Kernel
+ * e.g source path, no. of files etc.
+ */
+
+static int info_to_guest(XEN_GUEST_HANDLE(void) arg,int num)
+{
+
+ struct gcov_info *bb = bb_head;
+ node_info_t *tmp = xmalloc(struct node_info);
+ int i, j, active;
+
+ if( copy_from_guest(tmp, arg, 1) )
+ return -EFAULT;
+ if ( num == 0 )
+ {
+ safe_strcpy(tmp->src_path,SRC_PATH);
+ tmp->g_version=gcov_version;
+ tmp->n_files=num_xen_files;
+
+ /* Create the bb_list_head */
+ create_bb_list();
+ }
+ else
+ {
+ for(i=0;i<num_xen_files;i++)
+ {
+ tmp->n_funcs[i]=bb->n_functions;
+ active=num_counter_active(bb);
+ tmp->active_counters[i]= active;
+ for(j=0; j<GCOV_COUNTERS; j++) {
+ tmp->ctr_num[i][j]= bb->counts[j].num;
+ }
+
+ bb=bb->next;
+ }
+ }
+
+ if( copy_to_guest(arg, tmp, 1) )
+ return -EFAULT;
+
+
+ return 0;
+}
+
+/*internal hyercall functions*/
+int do_gcovprof_op(int op, XEN_GUEST_HANDLE(void) arg, int val)
+{
+ int ret = 0;
+ if ((op < 0) || (op > GCOVPROF_last_op))
+ {
+ printk(KERN_ERR XEN_GCOV_CORE "Invalid operation %d\n", op);
+ return -EINVAL;
+ }
+ switch (op)
+ {
+ case GCOVPROF_get_info:
+ ret = info_to_guest(arg, val);
+ break;
+
+ case GCOVPROF_start:
+ ret = ret_profiled_data(arg,val);
+ break;
+
+ case GCOVPROF_reset:
+ ret = reset_counts(arg,val);
+ break;
+
+ default:
+ ret = -ENOSYS;
+ }
+ return ret;
+}
+
+/*
+ * Call constructors and create gcov_info linked list
+ * List contains metadeta to construct gcov data files
+ * e.g data file name, execution counts etc.
+ */
+void do_global_ctors(ctor_t ctor[], unsigned long num)
+{
+ unsigned long i;
+
+ /* Call constructors and create gcov_info linked list*/
+ for (i = 0; i < num && ctor[i]; i++)
+ ctor[i] ();
+ /* Holds number of executable scanned by constructor */
+ num_xen_files = i-1;
+}
+
+
+/*Register supplied struct BB. Called by each object code constructor. */
+void __gcov_init(struct gcov_info *bb)
+{
+ if (!bb->version)
+ return;
+ /*Check for compatible gcc version */
+ if (gcov_version == 0)
+ gcov_version = bb->version;
+ else if (bb->version != gcov_version)
+ {
+ printk(KERN_WARNING XEN_GCOV_CORE "gcc version mismatch in "
+ "file '%s'!\n", bb->filename);
+ return;
+ }
+ /*Set up linked list */
+ bb->version = 0;
+ bb->next = bb_head;
+ bb_head = bb;
+
+}
+
+static int __init gcov_init(void)
+{
+ do_global_ctors(__CTOR_LIST__.ctor, __CTOR_LIST__.num);
+ printk(KERN_INFO XEN_GCOV_CORE "init done\n");
+ return 0;
+}
+
+__initcall(gcov_init);
+
+/* Unused functions needed to prevent linker errors. */
+void __gcov_flush(void) {}
+void __gcov_merge_add(gcov_type * counters, unsigned int n_counters){}
+void __gcov_merge_single(gcov_type * counters, unsigned int n_counters){}
+void __gcov_merge_delta(gcov_type * counters, unsigned int n_counters){}
+
+EXPORT_SYMBOL(__gcov_init);
+EXPORT_SYMBOL(do_global_ctors);
+EXPORT_SYMBOL(__gcov_flush);
+EXPORT_SYMBOL(__gcov_merge_add);
+EXPORT_SYMBOL(__gcov_merge_single);
+EXPORT_SYMBOL(__gcov_merge_delta);
diff -r efa1b905d893 xen/include/public/xen-gcov.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/public/xen-gcov.h Thu May 06 06:53:09 2010 +0530
@@ -0,0 +1,109 @@
+/******************************************************************************
+ * xen-gcov.h
+ *
+ * Interface for enabling and populating hypervisor profiling info.
+ *
+ * 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 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.
+ *
+ * Author: tej parkash <tej.parkash@hcl.in>
+ * Written by tej parkash and team
+ *
+ */
+/******************************************************************************/
+
+#ifndef __XEN_PUBLIC_GCOVPROF_H__
+#define __XEN_PUBLIC_GCOVPROF_H__
+
+#include "xen.h"
+
+/*
+ * Commands to HYPERVISOR_gcovprof_op()
+ */
+#define GCOVPROF_get_info 0
+#define GCOVPROF_start 1
+#define GCOVPROF_reset 2
+#define GCOVPROF_last_op 3
+
+/*gcc specific macros*/
+#define GCOV_COUNTERS 5
+#define GCOV_DATA_MAGIC ((gcov_unsigned_t) 0x67636461)
+#define GCOV_TAG_FUNCTION ((gcov_unsigned_t) 0x01000000)
+#define GCOV_TAG_COUNTER_BASE ((gcov_unsigned_t) 0x01a10000)
+#define GCOV_TAG_FOR_COUNTER(COUNT) \
+ (GCOV_TAG_COUNTER_BASE + ((gcov_unsigned_t) (COUNT) << 17))
+
+
+typedef unsigned gcov_unsigned_t __attribute__ ((mode (SI)));
+typedef signed gcov_type __attribute__ ((mode (DI)));
+typedef void (*gcov_merge_fn) (gcov_type *, gcov_unsigned_t);
+typedef void (*ctor_t)(void);
+
+struct gcov_fn_info
+{
+ gcov_unsigned_t ident; /* unique ident of function */
+ gcov_unsigned_t checksum; /* function checksum */
+ unsigned n_ctrs[0]; /* instrumented counters */
+};
+typedef struct gcov_fn_info gcov_fn_info_t;
+DEFINE_XEN_GUEST_HANDLE(gcov_fn_info_t);
+
+struct gcov_ctr_info
+{
+ gcov_unsigned_t num; /* number of counters. */
+ gcov_type *values; /* their values. */
+ gcov_merge_fn merge; /* The function used to merge them. */
+};
+typedef struct gcov_ctr_info gcov_ctr_info_t;
+DEFINE_XEN_GUEST_HANDLE(gcov_ctr_info_t);
+
+/* Information about a single object file. */
+struct gcov_info
+{
+ gcov_unsigned_t version; /* expected version number */
+ struct gcov_info *next; /* link to next, used by libgcov */
+
+ gcov_unsigned_t stamp; /* uniquifying time stamp */
+ char *filename;
+
+ unsigned n_functions; /* number of functions */
+ struct gcov_fn_info *functions; /* table of functions */
+
+ unsigned ctr_mask; /* mask of counters instrumented. */
+ struct gcov_ctr_info counts[0]; /* count data. The number of bits
+ set in the ctr_mask field
+ determines how big this array
+ is. */
+};
+typedef struct gcov_info gcov_info_t;
+DEFINE_XEN_GUEST_HANDLE(gcov_info_t);
+
+/* info to construct guest Nodes */
+struct node_info
+{
+ char src_path[100]; /* xen source code path */
+ unsigned long g_version;
+ unsigned int n_files; /* max. nodes */
+ gcov_unsigned_t **ctr_num; /* count per node */
+ unsigned int *n_funcs; /* funcs per node */
+ unsigned int *active_counters; /* No of active gcov counters per BB */
+};
+typedef struct node_info node_info_t;
+DEFINE_XEN_GUEST_HANDLE(node_info_t);
+
+#endif /* __XEN_PUBLIC_GCOVPROF_H__ */
diff -r efa1b905d893 xen/include/xen/config.h
--- a/xen/include/xen/config.h Tue May 04 13:59:55 2010 +0100
+++ b/xen/include/xen/config.h Thu May 06 06:53:09 2010 +0530
@@ -95,4 +95,23 @@
#define __cpuinitdata
#define __cpuinit
+#ifdef CONFIG_XEN_GCOV
+#define SORT(x) x
+#define CONSTRUCTORS \
+ __CTOR_LIST__ = .; \
+ LONG((__CTOR_END__ - __CTOR_LIST__) / \
+ (__CTOR_LIST2__ - __CTOR_LIST__) - 2) \
+ __CTOR_LIST2__ = .; \
+ *(SORT(.ctors)) \
+ LONG(0) \
+ __CTOR_END__ = .; \
+ __DTOR_LIST__ = .; \
+ LONG((__DTOR_END__ - __DTOR_LIST__) / \
+ (__CTOR_LIST2__ - __CTOR_LIST__) - 2) \
+ *(SORT(.dtors)) \
+ LONG(0) \
+ __DTOR_END__ = .;
+
+#endif /* CONFIG_XEN_GCOV */
+
#endif /* __XEN_CONFIG_H__ */
[-- Attachment #5: README --]
[-- Type: application/octet-stream, Size: 3390 bytes --]
---------------------------------------------------------------
- README file for the GCOV extention (LCOV)
- Includes access of Kernel/HYPERVISOR/Userspace Program
---------------------------------------------------------------
Description
-----------
LCOV is an extension of GCOV, a GNU tool which provides information about
what parts of a program are actually executed (i.e. "covered") while running
a particular test case. The functionality is HTML based output. Where coverage
rates are additionaly indicated using bar graphs and specific colors.
Contents
---------
1. About lcov config file (/etc/lcovrc)
2. An example of how to access kernel coverage data
3. An example of how to access HYPERVISOR coverage data
4. An example of how to access coverage data for a user space program
1. About lcov config file (/etc/lcovrc)
----------------------------------------
The LCOV package is available as either RPM or tarball from:
http://ltp.sourceforge.net/coverage/lcov.php
LCOV has been modified to support both kernel and xen hypervisor by editing lcov config file.
LCOV config file will be located in /etc/lcovrc, there is variable called lcov_gcov_dir which
has the directory path containing gcov kernel files.
* Kernel directory path lcov_gcov_dir = /proc/gcov
* Xen hypervisor directory path lcov_gcov_dir = /proc/xen/gcov
By defualt config file has kernel directory path (i.e /proc/gcov). User has to specify either
kernel path or xen hypervisor path.
2. An example of how to access kernel coverage data
----------------------------------------------------
Requirements: get and install gcov-kernel package
User has to make sure that lcov_gcov_dir should hold the directory path "/proc/gcov" in LCOV
config file (i.e /etc/lcovrc).
a) Capturing the current coverage state to a file
lcov --capture --output-file kernel.info
b) Resetting counters
lcov --zerocounters
c) Getting HTML output
genhtml kernel.info
Point the web browser of your choice to the resulting index.html file.
3. An example of how to access HYPERVISOR coverage data
----------------------------------------------------
Requirements: get and install GCOV-HYPERVISOR package
User has to make sure that lcov_gcov_dir should hold the directory path "/proc/xen/gcov" in LCOV
config file (i.e /etc/lcovrc).
a) Capturing the current coverage state to a file
lcov --capture --output-file kernel.info
b) Resetting counters
lcov --zerocounters
c) Getting HTML output
genhtml kernel.info
Point the web browser of your choice to the resulting index.html file.
4. An example of how to access coverage data for a user space program
---------------------------------------------------------------------
Requirements: compile the program in question using GCC with the options
-fprofile-arcs and -ftest-coverage. Assuming the compile directory is called
"appdir", do the following:
a) Resetting counters
lcov --directory appdir --zerocounters
b) Capturing the current coverage state to a file (works only after the
application has been started and stopped at least once)
lcov --directory appdir --capture --output-file app.info
c) Getting HTML output
genhtml app.info
Point the web browser of your choice to the resulting index.html file.
[-- Attachment #6: lcov-screenshot --]
[-- Type: application/octet-stream, Size: 126300 bytes --]
[-- Attachment #7: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
next reply other threads:[~2010-05-07 20:01 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-05-07 20:01 Tej [this message]
2010-05-10 14:53 ` [Xen-devel] Xen GCOV Patches for latest Xen Unbstable and linux 2.6.18.8 kernel(32/64bit) Konrad Rzeszutek Wilk
2010-05-10 17:21 ` Tej
2010-05-10 17:26 ` Tej
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=o2jf1c9d251005071301jfd33f723gc49e4013ae4a3d47@mail.gmail.com \
--to=bewith.tej@gmail.com \
--cc=george.dunlap@eu.citrix.com \
--cc=parkash.tej@gmail.com \
--cc=xen-devel@lists.xensource.com \
--cc=xen-users@lists.xensource.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).