blob: d201cd66fa21c139f9e0476ce55c20190840c3e5 [file] [log] [blame]
Jianliang Shen48704152023-10-17 17:06:00 +08001#!/usr/bin/env python3
2
3__copyright__ = '''
4/*
5 * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 *
9 */
10 '''
11
12import argparse
13import os
14import json
15import logging
16import re
17import requests
18from tfm_ci_pylib import utils
19
20mem_configs = {
21 'AN521_ARMCLANG_1_Minsizerel_BL2': 'AN521-ARMCC-Default-Minsizerel-BL2',
22 'AN521_ARMCLANG_1_Minsizerel_BL2_SMALL_PSOFF': 'AN521-ARMCC-Small-Minsizerel-BL2',
23 'AN521_ARMCLANG_2_Minsizerel_BL2_MEDIUM_PSOFF': 'AN521-ARMCC-Medium-Minsizerel-BL2',
24 'AN521_ARMCLANG_3_Minsizerel_BL2_LARGE_PSOFF': 'AN521-ARMCC-Large-Minsizerel-BL2'
25}
26
27profiling_configs = {
28 'AN521_GCC_1_Release_BL2_PROF': 'AN521-GCC-Level1-SFN-Release-BL2',
29 'AN521_GCC_1_Release_BL2_IPC_PROF': 'AN521-GCC-Level1-IPC-Release-BL2',
30 'AN521_GCC_2_Release_BL2_PROF': 'AN521-GCC-Level2-IPC-Release-BL2',
31 'AN521_GCC_3_Release_BL2_PROF': 'AN521-GCC-Level3-IPC-Release-BL2'
32}
33
34def get_git_commit_hash(repo='trusted-firmware-m'):
35 cur_dir = os.path.abspath(os.getcwd())
36
37 os.chdir(os.path.join(os.getenv('WORKSPACE'), repo)) # Going to the repo's directory
38 git_commit = os.popen('git rev-parse --short HEAD').read()[:-1]
39 os.chdir(cur_dir) # Going back to the initial directory
40
41 return git_commit
42
43def get_file_size(filename):
44 '''
45 This function uses fromelf of ARMCLANG to get the sizes of a file in the build binary directory of TF-M
46 '''
47 f_path = os.path.join(os.getenv('WORKSPACE'), 'trusted-firmware-m', 'build', 'bin', filename)
48 if os.path.exists(f_path) :
49 data_fromelf = utils.fromelf(f_path)
50 print(data_fromelf[1]) # Output of fromelf
51 return data_fromelf[0] # Data parsed from output of fromelf
52 else :
53 print(f_path + 'Not found')
54 return -1
55
56def save_mem_to_json(config_name, bl2_sizes, tfm_s_sizes):
57 '''
58 This function creates a json file containing all the data about memory footprint in share folder.
59 '''
60 try:
61 metrics = json.dumps({ 'bl2_code_size' : bl2_sizes['Code'],
62 'bl2_inline_data' : bl2_sizes['Inline Data'],
63 'bl2_ro_data' : bl2_sizes['RO Data'],
64 'bl2_rw_data' : bl2_sizes['RW Data'],
65 'bl2_zi_data' : bl2_sizes['ZI Data'],
66 'spe_code_size' : tfm_s_sizes['Code'],
67 'spe_inline_data' : tfm_s_sizes['Inline Data'],
68 'spe_ro_data' : tfm_s_sizes['RO Data'],
69 'spe_rw_data' : tfm_s_sizes['RW Data'],
70 'spe_zi_data' : tfm_s_sizes['ZI Data']})
71 except:
72 return -1
73
74 with open(os.path.join(os.getenv('SHARE_FOLDER'),
75 'Memory_footprint',
76 '{}_filesize.json'.format(config_name)), 'w') as F:
77 #Storing the json file
78 F.write(metrics)
79 return 0
80
81def get_prof_psa_client_api_data(f_log_path):
82 '''
83 Get PSA Client API profiling data report from target log.
84 '''
85
86 prof_data = {}
87 with open(f_log_path,'r') as f_log:
88 tfm_log = f_log.read()
89
90 # Extract TF-M PSA Client API profiling data
91 pattern = r'(secure|non-secure) ([^\n]+) average is (\d+) CPU cycles'
92 matches = re.findall(pattern, tfm_log)
93 for match in matches:
94 type, api, cpu_cycles = match
95 prof_data[('s_' if type == 'secure' else 'ns_') + api.replace(' ', '_')] = cpu_cycles
96
97 return prof_data
98
99
100def send_squad(user_args, job_dir, config_name):
101 '''
102 Send performance data to SQUAD dashboard.
103 '''
104 prof_data, mem_data = {}, {}
105
106 # Generate Profiling data from target log
107 if config_name in profiling_configs.keys():
108 target_log = os.path.join(job_dir, 'target_log.txt')
109 prof_data = get_prof_psa_client_api_data(target_log)
110 config_name = profiling_configs[config_name]
111
112 # Load Memory Footprint data from share folder json files.
113 if config_name in mem_configs.keys():
114 mem_json_path = os.path.join(os.getenv('SHARE_FOLDER'), 'Memory_footprint', '{}_filesize.json'.format(config_name))
115 with open(mem_json_path, 'r') as f:
116 mem_data = json.load(f)
117 config_name = mem_configs[config_name]
118
119 # Write result to JSON file
120 metrics = json.dumps({**prof_data, **mem_data})
121 with open(os.path.join(job_dir, 'performance.json'), 'w') as f_json:
122 f_json.write(metrics)
123
124 # SQAUD constant
125 SQUAD_TOKEN = user_args.squad_token
126 SQUAD_BASE_PROJECT_URL = ('https://qa-reports.linaro.org/api/submit/tf/tf-m/')
127 url = SQUAD_BASE_PROJECT_URL + get_git_commit_hash('trusted-firmware-m') + '/' + config_name
128 headers = {'Auth-Token': SQUAD_TOKEN}
129 data= {'metrics': metrics}
130
131 # Sending the data to SQUAD, 40s timeout
132 try:
133 result = requests.post(url, headers=headers, data=data, timeout=40)
134 except:
135 return -1
136
137 if not result.ok:
138 print(f'Error submitting to qa-reports: {result.reason}: {result.text}')
139 return -1
140 else :
141 print ('POST request sent to project ' + config_name)
142 return 0
143
144def main(user_args):
145 if user_args.generate_memory:
146 # Export ARMClang v6.13 to ENV PATH
147 os.environ['PATH'] += os.pathsep + os.getenv('ARMCLANG_6_13_PATH')
148 if os.getenv('CONFIG_NAME') in mem_configs.keys():
149 print('Configuration ' + os.getenv('CONFIG_NAME') + ' is a reference')
150
151 print('---------- BL2 Memory Footprint ----------')
152 bl2_sizes = get_file_size('bl2.axf')
153
154 print('------ TF-M Secure Memory Footprint ------')
155 tfm_s_sizes = get_file_size('tfm_s.axf')
156
157 if save_mem_to_json(os.getenv('CONFIG_NAME'), bl2_sizes, tfm_s_sizes) == -1:
158 print('Memory footprint generate failed.')
159
160 if user_args.send_squad:
161 with open(os.path.join(os.getenv('SHARE_FOLDER'), 'performance_config.txt'), 'r') as f:
162 for line in f:
163 config_name, job_dir = line.split()[0], line.split()[1]
164 send_squad(user_args, job_dir, config_name)
165
166def get_cmd_args():
167 parser = argparse.ArgumentParser(description='Performance')
168 cmdargs = parser.add_argument_group('Performance')
169
170 # Configuration control
171 cmdargs.add_argument(
172 '--generate-memory', dest='generate_memory', action='store_true', default=False, help='Generate memory footprint data'
173 )
174 cmdargs.add_argument(
175 '--send-squad', dest='send_squad', action='store_true', default=False, help='Send data to SQUAD'
176 )
177 cmdargs.add_argument(
178 '--squad-token', dest='squad_token', action='store', help='SQUAD BOARD TOKEN'
179 )
180
181 return parser.parse_args()
182
183
184if __name__ == '__main__':
185 logging.basicConfig(level=logging.INFO)
186 main(get_cmd_args())