首页 > *nix技术, 内核技术, 跟踪调试 > 试用内核gcov

试用内核gcov

2012年8月24日 发表评论 阅读评论 8,425 次浏览

对于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 <oberpar@linux.vnet.ibm.com>
        -:    6: *
        -:    7: *    Uses gcc-internal data definitions.
        -:    8: *    Based on the gcov-kernel patch by:
        -:    9: *		 Hubertus Franke <frankeh@us.ibm.com>
        -:   10: *		 Nigel Hinds <nhinds@us.ibm.com>
        -:   11: *		 Rajan Ravindran <rajancr@us.ibm.com>
        -:   12: *		 Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
        -:   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://www.lenky.info/archives/2012/08/1888http://lenky.info/?p=1888


备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。

法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以Email或书面等方式告知,本站将及时删除相关内容或链接。

  1. brookie
    2013年8月19日16:25 | #1

    @lenky
    嗯 我试下 谢了
    by the way:
    博客不错哦 特别是回复评论这么及时 赞

  2. brookie
    2013年8月19日16:06 | #2

    @lenky
    嗯 我试下 谢了
    by the way:
    博客不错哦 特别是回复评论这么及时 赞

  3. brookie
    2013年8月19日15:48 | #3

    @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目录下 就出现源文件目录
    其他操作都一样,这是为什么了? 按道理向后兼容撒

    • lenky
      2013年8月19日15:52 | #4

      呵 不清楚 如果怀疑是gcc问题 那你在ubantu上试试4.4.3

  4. brookie
    2013年8月19日14:52 | #5

    @lenky
    请问 你用的gcc版本是多少?

    • lenky
      2013年8月19日15:01 | #6

      这个不记得了, 但应该是CENTOS 6.0发行版上的gcc包。

  5. lenky
    2012年12月9日03:22 | #7

    @robin
    确定前面几个步骤都做对了么?

  6. 2012年12月8日14:45 | #8

    为什么我的内核/sys/kernel/debug/gcov 下面只有reset, 没有内核目录

  7. 2012年12月8日11:47 | #9

    为什么我的内核/sys/kernel/debug/gcov 下面只有debug, 没有内核目录

  1. 本文目前尚无任何 trackbacks 和 pingbacks.