blob: 53644cbab97aeee7130b4598d20417c08faa08d1 [file] [log] [blame]
Hugo L'Hostise55a2752021-01-27 11:09:08 +00001#!/usr/bin/env python
2
3#memory_footprint.py : Script for sending memory footprint data from the TFM CI
4#to a SQUAD web interface
5#
6#Copyright (c) 2020-2021, Arm Limited. All rights reserved.
7#
8#SPDX-License-Identifier: BSD-3-Clause
9
10
11import argparse
12import os
13import re
14import sys
15import json
16import requests
17import subprocess
18import configs
19from tfm_ci_pylib import utils
20
21# Arguments/parameters given by CI
22PATH_TO_TFM = sys.argv[1]
23CI_CONFIG = sys.argv[2]
24REFERENCE_CONFIGS = sys.argv[3].split(",")
25SQUAD_TOKEN = sys.argv[4]
26
27# local constant
28SQUAD_BASE_PROJECT_URL = ("https://qa-reports.linaro.org/api/submit/tf/tf-m/")
29
30# This function uses arm_non_eabi_size to get the sizes of a file
31# in the build directory of tfm
32def get_file_size(filename):
33 f_path = os.path.join(PATH_TO_TFM, "build", "bin", filename)
34 if os.path.exists(f_path) :
35 bl2_sizes = utils.arm_non_eabi_size(f_path)[0]
36 return bl2_sizes
37 else :
38 print(f_path + "Not found")
39 return -1
40
41# This function creates a json file containing all the data about
42# memory footprint and sends this data to SQUAD
43def send_file_size(change_id, config_name, bl2_sizes, tfms_sizes):
44 url = SQUAD_BASE_PROJECT_URL + change_id + '/' + config_name
45
46 try:
47 metrics = json.dumps({ "bl2_size" : bl2_sizes["dec"],
48 "bl2_data" : bl2_sizes["data"],
49 "bl2_bss" : bl2_sizes["bss"],
50 "tfms_size" : tfms_sizes["dec"],
51 "tfms_data" : tfms_sizes["data"],
52 "tfms_bss" : tfms_sizes["bss"]})
53 except:
54 return -1
55
56 headers = {"Auth-Token": SQUAD_TOKEN}
57 data= {"metrics": metrics}
58
59 try:
60 #Sending the data to SQUAD, 40s timeout
61 result = requests.post(url, headers=headers, data=data, timeout=40)
62 except:
63 return -1
64
65 with open(os.path.join(PATH_TO_TFM,
66 "..",
67 "tf-m-ci-scripts",
68 "Memory_footprint",
69 "filesize.json"), "w") as F:
70 #Storing the json file
71 F.write(metrics)
72
73 if not result.ok:
74 print(f"Error submitting to qa-reports: {result.reason}: {result.text}")
75 return -1
76 else :
77 print ("POST request sent to project " + config_name )
78 return 0
79
80#Function used to launch the configs.py script and get the printed output
81def get_configs_by_name(config_names):
82 clist = list(configs._builtin_configs.keys())
83 out_cfg = {}
84 for group in clist:
85 build_manager = configs.get_build_manager(group)
86 for _cfg_name in config_names:
87 if _cfg_name in build_manager._tbm_build_cfg.keys():
88 out_cfg[_cfg_name] = build_manager._tbm_build_cfg[_cfg_name]
89 return out_cfg
90
91# This funcion manipulates the format of the config given
92# as entry to extract the name of the configuration used
93def identify_config():
94 name_config = "Unknown"
95
96 try :
97 cfg = get_configs_by_name([CI_CONFIG])[CI_CONFIG]
98 if (cfg.psa_api and cfg.isolation_level == "1" and
99 not cfg.test_regression and cfg.test_psa_api == "OFF" and
100 cfg.cmake_build_type == "Release" and cfg.with_otp == "off" and
101 cfg.with_bl2 and cfg.with_ns and
102 cfg.profile == "" and cfg.partition_ps == "ON"):
103 name_config = "CoreIPC"
104 elif (not cfg.psa_api and cfg.isolation_level == "1" and
105 not cfg.test_regression and cfg.test_psa_api == "OFF" and
106 cfg.cmake_build_type == "Release" and cfg.with_otp == "off" and
107 cfg.with_bl2 and cfg.with_ns and
108 cfg.profile == "" and cfg.partition_ps == "ON"):
109 name_config = "Default"
110 elif (cfg.psa_api and cfg.isolation_level == "2" and
111 not cfg.test_regression and cfg.test_psa_api == "OFF" and
112 cfg.cmake_build_type == "Release" and cfg.with_otp == "off" and
113 cfg.with_bl2 and cfg.with_ns and
114 cfg.profile == "" and cfg.partition_ps == "ON"):
115 name_config = "CoreIPCTfmLevel2"
116 elif (not cfg.psa_api and cfg.isolation_level == "1" and
117 not cfg.test_regression and cfg.test_psa_api == "OFF" and
118 cfg.cmake_build_type == "Release" and cfg.with_otp == "off" and
119 cfg.with_bl2 and cfg.with_ns and
120 cfg.profile == "profile_small" and cfg.partition_ps == "OFF"):
121 name_config = "DefaultProfileS"
122 elif (cfg.psa_api and cfg.isolation_level == "2" and
123 not cfg.test_regression and cfg.test_psa_api == "OFF" and
124 cfg.cmake_build_type == "Release" and cfg.with_otp == "off" and
125 cfg.with_bl2 and cfg.with_ns and
126 cfg.profile == "profile_medium" and cfg.partition_ps == "ON"):
127 name_config = "DefaultProfileM"
128 ret = [cfg.tfm_platform,cfg.toolchain_file, name_config]
129 except:
130 ret = ["Unknown", "Unknown", "Unknown"]
131 return ret
132
133# Function based on get_local_git_info() from utils, getting change id for the tfm repo
134def get_change_id(directory):
135 directory = os.path.abspath(directory)
136 cur_dir = os.path.abspath(os.getcwd())
137 cmd = "git log HEAD -n 1 --pretty=format:'%b'"
138
139 os.chdir(directory) # Going to the repo's directory
140
141 git_info_rex = re.compile(r'(?P<body>^[\s\S]*?)((?:Change-Id:\s)'
142 r'(?P<change_id>.*)\n?)', re.MULTILINE)
143
144 r, e = subprocess.Popen(cmd,
145 shell=True,
146 stdout=subprocess.PIPE,
147 stderr=subprocess.PIPE).communicate()
148
149 if e:
150 print("Error", e)
151 return -1
152 else:
153 try:
154 txt_body = r.decode('ascii')
155 except UnicodeDecodeError as E:
156 txt_body = r.decode('utf-8')
157 result = txt_body.rstrip()
158
159 try:
160 change_id = git_info_rex.search(result).groupdict()["change_id"].strip()
161 except:
162 return -1
163
164 os.chdir(cur_dir) #Going back to the initial directory
165 return change_id
166
167if __name__ == "__main__":
168 for i in range(len(REFERENCE_CONFIGS)):
169 REFERENCE_CONFIGS[i] = REFERENCE_CONFIGS[i].strip().lower()
170 config = identify_config()
171 if (config[2].lower() in REFERENCE_CONFIGS
172 and config[0] == "mps2/an521"
173 and config[1] == "toolchain_GNUARM.cmake"):
174 # Pushing data for AN521 and GNUARM
175 print("Configuration " + config[2] + " is a reference")
176 try :
177 change_id = get_change_id(PATH_TO_TFM)
178 except :
179 change_id = -1
180 bl2_sizes = get_file_size("bl2.axf")
181 tfms_sizes = get_file_size("tfm_s.axf")
182 if (bl2_sizes != -1 and change_id != -1) :
183 send_file_size(change_id, config[2], bl2_sizes, tfms_sizes)
184 else :
185 #Directory or file weren't found
186 if change_id == -1 :
187 print("Error : trusted-firmware-m repo not found")
188 else :
189 print("Error : file not found")