diff -r efa1b905d893 xen/Rules.mk --- a/xen/Rules.mk Tue May 04 13:59:55 2010 +0100 +++ b/xen/Rules.mk Thu May 06 06:53:09 2010 +0530 @@ -10,6 +10,14 @@ crash_debug ?= n gdbsx ?= n frame_pointer ?= n +# gcov profiler build for xen hypervisor only +gcov ?= n + +# xen source path to get update in .gcno files +ifeq ($(gcov),y) +xen_src := $(CURDIR) +xentree := $(if $(xen_src),$(xen_src),$(CURDIR)) +endif XEN_ROOT=$(BASEDIR)/.. include $(XEN_ROOT)/Config.mk @@ -43,6 +51,7 @@ ALL_OBJS-$(x86) += $(BASEDIR)/crypto/built_in.o CFLAGS-y += -g -D__XEN__ +CFLAGS-$(gcov) += -fprofile-arcs -ftest-coverage -DCONFIG_XEN_GCOV CFLAGS-$(XSM_ENABLE) += -DXSM_ENABLE CFLAGS-$(FLASK_ENABLE) += -DFLASK_ENABLE -DXSM_MAGIC=0xf97cff8c CFLAGS-$(FLASK_ENABLE) += -DFLASK_DEVELOP -DFLASK_BOOTPARAM -DFLASK_AVC_STATS @@ -107,12 +116,17 @@ .PHONY: clean clean:: $(addprefix _clean_, $(subdir-all)) - rm -f *.o *~ core $(DEPS) + rm -f *.o *.gcno *~ core $(DEPS) _clean_%/: FORCE $(MAKE) -f $(BASEDIR)/Rules.mk -C $* clean %.o: %.c Makefile +ifeq ($(gcov),y) + $(CC) $(CFLAGS) -c -o $@ \ + $(if $(filter-out /%,$<),$(xentree)/$<,$<) +else $(CC) $(CFLAGS) -c $< -o $@ +endif %.o: %.S Makefile $(CC) $(AFLAGS) -c $< -o $@ diff -r efa1b905d893 xen/arch/x86/mm/Makefile --- a/xen/arch/x86/mm/Makefile Tue May 04 13:59:55 2010 +0100 +++ b/xen/arch/x86/mm/Makefile Thu May 06 06:53:09 2010 +0530 @@ -10,5 +10,18 @@ obj-y += mem_paging.o obj-y += mem_sharing.o +LN = /bin/ln +num=$*.c + guest_walk_%.o: guest_walk.c Makefile +ifeq ($(gcov),y) + $(CC) $(CFLAGS) -DGUEST_PAGING_LEVELS=$* -c -o $@ \ + $(if $(filter-out /%,$<),$(xentree)/$<,$<) + $(LN) -f -s guest_walk.c guest_walk_$(num) +else $(CC) $(CFLAGS) -DGUEST_PAGING_LEVELS=$* -c $< -o $@ +endif + +.PHONY: clean +clean:: + rm -f guest_walk_*.c diff -r efa1b905d893 xen/arch/x86/mm/hap/Makefile --- a/xen/arch/x86/mm/hap/Makefile Tue May 04 13:59:55 2010 +0100 +++ b/xen/arch/x86/mm/hap/Makefile Thu May 06 06:53:09 2010 +0530 @@ -4,8 +4,22 @@ obj-y += guest_walk_4level.o obj-y += p2m-ept.o +LN = /bin/ln + guest_levels = $(subst level,,$(filter %level,$(subst ., ,$(subst _, ,$(1))))) guest_walk_defns = -DGUEST_PAGING_LEVELS=$(call guest_levels,$(1)) +num = $(call guest_levels,$(@F))level.c + guest_walk_%level.o: guest_walk.c Makefile +ifeq ($(gcov),y) + $(CC) $(CFLAGS) $(call guest_walk_defns,$(@F)) -c -o $@ \ + $(if $(filter-out /%,$<),$(xentree)/$<,$<) + $(LN) -f -s guest_walk.c guest_walk_$(num) +else $(CC) $(CFLAGS) $(call guest_walk_defns,$(@F)) -c $< -o $@ +endif + +.PHONY: clean +clean:: + rm -f guest_walk_*.c diff -r efa1b905d893 xen/arch/x86/mm/shadow/Makefile --- a/xen/arch/x86/mm/shadow/Makefile Tue May 04 13:59:55 2010 +0100 +++ b/xen/arch/x86/mm/shadow/Makefile Thu May 06 06:53:09 2010 +0530 @@ -1,5 +1,18 @@ obj-$(x86_32) += common.o guest_2.o guest_3.o obj-$(x86_64) += common.o guest_2.o guest_3.o guest_4.o +LN = /bin/ln +num=$*.c + guest_%.o: multi.c Makefile +ifeq ($(gcov),y) + $(CC) $(CFLAGS) -DGUEST_PAGING_LEVELS=$* -c -o $@ \ + $(if $(filter-out /%,$<),$(xentree)/$<,$<) + $(LN) -f -s multi.c guest_$(num) +else $(CC) $(CFLAGS) -DGUEST_PAGING_LEVELS=$* -c $< -o $@ +endif + +.PHONY: clean +clean:: + rm -f guest_*.c diff -r efa1b905d893 xen/arch/x86/x86_32/entry.S --- a/xen/arch/x86/x86_32/entry.S Tue May 04 13:59:55 2010 +0100 +++ b/xen/arch/x86/x86_32/entry.S Thu May 06 06:53:09 2010 +0530 @@ -706,6 +706,9 @@ .long do_domctl .long do_kexec_op .long do_tmem_op +#ifdef CONFIG_XEN_GCOV + .long do_gcovprof_op +#endif .rept __HYPERVISOR_arch_0-((.-hypercall_table)/4) .long do_ni_hypercall .endr @@ -754,6 +757,9 @@ .byte 1 /* do_domctl */ .byte 2 /* do_kexec_op */ .byte 1 /* do_tmem_op */ +#ifdef CONFIG_XEN_GCOV + .byte 3 /* do_gcovprof_op */ +#endif .rept __HYPERVISOR_arch_0-(.-hypercall_args_table) .byte 0 /* do_ni_hypercall */ .endr diff -r efa1b905d893 xen/arch/x86/x86_64/entry.S --- a/xen/arch/x86/x86_64/entry.S Tue May 04 13:59:55 2010 +0100 +++ b/xen/arch/x86/x86_64/entry.S Thu May 06 06:53:09 2010 +0530 @@ -695,6 +695,9 @@ .quad do_domctl .quad do_kexec_op .quad do_tmem_op +#ifdef CONFIG_XEN_GCOV + .quad do_gcovprof_op +#endif .rept __HYPERVISOR_arch_0-((.-hypercall_table)/8) .quad do_ni_hypercall .endr @@ -743,6 +746,9 @@ .byte 1 /* do_domctl */ .byte 2 /* do_kexec */ .byte 1 /* do_tmem_op */ +#ifdef CONFIG_XEN_GCOV + .byte 3 /* do_gcovprof_op */ +#endif .rept __HYPERVISOR_arch_0-(.-hypercall_args_table) .byte 0 /* do_ni_hypercall */ .endr diff -r efa1b905d893 xen/common/Makefile --- a/xen/common/Makefile Tue May 04 13:59:55 2010 +0100 +++ b/xen/common/Makefile Thu May 06 06:53:09 2010 +0530 @@ -40,6 +40,7 @@ obj-$(CONFIG_X86) += decompress.o bunzip2.o unlzma.o +obj-$(gcov) += xen-gcov-core.o obj-$(perfc) += perfc.o obj-$(crash_debug) += gdbstub.o obj-$(xenoprof) += xenoprof.o @@ -53,3 +54,6 @@ subdir-$(ia64) += hvm subdir-y += libelf + +CFLAGS += -DSRC_PATH='"$(BASEDIR)"' + diff -r efa1b905d893 xen/common/xen-gcov-core.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/common/xen-gcov-core.c Thu May 06 06:53:09 2010 +0530 @@ -0,0 +1,389 @@ +/** + * xen-gcov-core.c: arch dependent code for hypervisor profiling + * + * Written by tej parkash and team(tej.parkash@xxxxxx) + * + */ +/***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define XEN_GCOV_CORE "xen-gcov-core:" +#define FILE_SIZE 100 + +/* No of XEN source files to profile */ +static int num_xen_files; + +gcov_unsigned_t gcov_version = 0; + +/* List head for gcov_info structure list */ +struct gcov_info *bb_head; + +/* head of xen-gcov-info linked list */ +struct gcov_info *bb_list_head = NULL; + + +/* global constructor list */ +struct ctor_list +{ + unsigned long num; + ctor_t ctor[]; +}; + +/* Start of global constructor list. */ +extern struct ctor_list __CTOR_LIST__; + +/* + * Determine whether counter TYPE is active in list node + * For gcc 3.4 to 4.3 only counter 0 will be active + * + */ +static inline int +counter_active(struct gcov_info *bb, unsigned int type) +{ + return (1 << type) & bb->ctr_mask; +} + +/* Return the number of active counter types for BB. */ +static inline unsigned int +num_counter_active(struct gcov_info *bb) +{ + unsigned int i; + unsigned int result; + + result = 0; + for (i=0; i < GCOV_COUNTERS; i++) + if (counter_active(bb, i)) + result++; + return result; +} + +/* + * Get number of bytes used for one entry in the gcov_fn_info array pointed to + * by BB->functions. + */ +static inline unsigned int +get_fn_stride(struct gcov_info *bb) +{ + unsigned int stride; + + stride = sizeof(struct gcov_fn_info) + num_counter_active(bb)* + sizeof(unsigned int); + if (__alignof__(struct gcov_fn_info) > sizeof(unsigned int)) + { + stride += __alignof__(struct gcov_fn_info) - 1; + stride &= ~(__alignof__(struct gcov_fn_info) - 1); + } + return stride; +} + +/* Get the address of gcov_fn_info for function FUNC of BB. */ +static inline struct gcov_fn_info * +get_fn_info(struct gcov_info *bb, unsigned int func) +{ + return (struct gcov_fn_info *) + ((char *)bb->functions + func * get_fn_stride(bb)); +} + +/* Reset the execution count values on each list node */ +static void reset(struct gcov_info *bb) +{ + + unsigned int i; + struct gcov_ctr_info *ctr; + ctr = bb->counts; + for (i=0; i < GCOV_COUNTERS; i++) + { + if (counter_active(bb, i)) + { + memset(ctr->values, 0, ctr->num * sizeof(gcov_type)); + ctr++; + } + } +} + + +/* + * Create xen_gcov_info linked list by accessing kernel nodes + * based on num of xen file to be profiled, This list act + * as temporary variable between Xen bb_head and kernel list_head + */ + +static inline int create_bb_list(void) +{ + struct gcov_info *node = NULL, *tmp_node = NULL, *bb = bb_head; + int i, j, len=0, active, len1=0; + + for (i = 0; i < num_xen_files; i++) + { + /* Allocate memory for struct gcov_info */ + active = num_counter_active(bb); + len = sizeof(struct gcov_info) + sizeof(struct gcov_ctr_info)*active; + node = (struct gcov_info *) xmalloc_bytes(len); + for (j=0; j < active; j++) + { + len1 = sizeof(gcov_type) *bb->counts[j].num; + node->counts[j].values = xmalloc_bytes(len1); + memset(node->counts[j].values, 0, len1); + } + + /* Allocate memory for array of struct gcov_fn_info */ + len = (sizeof(struct gcov_fn_info) + active*sizeof(unsigned int)) * + bb->n_functions; + node->functions = (struct gcov_fn_info *) xmalloc_bytes(len); + node->filename = (char *) xmalloc_bytes(FILE_SIZE*sizeof(char)); + node->next = NULL; + + if (bb_list_head == NULL) + { + bb_list_head = node; + tmp_node = node; + } + else + { + tmp_node->next = node; + tmp_node = node; + } + bb = bb->next; + } + + return 0; +} + + +/* + * Func to reset the execution counts. Reset all nodes count + * if mul defined else reset single file count specified in arg. + */ + +static int reset_counts(XEN_GUEST_HANDLE(void) arg, int mul) +{ + struct gcov_info *tmp=bb_head; + char bb_file[100]; + + if (!mul) + { + /* reset single data file */ + if ( copy_from_guest(&bb_file, arg, 1) ) + return -EFAULT; + for(;tmp!=NULL;tmp=tmp->next) + { + if(!strcmp(tmp->filename, bb_file)) + { + reset(tmp); + break; + } + else + continue; + } + } + else + { + /* reset all data files */ + for(;tmp!=NULL;tmp=tmp->next) + reset(tmp); + } + return 0; +} + +/* + * Func copies metadata in each gcov_info list nodes to guest. + * with this metadeta, guest populates and update the /proc + * with gcov data files (*.gcda) + */ + +static int ret_profiled_data(XEN_GUEST_HANDLE(void) arg, int val) +{ + struct gcov_info *bb, *tmp = bb_head; + struct gcov_fn_info *func,*fn_ptr; + int i, j, active,len; + + bb = bb_list_head; + if (copy_from_guest(bb_list_head, arg, 1)) + return -EFAULT; + + /* iterate through list nodes to copy metadata in Guest nodes*/ + for(;tmp!=NULL, bb!=NULL; tmp = tmp->next) + { + + bb->version = tmp->version; + bb->stamp = tmp->stamp; + len=strlen(tmp->filename)+1; + memcpy(bb->filename, tmp->filename,sizeof(char)*len); + bb->ctr_mask = tmp->ctr_mask; + bb->n_functions = tmp->n_functions; + + + active= num_counter_active(tmp); + /* Copy functions data */ + for(i=0;in_functions;i++) + { + fn_ptr= get_fn_info(bb,i); + func = get_fn_info(tmp,i); + fn_ptr->ident=func->ident; + fn_ptr->checksum=func->checksum; + for (j=0;j< active;j++) + fn_ptr->n_ctrs[j]=func->n_ctrs[j]; + } + + /* Copy count data */ + for (i=0; i < active; i++) { + bb->counts[i].num = tmp->counts[i].num; + bb->counts[i].merge = tmp->counts[i].merge; + len = sizeof(gcov_type)*tmp->counts[i].num; + memcpy(bb->counts[i].values, tmp->counts[i].values, len); + } + /*increment the bb_head pointers*/ + bb=bb->next; + } + + if ( copy_to_guest(arg, bb_list_head, 1) ) + return -EFAULT; + + return 0; +} + +/* + * Func to retrieve the inital gcov core information + * by Kernel + * e.g source path, no. of files etc. + */ + +static int info_to_guest(XEN_GUEST_HANDLE(void) arg,int num) +{ + + struct gcov_info *bb = bb_head; + node_info_t *tmp = xmalloc(struct node_info); + int i, j, active; + + if( copy_from_guest(tmp, arg, 1) ) + return -EFAULT; + if ( num == 0 ) + { + safe_strcpy(tmp->src_path,SRC_PATH); + tmp->g_version=gcov_version; + tmp->n_files=num_xen_files; + + /* Create the bb_list_head */ + create_bb_list(); + } + else + { + for(i=0;in_funcs[i]=bb->n_functions; + active=num_counter_active(bb); + tmp->active_counters[i]= active; + for(j=0; jctr_num[i][j]= bb->counts[j].num; + } + + bb=bb->next; + } + } + + if( copy_to_guest(arg, tmp, 1) ) + return -EFAULT; + + + return 0; +} + +/*internal hyercall functions*/ +int do_gcovprof_op(int op, XEN_GUEST_HANDLE(void) arg, int val) +{ + int ret = 0; + if ((op < 0) || (op > GCOVPROF_last_op)) + { + printk(KERN_ERR XEN_GCOV_CORE "Invalid operation %d\n", op); + return -EINVAL; + } + switch (op) + { + case GCOVPROF_get_info: + ret = info_to_guest(arg, val); + break; + + case GCOVPROF_start: + ret = ret_profiled_data(arg,val); + break; + + case GCOVPROF_reset: + ret = reset_counts(arg,val); + break; + + default: + ret = -ENOSYS; + } + return ret; +} + +/* + * Call constructors and create gcov_info linked list + * List contains metadeta to construct gcov data files + * e.g data file name, execution counts etc. + */ +void do_global_ctors(ctor_t ctor[], unsigned long num) +{ + unsigned long i; + + /* Call constructors and create gcov_info linked list*/ + for (i = 0; i < num && ctor[i]; i++) + ctor[i] (); + /* Holds number of executable scanned by constructor */ + num_xen_files = i-1; +} + + +/*Register supplied struct BB. Called by each object code constructor. */ +void __gcov_init(struct gcov_info *bb) +{ + if (!bb->version) + return; + /*Check for compatible gcc version */ + if (gcov_version == 0) + gcov_version = bb->version; + else if (bb->version != gcov_version) + { + printk(KERN_WARNING XEN_GCOV_CORE "gcc version mismatch in " + "file '%s'!\n", bb->filename); + return; + } + /*Set up linked list */ + bb->version = 0; + bb->next = bb_head; + bb_head = bb; + +} + +static int __init gcov_init(void) +{ + do_global_ctors(__CTOR_LIST__.ctor, __CTOR_LIST__.num); + printk(KERN_INFO XEN_GCOV_CORE "init done\n"); + return 0; +} + +__initcall(gcov_init); + +/* Unused functions needed to prevent linker errors. */ +void __gcov_flush(void) {} +void __gcov_merge_add(gcov_type * counters, unsigned int n_counters){} +void __gcov_merge_single(gcov_type * counters, unsigned int n_counters){} +void __gcov_merge_delta(gcov_type * counters, unsigned int n_counters){} + +EXPORT_SYMBOL(__gcov_init); +EXPORT_SYMBOL(do_global_ctors); +EXPORT_SYMBOL(__gcov_flush); +EXPORT_SYMBOL(__gcov_merge_add); +EXPORT_SYMBOL(__gcov_merge_single); +EXPORT_SYMBOL(__gcov_merge_delta); diff -r efa1b905d893 xen/include/public/xen-gcov.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/public/xen-gcov.h Thu May 06 06:53:09 2010 +0530 @@ -0,0 +1,109 @@ +/****************************************************************************** + * xen-gcov.h + * + * Interface for enabling and populating hypervisor profiling info. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Author: tej parkash + * Written by tej parkash and team + * + */ +/******************************************************************************/ + +#ifndef __XEN_PUBLIC_GCOVPROF_H__ +#define __XEN_PUBLIC_GCOVPROF_H__ + +#include "xen.h" + +/* + * Commands to HYPERVISOR_gcovprof_op() + */ +#define GCOVPROF_get_info 0 +#define GCOVPROF_start 1 +#define GCOVPROF_reset 2 +#define GCOVPROF_last_op 3 + +/*gcc specific macros*/ +#define GCOV_COUNTERS 5 +#define GCOV_DATA_MAGIC ((gcov_unsigned_t) 0x67636461) +#define GCOV_TAG_FUNCTION ((gcov_unsigned_t) 0x01000000) +#define GCOV_TAG_COUNTER_BASE ((gcov_unsigned_t) 0x01a10000) +#define GCOV_TAG_FOR_COUNTER(COUNT) \ + (GCOV_TAG_COUNTER_BASE + ((gcov_unsigned_t) (COUNT) << 17)) + + +typedef unsigned gcov_unsigned_t __attribute__ ((mode (SI))); +typedef signed gcov_type __attribute__ ((mode (DI))); +typedef void (*gcov_merge_fn) (gcov_type *, gcov_unsigned_t); +typedef void (*ctor_t)(void); + +struct gcov_fn_info +{ + gcov_unsigned_t ident; /* unique ident of function */ + gcov_unsigned_t checksum; /* function checksum */ + unsigned n_ctrs[0]; /* instrumented counters */ +}; +typedef struct gcov_fn_info gcov_fn_info_t; +DEFINE_XEN_GUEST_HANDLE(gcov_fn_info_t); + +struct gcov_ctr_info +{ + gcov_unsigned_t num; /* number of counters. */ + gcov_type *values; /* their values. */ + gcov_merge_fn merge; /* The function used to merge them. */ +}; +typedef struct gcov_ctr_info gcov_ctr_info_t; +DEFINE_XEN_GUEST_HANDLE(gcov_ctr_info_t); + +/* Information about a single object file. */ +struct gcov_info +{ + gcov_unsigned_t version; /* expected version number */ + struct gcov_info *next; /* link to next, used by libgcov */ + + gcov_unsigned_t stamp; /* uniquifying time stamp */ + char *filename; + + unsigned n_functions; /* number of functions */ + struct gcov_fn_info *functions; /* table of functions */ + + unsigned ctr_mask; /* mask of counters instrumented. */ + struct gcov_ctr_info counts[0]; /* count data. The number of bits + set in the ctr_mask field + determines how big this array + is. */ +}; +typedef struct gcov_info gcov_info_t; +DEFINE_XEN_GUEST_HANDLE(gcov_info_t); + +/* info to construct guest Nodes */ +struct node_info +{ + char src_path[100]; /* xen source code path */ + unsigned long g_version; + unsigned int n_files; /* max. nodes */ + gcov_unsigned_t **ctr_num; /* count per node */ + unsigned int *n_funcs; /* funcs per node */ + unsigned int *active_counters; /* No of active gcov counters per BB */ +}; +typedef struct node_info node_info_t; +DEFINE_XEN_GUEST_HANDLE(node_info_t); + +#endif /* __XEN_PUBLIC_GCOVPROF_H__ */ diff -r efa1b905d893 xen/include/xen/config.h --- a/xen/include/xen/config.h Tue May 04 13:59:55 2010 +0100 +++ b/xen/include/xen/config.h Thu May 06 06:53:09 2010 +0530 @@ -95,4 +95,23 @@ #define __cpuinitdata #define __cpuinit +#ifdef CONFIG_XEN_GCOV +#define SORT(x) x +#define CONSTRUCTORS \ + __CTOR_LIST__ = .; \ + LONG((__CTOR_END__ - __CTOR_LIST__) / \ + (__CTOR_LIST2__ - __CTOR_LIST__) - 2) \ + __CTOR_LIST2__ = .; \ + *(SORT(.ctors)) \ + LONG(0) \ + __CTOR_END__ = .; \ + __DTOR_LIST__ = .; \ + LONG((__DTOR_END__ - __DTOR_LIST__) / \ + (__CTOR_LIST2__ - __CTOR_LIST__) - 2) \ + *(SORT(.dtors)) \ + LONG(0) \ + __DTOR_END__ = .; + +#endif /* CONFIG_XEN_GCOV */ + #endif /* __XEN_CONFIG_H__ */