试用内核gcov
对于2.6.31及以上的内核,gcov已经默认支持:http://kernelnewbies.org/Linux_2_6_31#head-1c98f5fae2cb7f0fa65bb6de08d7c5c6475180a8
也就是不用再打补丁,执行make menuconfig,选中如下选项:
General setup —>
GCOV-based kernel profiling —>
[*] Enable gcov-based kernel profiling
[*] Profile entire Kernel
[root@localhost linux-2.6.38.8]# cat .config | grep GCOV # GCOV-based kernel profiling CONFIG_GCOV_KERNEL=y CONFIG_GCOV_PROFILE_ALL=y [root@localhost linux-2.6.38.8]#
编译安装这个内核:
[root@localhost linux-2.6.38.8]# make; make modules;make modules_install;make install;
重启机器后,mount加载debugfs文件系统,并调用gcov对相应文件做覆盖测量:
[root@localhost ~]# mount -t debugfs none /sys/kernel/debug [root@localhost ~]# cd /usr/src/linux-2.6.38.8 [root@localhost linux-2.6.38.8]# gcov kernel/gcov/base.c -o /sys/kernel/debug/gcov/usr/src/linux-2.6.38.8/kernel/gcov/ File 'kernel/gcov/base.c' Lines executed:80.00% of 45 kernel/gcov/base.c:creating 'base.c.gcov' [root@localhost linux-2.6.38.8]#
查看结果:
[root@localhost linux-2.6.38.8]# cat base.c.gcov -: 0:Source:kernel/gcov/base.c -: 0:Graph:/sys/kernel/debug/gcov/usr/src/linux-2.6.38.8/kernel/gcov/base.gcno -: 0:Data:/sys/kernel/debug/gcov/usr/src/linux-2.6.38.8/kernel/gcov/base.gcda -: 0:Runs:0 -: 0:Programs:0 -: 1:/* -: 2: * This code maintains a list of active profiling data structures. -: 3: * -: 4: * Copyright IBM Corp. 2009 -: 5: * Author(s): Peter Oberparleiter <[email protected]> -: 6: * -: 7: * Uses gcc-internal data definitions. -: 8: * Based on the gcov-kernel patch by: -: 9: * Hubertus Franke <[email protected]> -: 10: * Nigel Hinds <[email protected]> -: 11: * Rajan Ravindran <[email protected]> -: 12: * Peter Oberparleiter <[email protected]> -: 13: * Paul Larson -: 14: */ -: 15: -: 16:#define pr_fmt(fmt) "gcov: " fmt -: 17: -: 18:#include <linux/init.h> -: 19:#include <linux/module.h> -: 20:#include <linux/mutex.h> -: 21:#include "gcov.h" -: 22: -: 23:static struct gcov_info *gcov_info_head; -: 24:static int gcov_events_enabled; -: 25:static DEFINE_MUTEX(gcov_lock); -: 26: -: 27:/* -: 28: * __gcov_init is called by gcc-generated constructor code for each object -: 29: * file compiled with -fprofile-arcs. -: 30: */ 1617: 31:void __gcov_init(struct gcov_info *info) -: 32:{ -: 33: static unsigned int gcov_version; -: 34: 1617: 35: mutex_lock(&gcov_lock); 1617: 36: if (gcov_version == 0) { 1: 37: gcov_version = info->version; -: 38: /* -: 39: * Printing gcc's version magic may prove useful for debugging -: 40: * incompatibility reports. -: 41: */ 1: 42: pr_info("version magic: 0x%x\n", gcov_version); -: 43: } -: 44: /* -: 45: * Add new profiling data structure to list and inform event -: 46: * listener. -: 47: */ 1617: 48: info->next = gcov_info_head; 1617: 49: gcov_info_head = info; 1617: 50: if (gcov_events_enabled) 257: 51: gcov_event(GCOV_ADD, info); 1617: 52: mutex_unlock(&gcov_lock); 1617: 53:} -: 54:EXPORT_SYMBOL(__gcov_init); -: 55: -: 56:/* -: 57: * These functions may be referenced by gcc-generated profiling code but serve -: 58: * no function for kernel profiling. -: 59: */ #####: 60:void __gcov_flush(void) -: 61:{ -: 62: /* Unused. */ #####: 63:} -: 64:EXPORT_SYMBOL(__gcov_flush); -: 65: #####: 66:void __gcov_merge_add(gcov_type *counters, unsigned int n_counters) -: 67:{ -: 68: /* Unused. */ #####: 69:} -: 70:EXPORT_SYMBOL(__gcov_merge_add); -: 71: #####: 72:void __gcov_merge_single(gcov_type *counters, unsigned int n_counters) -: 73:{ -: 74: /* Unused. */ #####: 75:} -: 76:EXPORT_SYMBOL(__gcov_merge_single); -: 77: #####: 78:void __gcov_merge_delta(gcov_type *counters, unsigned int n_counters) -: 79:{ -: 80: /* Unused. */ #####: 81:} -: 82:EXPORT_SYMBOL(__gcov_merge_delta); -: 83: -: 84:/** -: 85: * gcov_enable_events - enable event reporting through gcov_event() -: 86: * -: 87: * Turn on reporting of profiling data load/unload-events through the -: 88: * gcov_event() callback. Also replay all previous events once. This function -: 89: * is needed because some events are potentially generated too early for the -: 90: * callback implementation to handle them initially. -: 91: */ 1: 92:void gcov_enable_events(void) -: 93:{ -: 94: struct gcov_info *info; -: 95: 1: 96: mutex_lock(&gcov_lock); 1: 97: gcov_events_enabled = 1; -: 98: /* Perform event callback for previously registered entries. */ 1361: 99: for (info = gcov_info_head; info; info = info->next) 1360: 100: gcov_event(GCOV_ADD, info); 1: 101: mutex_unlock(&gcov_lock); 1: 102:} -: 103: -: 104:#ifdef CONFIG_MODULES -: 105:static inline int within(void *addr, void *start, unsigned long size) -: 106:{ 13666: 107: return ((addr >= start) && (addr < start + size)); -: 108:} -: 109: -: 110:/* Update list and generate events when modules are unloaded. */ 158: 111:static int gcov_module_notifier(struct notifier_block *nb, unsigned long event, -: 112: void *data) -: 113:{ 158: 114: struct module *mod = data; -: 115: struct gcov_info *info; -: 116: struct gcov_info *prev; -: 117: 158: 118: if (event != MODULE_STATE_GOING) 149: 119: return NOTIFY_OK; 9: 120: mutex_lock(&gcov_lock); 9: 121: prev = NULL; -: 122: /* Remove entries located in module from linked list. */ 13675: 123: for (info = gcov_info_head; info; info = info->next) { 27332: 124: if (within(info, mod->module_core, mod->core_size)) { 9: 125: if (prev) #####: 126: prev->next = info->next; -: 127: else 9: 128: gcov_info_head = info->next; 9: 129: if (gcov_events_enabled) 9: 130: gcov_event(GCOV_REMOVE, info); -: 131: } else 13657: 132: prev = info; -: 133: } 9: 134: mutex_unlock(&gcov_lock); -: 135: 9: 136: return NOTIFY_OK; -: 137:} -: 138: -: 139:static struct notifier_block gcov_nb = { -: 140: .notifier_call = gcov_module_notifier, -: 141:}; -: 142: 1: 143:static int __init gcov_init(void) -: 144:{ 1: 145: return register_module_notifier(&gcov_nb); -: 146:} -: 147:device_initcall(gcov_init); -: 148:#endif /* CONFIG_MODULES */ [root@localhost linux-2.6.38.8]#
试试其他文件:
[root@localhost linux-2.6.38.8]# gcov /usr/src/linux-2.6.38.8/drivers/net/e1000/e1000_main.c -o /sys/kernel/debug/gcov/usr/src/linux-2.6.38.8/drivers/net/e1000/ [root@localhost linux-2.6.38.8]# ls *.gcov atomic.h.gcov getorder.h.gcov irqflags.h.gcov skbuff.h.gcov bitops.h.gcov gfp.h.gcov kobject.h.gcov slab.h.gcov checksum_64.h.gcov highmem.h.gcov list.h.gcov slub_def.h.gcov device.h.gcov if_vlan.h.gcov mii.h.gcov spinlock.h.gcov dma-mapping-common.h.gcov interrupt.h.gcov mm.h.gcov tcp.h.gcov dma-mapping.h.gcov io.h.gcov netdevice.h.gcov thread_info.h.gcov e1000_main.c.gcov ip.h.gcov paravirt.h.gcov uaccess.h.gcov etherdevice.h.gcov ipv6.h.gcov pci.h.gcov [root@localhost linux-2.6.38.8]# head e1000_main.c.gcov -: 0:Source:drivers/net/e1000/e1000_main.c -: 0:Graph:/sys/kernel/debug/gcov/usr/src/linux-2.6.38.8/drivers/net/e1000/e1000_main.gcno -: 0:Data:/sys/kernel/debug/gcov/usr/src/linux-2.6.38.8/drivers/net/e1000/e1000_main.gcda -: 0:Runs:0 -: 0:Programs:0 -: 1:/******************************************************************************* -: 2: -: 3: Intel PRO/1000 Linux driver -: 4: Copyright(c) 1999 - 2006 Intel Corporation. -: 5: [root@localhost linux-2.6.38.8]#
的确OK。值得注意的是,不能切换当前目录,否则得到的e1000_main.c.gcov没有源代码,全是EOF(一开始,我看把我的内核源码目录 /usr/src/linux-2.6.38.8/搞得很混乱,所以切换当前目录到/tmp目录,结果发现生成的文件没有对应的源代码):
[root@localhost tmp]# head e1000_main.c.gcov -: 0:Source:drivers/net/e1000/e1000_main.c -: 0:Graph:/sys/kernel/debug/gcov/usr/src/linux-2.6.38.8/drivers/net/e1000/e1000_main.gcno -: 0:Data:/sys/kernel/debug/gcov/usr/src/linux-2.6.38.8/drivers/net/e1000/e1000_main.gcda -: 0:Runs:0 -: 0:Programs:0 -: 1:/*EOF*/ -: 2:/*EOF*/ -: 3:/*EOF*/ -: 4:/*EOF*/ -: 5:/*EOF*/
试试自定义模块:
[root@localhost module_test]# cat module_test.c #include <linux/kernel.h> #include <linux/module.h> #include <linux/netfilter.h> #include <linux/netfilter_ipv4.h> #define OOPSTIMEOUT 100 static unsigned long start_time; static unsigned int fun_hook(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { printk(KERN_DEBUG "skb data len: %u\n", skb->len); return NF_ACCEPT; } static struct nf_hook_ops nf_ops = { .hook = fun_hook, .owner = THIS_MODULE, .pf = NFPROTO_IPV4, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP_PRI_NAT_DST, }; static int __init module_test_init(void) { int ret = 0; start_time = jiffies; ret = nf_register_hook(&nf_ops); if (ret < 0) { printk("error register hook %d.\n", ret); return ret; } printk("insmod ok, start_time: %lu.\n", start_time); return 0; } static void __exit module_test_exit(void) { nf_unregister_hook(&nf_ops); return; } module_init(module_test_init); module_exit(module_test_exit); MODULE_LICENSE("GPL"); [root@localhost module_test]# cat Makefile # Makefile MDIR = $(shell pwd) ifeq (, $(KSRC)) KSRC := /usr/src/linux-`uname -r` endif ifeq (, $(PROJECT_DIR)) PROJECT_DIR := $(PWD)/../ endif module := module_test obj-m := $(module).o srcs = $(wildcard, *.c) $(module)-objs := $(addsuffix .o, $(basename $(srcs))) EXTRA_CFLAGS += -g $(FLAG) -I$(PROJECT_DIR)/inc -I${SHAREDHDR} -I$(KERNELHDR) -O2 -D__KERNEL__ -DMODULE $(INCLUDE) -DEXPORT_SYMTAB TARGET = $(module).ko all: make -C $(KSRC) M=$(MDIR) modules debug: make EXTRA_FLAGS="${EXTRA_CFLAGS} -DDEBUG" -C $(KSRC) M=$(MDIR) modules clean: make -C $(KSRC) M=$(MDIR) clean install: all cp -f $(TARGET) $(INSTALL_DIR) [root@localhost module_test]# make make -C /usr/src/linux-`uname -r` M=/home/gcov/module_test modules make[1]: Entering directory `/usr/src/linux-2.6.38.8' CC [M] /home/gcov/module_test/module_test.o Building modules, stage 2. MODPOST 1 modules CC /home/gcov/module_test/module_test.mod.o LD [M] /home/gcov/module_test/module_test.ko make[1]: Leaving directory `/usr/src/linux-2.6.38.8' [root@localhost module_test]# insmod module_test.ko
看结果:
[root@localhost module_test]# gcov /home/gcov/module_test/module_test.c -o /sys/kernel/debug/gcov/home/gcov/module_test/ File '/home/gcov/module_test/module_test.c' Lines executed:71.43% of 14 /home/gcov/module_test/module_test.c:creating 'module_test.c.gcov' [root@localhost module_test]# cat module_test.c.gcov -: 0:Source:/home/gcov/module_test/module_test.c -: 0:Graph:/sys/kernel/debug/gcov/home/gcov/module_test/module_test.gcno -: 0:Data:/sys/kernel/debug/gcov/home/gcov/module_test/module_test.gcda -: 0:Runs:0 -: 0:Programs:0 -: 1: -: 2:#include <linux/kernel.h> -: 3:#include <linux/module.h> -: 4:#include <linux/netfilter.h> -: 5:#include <linux/netfilter_ipv4.h> -: 6: -: 7:#define OOPSTIMEOUT 100 -: 8:static unsigned long start_time; -: 9: 37: 10:static unsigned int fun_hook(unsigned int hooknum, -: 11: struct sk_buff *skb, -: 12: const struct net_device *in, -: 13: const struct net_device *out, -: 14: int (*okfn)(struct sk_buff *)) -: 15:{ 37: 16: printk(KERN_DEBUG "skb data len: %u\n", skb->len); -: 17: 37: 18: return NF_ACCEPT; -: 19:} -: 20: -: 21:static struct nf_hook_ops nf_ops = { -: 22: .hook = fun_hook, -: 23: .owner = THIS_MODULE, -: 24: .pf = NFPROTO_IPV4, -: 25: .hooknum = NF_INET_PRE_ROUTING, -: 26: .priority = NF_IP_PRI_NAT_DST, -: 27:}; -: 28: 1: 29:static int __init module_test_init(void) -: 30:{ 1: 31: int ret = 0; 1: 32: start_time = jiffies; -: 33: 1: 34: ret = nf_register_hook(&nf_ops); 1: 35: if (ret < 0) { #####: 36: printk("error register hook %d.\n", ret); #####: 37: return ret; -: 38: } 1: 39: printk("insmod ok, start_time: %lu.\n", start_time); -: 40: 1: 41: return 0; -: 42:} -: 43: #####: 44:static void __exit module_test_exit(void) -: 45:{ #####: 46: nf_unregister_hook(&nf_ops); -: 47: return; -: 48:} -: 49: -: 50:module_init(module_test_init); -: 51:module_exit(module_test_exit); -: 52: -: 53:MODULE_LICENSE("GPL"); -: 54: [root@localhost module_test]#
完全参考:http://ltp.sourceforge.net/coverage/gcov.php
转载请保留地址:http://lenky.info/archives/2012/08/24/1888 或 http://lenky.info/?p=1888
备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。
法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以或书面等方式告知,本站将及时删除相关内容或链接。
@lenky
嗯 我试下 谢了
by the way:
博客不错哦 特别是回复评论这么及时 赞
@lenky
嗯 我试下 谢了
by the way:
博客不错哦 特别是回复评论这么及时 赞
@lenky
我用ubuntu 12.10 自带的gcc 版本为gcc-4.7.3 编译内核版本为 3.4.57 /sys/kernel/debug/gcov目录下也是只有reset文件,
我换成ubuntu 10.04 自带的gcc 版本为 gcc-4.4.3 编译内核版本一样 /sys/kernel/debug/gcov目录下 就出现源文件目录
其他操作都一样,这是为什么了? 按道理向后兼容撒
呵 不清楚 如果怀疑是gcc问题 那你在ubantu上试试4.4.3
@lenky
请问 你用的gcc版本是多少?
这个不记得了, 但应该是CENTOS 6.0发行版上的gcc包。
@robin
确定前面几个步骤都做对了么?
为什么我的内核/sys/kernel/debug/gcov 下面只有reset, 没有内核目录
为什么我的内核/sys/kernel/debug/gcov 下面只有debug, 没有内核目录