http://www.lenky.info/archives/2012/08/1888
对于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
1
2
3
4
5
|
[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]#
|
编译安装这个内核:
1
|
[root@localhost linux-2.6.38.8]# make; make modules;make modules_install;make install;
|
重启机器后,mount加载debugfs文件系统,并调用gcov对相应文件做覆盖测量:
1
2
3
4
5
6
7
8
|
[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]#
|
查看结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
[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]#
|
试试其他文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
[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目录,结果发现生成的文件没有对应的源代码):
1
2
3
4
5
6
7
8
9
10
11
|
[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*/
|
试试自定义模块:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
[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
|
看结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
[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/1888 或 http://lenky.info/?p=1888
备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来信讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。
法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以Email或书面等方式告知,本站将及时删除相关内容或链接。