* [RFC][PATCH] Hypervisor profiling using GCOV
@ 2009-02-16 16:36 Tej
0 siblings, 0 replies; 4+ messages in thread
From: Tej @ 2009-02-16 16:36 UTC (permalink / raw)
To: xen-devel
Cc: jeremy, George.Dunlap, Peter.Oberparleiter, keir.fraser,
mark.williamson, stephen.spector
[-- Attachment #1: Type: text/plain, Size: 2205 bytes --]
gcov is a test coverage program. generally used with GCC to analyze
programs to help create more efficient, faster running code and to
discover untested parts of your program. Software developers also use
coverage testing in concert with testsuites, to make sure software is
actually good enough for a release
Our efforts on the same line added the gcov(gcc) profiling support for
hypervisor only.
Current code base support xen-3.3.onwards, x86_32 and gcc 3.4 to 4.3.
xen-patch: code for hypervisor which populate the gcov_info (gcc 3.4
onward) with data file information, base code is taken from
http://ltp.sourceforge.net/coverage/gcov.php. added xen support and a
way to interact with linux since hypervisor itself cannot populate the
/proc filesystem.
linux-patch: code for linux kernel basically enquire the hypervisor
part to revert all data file information and populate the
/proc/xen/gcov with data and graph file (optional)
command-line/modules parameter:
1. xen-gcov-link: if set, it creates the *.c and *.gcno linking under
/proc/xen/gcov, else to run gcov/lcov we have to create manually
linking.
2. xen-gcov-update: update the data files after xen-gcov-update secs,
default value is 5sec... e.g while running a test suite, requires
lower value of xen-gcov-update.
tunable xen-gcov-update exist at /proc/sys/xen
usage: echo <num> >/proc/sys/xen/xen-gcov-update
Running lcov straight-a-way could be problematic because lcov is
written to see profiling info @/proc/gcov. To accomodate
/proc/xen/gcov edit the config file /etc/lcovrc parameter as
lcov_gcov_dir = /proc/gcov to /proc/xen/gcov and perform modprobe
xen-gcov-proc.
We are having patches to accomodate both but changing config file
could be a better options. Still if someone need patch please free to
mail me @bewith.tej@gmail.com
YES, We are aware that gcov profiling is quite basic profiling
concept, but its a begning from our end to make xen hypervisor best
and robust, in future we will be working on changes required for 64bit
hypervisor, older xen versions (if required), PERFMON features of
Modern CPU's.
Comments, reports, suggestions, and any other types of feedback is
more than welcome
-tej & team
[-- Attachment #2: linux-2.6.18-gcov-v1.patch --]
[-- Type: text/x-diff, Size: 36434 bytes --]
diff -r 3aa9b8a7876b drivers/xen/Kconfig
--- a/drivers/xen/Kconfig Fri Feb 06 12:01:56 2009 +0000
+++ b/drivers/xen/Kconfig Tue Feb 17 02:57:49 2009 +0530
@@ -263,6 +263,11 @@
default y
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"
diff -r 3aa9b8a7876b drivers/xen/Makefile
--- a/drivers/xen/Makefile Fri Feb 06 12:01:56 2009 +0000
+++ b/drivers/xen/Makefile Tue Feb 17 02:57:49 2009 +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 3aa9b8a7876b drivers/xen/core/xen_proc.c
--- a/drivers/xen/core/xen_proc.c Fri Feb 06 12:01:56 2009 +0000
+++ b/drivers/xen/core/xen_proc.c Tue Feb 17 02:57:49 2009 +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 3aa9b8a7876b drivers/xen/gcov/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/gcov/Makefile Tue Feb 17 02:57:49 2009 +0530
@@ -0,0 +1,1 @@
+obj-$(CONFIG_XEN_GCOV_PROC) := xen-gcov-proc.o
diff -r 3aa9b8a7876b 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 Tue Feb 17 02:57:49 2009 +0530
@@ -0,0 +1,1054 @@
+/**
+ * @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-i386/uaccess.h>
+#include <asm-i386/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)
+
+/* If set to non-zero, create links to additional files 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(gcov_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 gcov_variables *gcov_var = 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 xen_gcov_info *list_head = NULL;
+
+/* xen_sourcepath length */
+static int sourcepath_len;
+
+unsigned long xen_gcov_version;
+
+/* Retrieve proc_dir_entry associated with INODE. */
+/*static struct proc_dir_entry *PDE(const struct inode *inode)
+{
+ return ((struct proc_dir_entry *)inode->u.generic_ip);
+}*/
+
+
+/* Create nodes for all gcda files based on xen_file_nos value */
+static inline int create_bb_list(void)
+{
+ int i;
+ struct xen_gcov_info *node = NULL, *tmp_node = NULL;
+
+ for (i = 0; i < gcov_var->n_files; i++) {
+ node = kmalloc(sizeof(struct xen_gcov_info), GFP_KERNEL);
+ node->counts[0].values =
+ kmalloc(sizeof(gcov_type) * gcov_var->ctr_num[i],
+ GFP_KERNEL);
+ node->functions =
+ kmalloc(sizeof(struct xen_gcov_fn_info) *
+ gcov_var->n_funcs[i], 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 xen_gcov_info *node = NULL;
+ struct xen_gcov_info *temp = list_head;
+ for (;temp!=NULL;temp = temp->next) {
+ node = temp;
+ kfree(node->counts[0].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;
+}
+
+/* Determine whether counter TYPE is active in BB. */
+static int counter_active(struct xen_gcov_info *bb, unsigned int type)
+{
+ return ((1 << type) & bb->ctr_mask);
+}
+
+/* Return size of .gcda counter section. */
+static size_t
+sizeof_counter_data(struct xen_gcov_info *bb, unsigned int row,
+ unsigned int col)
+{
+
+ struct xen_gcov_fn_info *func =
+ (struct xen_gcov_fn_info *)&bb->functions[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 xen_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 xen_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 xen_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 xen_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 = (struct xen_gcov_fn_info *)&bb->functions[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 xen_gcov_info *bb, unsigned int func,
+ unsigned int type, char *buf, size_t count, loff_t offset)
+{
+ struct xen_gcov_fn_info *func_ptr;
+ char data[8];
+ char *from;
+ size_t len;
+ ssize_t result;
+ unsigned int i;
+
+ func_ptr = (struct xen_gcov_fn_info *)&bb->functions[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 xen_gcov_info *bb, unsigned int func, char *buf,
+ size_t count, loff_t offset)
+{
+ char data[4];
+ char *from;
+ size_t len;
+ unsigned int i;
+ loff_t off;
+ size_t size;
+ ssize_t result;
+ ssize_t rc;
+ 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) bb->
+ functions[func].ident, data);
+ len = 4 - (offset - 8);
+ from = data + (offset - 8);
+ } else {
+ /* Function checksum */
+ store_int32((uint32_t) bb->
+ functions[func].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 xen_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 xen_gcov_info *bb)
+{
+ return 8 + PAD8(strlen(bb->file) + 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->file);
+ 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->file + 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(&gcov_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(&gcov_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->file, RESET_GCDA)) {
+ printk(KERN_ERR GCOV_PROC_HEADER
+ "Failed to reset file %s\n", node->bb->file);
+ 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 xen_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 xen_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->file) +
+ strlen(da_ending) +
+ strlen(gcov_var->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->file);
+ 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 xen_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->file);
+ 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 variables from core */
+static inline int gcov_core_vars(void)
+{
+
+ int ret;
+ gcov_var = kmalloc(sizeof(struct gcov_variables), GFP_KERNEL);
+ if ((ret =
+ HYPERVISOR_gcovprof_op(GCOVPROF_seek_vars, gcov_var, 0)) != 0)
+ return ret;
+
+ xen_gcov_version = gcov_var->g_version;
+
+ gcov_var->ctr_num =
+ kmalloc(gcov_var->n_files * sizeof(gcov_unsigned_t), GFP_KERNEL);
+
+ gcov_var->n_funcs =
+ kmalloc(gcov_var->n_files * sizeof(gcov_unsigned_t), GFP_KERNEL);
+
+ if ((ret =
+ HYPERVISOR_gcovprof_op(GCOVPROF_seek_vars, gcov_var, 1)) != 0)
+ return ret;
+
+ sourcepath_len = strlen(gcov_var->src_path);
+ return ret;
+}
+
+static int __init xen_gcov_init(void)
+{
+ struct xen_gcov_info *bb;
+ int ret, rc = 0;
+ /* seek gcov core variable information & construct the gcov_info list */
+ if (gcov_core_vars()) {
+ printk(KERN_ERR GCOV_PROC_HEADER
+ "Failed to get the varaibales from core\n");
+ return -EIO;
+ }
+
+ /*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 xen_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->file, 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(gcov_var);
+ 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 3aa9b8a7876b include/asm-i386/mach-xen/asm/hypercall.h
--- a/include/asm-i386/mach-xen/asm/hypercall.h Fri Feb 06 12:01:56 2009 +0000
+++ b/include/asm-i386/mach-xen/asm/hypercall.h Tue Feb 17 02:57:49 2009 +0530
@@ -398,6 +398,13 @@
}
static inline int __must_check
+HYPERVISOR_gcovprof_op(
+ int cmd, void *arg, int val)
+{
+ return _hypercall3(int, gcovprof_op, cmd, arg, val);
+}
+
+static inline int __must_check
HYPERVISOR_kexec_op(
unsigned long op, void *args)
{
diff -r 3aa9b8a7876b include/xen/interface/xen-gcov.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/include/xen/interface/xen-gcov.h Tue Feb 17 02:57:49 2009 +0530
@@ -0,0 +1,123 @@
+/******************************************************************************
+ * 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_seek_vars 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
+
+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 xen_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 xen_gcov_fn_info
+{
+ gcov_unsigned_t ident; /* unique ident of function */
+ gcov_unsigned_t checksum; /* function checksum */
+ unsigned int n_ctrs[GCOV_COUNTERS]; /* instrumented counters */
+};
+typedef struct xen_gcov_fn_info xen_gcov_fn_info_t;
+DEFINE_XEN_GUEST_HANDLE(xen_gcov_fn_info_t);
+
+struct xen_gcov_ctr_info
+{
+ gcov_unsigned_t num; /* number of counters. */
+ gcov_type *values; /* thier values. */
+ gcov_merge_fn merge; /* merge function */
+};
+typedef struct xen_gcov_ctr_info xen_gcov_ctr_info_t;
+DEFINE_XEN_GUEST_HANDLE(xen_gcov_ctr_info_t);
+
+/* Information about a single object file. */
+struct xen_gcov_info
+{
+ gcov_unsigned_t version; /* expected version number */
+ struct xen_gcov_info *next; /* link to next, used by libgcov */
+
+ gcov_unsigned_t stamp; /* uniquifying time stamp */
+ char file[100];
+
+ unsigned int n_functions; /* number of functions */
+ struct xen_gcov_fn_info *functions; /* table of functions */
+
+ unsigned int ctr_mask; /* mask of counters instrumented. */
+ struct xen_gcov_ctr_info counts[GCOV_COUNTERS]; /* count data */
+};
+typedef struct xen_gcov_info xen_gcov_info_t;
+DEFINE_XEN_GUEST_HANDLE(xen_gcov_info_t);
+
+struct gcov_variables
+{
+ 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 */
+
+};
+typedef struct gcov_variables gcov_variables_t;
+DEFINE_XEN_GUEST_HANDLE(gcov_variables_t);
+
+#endif /* __XEN_PUBLIC_GCOVPROF_H__ */
diff -r 3aa9b8a7876b include/xen/interface/xen.h
--- a/include/xen/interface/xen.h Fri Feb 06 12:01:56 2009 +0000
+++ b/include/xen/interface/xen.h Tue Feb 17 02:57:49 2009 +0530
@@ -91,6 +91,7 @@
#define __HYPERVISOR_sysctl 35
#define __HYPERVISOR_domctl 36
#define __HYPERVISOR_kexec_op 37
+#define __HYPERVISOR_gcovprof_op 38
/* Architecture-specific hypercall definitions. */
#define __HYPERVISOR_arch_0 48
diff -r 3aa9b8a7876b include/xen/xen_proc.h
--- a/include/xen/xen_proc.h Fri Feb 06 12:01:56 2009 +0000
+++ b/include/xen/xen_proc.h Tue Feb 17 02:57:49 2009 +0530
@@ -4,6 +4,8 @@
#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: xen-3.3.0-gcov-v1.patch --]
[-- Type: text/x-diff, Size: 16822 bytes --]
diff -r b1ab0c6c6019 xen/Rules.mk
--- a/xen/Rules.mk Mon Feb 16 20:52:23 2009 +0530
+++ b/xen/Rules.mk Mon Feb 16 21:03:21 2009 +0530
@@ -9,6 +9,10 @@
crash_debug ?= n
frame_pointer ?= n
+# xen source path to get update in .gcno files
+xen_src := $(CURDIR)
+xentree := $(if $(xen_src),$(xen_src),$(CURDIR))
+
XEN_ROOT=$(BASEDIR)/..
include $(XEN_ROOT)/Config.mk
@@ -56,6 +60,7 @@
ALL_OBJS-y += $(BASEDIR)/arch/$(TARGET_ARCH)/built_in.o
CFLAGS-y += -g -D__XEN__
+CFLAGS-y += -fprofile-arcs -ftest-coverage
CFLAGS-$(XSM_ENABLE) += -DXSM_ENABLE
CFLAGS-$(FLASK_ENABLE) += -DFLASK_ENABLE -DXSM_MAGIC=0xf97cff8c
CFLAGS-$(FLASK_ENABLE) += -DFLASK_DEVELOP -DFLASK_BOOTPARAM -DFLASK_AVC_STATS
@@ -117,7 +122,9 @@
$(MAKE) -f $(BASEDIR)/Rules.mk -C $* clean
%.o: %.c $(HDRS) Makefile
- $(CC) $(CFLAGS) -c $< -o $@
+ $(CC) $(CFLAGS) -c -o $@ \
+ $(if $(filter-out /%,$<),$(xentree)/$<,$<)
+
%.o: %.S $(AHDRS) Makefile
$(CC) $(AFLAGS) -c $< -o $@
diff -r b1ab0c6c6019 xen/arch/x86/mm/hap/Makefile
--- a/xen/arch/x86/mm/hap/Makefile Mon Feb 16 20:52:23 2009 +0530
+++ b/xen/arch/x86/mm/hap/Makefile Mon Feb 16 21:03:21 2009 +0530
@@ -4,8 +4,17 @@
obj-y += guest_walk_4level.o
obj-y += p2m-ept.o
+LN = /bin/ln
+xen_src := $(CURDIR)
+xentree := $(if $(xen_src),$(xen_src),$(CURDIR))
+
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 $(HDRS) Makefile
- $(CC) $(CFLAGS) $(call guest_walk_defns,$(@F)) -c $< -o $@
+ $(CC) $(CFLAGS) $(call guest_walk_defns,$(@F)) -c -o $@ \
+ $(if $(filter-out /%,$<),$(xentree)/$<,$<)
+ $(LN) -f -s guest_walk.c guest_walk_$(num)
+
diff -r b1ab0c6c6019 xen/arch/x86/mm/shadow/Makefile
--- a/xen/arch/x86/mm/shadow/Makefile Mon Feb 16 20:52:23 2009 +0530
+++ b/xen/arch/x86/mm/shadow/Makefile Mon Feb 16 21:03:21 2009 +0530
@@ -1,5 +1,10 @@
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 $(HDRS) Makefile
- $(CC) $(CFLAGS) -DGUEST_PAGING_LEVELS=$* -c $< -o $@
+ $(CC) $(CFLAGS) -DGUEST_PAGING_LEVELS=$* -c -o $@ \
+ $(if $(filter-out /%,$<),$(xentree)/$<,$<)
+ $(LN) -f -s multi.c guest_$(num)
diff -r b1ab0c6c6019 xen/arch/x86/x86_32/entry.S
--- a/xen/arch/x86/x86_32/entry.S Mon Feb 16 20:52:23 2009 +0530
+++ b/xen/arch/x86/x86_32/entry.S Mon Feb 16 21:03:21 2009 +0530
@@ -703,6 +703,7 @@
.long do_sysctl /* 35 */
.long do_domctl
.long do_kexec_op
+ .long do_gcovprof_op
.rept __HYPERVISOR_arch_0-((.-hypercall_table)/4)
.long do_ni_hypercall
.endr
@@ -750,6 +751,7 @@
.byte 1 /* do_sysctl */ /* 35 */
.byte 1 /* do_domctl */
.byte 2 /* do_kexec_op */
+ .byte 3 /* do_gcovprof_op */
.rept __HYPERVISOR_arch_0-(.-hypercall_args_table)
.byte 0 /* do_ni_hypercall */
.endr
diff -r b1ab0c6c6019 xen/common/Makefile
--- a/xen/common/Makefile Mon Feb 16 20:52:23 2009 +0530
+++ b/xen/common/Makefile Mon Feb 16 21:03:21 2009 +0530
@@ -27,6 +27,7 @@
obj-y += vsprintf.o
obj-y += xmalloc.o
obj-y += rcupdate.o
+obj-y += xen-gcov-core.o
obj-$(perfc) += perfc.o
obj-$(crash_debug) += gdbstub.o
@@ -42,6 +43,8 @@
subdir-y += libelf
+CFLAGS += -DSRC_PATH='"$(BASEDIR)"'
+
# Object file contains changeset and compiler information.
version.o: $(BASEDIR)/include/xen/compile.h
diff -r b1ab0c6c6019 xen/common/xen-gcov-core.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/common/xen-gcov-core.c Mon Feb 16 21:03:21 2009 +0530
@@ -0,0 +1,242 @@
+/**
+ * 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:"
+
+static int num_xen_files;
+gcov_unsigned_t gcov_version = 0;
+struct gcov_info *bb_head;
+
+struct ctor_list {
+ unsigned long num;
+ ctor_t ctor[];
+};
+extern struct ctor_list __CTOR_LIST__;
+
+
+static inline int
+counter_active(struct gcov_info *bb, unsigned int type)
+{
+ return (1 << type) & bb->ctr_mask;
+}
+
+static inline unsigned int
+get_fn_stride(struct gcov_info *bb)
+{
+ unsigned int stride;
+
+ stride = sizeof(struct gcov_fn_info) + 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;
+}
+
+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));
+}
+
+static void reset_gcda(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++;
+ }
+}
+
+/* Function to reset the bb counter. */
+static int reset_bb(XEN_GUEST_HANDLE(void) arg, int val)
+{
+ struct gcov_info *tmp=bb_head;
+ char bb_file[100];
+ if ( val == 0){
+ /* 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_gcda(tmp);
+ break;
+ }
+ else
+ continue;
+ }
+ }
+ else {
+ /* reset all data files */
+ for(;tmp!=NULL;tmp=tmp->next)
+ reset_gcda(tmp);
+ }
+ return 0;
+}
+
+
+/*copy bb_head info */
+
+static int start_prof(XEN_GUEST_HANDLE(void) arg, int val)
+{
+ /*Add the code to copy the no of files to be add to xen */
+ struct xen_gcov_info bb_tmp;
+ struct gcov_info *tmp = bb_head;
+ struct gcov_fn_info *func;
+ struct gcov_ctr_info *ctr;
+ struct xen_gcov_ctr_info *xctr;
+ struct xen_gcov_info *bb = &bb_tmp;
+ int i,j;
+
+ if ( copy_from_guest(&bb_tmp, arg, 1) )
+ return -EFAULT;
+ for(;tmp!=NULL&&bb!=NULL;tmp=tmp->next){
+ ctr = tmp->counts;
+ xctr = bb->counts;
+ memcpy(bb->counts[0].values, ctr->values, ctr->num*sizeof(gcov_type));
+ xctr->num = ctr->num;
+ xctr->merge = ctr->merge;
+ bb->version = tmp->version;
+ bb->stamp = tmp->stamp;
+ safe_strcpy(bb->file, tmp->filename);
+ bb->ctr_mask = tmp->ctr_mask;
+ bb->n_functions = tmp->n_functions;
+ for(i=0;i<tmp->n_functions;i++) {
+ func = get_fn_info(tmp,i);
+ bb->functions[i].ident=func->ident;
+ bb->functions[i].checksum=func->checksum;
+ for (j=0;j<GCOV_COUNTERS;j++) {
+ bb->functions[i].n_ctrs[j]=func->n_ctrs[j];
+ }
+ }
+ /*increment the bb_head pointers*/
+ bb=bb->next;
+ }
+ if ( copy_to_guest(arg, &bb_tmp, 1) )
+ return -EFAULT;
+ return 0;
+}
+
+
+static int var_info(XEN_GUEST_HANDLE(void) arg,int val)
+{
+ struct gcov_variables gcov_var;
+ struct gcov_variables *tmp=&gcov_var;
+ struct gcov_info *bb;
+ int i;
+ if( copy_from_guest(&gcov_var, arg, 1) )
+ return -EFAULT;
+ if ( val == 0 ) {
+ safe_strcpy(tmp->src_path,SRC_PATH);
+ tmp->g_version=gcov_version;
+ tmp->n_files=num_xen_files;
+ } else {
+ for(i=0,bb=bb_head;bb!=NULL;bb=bb->next,i++){
+ tmp->ctr_num[i]=bb->counts->num;
+ tmp->n_funcs[i]=bb->n_functions;
+ }
+ }
+
+ if( copy_to_guest(arg, &gcov_var, 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_seek_vars:
+ /*fun seeks vars to be used by proc code */
+ ret = var_info(arg, val);
+ break;
+ case GCOVPROF_start:
+ /*update linux kernel with profiling info */
+ ret = start_prof(arg,val);
+ break;
+ case GCOVPROF_reset:
+ /*reset the gcda or vmlinux*/
+ ret = reset_bb(arg,val);
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+ return ret;
+}
+
+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] ();
+}
+
+ /*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)
+{
+ num_xen_files = __CTOR_LIST__.num;
+ do_global_ctors(__CTOR_LIST__.ctor, __CTOR_LIST__.num);
+ printk(KERN_INFO XEN_GCOV_CORE "init done\n");
+ return 0;
+}
+
+/* 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);
+__initcall(gcov_init);
diff -r b1ab0c6c6019 xen/include/public/xen-gcov.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/public/xen-gcov.h Mon Feb 16 21:03:21 2009 +0530
@@ -0,0 +1,139 @@
+/******************************************************************************
+ * 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_seek_vars 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 */
+};
+
+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. */
+};
+
+/* 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 */
+ const 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. */
+};
+
+
+struct xen_gcov_fn_info{
+ gcov_unsigned_t ident; /* unique ident of function */
+ gcov_unsigned_t checksum; /* function checksum */
+ unsigned int n_ctrs[GCOV_COUNTERS]; /* instrumented counters */
+};
+typedef struct xen_gcov_fn_info xen_gcov_fn_info_t;
+DEFINE_XEN_GUEST_HANDLE(xen_gcov_fn_info_t);
+
+
+
+struct xen_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 xen_gcov_ctr_info xen_gcov_ctr_info_t;
+DEFINE_XEN_GUEST_HANDLE(xen_gcov_ctr_info_t);
+
+/* Information about a single object file. */
+struct xen_gcov_info
+{
+ gcov_unsigned_t version; /* expected version number */
+ struct xen_gcov_info *next; /* link to next, used by libgcov */
+
+ gcov_unsigned_t stamp; /* uniquifying time stamp */
+ char file[100];
+
+ unsigned int n_functions; /* number of functions */
+ struct xen_gcov_fn_info *functions; /* table of functions */
+
+ unsigned int ctr_mask; /* mask of counters instrumented. */
+ struct xen_gcov_ctr_info counts[GCOV_COUNTERS]; /* count data.*/
+};
+typedef struct xen_gcov_info xen_gcov_info_t;
+DEFINE_XEN_GUEST_HANDLE(xen_gcov_info_t);
+
+struct gcov_variables
+{
+ char src_path[100];
+ unsigned long g_version;
+ unsigned int n_files;
+ gcov_unsigned_t *ctr_num;
+ unsigned int *n_funcs;
+};
+typedef struct gcov_variables gcov_variables_t;
+DEFINE_XEN_GUEST_HANDLE(gcov_variables_t);
+
+#endif /* __XEN_PUBLIC_GCOVPROF_H__ */
diff -r b1ab0c6c6019 xen/include/xen/config.h
--- a/xen/include/xen/config.h Mon Feb 16 20:52:23 2009 +0530
+++ b/xen/include/xen/config.h Mon Feb 16 21:03:21 2009 +0530
@@ -96,4 +96,20 @@
#define __cpuinitdata
#define __cpuinit
+#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 /* __XEN_CONFIG_H__ */
[-- Attachment #4: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [RFC][PATCH] Hypervisor profiling using GCOV
[not found] ` <C5C17211.2D71%keir.fraser@eu.citrix.com>
@ 2009-02-18 16:58 ` Tej
2009-02-19 14:53 ` George Dunlap
0 siblings, 1 reply; 4+ messages in thread
From: Tej @ 2009-02-18 16:58 UTC (permalink / raw)
To: Keir Fraser; +Cc: George Dunlap, xen-devel
On Wed, Feb 18, 2009 at 1:36 PM, Keir Fraser <keir.fraser@eu.citrix.com> wrote:
> On 18/02/2009 04:03, "Tej" <bewith.tej@gmail.com> wrote:
>
>> hey keir
>>
>> i need some input from you, regarding this tool.. It is worth
>> investigating further in hypervisor profiling.
>> or anything like this tool need a better design/coding/new features
>> anything of this sort.
>
> Does it get us significantly more than the existing xentrace and xenoprofile
> tools? Especially the latter, which already does program-counter tracing and
> generation of stats from that, via the oprofile tool.
thanks for our feedback
i agree xenoprofile is advanced proffiling tool in xen since ages, but
GCOV could be useful tool to naive tester/programmer on XEN who really
don't understand xenoprofile stats....
e.g If i start with any hypervisor subsystem (scheduler), i will run
xm test suite for scheduler and see what all code is getting affected
over a period of time and proceed with it...
>
> George Dunlap does most of our profiling internally. You might ask him what
> he thinks compared with these existing supported tools.
George, Do you have any comments on this
>
> -- Keir
>
>
>
thanks
-tej
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [RFC][PATCH] Hypervisor profiling using GCOV
2009-02-18 16:58 ` [RFC][PATCH] Hypervisor profiling using GCOV Tej
@ 2009-02-19 14:53 ` George Dunlap
2009-02-19 16:04 ` Tej
0 siblings, 1 reply; 4+ messages in thread
From: George Dunlap @ 2009-02-19 14:53 UTC (permalink / raw)
To: Tej; +Cc: xen-devel@lists.xensource.com, Keir Fraser
Tej wrote:
>> Does it get us significantly more than the existing xentrace and xenoprofile
>> tools? Especially the latter, which already does program-counter tracing and
>> generation of stats from that, via the oprofile tool.
>>
>
> thanks for our feedback
> i agree xenoprofile is advanced proffiling tool in xen since ages, but
> GCOV could be useful tool to naive tester/programmer on XEN who really
> don't understand xenoprofile stats....
>
Don't undersell gcov; its purpose is slightly different from either
xentrace or xenoprofile. Xentrace can be used to get information about
what paths or reasons caused vmexits (as well as just seeing specific
patterns that happen). xenoprofile is a relatively low-overhead way of
just profiling (which unfortuantely doesn't work properly in 32-on-64
mode ATM). gcov's main purpose is to tell you code coverage; profiling
is just a side-effect.
I looked at the LTP page about lcov, and it looks like it was pretty
useful for them. It has graphical output with the number of times /
percentage a given path was taken. It probably is worth porting to Xen
for the same reason -- to see how well given paths in Xen actually get
exercised.
> e.g If i start with any hypervisor subsystem (scheduler), i will run
> xm test suite for scheduler and see what all code is getting affected
> over a period of time and proceed with it...
>
It sounds like the main problem with xenoprofile is that it's hard to
set up and use ATM: it could use some attention to the code, and some
well-worded HOWTOs. The fact that 32-on-64 doesn't work properly
(truncates the long EIPs) doesn't help. :-)
So I think that it probably would be useful. Unfortunately, I don't
have time in the near future to look at either of these (new "xcov"
functionality, or fixing xenoprofile). Gianluca's been doing some
interesting work with testing. I'll ask him if he's interested in
looking at it.
Thanks for your work though, Tej!
-George
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [RFC][PATCH] Hypervisor profiling using GCOV
2009-02-19 14:53 ` George Dunlap
@ 2009-02-19 16:04 ` Tej
0 siblings, 0 replies; 4+ messages in thread
From: Tej @ 2009-02-19 16:04 UTC (permalink / raw)
To: George Dunlap; +Cc: gianluca.guida, xen-devel@lists.xensource.com, Keir Fraser
[-- Attachment #1: Type: text/plain, Size: 2645 bytes --]
On Thu, Feb 19, 2009 at 8:23 PM, George Dunlap
<george.dunlap@eu.citrix.com> wrote:
> Tej wrote:
>>>
>>> Does it get us significantly more than the existing xentrace and
>>> xenoprofile
>>> tools? Especially the latter, which already does program-counter tracing
>>> and
>>> generation of stats from that, via the oprofile tool.
>>>
>>
>> thanks for our feedback
>> i agree xenoprofile is advanced proffiling tool in xen since ages, but
>> GCOV could be useful tool to naive tester/programmer on XEN who really
>> don't understand xenoprofile stats....
>>
>
> Don't undersell gcov; its purpose is slightly different from either xentrace
> or xenoprofile. Xentrace can be used to get information about what paths or
> reasons caused vmexits (as well as just seeing specific patterns that
> happen). xenoprofile is a relatively low-overhead way of just profiling
> (which unfortuantely doesn't work properly in 32-on-64 mode ATM). gcov's
> main purpose is to tell you code coverage; profiling is just a side-effect.
>
> I looked at the LTP page about lcov, and it looks like it was pretty useful
> for them. It has graphical output with the number of times / percentage a
> given path was taken. It probably is worth porting to Xen for the same
> reason -- to see how well given paths in Xen actually get exercised.
>>
>> e.g If i start with any hypervisor subsystem (scheduler), i will run
>> xm test suite for scheduler and see what all code is getting affected
>> over a period of time and proceed with it...
>>
>
> It sounds like the main problem with xenoprofile is that it's hard to set up
> and use ATM: it could use some attention to the code, and some well-worded
> HOWTOs. The fact that 32-on-64 doesn't work properly (truncates the long
> EIPs) doesn't help. :-)
>
> So I think that it probably would be useful. Unfortunately, I don't have
> time in the near future to look at either of these (new "xcov"
> functionality, or fixing xenoprofile). Gianluca's been doing some
> interesting work with testing. I'll ask him if he's interested in looking
> at it.
thanks for your valuable feedback....
I need some comments from you or Gianluca regarding the basic design
and coding standard, or any other way it can be improved. Patches are
mainly to show the design and approach we have followed to produce
code coverage.
I am planning to change code of lcov to support xen code coverage out
of box rather than changing lcov config file.
any comments on this?
Anyway here are the patches for xen-3.2 and xen-3.1.*
in Xen-3.2 previous linux patches will do.
>
> Thanks for your work though, Tej!
thanks
-tej
>
> -George
>
[-- Attachment #2: xen-3.1-gcov-v1.patch --]
[-- Type: application/octet-stream, Size: 53079 bytes --]
diff -r 0ca89fa82946 linux-2.6-xen-sparse/drivers/xen/Kconfig
--- a/linux-2.6-xen-sparse/drivers/xen/Kconfig Wed Feb 18 10:45:42 2009 +0530
+++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig Thu Feb 19 13:14:47 2009 +0530
@@ -237,6 +237,12 @@
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 0ca89fa82946 linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile Wed Feb 18 10:45:42 2009 +0530
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Thu Feb 19 13:14:47 2009 +0530
@@ -6,6 +6,7 @@
obj-y += gntdev/
obj-y += balloon/
obj-y += char/
+obj-y += gcov/
obj-y += util.o
obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/
diff -r 0ca89fa82946 linux-2.6-xen-sparse/drivers/xen/core/xen_proc.c
--- a/linux-2.6-xen-sparse/drivers/xen/core/xen_proc.c Wed Feb 18 10:45:42 2009 +0530
+++ b/linux-2.6-xen-sparse/drivers/xen/core/xen_proc.c Thu Feb 19 13:14:47 2009 +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 0ca89fa82946 linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h Wed Feb 18 10:45:42 2009 +0530
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h Thu Feb 19 13:14:47 2009 +0530
@@ -395,6 +395,13 @@
return _hypercall2(int, xenoprof_op, op, arg);
}
+static inline int
+HYPERVISOR_gcovprof_op(
+ int cmd, void *arg, int val)
+{
+ return _hypercall3(int, gcovprof_op, cmd, arg, val);
+}
+
static inline int
HYPERVISOR_kexec_op(
unsigned long op, void *args)
diff -r 0ca89fa82946 linux-2.6-xen-sparse/include/xen/xen_proc.h
--- a/linux-2.6-xen-sparse/include/xen/xen_proc.h Wed Feb 18 10:45:42 2009 +0530
+++ b/linux-2.6-xen-sparse/include/xen/xen_proc.h Thu Feb 19 13:14:47 2009 +0530
@@ -3,6 +3,8 @@
#define __ASM_XEN_PROC_H__
#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);
diff -r 0ca89fa82946 linux-2.6.18.8-xen/drivers/xen/gcov/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6.18.8-xen/drivers/xen/gcov/Makefile Thu Feb 19 13:14:47 2009 +0530
@@ -0,0 +1,1 @@
+obj-$(CONFIG_XEN_GCOV_PROC) := xen-gcov-proc.o
diff -r 0ca89fa82946 linux-2.6.18.8-xen/drivers/xen/gcov/xen-gcov-proc.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6.18.8-xen/drivers/xen/gcov/xen-gcov-proc.c Thu Feb 19 13:14:47 2009 +0530
@@ -0,0 +1,1054 @@
+/**
+ * @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-i386/uaccess.h>
+#include <asm-i386/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)
+
+/* If set to non-zero, create links to additional files 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(gcov_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 gcov_variables *gcov_var = 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 xen_gcov_info *list_head = NULL;
+
+/* xen_sourcepath length */
+static int sourcepath_len;
+
+unsigned long xen_gcov_version;
+
+/* Retrieve proc_dir_entry associated with INODE. */
+/*static struct proc_dir_entry *PDE(const struct inode *inode)
+{
+ return ((struct proc_dir_entry *)inode->u.generic_ip);
+}*/
+
+
+/* Create nodes for all gcda files based on xen_file_nos value */
+static inline int create_bb_list(void)
+{
+ int i;
+ struct xen_gcov_info *node = NULL, *tmp_node = NULL;
+
+ for (i = 0; i < gcov_var->n_files; i++) {
+ node = kmalloc(sizeof(struct xen_gcov_info), GFP_KERNEL);
+ node->counts[0].values =
+ kmalloc(sizeof(gcov_type) * gcov_var->ctr_num[i],
+ GFP_KERNEL);
+ node->functions =
+ kmalloc(sizeof(struct xen_gcov_fn_info) *
+ gcov_var->n_funcs[i], 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 xen_gcov_info *node = NULL;
+ struct xen_gcov_info *temp = list_head;
+ for (;temp!=NULL;temp = temp->next) {
+ node = temp;
+ kfree(node->counts[0].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;
+}
+
+/* Determine whether counter TYPE is active in BB. */
+static int counter_active(struct xen_gcov_info *bb, unsigned int type)
+{
+ return ((1 << type) & bb->ctr_mask);
+}
+
+/* Return size of .gcda counter section. */
+static size_t
+sizeof_counter_data(struct xen_gcov_info *bb, unsigned int row,
+ unsigned int col)
+{
+
+ struct xen_gcov_fn_info *func =
+ (struct xen_gcov_fn_info *)&bb->functions[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 xen_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 xen_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 xen_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 xen_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 = (struct xen_gcov_fn_info *)&bb->functions[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 xen_gcov_info *bb, unsigned int func,
+ unsigned int type, char *buf, size_t count, loff_t offset)
+{
+ struct xen_gcov_fn_info *func_ptr;
+ char data[8];
+ char *from;
+ size_t len;
+ ssize_t result;
+ unsigned int i;
+
+ func_ptr = (struct xen_gcov_fn_info *)&bb->functions[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 xen_gcov_info *bb, unsigned int func, char *buf,
+ size_t count, loff_t offset)
+{
+ char data[4];
+ char *from;
+ size_t len;
+ unsigned int i;
+ loff_t off;
+ size_t size;
+ ssize_t result;
+ ssize_t rc;
+ 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) bb->
+ functions[func].ident, data);
+ len = 4 - (offset - 8);
+ from = data + (offset - 8);
+ } else {
+ /* Function checksum */
+ store_int32((uint32_t) bb->
+ functions[func].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 xen_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 xen_gcov_info *bb)
+{
+ return 8 + PAD8(strlen(bb->file) + 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->file);
+ 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->file + 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(&gcov_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(&gcov_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->file, RESET_GCDA)) {
+ printk(KERN_ERR GCOV_PROC_HEADER
+ "Failed to reset file %s\n", node->bb->file);
+ 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 xen_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 xen_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->file) +
+ strlen(da_ending) +
+ strlen(gcov_var->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->file);
+ 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 xen_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->file);
+ 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 variables from core */
+static inline int gcov_core_vars(void)
+{
+
+ int ret;
+ gcov_var = kmalloc(sizeof(struct gcov_variables), GFP_KERNEL);
+ if ((ret =
+ HYPERVISOR_gcovprof_op(GCOVPROF_seek_vars, gcov_var, 0)) != 0)
+ return ret;
+
+ xen_gcov_version = gcov_var->g_version;
+
+ gcov_var->ctr_num =
+ kmalloc(gcov_var->n_files * sizeof(gcov_unsigned_t), GFP_KERNEL);
+
+ gcov_var->n_funcs =
+ kmalloc(gcov_var->n_files * sizeof(gcov_unsigned_t), GFP_KERNEL);
+
+ if ((ret =
+ HYPERVISOR_gcovprof_op(GCOVPROF_seek_vars, gcov_var, 1)) != 0)
+ return ret;
+
+ sourcepath_len = strlen(gcov_var->src_path);
+ return ret;
+}
+
+static int __init xen_gcov_init(void)
+{
+ struct xen_gcov_info *bb;
+ int ret, rc = 0;
+ /* seek gcov core variable information & construct the gcov_info list */
+ if (gcov_core_vars()) {
+ printk(KERN_ERR GCOV_PROC_HEADER
+ "Failed to get the varaibales from core\n");
+ return -EIO;
+ }
+
+ /*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 xen_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->file, 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(gcov_var);
+ 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 0ca89fa82946 linux-2.6.18.8-xen/include/xen/interface/xen-gcov.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6.18.8-xen/include/xen/interface/xen-gcov.h Thu Feb 19 13:14:47 2009 +0530
@@ -0,0 +1,123 @@
+/******************************************************************************
+ * 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_seek_vars 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
+
+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 xen_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 xen_gcov_fn_info
+{
+ gcov_unsigned_t ident; /* unique ident of function */
+ gcov_unsigned_t checksum; /* function checksum */
+ unsigned int n_ctrs[GCOV_COUNTERS]; /* instrumented counters */
+};
+typedef struct xen_gcov_fn_info xen_gcov_fn_info_t;
+DEFINE_XEN_GUEST_HANDLE(xen_gcov_fn_info_t);
+
+struct xen_gcov_ctr_info
+{
+ gcov_unsigned_t num; /* number of counters. */
+ gcov_type *values; /* thier values. */
+ gcov_merge_fn merge; /* merge function */
+};
+typedef struct xen_gcov_ctr_info xen_gcov_ctr_info_t;
+DEFINE_XEN_GUEST_HANDLE(xen_gcov_ctr_info_t);
+
+/* Information about a single object file. */
+struct xen_gcov_info
+{
+ gcov_unsigned_t version; /* expected version number */
+ struct xen_gcov_info *next; /* link to next, used by libgcov */
+
+ gcov_unsigned_t stamp; /* uniquifying time stamp */
+ char file[100];
+
+ unsigned int n_functions; /* number of functions */
+ struct xen_gcov_fn_info *functions; /* table of functions */
+
+ unsigned int ctr_mask; /* mask of counters instrumented. */
+ struct xen_gcov_ctr_info counts[GCOV_COUNTERS]; /* count data */
+};
+typedef struct xen_gcov_info xen_gcov_info_t;
+DEFINE_XEN_GUEST_HANDLE(xen_gcov_info_t);
+
+struct gcov_variables
+{
+ 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 */
+
+};
+typedef struct gcov_variables gcov_variables_t;
+DEFINE_XEN_GUEST_HANDLE(gcov_variables_t);
+
+#endif /* __XEN_PUBLIC_GCOVPROF_H__ */
diff -r 0ca89fa82946 xen/Rules.mk
--- a/xen/Rules.mk Wed Feb 18 10:45:42 2009 +0530
+++ b/xen/Rules.mk Thu Feb 19 13:14:47 2009 +0530
@@ -8,6 +8,11 @@
perfc_arrays ?= n
crash_debug ?= n
frame_pointer ?= n
+
+# xen source path to get update in .gcno files
+xen_src := $(CURDIR)
+xentree := $(if $(xen_src),$(xen_src),$(CURDIR))
+
XEN_ROOT=$(BASEDIR)/..
include $(XEN_ROOT)/Config.mk
@@ -56,6 +61,7 @@
ALL_OBJS-y += $(BASEDIR)/arch/$(TARGET_ARCH)/built_in.o
CFLAGS-y += -g -D__XEN__
+CFLAGS-y += -fprofile-arcs -ftest-coverage
CFLAGS-$(ACM_SECURITY) += -DACM_SECURITY
CFLAGS-$(verbose) += -DVERBOSE
CFLAGS-$(crash_debug) += -DCRASH_DEBUG
@@ -114,7 +120,8 @@
$(MAKE) -f $(BASEDIR)/Rules.mk -C $* clean
%.o: %.c $(HDRS) Makefile
- $(CC) $(CFLAGS) -c $< -o $@
+ $(CC) $(CFLAGS) -c -o $@ \
+ $(if $(filter-out /%,$<),$(xentree)/$<,$<)
%.o: %.S $(AHDRS) Makefile
$(CC) $(AFLAGS) -c $< -o $@
diff -r 0ca89fa82946 xen/arch/x86/mm/shadow/Makefile
--- a/xen/arch/x86/mm/shadow/Makefile Wed Feb 18 10:45:42 2009 +0530
+++ b/xen/arch/x86/mm/shadow/Makefile Thu Feb 19 13:14:47 2009 +0530
@@ -6,10 +6,15 @@
obj-$(x86_64) += common.o g4_on_s4.o g3_on_s3.o g2_on_s3.o
+LN = /bin/ln
+num=$*.c
+
guest_levels = $(subst g,,$(filter g%,$(subst ., ,$(subst _, ,$(1)))))
shadow_levels = $(subst s,,$(filter s%,$(subst ., ,$(subst _, ,$(1)))))
shadow_defns = -DGUEST_PAGING_LEVELS=$(call guest_levels,$(1)) \
-DSHADOW_PAGING_LEVELS=$(call shadow_levels,$(1))
g%.o: multi.c $(HDRS) Makefile
- $(CC) $(CFLAGS) $(call shadow_defns,$(@F)) -c $< -o $@
+ $(CC) $(CFLAGS) $(call shadow_defns,$(@F)) -c -o $@ \
+ $(if $(filter-out /%,$<),$(xentree)/$<,$<)
+ $(LN) -f -s multi.c g$(num)
diff -r 0ca89fa82946 xen/arch/x86/x86_32/entry.S
--- a/xen/arch/x86/x86_32/entry.S Wed Feb 18 10:45:42 2009 +0530
+++ b/xen/arch/x86/x86_32/entry.S Thu Feb 19 13:14:47 2009 +0530
@@ -676,6 +676,7 @@
.long do_sysctl /* 35 */
.long do_domctl
.long do_kexec_op
+ .long do_gcovprof_op
.rept NR_hypercalls-((.-hypercall_table)/4)
.long do_ni_hypercall
.endr
@@ -719,6 +720,7 @@
.byte 1 /* do_sysctl */ /* 35 */
.byte 1 /* do_domctl */
.byte 2 /* do_kexec_op */
+ .byte 3 /* do_gcovprof_op */
.rept NR_hypercalls-(.-hypercall_args_table)
.byte 0 /* do_ni_hypercall */
.endr
diff -r 0ca89fa82946 xen/common/Makefile
--- a/xen/common/Makefile Wed Feb 18 10:45:42 2009 +0530
+++ b/xen/common/Makefile Thu Feb 19 13:14:47 2009 +0530
@@ -27,6 +27,7 @@
obj-y += vsprintf.o
obj-y += xmalloc.o
obj-y += rcupdate.o
+obj-y += xen-gcov-core.o
obj-$(perfc) += perfc.o
obj-$(crash_debug) += gdbstub.o
@@ -38,6 +39,8 @@
subdir-y += libelf
+CFLAGS += -DSRC_PATH='"$(BASEDIR)"'
+
# Object file contains changeset and compiler information.
version.o: $(BASEDIR)/include/xen/compile.h
diff -r 0ca89fa82946 xen/common/xen-gcov-core.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/common/xen-gcov-core.c Thu Feb 19 13:14:47 2009 +0530
@@ -0,0 +1,241 @@
+/**
+ * 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 <xen/config.h>
+#include <xen/lib.h>
+
+
+#define XEN_GCOV_CORE "xen-gcov-core:"
+
+static int num_xen_files;
+gcov_unsigned_t gcov_version = 0;
+struct gcov_info *bb_head;
+
+struct ctor_list {
+ unsigned long num;
+ ctor_t ctor[];
+};
+extern struct ctor_list __CTOR_LIST__;
+
+
+static inline int
+counter_active(struct gcov_info *bb, unsigned int type)
+{
+ return (1 << type) & bb->ctr_mask;
+}
+
+static inline unsigned int
+get_fn_stride(struct gcov_info *bb)
+{
+ unsigned int stride;
+
+ stride = sizeof(struct gcov_fn_info) + 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;
+}
+
+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));
+}
+
+static void reset_gcda(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++;
+ }
+}
+
+/* Function to reset the bb counter. */
+static int reset_bb(XEN_GUEST_HANDLE(void) arg, int val)
+{
+ struct gcov_info *tmp=bb_head;
+ char bb_file[100];
+ if ( val == 0){
+ /* 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_gcda(tmp);
+ break;
+ }
+ else
+ continue;
+ }
+ }
+ else {
+ /* reset all data files */
+ for(;tmp!=NULL;tmp=tmp->next)
+ reset_gcda(tmp);
+ }
+ return 0;
+}
+
+
+/*copy bb_head info */
+
+static int start_prof(XEN_GUEST_HANDLE(void) arg, int val)
+{
+ /*Add the code to copy the no of files to be add to xen */
+ struct xen_gcov_info bb_tmp;
+ struct gcov_info *tmp = bb_head;
+ struct gcov_fn_info *func;
+ struct gcov_ctr_info *ctr;
+ struct xen_gcov_ctr_info *xctr;
+ struct xen_gcov_info *bb = &bb_tmp;
+ int i,j;
+
+ if ( copy_from_guest(&bb_tmp, arg, 1) )
+ return -EFAULT;
+ for(;tmp!=NULL&&bb!=NULL;tmp=tmp->next){
+ ctr = tmp->counts;
+ xctr = bb->counts;
+ memcpy(bb->counts[0].values, ctr->values, ctr->num*sizeof(gcov_type));
+ xctr->num = ctr->num;
+ xctr->merge = ctr->merge;
+ bb->version = tmp->version;
+ bb->stamp = tmp->stamp;
+ safe_strcpy(bb->file, tmp->filename);
+ bb->ctr_mask = tmp->ctr_mask;
+ bb->n_functions = tmp->n_functions;
+ for(i=0;i<tmp->n_functions;i++) {
+ func = get_fn_info(tmp,i);
+ bb->functions[i].ident=func->ident;
+ bb->functions[i].checksum=func->checksum;
+ for (j=0;j<GCOV_COUNTERS;j++) {
+ bb->functions[i].n_ctrs[j]=func->n_ctrs[j];
+ }
+ }
+ /*increment the bb_head pointers*/
+ bb=bb->next;
+ }
+ if ( copy_to_guest(arg, &bb_tmp, 1) )
+ return -EFAULT;
+ return 0;
+}
+
+
+static int var_info(XEN_GUEST_HANDLE(void) arg,int val)
+{
+ struct gcov_variables gcov_var;
+ struct gcov_variables *tmp=&gcov_var;
+ struct gcov_info *bb;
+ int i;
+ if( copy_from_guest(&gcov_var, arg, 1) )
+ return -EFAULT;
+ if ( val == 0 ) {
+ safe_strcpy(tmp->src_path,SRC_PATH);
+ tmp->g_version=gcov_version;
+ tmp->n_files=num_xen_files;
+ } else {
+ for(i=0,bb=bb_head;bb!=NULL;bb=bb->next,i++){
+ tmp->ctr_num[i]=bb->counts->num;
+ tmp->n_funcs[i]=bb->n_functions;
+ }
+ }
+
+ if( copy_to_guest(arg, &gcov_var, 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_seek_vars:
+ /*fun seeks vars to be used by proc code */
+ ret = var_info(arg, val);
+ break;
+ case GCOVPROF_start:
+ /*update linux kernel with profiling info */
+ ret = start_prof(arg,val);
+ break;
+ case GCOVPROF_reset:
+ /*reset the gcda or vmlinux*/
+ ret = reset_bb(arg,val);
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+ return ret;
+}
+
+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] ();
+}
+
+ /*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)
+{
+ num_xen_files = __CTOR_LIST__.num;
+ do_global_ctors(__CTOR_LIST__.ctor, __CTOR_LIST__.num);
+ printk(KERN_INFO XEN_GCOV_CORE "init done\n");
+ return 0;
+}
+
+/* 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);
+__initcall(gcov_init);
diff -r 0ca89fa82946 xen/include/public/xen-gcov.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/public/xen-gcov.h Thu Feb 19 13:14:47 2009 +0530
@@ -0,0 +1,139 @@
+/******************************************************************************
+ * 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_seek_vars 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 */
+};
+
+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. */
+};
+
+/* 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 */
+ const 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. */
+};
+
+
+struct xen_gcov_fn_info{
+ gcov_unsigned_t ident; /* unique ident of function */
+ gcov_unsigned_t checksum; /* function checksum */
+ unsigned int n_ctrs[GCOV_COUNTERS]; /* instrumented counters */
+};
+typedef struct xen_gcov_fn_info xen_gcov_fn_info_t;
+DEFINE_XEN_GUEST_HANDLE(xen_gcov_fn_info_t);
+
+
+
+struct xen_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 xen_gcov_ctr_info xen_gcov_ctr_info_t;
+DEFINE_XEN_GUEST_HANDLE(xen_gcov_ctr_info_t);
+
+/* Information about a single object file. */
+struct xen_gcov_info
+{
+ gcov_unsigned_t version; /* expected version number */
+ struct xen_gcov_info *next; /* link to next, used by libgcov */
+
+ gcov_unsigned_t stamp; /* uniquifying time stamp */
+ char file[100];
+
+ unsigned int n_functions; /* number of functions */
+ struct xen_gcov_fn_info *functions; /* table of functions */
+
+ unsigned int ctr_mask; /* mask of counters instrumented. */
+ struct xen_gcov_ctr_info counts[GCOV_COUNTERS]; /* count data.*/
+};
+typedef struct xen_gcov_info xen_gcov_info_t;
+DEFINE_XEN_GUEST_HANDLE(xen_gcov_info_t);
+
+struct gcov_variables
+{
+ char src_path[100];
+ unsigned long g_version;
+ unsigned int n_files;
+ gcov_unsigned_t *ctr_num;
+ unsigned int *n_funcs;
+};
+typedef struct gcov_variables gcov_variables_t;
+DEFINE_XEN_GUEST_HANDLE(gcov_variables_t);
+
+#endif /* __XEN_PUBLIC_GCOVPROF_H__ */
diff -r 0ca89fa82946 xen/include/public/xen.h
--- a/xen/include/public/xen.h Wed Feb 18 10:45:42 2009 +0530
+++ b/xen/include/public/xen.h Thu Feb 19 13:14:47 2009 +0530
@@ -80,6 +80,7 @@
#define __HYPERVISOR_sysctl 35
#define __HYPERVISOR_domctl 36
#define __HYPERVISOR_kexec_op 37
+#define __HYPERVISOR_gcovprof_op 38
/* Architecture-specific hypercall definitions. */
#define __HYPERVISOR_arch_0 48
diff -r 0ca89fa82946 xen/include/xen/config.h
--- a/xen/include/xen/config.h Wed Feb 18 10:45:42 2009 +0530
+++ b/xen/include/xen/config.h Thu Feb 19 13:14:47 2009 +0530
@@ -95,4 +95,21 @@
#define __cpuinitdata
#define __cpuinit
+#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 /* __XEN_CONFIG_H__ */
[-- Attachment #3: xen-3.2.0-gcov-v1.patch --]
[-- Type: application/octet-stream, Size: 17090 bytes --]
diff -r 8610d3bf7b25 xen/Rules.mk
--- a/xen/Rules.mk Thu Feb 19 14:08:22 2009 +0530
+++ b/xen/Rules.mk Thu Feb 19 14:40:03 2009 +0530
@@ -8,6 +8,10 @@
perfc_arrays ?= n
crash_debug ?= n
frame_pointer ?= n
+
+# xen source path to get update in .gcno files
+xen_src := $(CURDIR)
+xentree := $(if $(xen_src),$(xen_src),$(CURDIR))
XEN_ROOT=$(BASEDIR)/..
include $(XEN_ROOT)/Config.mk
@@ -59,6 +63,7 @@
ALL_OBJS-y += $(BASEDIR)/arch/$(TARGET_ARCH)/built_in.o
CFLAGS-y += -g -D__XEN__
+CFLAGS-y += -fprofile-arcs -ftest-coverage
CFLAGS-$(XSM_ENABLE) += -DXSM_ENABLE
CFLAGS-$(FLASK_ENABLE) += -DFLASK_ENABLE -DXSM_MAGIC=0xf97cff8c
CFLAGS-$(FLASK_ENABLE) += -DFLASK_DEVELOP -DFLASK_BOOTPARAM -DFLASK_AVC_STATS
@@ -120,7 +125,9 @@
$(MAKE) -f $(BASEDIR)/Rules.mk -C $* clean
%.o: %.c $(HDRS) Makefile
- $(CC) $(CFLAGS) -c $< -o $@
+ $(CC) $(CFLAGS) -c -o $@ \
+ $(if $(filter-out /%,$<),$(xentree)/$<,$<)
+
%.o: %.S $(AHDRS) Makefile
$(CC) $(AFLAGS) -c $< -o $@
diff -r 8610d3bf7b25 xen/arch/x86/mm/hap/Makefile
--- a/xen/arch/x86/mm/hap/Makefile Thu Feb 19 14:08:22 2009 +0530
+++ b/xen/arch/x86/mm/hap/Makefile Thu Feb 19 14:40:03 2009 +0530
@@ -3,8 +3,17 @@
obj-y += guest_walk_3level.o
obj-y += guest_walk_4level.o
+LN = /bin/ln
+xen_src := $(CURDIR)
+xentree := $(if $(xen_src),$(xen_src),$(CURDIR))
+
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 $(HDRS) Makefile
- $(CC) $(CFLAGS) $(call guest_walk_defns,$(@F)) -c $< -o $@
+ $(CC) $(CFLAGS) $(call guest_walk_defns,$(@F)) -c -o $@ \
+ $(if $(filter-out /%,$<),$(xentree)/$<,$<)
+ $(LN) -f -s guest_walk.c guest_walk_$(exp)
+
diff -r 8610d3bf7b25 xen/arch/x86/mm/shadow/Makefile
--- a/xen/arch/x86/mm/shadow/Makefile Thu Feb 19 14:08:22 2009 +0530
+++ b/xen/arch/x86/mm/shadow/Makefile Thu Feb 19 14:40:03 2009 +0530
@@ -6,10 +6,16 @@
obj-$(x86_64) += common.o g4_on_s4.o g3_on_s3.o g2_on_s3.o
+LN = /bin/ln
+num=$*.c
+
guest_levels = $(subst g,,$(filter g%,$(subst ., ,$(subst _, ,$(1)))))
shadow_levels = $(subst s,,$(filter s%,$(subst ., ,$(subst _, ,$(1)))))
shadow_defns = -DGUEST_PAGING_LEVELS=$(call guest_levels,$(1)) \
-DSHADOW_PAGING_LEVELS=$(call shadow_levels,$(1))
g%.o: multi.c $(HDRS) Makefile
- $(CC) $(CFLAGS) $(call shadow_defns,$(@F)) -c $< -o $@
+ $(CC) $(CFLAGS) $(call shadow_defns,$(@F)) -c -o $@ \
+ $(if $(filter-out /%,$@),$(xentree)/$<,$<)
+ $(LN) -f -s multi.c g$(num)
+
diff -r 8610d3bf7b25 xen/arch/x86/x86_32/entry.S
--- a/xen/arch/x86/x86_32/entry.S Thu Feb 19 14:08:22 2009 +0530
+++ b/xen/arch/x86/x86_32/entry.S Thu Feb 19 14:40:03 2009 +0530
@@ -682,6 +682,7 @@
.long do_sysctl /* 35 */
.long do_domctl
.long do_kexec_op
+ .long do_gcovprof_op
.rept NR_hypercalls-((.-hypercall_table)/4)
.long do_ni_hypercall
.endr
@@ -725,6 +726,7 @@
.byte 1 /* do_sysctl */ /* 35 */
.byte 1 /* do_domctl */
.byte 2 /* do_kexec_op */
+ .byte 3 /* do_gcovprof_op */
.rept NR_hypercalls-(.-hypercall_args_table)
.byte 0 /* do_ni_hypercall */
.endr
diff -r 8610d3bf7b25 xen/common/Makefile
--- a/xen/common/Makefile Thu Feb 19 14:08:22 2009 +0530
+++ b/xen/common/Makefile Thu Feb 19 14:40:03 2009 +0530
@@ -26,6 +26,7 @@
obj-y += vsprintf.o
obj-y += xmalloc.o
obj-y += rcupdate.o
+obj-y += xen-gcov-core.o
obj-$(perfc) += perfc.o
obj-$(crash_debug) += gdbstub.o
@@ -41,6 +42,8 @@
subdir-y += libelf
+CFLAGS += -DSRC_PATH='"$(BASEDIR)"'
+
# Object file contains changeset and compiler information.
version.o: $(BASEDIR)/include/xen/compile.h
diff -r 8610d3bf7b25 xen/common/xen-gcov-core.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/common/xen-gcov-core.c Thu Feb 19 14:40:03 2009 +0530
@@ -0,0 +1,242 @@
+/**
+ * xen-gcov-core.c: arch dependent code for hypervisor profiling
+ *
+ * Written by tej parkash and team(tej.parkash@xxxxxx)
+ *
+ */
+/***************************************************************************/
+#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:"
+
+static int num_xen_files;
+gcov_unsigned_t gcov_version = 0;
+struct gcov_info *bb_head;
+
+struct ctor_list {
+ unsigned long num;
+ ctor_t ctor[];
+};
+extern struct ctor_list __CTOR_LIST__;
+
+
+static inline int
+counter_active(struct gcov_info *bb, unsigned int type)
+{
+ return (1 << type) & bb->ctr_mask;
+}
+
+static inline unsigned int
+get_fn_stride(struct gcov_info *bb)
+{
+ unsigned int stride;
+
+ stride = sizeof(struct gcov_fn_info) + 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;
+}
+
+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));
+}
+
+static void reset_gcda(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++;
+ }
+}
+
+/* Function to reset the bb counter. */
+static int reset_bb(XEN_GUEST_HANDLE(void) arg, int val)
+{
+ struct gcov_info *tmp=bb_head;
+ char bb_file[100];
+ if ( val == 0){
+ /* 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_gcda(tmp);
+ break;
+ }
+ else
+ continue;
+ }
+ }
+ else {
+ /* reset all data files */
+ for(;tmp!=NULL;tmp=tmp->next)
+ reset_gcda(tmp);
+ }
+ return 0;
+}
+
+
+/*copy bb_head info */
+
+static int start_prof(XEN_GUEST_HANDLE(void) arg, int val)
+{
+ /*Add the code to copy the no of files to be add to xen */
+ struct xen_gcov_info bb_tmp;
+ struct gcov_info *tmp = bb_head;
+ struct gcov_fn_info *func;
+ struct gcov_ctr_info *ctr;
+ struct xen_gcov_ctr_info *xctr;
+ struct xen_gcov_info *bb = &bb_tmp;
+ int i,j;
+
+ if ( copy_from_guest(&bb_tmp, arg, 1) )
+ return -EFAULT;
+ for(;tmp!=NULL&&bb!=NULL;tmp=tmp->next){
+ ctr = tmp->counts;
+ xctr = bb->counts;
+ memcpy(bb->counts[0].values, ctr->values, ctr->num*sizeof(gcov_type));
+ xctr->num = ctr->num;
+ xctr->merge = ctr->merge;
+ bb->version = tmp->version;
+ bb->stamp = tmp->stamp;
+ safe_strcpy(bb->file, tmp->filename);
+ bb->ctr_mask = tmp->ctr_mask;
+ bb->n_functions = tmp->n_functions;
+ for(i=0;i<tmp->n_functions;i++) {
+ func = get_fn_info(tmp,i);
+ bb->functions[i].ident=func->ident;
+ bb->functions[i].checksum=func->checksum;
+ for (j=0;j<GCOV_COUNTERS;j++) {
+ bb->functions[i].n_ctrs[j]=func->n_ctrs[j];
+ }
+ }
+ /*increment the bb_head pointers*/
+ bb=bb->next;
+ }
+ if ( copy_to_guest(arg, &bb_tmp, 1) )
+ return -EFAULT;
+ return 0;
+}
+
+
+static int var_info(XEN_GUEST_HANDLE(void) arg,int val)
+{
+ struct gcov_variables gcov_var;
+ struct gcov_variables *tmp=&gcov_var;
+ struct gcov_info *bb;
+ int i;
+ if( copy_from_guest(&gcov_var, arg, 1) )
+ return -EFAULT;
+ if ( val == 0 ) {
+ safe_strcpy(tmp->src_path,SRC_PATH);
+ tmp->g_version=gcov_version;
+ tmp->n_files=num_xen_files;
+ } else {
+ for(i=0,bb=bb_head;bb!=NULL;bb=bb->next,i++){
+ tmp->ctr_num[i]=bb->counts->num;
+ tmp->n_funcs[i]=bb->n_functions;
+ }
+ }
+
+ if( copy_to_guest(arg, &gcov_var, 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_seek_vars:
+ /*fun seeks vars to be used by proc code */
+ ret = var_info(arg, val);
+ break;
+ case GCOVPROF_start:
+ /*update linux kernel with profiling info */
+ ret = start_prof(arg,val);
+ break;
+ case GCOVPROF_reset:
+ /*reset the gcda or vmlinux*/
+ ret = reset_bb(arg,val);
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+ return ret;
+}
+
+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] ();
+}
+
+ /*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)
+{
+ num_xen_files = __CTOR_LIST__.num;
+ do_global_ctors(__CTOR_LIST__.ctor, __CTOR_LIST__.num);
+ printk(KERN_INFO XEN_GCOV_CORE "init done\n");
+ return 0;
+}
+
+/* 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);
+__initcall(gcov_init);
diff -r 8610d3bf7b25 xen/include/public/xen-gcov.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/public/xen-gcov.h Thu Feb 19 14:40:03 2009 +0530
@@ -0,0 +1,139 @@
+/******************************************************************************
+ * 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@xxxxxx>
+ * 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_seek_vars 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 */
+};
+
+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. */
+};
+
+/* 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 */
+ const 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. */
+};
+
+
+struct xen_gcov_fn_info{
+ gcov_unsigned_t ident; /* unique ident of function */
+ gcov_unsigned_t checksum; /* function checksum */
+ unsigned int n_ctrs[GCOV_COUNTERS]; /* instrumented counters */
+};
+typedef struct xen_gcov_fn_info xen_gcov_fn_info_t;
+DEFINE_XEN_GUEST_HANDLE(xen_gcov_fn_info_t);
+
+
+
+struct xen_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 xen_gcov_ctr_info xen_gcov_ctr_info_t;
+DEFINE_XEN_GUEST_HANDLE(xen_gcov_ctr_info_t);
+
+/* Information about a single object file. */
+struct xen_gcov_info
+{
+ gcov_unsigned_t version; /* expected version number */
+ struct xen_gcov_info *next; /* link to next, used by libgcov */
+
+ gcov_unsigned_t stamp; /* uniquifying time stamp */
+ char file[100];
+
+ unsigned int n_functions; /* number of functions */
+ struct xen_gcov_fn_info *functions; /* table of functions */
+
+ unsigned int ctr_mask; /* mask of counters instrumented. */
+ struct xen_gcov_ctr_info counts[GCOV_COUNTERS]; /* count data.*/
+};
+typedef struct xen_gcov_info xen_gcov_info_t;
+DEFINE_XEN_GUEST_HANDLE(xen_gcov_info_t);
+
+struct gcov_variables
+{
+ char src_path[100];
+ unsigned long g_version;
+ unsigned int n_files;
+ gcov_unsigned_t *ctr_num;
+ unsigned int *n_funcs;
+};
+typedef struct gcov_variables gcov_variables_t;
+DEFINE_XEN_GUEST_HANDLE(gcov_variables_t);
+
+#endif /* __XEN_PUBLIC_GCOVPROF_H__ */
diff -r 8610d3bf7b25 xen/include/xen/config.h
--- a/xen/include/xen/config.h Thu Feb 19 14:08:22 2009 +0530
+++ b/xen/include/xen/config.h Thu Feb 19 14:40:03 2009 +0530
@@ -96,4 +96,20 @@
#define __cpuinitdata
#define __cpuinit
+#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 /* __XEN_CONFIG_H__ */
[-- Attachment #4: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2009-02-19 16:04 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <f1c9d250902172003u22ec4977u852a87ecc4f6a930@mail.gmail.com>
[not found] ` <C5C17211.2D71%keir.fraser@eu.citrix.com>
2009-02-18 16:58 ` [RFC][PATCH] Hypervisor profiling using GCOV Tej
2009-02-19 14:53 ` George Dunlap
2009-02-19 16:04 ` Tej
2009-02-16 16:36 Tej
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.