blob: b60b6047712bce4d270ff2230be7e24f803b7c98 [file] [log] [blame]
#!/usr/bin/env python
#memory_footprint.py : Script for sending memory footprint data from the TFM CI
#to a SQUAD web interface
#
#Copyright (c) 2020-2021, Arm Limited. All rights reserved.
#
#SPDX-License-Identifier: BSD-3-Clause
import argparse
import os
import re
import sys
import json
import requests
import subprocess
import configs
from tfm_ci_pylib import utils
# Arguments/parameters given by CI
PATH_TO_TFM = sys.argv[1]
CI_CONFIG = sys.argv[2]
REFERENCE_CONFIGS = sys.argv[3].split(",")
SQUAD_TOKEN = "e895cf7816ebe3aa878b3ce4504533d4b7b3425e"
# local constant
SQUAD_BASE_PROJECT_URL = ("https://staging-qa-reports.linaro.org/api/submit/~hugo.lhostis/tfm_metrics/")
# This function uses arm_non_eabi_size to get the sizes of a file
# in the build directory of tfm
def get_file_size(filename):
f_path = os.path.join(PATH_TO_TFM, "build", "bin", filename)
if os.path.exists(f_path) :
file_sizes = utils.arm_non_eabi_size(f_path)[0]
return file_sizes
else :
print(f_path + "Not found")
return -1
# This function creates a json file containing all the data about
# memory footprint and sends this data to SQUAD
def send_file_size(change_id, config_name, bl2_sizes, tfms_sizes):
url = SQUAD_BASE_PROJECT_URL + change_id + '/' + config_name
try:
metrics = json.dumps({ "bl2_size" : bl2_sizes["dec"],
"bl2_data" : bl2_sizes["data"],
"bl2_bss" : bl2_sizes["bss"],
"bl2_text" : bl2_sizes["text"],
"tfms_size" : tfms_sizes["dec"],
"tfms_data" : tfms_sizes["data"],
"tfms_bss" : tfms_sizes["bss"],
"tfms_text" : tfms_sizes["text"]})
except:
return -1
headers = {"Auth-Token": SQUAD_TOKEN}
data= {"metrics": metrics}
try:
#Sending the data to SQUAD, 40s timeout
result = requests.post(url, headers=headers, data=data, timeout=40)
except:
return -1
with open(os.path.join(PATH_TO_TFM,
"..",
"tf-m-ci-scripts",
"Memory_footprint",
"filesize.json"), "w") as F:
#Storing the json file
F.write(metrics)
if not result.ok:
print(f"Error submitting to qa-reports: {result.reason}: {result.text}")
return -1
else :
print ("POST request sent to project " + config_name )
return 0
#Function used to launch the configs.py script and get the printed output
def get_configs_by_name(config_names):
clist = list(configs._builtin_configs.keys())
out_cfg = {}
for group in clist:
build_manager = configs.get_build_manager(group)
for _cfg_name in config_names:
if _cfg_name in build_manager._tbm_build_cfg.keys():
out_cfg[_cfg_name] = build_manager._tbm_build_cfg[_cfg_name]
return out_cfg
# This funcion manipulates the format of the config given
# as entry to extract the name of the configuration used
def identify_config():
name_config = "Unknown"
try :
cfg = get_configs_by_name([CI_CONFIG])[CI_CONFIG]
if (cfg.psa_api and cfg.isolation_level == "1" and
not cfg.test_regression and cfg.test_psa_api == "OFF" and
cfg.cmake_build_type == "Release" and cfg.with_otp == "off" and
cfg.with_bl2 and cfg.with_ns and
cfg.profile == "" and cfg.partition_ps == "ON"):
name_config = "CoreIPC"
elif (not cfg.psa_api and cfg.isolation_level == "1" and
not cfg.test_regression and cfg.test_psa_api == "OFF" and
cfg.cmake_build_type == "Release" and cfg.with_otp == "off" and
cfg.with_bl2 and cfg.with_ns and
cfg.profile == "" and cfg.partition_ps == "ON"):
name_config = "Default"
elif (cfg.psa_api and cfg.isolation_level == "2" and
not cfg.test_regression and cfg.test_psa_api == "OFF" and
cfg.cmake_build_type == "Release" and cfg.with_otp == "off" and
cfg.with_bl2 and cfg.with_ns and
cfg.profile == "" and cfg.partition_ps == "ON"):
name_config = "CoreIPCTfmLevel2"
elif (not cfg.psa_api and cfg.isolation_level == "1" and
not cfg.test_regression and cfg.test_psa_api == "OFF" and
cfg.cmake_build_type == "Release" and cfg.with_otp == "off" and
cfg.with_bl2 and cfg.with_ns and
cfg.profile == "profile_small" and cfg.partition_ps == "OFF"):
name_config = "DefaultProfileS"
elif (not cfg.psa_api and cfg.isolation_level == "1" and
not cfg.test_regression and cfg.test_psa_api == "OFF" and
cfg.cmake_build_type == "Minsizerel" and cfg.with_otp == "off" and
cfg.with_bl2 and cfg.with_ns and
cfg.profile == "profile_small" and cfg.partition_ps == "OFF"):
name_config = "MinSizeProfileS"
elif (cfg.psa_api and cfg.isolation_level == "2" and
not cfg.test_regression and cfg.test_psa_api == "OFF" and
cfg.cmake_build_type == "Release" and cfg.with_otp == "off" and
cfg.with_bl2 and cfg.with_ns and
cfg.profile == "profile_medium" and cfg.partition_ps == "ON"):
name_config = "DefaultProfileM"
elif (cfg.psa_api and cfg.isolation_level == "3" and
not cfg.test_regression and cfg.test_psa_api == "OFF" and
cfg.cmake_build_type == "Release" and cfg.with_otp == "off" and
cfg.with_bl2 and cfg.with_ns and
cfg.profile == "profile_large" and cfg.partition_ps == "ON"):
name_config = "DefaultProfileL"
ret = [cfg.tfm_platform,cfg.toolchain_file, name_config]
except:
ret = ["Unknown", "Unknown", "Unknown"]
return ret
# Function based on get_local_git_info() from utils, getting change id for the tfm repo
def get_change_id(directory):
directory = os.path.abspath(directory)
cur_dir = os.path.abspath(os.getcwd())
cmd = "git log HEAD -n 1 --pretty=format:'%b'"
os.chdir(directory) # Going to the repo's directory
git_info_rex = re.compile(r'(?P<body>^[\s\S]*?)((?:Change-Id:\s)'
r'(?P<change_id>.*)\n?)', re.MULTILINE)
r, e = subprocess.Popen(cmd,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE).communicate()
if e:
print("Error", e)
return -1
else:
try:
txt_body = r.decode('ascii')
except UnicodeDecodeError as E:
txt_body = r.decode('utf-8')
result = txt_body.rstrip()
try:
change_id = git_info_rex.search(result).groupdict()["change_id"].strip()
except:
return -1
os.chdir(cur_dir) #Going back to the initial directory
return change_id
if __name__ == "__main__":
for i in range(len(REFERENCE_CONFIGS)):
REFERENCE_CONFIGS[i] = REFERENCE_CONFIGS[i].strip().lower()
config = identify_config()
if (config[2].lower() in REFERENCE_CONFIGS
and config[0] == "mps2/an521"
and config[1] == "toolchain_GNUARM.cmake"):
# Pushing data for AN521 and GNUARM
print("Configuration " + config[2] + " is a reference")
try :
change_id = get_change_id(PATH_TO_TFM)
except :
change_id = -1
bl2_sizes = get_file_size("bl2.axf")
tfms_sizes = get_file_size("tfm_s.axf")
if (bl2_sizes != -1 and change_id != -1) :
send_file_size(change_id, config[2], bl2_sizes, tfms_sizes)
else :
#Directory or file weren't found
if change_id == -1 :
print("Error : trusted-firmware-m repo not found")
else :
print("Error : file not found")