-
Notifications
You must be signed in to change notification settings - Fork 11
/
parse.py
126 lines (106 loc) · 3.67 KB
/
parse.py
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
#!/usr/bin/env python2
import argparse
import os, sys
import pymongo # pip install pymongo
import fileinput
import subprocess
import re
def function(filename, name, calls, retns, blocks):
return {
'filename': filename.replace('.gcov',''),
'name': subprocess.check_output(['c++filt', name]).strip(),
'calls': calls,
'retns': retns,
'blocks': blocks,
'lines': []
}
def sourceline(lineno, source, hits):
return {
'lineno': int(lineno),
'source': source,
'hits': int(hits),
'branches': [],
'blocks': []
}
def branch(number, taken):
return {
'number': number,
'taken': taken
}
block = branch
def main():
a = argparse.ArgumentParser()
a.add_argument('name')
a.add_argument('gcov', nargs='+', metavar='file.c.gcov', help='.c.gcov file')
args = a.parse_args()
db = pymongo.MongoClient().gcov[args.name]
db.drop()
# Filter out missing files
for file in [f for f in args.gcov if not os.path.exists(f)]:
print "File %r does not exist" % file
sys.exit()
# Read input line-by-line
finput = fileinput.FileInput(args.gcov, mode='r')
func = None
for line in finput:
words = re.split('[\s:]+', line.strip())
# Reset everything on a new file or when a new function is found.
if finput.isfirstline():
if func:
if func['lines']:
func['start'] = func['lines'][0]['lineno']
db.save(func)
func = None
# Line was not executed. Fake a 'zero' count.
# -: 54:#ifndef PR_MCE_KILL_SET
if words[0] in ('#####','-','$$$$$'):
if not func:
continue
words[0] = '0'
# Line is an unconditional jump, and always taken
# Its statistics are accounted for already.
# This is only emitted with the '-u' flag
if words[0] == 'unconditional':
pass
# Function statistics
# function cpu_thread_is_idle called 38 returned 100% blocks executed 91%
elif words[0] == 'function':
if func:
if func['lines']:
func['start'] = func['lines'][0]['lineno']
db.save(func)
func = function(finput.filename(), words[1], int(words[3]), int(words[5][:-1]), int(words[-1][:-1]))
# Begin a source line
# 1: 10: if(argc == 1) {
elif words[0].isdigit() and words[1].isdigit():
count = int(words[0])
lineno = int(words[1])
source = line.split(':',2)[-1].rstrip()
func['lines'].append(sourceline(lineno, source, count))
# Begin a block within a source line
# 1: 10-block 0
elif words[1].endswith('-block'):
count = int(words[0].rstrip(':'))
number = int(words[2])
func['lines'][-1]['blocks'].append(block(number, count))
# Begin a branch within a source line
# 3: 17: x++ && x++;
# 3: 17-block 0
# branch 0 taken 3
# branch 1 taken 0
# 3: 17-block 1
# unconditional 2 taken 3
#
# branch 0 never executed
elif words[0] == 'branch':
number = int(words[1])
count = 0
if words[2] != 'never':
count = int(words[3])
func['lines'][-1]['branches'].append(branch(number, count))
else:
print "Got unknown line!\n%r" % line
sys.exit()
print "Parsed %i lines" % finput.lineno()
if __name__ == '__main__':
main()