action: footprint tracking
Add action and scripts for footprint tracking. Signed-off-by: Anas Nashif <anas.nashif@intel.com>
This commit is contained in:
parent
302ac4995b
commit
dfc259d13c
5 changed files with 291 additions and 0 deletions
64
.github/workflows/footprint-tracking.yml
vendored
Normal file
64
.github/workflows/footprint-tracking.yml
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
name: Footprint Tracking
|
||||
|
||||
# Run every 12 hours and on tags
|
||||
on:
|
||||
schedule:
|
||||
- cron: '50 1/12 * * *'
|
||||
push:
|
||||
paths:
|
||||
- 'VERSION'
|
||||
tags:
|
||||
# only publish v* tags, do not care about zephyr-v* which point to the
|
||||
# same commit
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
footprint-tracking-cancel:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.6.0
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
footprint-tracking:
|
||||
runs-on: ubuntu-latest
|
||||
needs: footprint-tracking-cancel
|
||||
container:
|
||||
image: zephyrprojectrtos/ci:v0.17.1
|
||||
options: '--entrypoint /bin/bash'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
env:
|
||||
ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.12.4
|
||||
CLANG_ROOT_DIR: /usr/lib/llvm-12
|
||||
ZEPHYR_TOOLCHAIN_VARIANT: zephyr
|
||||
steps:
|
||||
- name: Update PATH for west
|
||||
run: |
|
||||
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: west setup
|
||||
run: |
|
||||
west init -l . || true
|
||||
west update
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.FOOTPRINT_AWS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.FOOTPRINT_AWS_ACCESS_KEY }}
|
||||
aws-region: us-east-1
|
||||
|
||||
- name: Record Footprint
|
||||
env:
|
||||
BASE_REF: ${{ github.base_ref }}
|
||||
run: |
|
||||
export ZEPHYR_BASE=${PWD}
|
||||
./scripts/footprint/track.py -p scripts/footprint/plan.txt
|
||||
aws s3 sync --quiet footprint_data/ s3://testing.zephyrproject.org/footprint_data/
|
|
@ -564,6 +564,7 @@
|
|||
/scripts/coccicheck @himanshujha199640 @JuliaLawall
|
||||
/scripts/coccinelle/ @himanshujha199640 @JuliaLawall
|
||||
/scripts/coredump/ @dcpleung
|
||||
/scripts/footprint/ @nashif
|
||||
/scripts/kconfig/ @ulfalizer
|
||||
/scripts/logging/dictionary/ @dcpleung
|
||||
/scripts/pylib/twister/expr_parser.py @nashif
|
||||
|
|
10
scripts/footprint/plan.txt
Normal file
10
scripts/footprint/plan.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
footprints,default,frdm_k64f,tests/benchmarks/footprints,
|
||||
footprints,userspace,frdm_k64f,tests/benchmarks/footprints,-DCONF_FILE=prj_userspace.conf
|
||||
footprints,default,disco_l475_iot1,tests/benchmarks/footprints,
|
||||
footprints,userspace,disco_l475_iot1,tests/benchmarks/footprints,-DCONF_FILE=prj_userspace.conf
|
||||
footprints,default,nrf5340dk_nrf5340_cpuapp,tests/benchmarks/footprints,
|
||||
footprints,default,nrf51dk_nrf51422,tests/benchmarks/footprints,
|
||||
footprints,default,altera_max10,tests/benchmarks/footprints,
|
||||
footprints,default,hifive1_revb,tests/benchmarks/footprints,
|
||||
footprints,default,ehl_crb,tests/benchmarks/footprints,
|
||||
footprints,userspace,ehl_crb,tests/benchmarks/footprints,-DCONF_FILE=prj_userspace.conf
|
63
scripts/footprint/track.py
Executable file
63
scripts/footprint/track.py
Executable file
|
@ -0,0 +1,63 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2021 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import csv
|
||||
import subprocess
|
||||
from git import Git
|
||||
import pathlib
|
||||
import shutil
|
||||
import argparse
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generate footprint data based on a predefined plan.")
|
||||
parser.add_argument("-p", "--plan", help="Path of test plan", required=True)
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
g = Git(".")
|
||||
version = g.describe("--abbrev=12")
|
||||
pathlib.Path(f'footprint_data/{version}').mkdir(exist_ok=True, parents=True)
|
||||
|
||||
with open(args.plan) as csvfile:
|
||||
csvreader = csv.reader(csvfile)
|
||||
for row in csvreader:
|
||||
name=row[0]
|
||||
feature=row[1]
|
||||
board=row[2]
|
||||
app=row[3]
|
||||
options=row[4]
|
||||
|
||||
cmd = ['west',
|
||||
'build',
|
||||
'-d',
|
||||
f'out/{name}/{feature}/{board}',
|
||||
'-b',
|
||||
board,
|
||||
f'{app}',
|
||||
'-t',
|
||||
'footprint']
|
||||
|
||||
if options != '':
|
||||
cmd += ['--', f'{options}']
|
||||
|
||||
print(" ".join(cmd))
|
||||
|
||||
|
||||
try:
|
||||
subprocess.check_output(cmd, stderr=subprocess.STDOUT, timeout=120, universal_newlines=True)
|
||||
print("Copying files...")
|
||||
pathlib.Path(f'footprint_data/{version}/{name}/{feature}/{board}').mkdir(parents=True, exist_ok=True)
|
||||
|
||||
shutil.copy(f'out/{name}/{feature}/{board}/ram.json', f'footprint_data/{version}/{name}/{feature}/{board}')
|
||||
shutil.copy(f'out/{name}/{feature}/{board}/rom.json', f'footprint_data/{version}/{name}/{feature}/{board}')
|
||||
except subprocess.CalledProcessError as exc:
|
||||
print("Status : FAIL", exc.returncode, exc.output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
153
scripts/footprint/upload_data.py
Executable file
153
scripts/footprint/upload_data.py
Executable file
|
@ -0,0 +1,153 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2021 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from anytree.importer import DictImporter
|
||||
from anytree import PreOrderIter
|
||||
from anytree.search import find
|
||||
importer = DictImporter()
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import os
|
||||
import json
|
||||
from git import Repo
|
||||
from git.exc import BadName
|
||||
|
||||
from influxdb import InfluxDBClient
|
||||
import glob
|
||||
import argparse
|
||||
from tabulate import tabulate
|
||||
|
||||
TODAY = datetime.utcnow()
|
||||
two_mon_rel = relativedelta(months=4)
|
||||
|
||||
influx_dsn = 'influxdb://localhost:8086/footprint_tracking'
|
||||
|
||||
def create_event(data, board, feature, commit, current_time, typ, application):
|
||||
footprint_data = []
|
||||
client = InfluxDBClient.from_dsn(influx_dsn)
|
||||
client.create_database('footprint_tracking')
|
||||
for d in data.keys():
|
||||
footprint_data.append({
|
||||
"measurement": d,
|
||||
"tags": {
|
||||
"board": board,
|
||||
"commit": commit,
|
||||
"application": application,
|
||||
"type": typ,
|
||||
"feature": feature
|
||||
},
|
||||
"time": current_time,
|
||||
"fields": {
|
||||
"value": data[d]
|
||||
}
|
||||
})
|
||||
|
||||
client.write_points(footprint_data, time_precision='s', database='footprint_tracking')
|
||||
|
||||
|
||||
def parse_args():
|
||||
global args
|
||||
parser = argparse.ArgumentParser(
|
||||
description=__doc__,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
|
||||
parser.add_argument("-d", "--data", help="Data Directory")
|
||||
parser.add_argument("-y", "--dryrun", action="store_true", help="Dry run, do not upload to database")
|
||||
parser.add_argument("-z", "--zephyr-base", help="Zephyr tree")
|
||||
parser.add_argument("-f", "--file", help="JSON file with footprint data")
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
def parse_file(json_file):
|
||||
|
||||
with open(json_file, "r") as fp:
|
||||
contents = json.load(fp)
|
||||
root = importer.import_(contents['symbols'])
|
||||
|
||||
zr = find(root, lambda node: node.name == 'ZEPHYR_BASE')
|
||||
ws = find(root, lambda node: node.name == 'WORKSPACE')
|
||||
|
||||
data = {}
|
||||
if zr and ws:
|
||||
trees = [zr, ws]
|
||||
else:
|
||||
trees = [root]
|
||||
|
||||
for node in PreOrderIter(root, maxlevel=2):
|
||||
if node.name not in ['WORKSPACE', 'ZEPHYR_BASE']:
|
||||
if node.name in ['Root', 'Symbols']:
|
||||
data['all'] = node.size
|
||||
else:
|
||||
data[node.name] = node.size
|
||||
|
||||
for t in trees:
|
||||
root = t.name
|
||||
for node in PreOrderIter(t, maxlevel=2):
|
||||
if node.name == root:
|
||||
continue
|
||||
comp = node.name
|
||||
if comp in ['Root', 'Symbols']:
|
||||
data['all'] = node.size
|
||||
else:
|
||||
data[comp] = node.size
|
||||
|
||||
return data
|
||||
|
||||
def process_files(data_dir, zephyr_base, dry_run):
|
||||
repo = Repo(zephyr_base)
|
||||
|
||||
for hash in os.listdir(f'{data_dir}'):
|
||||
if not dry_run:
|
||||
client = InfluxDBClient.from_dsn(influx_dsn)
|
||||
result = client.query(f"select * from kernel where commit = '{hash}';")
|
||||
if result:
|
||||
print(f"Skipping {hash}...")
|
||||
continue
|
||||
print(f"Importing {hash}...")
|
||||
for file in glob.glob(f"{args.data}/{hash}/**/*json", recursive=True):
|
||||
file_data = file.split("/")
|
||||
json_file = os.path.basename(file)
|
||||
if 'ram' in json_file:
|
||||
typ = 'ram'
|
||||
else:
|
||||
typ = 'rom'
|
||||
commit = file_data[1]
|
||||
app = file_data[2]
|
||||
feature = file_data[3]
|
||||
board = file_data[4]
|
||||
|
||||
data = parse_file(file)
|
||||
|
||||
try:
|
||||
gitcommit = repo.commit(f'{commit}')
|
||||
current_time = gitcommit.committed_datetime
|
||||
except BadName:
|
||||
cidx = commit.find('-g') + 2
|
||||
gitcommit = repo.commit(f'{commit[cidx:]}')
|
||||
current_time = gitcommit.committed_datetime
|
||||
|
||||
print(current_time)
|
||||
|
||||
if not dry_run:
|
||||
create_event(data, board, feature, commit, current_time, typ, app)
|
||||
|
||||
def main():
|
||||
parse_args()
|
||||
|
||||
if args.data and args.zephyr_base:
|
||||
process_files(args.data, args.zephyr_base, args.dryrun)
|
||||
|
||||
if args.file:
|
||||
data = parse_file(args.file)
|
||||
items = []
|
||||
for component,value in data.items():
|
||||
items.append([component,value])
|
||||
|
||||
table = tabulate(items, headers=['Component', 'Size'], tablefmt='orgtbl')
|
||||
print(table)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Add table
Add a link
Reference in a new issue