xref: /btstack/tool/metrics/metrics_ccsm.py (revision 39127754112d635f8d55bf39817a539acc1c6e74)
1974bd5b3SMilanka Ringwald#!/usr/bin/env python3
2974bd5b3SMilanka Ringwald
3974bd5b3SMilanka Ringwald# requires https://github.com/bright-tools/ccsm
4974bd5b3SMilanka Ringwald
5974bd5b3SMilanka Ringwaldimport os
6974bd5b3SMilanka Ringwaldimport sys
7974bd5b3SMilanka Ringwaldimport csv
8974bd5b3SMilanka Ringwald
9974bd5b3SMilanka Ringwaldfolders = [
10974bd5b3SMilanka Ringwald'src',
11974bd5b3SMilanka Ringwald'src/ble',
12974bd5b3SMilanka Ringwald'src/ble/gatt-service',
13974bd5b3SMilanka Ringwald'src/classic',
14974bd5b3SMilanka Ringwald]
15974bd5b3SMilanka Ringwald
16974bd5b3SMilanka Ringwaldmetrics = {}
17974bd5b3SMilanka Ringwaldtargets = {}
1834114554SMilanka Ringwaldhistogram_data = {}
19974bd5b3SMilanka Ringwald
20974bd5b3SMilanka Ringwaldtargets['PATH']   = 1000
21974bd5b3SMilanka Ringwaldtargets['GOTO']   = 0
22974bd5b3SMilanka Ringwaldtargets['CCN']    = 20
23974bd5b3SMilanka Ringwaldtargets['CALLS']  = 12
24974bd5b3SMilanka Ringwaldtargets['PARAM']  = 7
25974bd5b3SMilanka Ringwaldtargets['STMT']   = 100
26974bd5b3SMilanka Ringwaldtargets['LEVEL']  = 6
27974bd5b3SMilanka Ringwaldtargets['RETURN'] = 1
28974bd5b3SMilanka Ringwald
29974bd5b3SMilanka Ringwaldexcluded_functions = [
30974bd5b3SMilanka Ringwald    # deprecated functions
31974bd5b3SMilanka Ringwald    'src/l2cap.c:l2cap_le_register_service',
32974bd5b3SMilanka Ringwald    'src/l2cap.c:l2cap_le_unregister_service',
33974bd5b3SMilanka Ringwald    'src/l2cap.c:l2cap_le_accept_connection',
34974bd5b3SMilanka Ringwald    'src/l2cap.c:l2cap_le_decline_connection',
35974bd5b3SMilanka Ringwald    'src/l2cap.c:l2cap_le_provide_credits',
36974bd5b3SMilanka Ringwald    'src/l2cap.c:l2cap_le_create_channel',
37974bd5b3SMilanka Ringwald    'src/l2cap.c:l2cap_le_can_send_now',
38974bd5b3SMilanka Ringwald    'src/l2cap.c:l2cap_le_request_can_send_now_event',
39974bd5b3SMilanka Ringwald    'src/l2cap.c:l2cap_le_send_data',
40974bd5b3SMilanka Ringwald    'src/l2cap.c:l2cap_le_disconnect',
41974bd5b3SMilanka Ringwald    'src/l2cap.c:l2cap_cbm_can_send_now',
42974bd5b3SMilanka Ringwald    'src/l2cap.c:l2cap_cbm_request_can_send_now_even'
43974bd5b3SMilanka Ringwald]
44974bd5b3SMilanka Ringwald
4534114554SMilanka Ringwalddef histogram_add_data(key, value):
4634114554SMilanka Ringwald    global histogram_data
4734114554SMilanka Ringwald    if key not in histogram_data.keys():
4834114554SMilanka Ringwald        histogram_data[key] = []
4934114554SMilanka Ringwald    histogram_data[key].append(value)
5034114554SMilanka Ringwald
5134114554SMilanka Ringwald
52974bd5b3SMilanka Ringwalddef metric_sum(name, value):
53974bd5b3SMilanka Ringwald    global metrics
54974bd5b3SMilanka Ringwald    old = 0
55974bd5b3SMilanka Ringwald    if name in metrics:
56974bd5b3SMilanka Ringwald        old = metrics[name]
57974bd5b3SMilanka Ringwald    metrics[name] = old + value
58974bd5b3SMilanka Ringwald
59974bd5b3SMilanka Ringwald
60974bd5b3SMilanka Ringwalddef metric_list(name, item):
61974bd5b3SMilanka Ringwald    global metrics
62974bd5b3SMilanka Ringwald    value = []
63974bd5b3SMilanka Ringwald    if name in metrics:
64974bd5b3SMilanka Ringwald        value = metrics[name]
65974bd5b3SMilanka Ringwald    value.append(item)
66974bd5b3SMilanka Ringwald    metrics[name] = value
67974bd5b3SMilanka Ringwald
68974bd5b3SMilanka Ringwalddef metric_max(name, max):
69974bd5b3SMilanka Ringwald    global metrics
70974bd5b3SMilanka Ringwald    if name in metrics:
71974bd5b3SMilanka Ringwald        if metrics[name] > max:
72974bd5b3SMilanka Ringwald            return
73974bd5b3SMilanka Ringwald    metrics[name] = max
74974bd5b3SMilanka Ringwald
75974bd5b3SMilanka Ringwalddef metric_measure(metric_name, function_name, actual):
76974bd5b3SMilanka Ringwald    metric_max(metric_name + '_MAX', actual)
77974bd5b3SMilanka Ringwald    if metric_name in targets:
78974bd5b3SMilanka Ringwald        metric_sum(metric_name + '_SUM', actual)
79974bd5b3SMilanka Ringwald        if actual > targets[metric_name]:
80974bd5b3SMilanka Ringwald            metric_sum(metric_name + '_DEVIATIONS', 1)
81*39127754SMatthias Ringwald            metric_list(metric_name + '_LIST', function_name + ' - %u' % actual)
82974bd5b3SMilanka Ringwald
83974bd5b3SMilanka Ringwald
849aec9f02SMilanka Ringwalddef analyze_folders(btstack_root, folders, metrics_file):
85974bd5b3SMilanka Ringwald    global excluded_functions
86974bd5b3SMilanka Ringwald
87974bd5b3SMilanka Ringwald    # File,Name,"'goto' keyword count (raw source)","Return points","Statement count (raw source)(local)",
88974bd5b3SMilanka Ringwald    # "Statement count (raw source)(cumulative)","Comment density","McCabe complexity (raw source)",
89974bd5b3SMilanka Ringwald    # "Number of paths through the function","No. different functions called","Function Parameters",
90974bd5b3SMilanka Ringwald    # "Nesting Level","VOCF","Number of functions which call this function",
91974bd5b3SMilanka Ringwald    fields = [ 'file','function','GOTO','RETURN','_','STMT' ,'_','CCN','PATH','CALLS','PARAM','LEVEL','_','_','_']
92974bd5b3SMilanka Ringwald
93974bd5b3SMilanka Ringwald    # init deviations
94974bd5b3SMilanka Ringwald    for key in fields:
95974bd5b3SMilanka Ringwald        metrics[key + '_DEVIATIONS'] = 0
96974bd5b3SMilanka Ringwald
97974bd5b3SMilanka Ringwald    # for now, just read the file
989aec9f02SMilanka Ringwald    with open(metrics_file) as fd:
99974bd5b3SMilanka Ringwald        rd = csv.reader(fd, delimiter="\t")
100974bd5b3SMilanka Ringwald        last_function_name = ''
101974bd5b3SMilanka Ringwald        for row in rd:
102974bd5b3SMilanka Ringwald            file = ''
103974bd5b3SMilanka Ringwald            function_metrics = {}
104cfc3484eSMatthias Ringwald            # skip optional header
105cfc3484eSMatthias Ringwald            if row[0].startswith('#'):
106cfc3484eSMatthias Ringwald                continue
107cfc3484eSMatthias Ringwald
108974bd5b3SMilanka Ringwald            for key, value in zip(fields, row):
109974bd5b3SMilanka Ringwald                if key == 'file':
110974bd5b3SMilanka Ringwald                    # get rid of directory traversal on buildbot
111974bd5b3SMilanka Ringwald                    pos_metrics_folder = value.find('tool/metrics/')
112974bd5b3SMilanka Ringwald                    if pos_metrics_folder > 0:
113974bd5b3SMilanka Ringwald                        value = value[pos_metrics_folder+13:]
114974bd5b3SMilanka Ringwald                    # streamline path
115974bd5b3SMilanka Ringwald                    file = value.replace('../../','')
116974bd5b3SMilanka Ringwald                    continue
117974bd5b3SMilanka Ringwald                if key == 'function':
118974bd5b3SMilanka Ringwald                    function_name = value
119974bd5b3SMilanka Ringwald                    continue
120974bd5b3SMilanka Ringwald                if key == '_':
121974bd5b3SMilanka Ringwald                    continue
122974bd5b3SMilanka Ringwald                function_metrics[key] = value
12334114554SMilanka Ringwald                histogram_add_data(key,int(value))
12434114554SMilanka Ringwald
125974bd5b3SMilanka Ringwald            if file.endswith('.h'):
126974bd5b3SMilanka Ringwald                continue
127974bd5b3SMilanka Ringwald            qualified_function_name = file+':'+function_name
128974bd5b3SMilanka Ringwald            # excluded functions
129974bd5b3SMilanka Ringwald            if qualified_function_name in excluded_functions:
130974bd5b3SMilanka Ringwald                continue
131974bd5b3SMilanka Ringwald            metric_sum('FUNC', 1)
132974bd5b3SMilanka Ringwald            for key,value in function_metrics.items():
133974bd5b3SMilanka Ringwald                metric_measure(key, qualified_function_name, int(function_metrics[key]))
134974bd5b3SMilanka Ringwald
1359aec9f02SMilanka Ringwalddef analyze(folders, metrics_file):
136974bd5b3SMilanka Ringwald    # print ("\nAnalyzing:")
137974bd5b3SMilanka Ringwald    # for path in folders:
138974bd5b3SMilanka Ringwald    #     print('- %s' % path)
139974bd5b3SMilanka Ringwald    #     analyze_folder(btstack_root + "/" + path)
140974bd5b3SMilanka Ringwald    btstack_root = os.path.abspath(os.path.dirname(sys.argv[0]) + '/../..')
1419aec9f02SMilanka Ringwald    analyze_folders(btstack_root, folders, metrics_file)
142974bd5b3SMilanka Ringwald
143974bd5b3SMilanka Ringwalddef list_targets():
144974bd5b3SMilanka Ringwald    print ("Targets:")
145974bd5b3SMilanka Ringwald    for key,value in sorted(targets.items()):
146974bd5b3SMilanka Ringwald        print ('- %-20s: %u' % (key, value))
147974bd5b3SMilanka Ringwald
148974bd5b3SMilanka Ringwalddef list_metrics():
149974bd5b3SMilanka Ringwald    print ("\nResult:")
150974bd5b3SMilanka Ringwald    num_funcs = metrics['FUNC']
151974bd5b3SMilanka Ringwald    for key,value in sorted(metrics.items()):
152974bd5b3SMilanka Ringwald        if key.endswith('LIST'):
153974bd5b3SMilanka Ringwald            continue
154974bd5b3SMilanka Ringwald        if key.endswith('_SUM'):
155974bd5b3SMilanka Ringwald            average = 1.0 * value / num_funcs
156974bd5b3SMilanka Ringwald            metric = key.replace('_SUM','_AVERAGE')
157974bd5b3SMilanka Ringwald            print ('- %-20s: %4.3f' % (metric, average))
158974bd5b3SMilanka Ringwald        else:
159974bd5b3SMilanka Ringwald            print ('- %-20s: %5u' % (key, value))
160974bd5b3SMilanka Ringwald
161974bd5b3SMilanka Ringwalddef list_metrics_table():
162974bd5b3SMilanka Ringwald    row = "%-11s |%11s |%11s |%11s"
163974bd5b3SMilanka Ringwald
164974bd5b3SMilanka Ringwald    print( row % ('Name', 'Target', 'Deviations', 'Max value'))
165974bd5b3SMilanka Ringwald    print("------------|------------|------------|------------")
166974bd5b3SMilanka Ringwald
167974bd5b3SMilanka Ringwald    ordered_metrics = [ 'PATH', 'GOTO', 'CCN', 'CALLS', 'PARAM', 'STMT', 'LEVEL', 'RETURN', 'FUNC'];
168974bd5b3SMilanka Ringwald    for metric_name in ordered_metrics:
169974bd5b3SMilanka Ringwald        if metric_name in targets:
170974bd5b3SMilanka Ringwald            target = targets[metric_name]
171974bd5b3SMilanka Ringwald            deviations = metrics[metric_name + '_DEVIATIONS']
172974bd5b3SMilanka Ringwald            max = metrics[metric_name + '_MAX']
173974bd5b3SMilanka Ringwald            print ( row % ( metric_name, target, deviations, max))
174974bd5b3SMilanka Ringwald        else:
175974bd5b3SMilanka Ringwald            max = metrics[metric_name]
176974bd5b3SMilanka Ringwald            print ( row % ( metric_name, '', '', max))
177974bd5b3SMilanka Ringwald
178974bd5b3SMilanka Ringwalddef list_deviations():
179974bd5b3SMilanka Ringwald    global metrics
180974bd5b3SMilanka Ringwald    for key,value in sorted(metrics.items()):
181974bd5b3SMilanka Ringwald        if not key.endswith('LIST'):
182974bd5b3SMilanka Ringwald            continue
183974bd5b3SMilanka Ringwald        print ("\n%s" % key)
184974bd5b3SMilanka Ringwald        print ('\n'.join(value))
185974bd5b3SMilanka Ringwald
186e174300aSMilanka Ringwalddef main(argv):
1879aec9f02SMilanka Ringwald    analyze(folders, "metrics.tsv")
188974bd5b3SMilanka Ringwald    list_metrics_table()
189974bd5b3SMilanka Ringwald    # list_targets()
190974bd5b3SMilanka Ringwald    # list_metrics()
191974bd5b3SMilanka Ringwald    # list_deviations()
192e174300aSMilanka Ringwald
193e174300aSMilanka Ringwaldif __name__ == "__main__":
194e174300aSMilanka Ringwald   main(sys.argv[1:])
195