OpenCores
URL https://opencores.org/ocsvn/s80186/s80186/trunk

Subversion Repositories s80186

[/] [s80186/] [trunk/] [scripts/] [verilator-cobertura] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 jamieiles
#!/usr/bin/env python
2
 
3
# Copyright Jamie Iles, 2017
4
#
5
# This file is part of s80x86.
6
#
7
# s80x86 is free software: you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# s80x86 is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with s80x86.  If not, see .
19
 
20
import argparse
21
import sys
22
import os.path
23
import time
24
 
25
from collections import namedtuple, defaultdict
26
from xml.dom import minidom
27
from xml.etree.ElementTree import Element, SubElement, tostring
28
 
29
def get_coverage(filename):
30
    CoveragePoint = namedtuple('CoveragePoint', ['file', 'line', 'count'])
31
    FIELD_SPLIT = '\x01'
32
    KEY_VALUE_SPLIT = '\x02'
33
 
34
    def parse_point(point, count):
35
        filename = None
36
        line = None
37
 
38
        for pair in point:
39
            if not KEY_VALUE_SPLIT in pair:
40
                continue
41
            key, value = pair.split(KEY_VALUE_SPLIT)
42
            if key == 'f':
43
                filename = value
44
            if key == 'l':
45
                line = value
46
 
47
        if not filename or not line:
48
            return None
49
 
50
        return CoveragePoint(filename, line, int(count))
51
 
52
    def parse_coverage(filename):
53
        with open(filename) as coverage:
54
            coverage_lines = filter(lambda x: x.startswith('C'), coverage.readlines())
55
 
56
        coverage = defaultdict(lambda: defaultdict(int))
57
 
58
        for l in coverage_lines:
59
            line_type, data, count = l.split()
60
            entry_dict = data.replace("'", "").split(FIELD_SPLIT)
61
            point = parse_point(entry_dict, count)
62
            if point:
63
                coverage[point.file][point.line] += point.count
64
 
65
        return coverage
66
 
67
    return parse_coverage(filename)
68
 
69
def verilator_to_cobertura(coverage_info):
70
    line_rates = {}
71
    global_line_rate = 0.0
72
 
73
    total_lines = 0.0
74
    covered_lines = 0.0
75
    for filename, lines in coverage_info.items():
76
        file_covered_lines = 0.0
77
        for line, count in lines.items():
78
            total_lines += 1
79
            if count > 0:
80
                file_covered_lines += 1
81
                covered_lines += 1
82
        line_rates[filename] = file_covered_lines / len(lines)
83
    global_line_rate = 0.0 if not total_lines else covered_lines / total_lines
84
 
85
    coverage = Element('coverage', attrib={
86
                       'branch-rate': '0.0',
87
                       'complexity': '0.0',
88
                       'line-rate': str(global_line_rate),
89
                       'timestamp': str(int(time.time())),
90
                       'version': 'verilator-cobertura-1',
91
                       })
92
    sources = SubElement(coverage, 'sources')
93
    source = SubElement(sources, 'source')
94
    source.text = args.source_root
95
    packages = SubElement(coverage, 'packages')
96
    package = SubElement(packages, 'package', attrib={
97
                         'name': 'verilator',
98
                         'branch-rate': '0.0',
99
                         'complexity': '0.0',
100
                         'line-rate': str(global_line_rate),
101
                         })
102
    classes = SubElement(package, 'classes')
103
    for filename, lines in coverage_info.items():
104
        f = SubElement(classes, 'class', attrib={
105
                       'filename': os.path.relpath(filename, args.source_root),
106
                       'name': os.path.basename(filename).replace('.', '_'),
107
                       'line-rate': str(line_rates[filename]),
108
                       'branch-rate': '0.0',
109
                       'complexity': '0.0',
110
                       })
111
        lines_elem = SubElement(f, 'lines')
112
        for line in sorted(lines.keys(), key=lambda x: int(x)):
113
            count = lines[line]
114
            # Maximum of 31-bits so that cobertura plugin doesn't get sad.
115
            # With toggles etc this can get pretty large.
116
            if count > 0x7fffffff:
117
                count = 0x7fffffff
118
            l = SubElement(lines_elem, 'line',
119
                        attrib={'hits': str(count), 'number': str(line), 'branch': 'false'})
120
 
121
    return minidom.parseString(tostring(coverage)).toprettyxml(indent="  ").replace('', '\n')
122
 
123
parser = argparse.ArgumentParser()
124
parser.add_argument('--source-root', default='/')
125
parser.add_argument('--output', default='-')
126
parser.add_argument('coverage_file')
127
args = parser.parse_args()
128
 
129
coverage_info = get_coverage(args.coverage_file)
130
report = verilator_to_cobertura(coverage_info)
131
 
132
if args.output == '-':
133
    print report
134
else:
135
    with open(args.output, 'w') as outfile:
136
        outfile.write(report)

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.