mirror of
https://github.com/bluekitchen/btstack.git
synced 2024-12-29 09:26:08 +00:00
196 lines
6.0 KiB
Python
Executable File
196 lines
6.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# requires https://github.com/bright-tools/ccsm
|
|
|
|
import os
|
|
import sys
|
|
import csv
|
|
|
|
folders = [
|
|
'src',
|
|
'src/ble',
|
|
'src/ble/gatt-service',
|
|
'src/classic',
|
|
]
|
|
|
|
metrics = {}
|
|
targets = {}
|
|
histogram_data = {}
|
|
|
|
targets['PATH'] = 1000
|
|
targets['GOTO'] = 0
|
|
targets['CCN'] = 20
|
|
targets['CALLS'] = 12
|
|
targets['PARAM'] = 7
|
|
targets['STMT'] = 100
|
|
targets['LEVEL'] = 6
|
|
targets['RETURN'] = 1
|
|
|
|
excluded_functions = [
|
|
# deprecated functions
|
|
'src/l2cap.c:l2cap_le_register_service',
|
|
'src/l2cap.c:l2cap_le_unregister_service',
|
|
'src/l2cap.c:l2cap_le_accept_connection',
|
|
'src/l2cap.c:l2cap_le_decline_connection',
|
|
'src/l2cap.c:l2cap_le_provide_credits',
|
|
'src/l2cap.c:l2cap_le_create_channel',
|
|
'src/l2cap.c:l2cap_le_can_send_now',
|
|
'src/l2cap.c:l2cap_le_request_can_send_now_event',
|
|
'src/l2cap.c:l2cap_le_send_data',
|
|
'src/l2cap.c:l2cap_le_disconnect',
|
|
'src/l2cap.c:l2cap_cbm_can_send_now',
|
|
'src/l2cap.c:l2cap_cbm_request_can_send_now_even'
|
|
]
|
|
|
|
def histogram_add_data(key, value):
|
|
global histogram_data
|
|
if key not in histogram_data.keys():
|
|
histogram_data[key] = []
|
|
histogram_data[key].append(value)
|
|
|
|
|
|
def metric_sum(name, value):
|
|
global metrics
|
|
old = 0
|
|
if name in metrics:
|
|
old = metrics[name]
|
|
metrics[name] = old + value
|
|
|
|
|
|
def metric_list(name, item):
|
|
global metrics
|
|
value = []
|
|
if name in metrics:
|
|
value = metrics[name]
|
|
value.append(item)
|
|
metrics[name] = value
|
|
|
|
def metric_max(name, max):
|
|
global metrics
|
|
if name in metrics:
|
|
if metrics[name] > max:
|
|
return
|
|
metrics[name] = max
|
|
|
|
def metric_measure(metric_name, function_name, actual):
|
|
metric_max(metric_name + '_MAX', actual)
|
|
if metric_name in targets:
|
|
metric_sum(metric_name + '_SUM', actual)
|
|
if actual > targets[metric_name]:
|
|
metric_sum(metric_name + '_DEVIATIONS', 1)
|
|
# metric_list(metric_name + '_LIST', function_name + '(%u)' % actual)
|
|
metric_list(metric_name + '_LIST', function_name)
|
|
|
|
|
|
def analyze_folders(btstack_root, folders, metrics_file):
|
|
global excluded_functions
|
|
|
|
# File,Name,"'goto' keyword count (raw source)","Return points","Statement count (raw source)(local)",
|
|
# "Statement count (raw source)(cumulative)","Comment density","McCabe complexity (raw source)",
|
|
# "Number of paths through the function","No. different functions called","Function Parameters",
|
|
# "Nesting Level","VOCF","Number of functions which call this function",
|
|
fields = [ 'file','function','GOTO','RETURN','_','STMT' ,'_','CCN','PATH','CALLS','PARAM','LEVEL','_','_','_']
|
|
|
|
# init deviations
|
|
for key in fields:
|
|
metrics[key + '_DEVIATIONS'] = 0
|
|
|
|
# for now, just read the file
|
|
with open(metrics_file) as fd:
|
|
rd = csv.reader(fd, delimiter="\t")
|
|
last_function_name = ''
|
|
for row in rd:
|
|
file = ''
|
|
function_metrics = {}
|
|
# skip optional header
|
|
if row[0].startswith('#'):
|
|
continue
|
|
|
|
for key, value in zip(fields, row):
|
|
if key == 'file':
|
|
# get rid of directory traversal on buildbot
|
|
pos_metrics_folder = value.find('tool/metrics/')
|
|
if pos_metrics_folder > 0:
|
|
value = value[pos_metrics_folder+13:]
|
|
# streamline path
|
|
file = value.replace('../../','')
|
|
continue
|
|
if key == 'function':
|
|
function_name = value
|
|
continue
|
|
if key == '_':
|
|
continue
|
|
function_metrics[key] = value
|
|
histogram_add_data(key,int(value))
|
|
|
|
if file.endswith('.h'):
|
|
continue
|
|
qualified_function_name = file+':'+function_name
|
|
# excluded functions
|
|
if qualified_function_name in excluded_functions:
|
|
continue
|
|
metric_sum('FUNC', 1)
|
|
for key,value in function_metrics.items():
|
|
metric_measure(key, qualified_function_name, int(function_metrics[key]))
|
|
|
|
def analyze(folders, metrics_file):
|
|
# print ("\nAnalyzing:")
|
|
# for path in folders:
|
|
# print('- %s' % path)
|
|
# analyze_folder(btstack_root + "/" + path)
|
|
btstack_root = os.path.abspath(os.path.dirname(sys.argv[0]) + '/../..')
|
|
analyze_folders(btstack_root, folders, metrics_file)
|
|
|
|
def list_targets():
|
|
print ("Targets:")
|
|
for key,value in sorted(targets.items()):
|
|
print ('- %-20s: %u' % (key, value))
|
|
|
|
def list_metrics():
|
|
print ("\nResult:")
|
|
num_funcs = metrics['FUNC']
|
|
for key,value in sorted(metrics.items()):
|
|
if key.endswith('LIST'):
|
|
continue
|
|
if key.endswith('_SUM'):
|
|
average = 1.0 * value / num_funcs
|
|
metric = key.replace('_SUM','_AVERAGE')
|
|
print ('- %-20s: %4.3f' % (metric, average))
|
|
else:
|
|
print ('- %-20s: %5u' % (key, value))
|
|
|
|
def list_metrics_table():
|
|
row = "%-11s |%11s |%11s |%11s"
|
|
|
|
print( row % ('Name', 'Target', 'Deviations', 'Max value'))
|
|
print("------------|------------|------------|------------")
|
|
|
|
ordered_metrics = [ 'PATH', 'GOTO', 'CCN', 'CALLS', 'PARAM', 'STMT', 'LEVEL', 'RETURN', 'FUNC'];
|
|
for metric_name in ordered_metrics:
|
|
if metric_name in targets:
|
|
target = targets[metric_name]
|
|
deviations = metrics[metric_name + '_DEVIATIONS']
|
|
max = metrics[metric_name + '_MAX']
|
|
print ( row % ( metric_name, target, deviations, max))
|
|
else:
|
|
max = metrics[metric_name]
|
|
print ( row % ( metric_name, '', '', max))
|
|
|
|
def list_deviations():
|
|
global metrics
|
|
for key,value in sorted(metrics.items()):
|
|
if not key.endswith('LIST'):
|
|
continue
|
|
print ("\n%s" % key)
|
|
print ('\n'.join(value))
|
|
|
|
def main(argv):
|
|
analyze(folders, "metrics.tsv")
|
|
list_metrics_table()
|
|
# list_targets()
|
|
# list_metrics()
|
|
# list_deviations()
|
|
|
|
if __name__ == "__main__":
|
|
main(sys.argv[1:])
|