CI: add size info for binaries

pull/5688/head
Fu Hanxi 2020-07-21 16:00:05 +08:00 zatwierdzone przez Ivan Grokhotkov
rodzic 789e99a37d
commit 6885421976
19 zmienionych plików z 387 dodań i 399 usunięć

Wyświetl plik

@ -107,7 +107,7 @@ void ets_secure_boot_verify_boot_bootloader(void);
* @return true if is Secure boot v2 has been enabled
* False if Secure boot v2 has not been enabled.
*/
bool ets_use_secure_boot_v2();
bool ets_use_secure_boot_v2(void);
#endif /* CONFIG_ESP32_REV_MIN_3 */

Wyświetl plik

@ -0,0 +1,22 @@
#!/usr/bin/env python
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import ttfw_idf
@ttfw_idf.idf_example_test(env_tag="Example_GENERIC", target=['esp32', 'esp32s2'], ci_target=['esp32'])
def test_examples_hello_world(env, extra_data):
app_name = 'hello_world'
dut = env.get_dut(app_name, "examples/get-started/hello_world")
dut.start_app()
res = dut.expect(ttfw_idf.MINIMUM_FREE_HEAP_SIZE_RE)
if not res:
raise ValueError('Maximum heap size info not found')
ttfw_idf.print_heap_size(app_name, dut.app.config_name, dut.TARGET, res[0])
if __name__ == '__main__':
test_examples_hello_world()

Wyświetl plik

@ -31,7 +31,7 @@ void app_main(void)
printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
printf("Free heap: %d\n", esp_get_free_heap_size());
printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size());
for (int i = 10; i >= 0; i--) {
printf("Restarting in %d seconds...\n", i);

Wyświetl plik

@ -0,0 +1,22 @@
#!/usr/bin/env python
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import ttfw_idf
@ttfw_idf.idf_example_test(env_tag="Example_TWAI1", target=['esp32', 'esp32s2'], ci_target=['esp32'])
def test_examples_gpio(env, extra_data):
app_name = "gpio"
dut = env.get_dut(app_name, "examples/peripherals/gpio")
dut.start_app()
res = dut.expect(ttfw_idf.MINIMUM_FREE_HEAP_SIZE_RE)
if not res:
raise ValueError('Maximum heap size info not found')
ttfw_idf.print_heap_size(app_name, dut.app.config_name, dut.TARGET, res[0])
if __name__ == '__main__':
test_examples_gpio()

Wyświetl plik

@ -103,6 +103,8 @@ void app_main(void)
//hook isr handler for specific gpio pin again
gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);
printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size());
int cnt = 0;
while(1) {
printf("cnt: %d\n", cnt++);

Wyświetl plik

@ -65,6 +65,11 @@ def main():
type=argparse.FileType("w"),
help="If specified, the list of builds (with all the placeholders expanded) will be written to this file.",
)
parser.add_argument(
"--size-info",
type=argparse.FileType("a"),
help="If specified, the test case name and size info json will be written to this file"
)
parser.add_argument(
"build_list",
type=argparse.FileType("r"),
@ -119,6 +124,8 @@ def main():
else:
raise SystemExit(1)
else:
if args.size_info:
build_info.write_size_info(args.size_info)
if not build_info.preserve:
logging.info("Removing build directory {}".format(build_info.build_dir))
# we only remove binaries here, log files are still needed by check_build_warnings.py

Wyświetl plik

@ -1,105 +0,0 @@
#!/usr/bin/env bash
#
# Build all examples from the examples directory, in BUILD_PATH to
# ensure they can run when copied to a new directory.
#
# Runs as part of CI process.
#
# -----------------------------------------------------------------------------
# Safety settings (see https://gist.github.com/ilg-ul/383869cbb01f61a51c4d).
if [[ ! -z ${DEBUG_SHELL} ]]
then
set -x # Activate the expand mode if DEBUG is anything but empty.
fi
set -o errexit # Exit if command failed.
set -o pipefail # Exit if pipe failed.
export PATH="$IDF_PATH/tools/ci:$IDF_PATH/tools:$PATH"
# -----------------------------------------------------------------------------
die() {
echo "${1:-"Unknown Error"}" 1>&2
exit 1
}
[ -z ${IDF_PATH} ] && die "IDF_PATH is not set"
[ -z ${LOG_PATH} ] && die "LOG_PATH is not set"
[ -z ${BUILD_PATH} ] && die "BUILD_PATH is not set"
[ -z ${IDF_TARGET} ] && die "IDF_TARGET is not set"
[ -z ${EXAMPLE_TEST_BUILD_SYSTEM} ] && die "EXAMPLE_TEST_BUILD_SYSTEM is not set"
[ -z ${SCAN_EXAMPLE_TEST_JSON} ] && die "SCAN_EXAMPLE_TEST_JSON is not set"
[ -d ${LOG_PATH} ] || mkdir -p ${LOG_PATH}
[ -d ${BUILD_PATH} ] || mkdir -p ${BUILD_PATH}
if [ -z ${CI_NODE_TOTAL} ]; then
CI_NODE_TOTAL=1
echo "Assuming CI_NODE_TOTAL=${CI_NODE_TOTAL}"
fi
if [ -z ${CI_NODE_INDEX} ]; then
# Gitlab uses a 1-based index
CI_NODE_INDEX=1
echo "Assuming CI_NODE_INDEX=${CI_NODE_INDEX}"
fi
export EXTRA_CFLAGS="${PEDANTIC_CFLAGS:-}"
export EXTRA_CXXFLAGS="${PEDANTIC_CXXFLAGS:-}"
set -o nounset # Exit if variable not set.
export REALPATH=realpath
if [ "$(uname -s)" = "Darwin" ]; then
export REALPATH=grealpath
fi
# Convert LOG_PATH and BUILD_PATH to relative, to make the json file less verbose.
LOG_PATH=$(${REALPATH} --relative-to ${IDF_PATH} ${LOG_PATH})
BUILD_PATH=$(${REALPATH} --relative-to ${IDF_PATH} ${BUILD_PATH})
ALL_BUILD_LIST_JSON="${BUILD_PATH}/list.json"
JOB_BUILD_LIST_JSON="${BUILD_PATH}/list_job_${CI_NODE_INDEX}.json"
echo "build_examples running for target $IDF_TARGET"
cd ${IDF_PATH}
# This part of the script produces the same result for all the example build jobs. It may be moved to a separate stage
# (pre-build) later, then the build jobs will receive ${BUILD_LIST_JSON} file as an artifact.
# If changing the work-dir or build-dir format, remember to update the "artifacts" in gitlab-ci configs, and IDFApp.py.
${IDF_PATH}/tools/find_apps.py \
-vv \
--format json \
--work-dir "${BUILD_PATH}/@f/@w/@t" \
--build-dir build \
--build-log "${LOG_PATH}/@f_@w.txt" \
--output ${ALL_BUILD_LIST_JSON} \
--config 'sdkconfig.ci=default' \
--config 'sdkconfig.ci.*=' \
--config '=default' \
--app-list ${SCAN_EXAMPLE_TEST_JSON}
# --config rules above explained:
# 1. If sdkconfig.ci exists, use it build the example with configuration name "default"
# 2. If sdkconfig.ci.* exists, use it to build the "*" configuration
# 3. If none of the above exist, build the default configuration under the name "default"
# The part below is where the actual builds happen
${IDF_PATH}/tools/build_apps.py \
-vv \
--format json \
--keep-going \
--parallel-count ${CI_NODE_TOTAL} \
--parallel-index ${CI_NODE_INDEX} \
--output-build-list ${JOB_BUILD_LIST_JSON} \
${ALL_BUILD_LIST_JSON}\
# Check for build warnings
${IDF_PATH}/tools/ci/check_build_warnings.py -vv ${JOB_BUILD_LIST_JSON}

Wyświetl plik

@ -1,100 +0,0 @@
#!/usr/bin/env bash
#
# Build test apps
#
# Runs as part of CI process.
#
# -----------------------------------------------------------------------------
# Safety settings (see https://gist.github.com/ilg-ul/383869cbb01f61a51c4d).
if [[ ! -z ${DEBUG_SHELL} ]]
then
set -x # Activate the expand mode if DEBUG is anything but empty.
fi
set -o errexit # Exit if command failed.
set -o pipefail # Exit if pipe failed.
export PATH="$IDF_PATH/tools/ci:$IDF_PATH/tools:$PATH"
# -----------------------------------------------------------------------------
die() {
echo "${1:-"Unknown Error"}" 1>&2
exit 1
}
[ -z ${IDF_PATH} ] && die "IDF_PATH is not set"
[ -z ${LOG_PATH} ] && die "LOG_PATH is not set"
[ -z ${BUILD_PATH} ] && die "BUILD_PATH is not set"
[ -z ${IDF_TARGET} ] && die "IDF_TARGET is not set"
[ -z ${SCAN_CUSTOM_TEST_JSON} ] && die "SCAN_CUSTOM_TEST_JSON is not set"
[ -d ${LOG_PATH} ] || mkdir -p ${LOG_PATH}
[ -d ${BUILD_PATH} ] || mkdir -p ${BUILD_PATH}
if [ -z ${CI_NODE_TOTAL} ]; then
CI_NODE_TOTAL=1
echo "Assuming CI_NODE_TOTAL=${CI_NODE_TOTAL}"
fi
if [ -z ${CI_NODE_INDEX} ]; then
# Gitlab uses a 1-based index
CI_NODE_INDEX=1
echo "Assuming CI_NODE_INDEX=${CI_NODE_INDEX}"
fi
set -o nounset # Exit if variable not set.
# Convert LOG_PATH to relative, to make the json file less verbose.
LOG_PATH=$(realpath --relative-to ${IDF_PATH} ${LOG_PATH})
BUILD_PATH=$(realpath --relative-to ${IDF_PATH} ${BUILD_PATH})
ALL_BUILD_LIST_JSON="${BUILD_PATH}/list.json"
JOB_BUILD_LIST_JSON="${BUILD_PATH}/list_job_${CI_NODE_INDEX}.json"
echo "build_test_apps running for target $IDF_TARGET"
cd ${IDF_PATH}
# This part of the script produces the same result for all the test app build jobs. It may be moved to a separate stage
# (pre-build) later, then the build jobs will receive ${BUILD_LIST_JSON} file as an artifact.
# If changing the work-dir or build-dir, remember to update the "artifacts" in gitlab-ci configs, and IDFApp.py.
${IDF_PATH}/tools/find_apps.py \
-vv \
--format json \
--work-dir "${BUILD_PATH}/@f/@w/@t" \
--build-dir build \
--build-log "${LOG_PATH}/@f_@w.txt" \
--output ${ALL_BUILD_LIST_JSON} \
--config 'sdkconfig.ci=default' \
--config 'sdkconfig.ci.*=' \
--config '=default' \
--app-list ${SCAN_CUSTOM_TEST_JSON}
# --config rules above explained:
# 1. If sdkconfig.ci exists, use it build the example with configuration name "default"
# 2. If sdkconfig.ci.* exists, use it to build the "*" configuration
# 3. If none of the above exist, build the default configuration under the name "default"
# --work-dir and --build-log above uses "placeholders" @x:
# - @f: full path to the test with slashes replaced with underscores
# - @w: wildcard used as config name
# - @t: target name
# so the workdir .../@f/@w/@t would expand to e.g. tools_test_apps_system_startup/default/esp32
# The part below is where the actual builds happen
${IDF_PATH}/tools/build_apps.py \
-vv \
--format json \
--keep-going \
--parallel-count ${CI_NODE_TOTAL} \
--parallel-index ${CI_NODE_INDEX} \
--output-build-list ${JOB_BUILD_LIST_JSON} \
${ALL_BUILD_LIST_JSON}\
# Check for build warnings
${IDF_PATH}/tools/ci/check_build_warnings.py -vv ${JOB_BUILD_LIST_JSON}

Wyświetl plik

@ -1,108 +0,0 @@
#!/bin/bash
#
# Build unit test app
#
# Runs as part of CI process.
#
# -----------------------------------------------------------------------------
# Safety settings (see https://gist.github.com/ilg-ul/383869cbb01f61a51c4d).
if [[ ! -z ${DEBUG_SHELL} ]]
then
set -x # Activate the expand mode if DEBUG is anything but empty.
fi
set -o errexit # Exit if command failed.
set -o pipefail # Exit if pipe failed.
export PATH="$IDF_PATH/tools/ci:$IDF_PATH/tools:$PATH"
# -----------------------------------------------------------------------------
die() {
echo "${1:-"Unknown Error"}" 1>&2
exit 1
}
[ -z ${IDF_PATH} ] && die "IDF_PATH is not set"
[ -z ${LOG_PATH} ] && die "LOG_PATH is not set"
[ -z ${IDF_TARGET} ] && die "IDF_TARGET is not set"
[ -d ${LOG_PATH} ] || mkdir -p ${LOG_PATH}
# Relative to IDF_PATH
# If changing the BUILD_PATH, remember to update the "artifacts" in gitlab-ci configs, and IDFApp.py.
BUILD_PATH=${IDF_PATH}/tools/unit-test-app/builds
OUTPUT_PATH=${IDF_PATH}/tools/unit-test-app/output
mkdir -p ${BUILD_PATH}/${IDF_TARGET}
mkdir -p ${OUTPUT_PATH}/${IDF_TARGET}
if [ -z ${CI_NODE_TOTAL} ]; then
CI_NODE_TOTAL=1
echo "Assuming CI_NODE_TOTAL=${CI_NODE_TOTAL}"
fi
if [ -z ${CI_NODE_INDEX} ]; then
# Gitlab uses a 1-based index
CI_NODE_INDEX=1
echo "Assuming CI_NODE_INDEX=${CI_NODE_INDEX}"
fi
set -o nounset # Exit if variable not set.
# Convert LOG_PATH to relative, to make the json file less verbose.
LOG_PATH=$(realpath --relative-to ${IDF_PATH} ${LOG_PATH})
ALL_BUILD_LIST_JSON="${BUILD_PATH}/${IDF_TARGET}/list.json"
JOB_BUILD_LIST_JSON="${BUILD_PATH}/${IDF_TARGET}/list_job_${CI_NODE_INDEX}.json"
echo "build_unit_test running for target $IDF_TARGET"
cd ${IDF_PATH}
# This part of the script produces the same result for all the unit test app build jobs. It may be moved to a separate stage
# (pre-build) later, then the build jobs will receive ${BUILD_LIST_JSON} file as an artifact.
${IDF_PATH}/tools/find_apps.py \
-p tools/unit-test-app \
-vv \
--format json \
--build-system cmake \
--target ${IDF_TARGET} \
--recursive \
--build-dir "builds/@t/@w" \
--build-log "${LOG_PATH}/@w.txt" \
--output ${ALL_BUILD_LIST_JSON} \
--config 'configs/*='
# The part below is where the actual builds happen
${IDF_PATH}/tools/build_apps.py \
-vv \
--format json \
--keep-going \
--parallel-count ${CI_NODE_TOTAL} \
--parallel-index ${CI_NODE_INDEX} \
--output-build-list ${JOB_BUILD_LIST_JSON} \
${ALL_BUILD_LIST_JSON}\
# Copy build artifacts to output directory
build_names=$(cd ${BUILD_PATH}/${IDF_TARGET}; find . -maxdepth 1 \! -name . -prune -type d | cut -c 3-)
for build_name in $build_names; do
src=${BUILD_PATH}/${IDF_TARGET}/${build_name}
dst=${OUTPUT_PATH}/${IDF_TARGET}/${build_name}
echo "Copying artifacts from ${src} to ${dst}"
rm -rf ${dst}
mkdir -p ${dst}
cp ${src}/{*.bin,*.elf,*.map,sdkconfig,flasher_args.json} ${dst}/
mkdir -p ${dst}/bootloader
cp ${src}/bootloader/*.bin ${dst}/bootloader/
mkdir -p ${dst}/partition_table
cp ${src}/partition_table/*.bin ${dst}/partition_table/
done
# Check for build warnings
${IDF_PATH}/tools/ci/check_build_warnings.py -vv ${JOB_BUILD_LIST_JSON}

Wyświetl plik

@ -6,6 +6,7 @@
variables:
BATCH_BUILD: "1"
V: "0"
SIZE_INFO_LOCATION: "$CI_PROJECT_DIR/size_info.txt"
.build_ssc_template:
extends: .build_template
@ -45,8 +46,10 @@ build_ssc_esp32s2:
paths:
- tools/unit-test-app/output/${IDF_TARGET}
- tools/unit-test-app/builds/${IDF_TARGET}/*.json
- tools/unit-test-app/builds/${IDF_TARGET}/*/size.json
- components/idf_test/unit_test/*.yml
- ${LOG_PATH}
- $LOG_PATH
- $SIZE_INFO_LOCATION
when: always
expire_in: 4 days
only:
@ -58,16 +61,17 @@ build_ssc_esp32s2:
- $BOT_LABEL_REGULAR_TEST
variables:
LOG_PATH: "$CI_PROJECT_DIR/log_ut_cmake"
BUILD_PATH: ${CI_PROJECT_DIR}/tools/unit-test-app/builds
OUTPUT_PATH: ${CI_PROJECT_DIR}/tools/unit-test-app/output
BUILD_SYSTEM: "cmake"
TEST_TYPE: "unit_test"
script:
# RISC-V toolchain is optional but ULP may need it, so install:
- $IDF_PATH/tools/idf_tools.py install riscv-none-embed-gcc
- . $IDF_PATH/export.sh
- export EXTRA_CFLAGS=${PEDANTIC_CFLAGS}
- export EXTRA_CXXFLAGS=${PEDANTIC_CXXFLAGS}
- mkdir -p ${LOG_PATH}
- ${CI_PROJECT_DIR}/tools/ci/build_unit_test.sh
- ${IDF_PATH}/tools/ci/find_apps_build_apps.sh
- cd $CI_PROJECT_DIR/tools/unit-test-app
- python tools/UnitTestParser.py
- python tools/UnitTestParser.py ${BUILD_PATH}
build_esp_idf_tests_cmake_esp32:
extends: .build_esp_idf_tests_cmake
@ -85,8 +89,6 @@ build_esp_idf_tests_cmake_esp32s2:
artifacts:
when: always
expire_in: 4 days
variables:
SCAN_EXAMPLE_TEST_JSON: ${CI_PROJECT_DIR}/examples/test_configs/scan_${IDF_TARGET}_${EXAMPLE_TEST_BUILD_SYSTEM}.json
only:
# Here both 'variables' and 'refs' conditions are given. They are combined with "AND" logic.
variables:
@ -95,15 +97,16 @@ build_esp_idf_tests_cmake_esp32s2:
- $BOT_LABEL_EXAMPLE_TEST
- $BOT_LABEL_REGULAR_TEST
- $BOT_LABEL_WEEKEND_TEST
variables:
SCAN_TEST_JSON: ${CI_PROJECT_DIR}/examples/test_configs/scan_${IDF_TARGET}_${BUILD_SYSTEM}.json
TEST_TYPE: "example_test"
script:
# RISC-V toolchain is optional but ULP may need it, so install:
# RISC-V toolchain is optional but ULP may need it, so install:
- $IDF_PATH/tools/idf_tools.py install riscv-none-embed-gcc
- . $IDF_PATH/export.sh
# it's not possible to build 100% out-of-tree and have the "artifacts"
# mechanism work, but this is the next best thing
- mkdir ${BUILD_PATH}
- mkdir -p ${LOG_PATH}
- ${IDF_PATH}/tools/ci/build_examples.sh
- ${IDF_PATH}/tools/ci/find_apps_build_apps.sh
build_examples_make:
extends: .build_examples_template
@ -113,10 +116,12 @@ build_examples_make:
artifacts:
paths:
- $LOG_PATH
- build_examples/*/*/*/build/size.json
- $SIZE_INFO_LOCATION
variables:
LOG_PATH: "${CI_PROJECT_DIR}/log_examples_make"
BUILD_PATH: "${CI_PROJECT_DIR}/build_examples_make"
EXAMPLE_TEST_BUILD_SYSTEM: "make"
BUILD_SYSTEM: "make"
IDF_TARGET: "esp32" # currently we only support esp32
only:
refs:
@ -138,6 +143,7 @@ build_examples_make:
- build_examples/list.json
- build_examples/list_job_*.json
- build_examples/*/*/*/sdkconfig
- build_examples/*/*/*/build/size.json
- build_examples/*/*/*/build/*.bin
- build_examples/*/*/*/build/*.elf
- build_examples/*/*/*/build/*.map
@ -145,10 +151,11 @@ build_examples_make:
- build_examples/*/*/*/build/bootloader/*.bin
- build_examples/*/*/*/build/partition_table/*.bin
- $LOG_PATH
- $SIZE_INFO_LOCATION
variables:
LOG_PATH: "${CI_PROJECT_DIR}/log_examples"
BUILD_PATH: "${CI_PROJECT_DIR}/build_examples"
EXAMPLE_TEST_BUILD_SYSTEM: "cmake"
BUILD_SYSTEM: "cmake"
build_examples_cmake_esp32:
extends: .build_examples_cmake
@ -170,20 +177,23 @@ build_examples_cmake_esp32s2:
paths:
- build_test_apps/list.json
- build_test_apps/list_job_*.json
- build_test_apps/*/*/*/build/*.bin
- build_test_apps/*/*/*/sdkconfig
- build_test_apps/*/*/*/build/size.json
- build_test_apps/*/*/*/build/*.bin
- build_test_apps/*/*/*/build/*.elf
- build_test_apps/*/*/*/build/*.map
- build_test_apps/*/*/*/build/flasher_args.json
- build_test_apps/*/*/*/build/bootloader/*.bin
- build_test_apps/*/*/*/build/partition_table/*.bin
- $LOG_PATH
- $SIZE_INFO_LOCATION
expire_in: 3 days
variables:
LOG_PATH: "${CI_PROJECT_DIR}/log_test_apps"
BUILD_PATH: "${CI_PROJECT_DIR}/build_test_apps"
CUSTOM_TEST_BUILD_SYSTEM: "cmake"
SCAN_CUSTOM_TEST_JSON: ${CI_PROJECT_DIR}/tools/test_apps/test_configs/scan_${IDF_TARGET}_${CUSTOM_TEST_BUILD_SYSTEM}.json
BUILD_SYSTEM: "cmake"
SCAN_TEST_JSON: ${CI_PROJECT_DIR}/tools/test_apps/test_configs/scan_${IDF_TARGET}_${BUILD_SYSTEM}.json
TEST_TYPE: custom_test
only:
variables:
- $BOT_TRIGGER_WITH_LABEL == null
@ -192,9 +202,7 @@ build_examples_cmake_esp32s2:
- $BOT_LABEL_CUSTOM_TEST
- $BOT_LABEL_WEEKEND_TEST
script:
- mkdir -p ${BUILD_PATH}
- mkdir -p ${LOG_PATH}
- ${IDF_PATH}/tools/ci/build_test_apps.sh
- ${IDF_PATH}/tools/ci/find_apps_build_apps.sh
build_test_apps_esp32:
extends: .build_test_apps

Wyświetl plik

@ -224,7 +224,7 @@ example_test_001B:
example_test_001C:
extends: .example_test_template
parallel: 2
parallel: 3
tags:
- ESP32
- Example_GENERIC

Wyświetl plik

@ -33,10 +33,6 @@ tools/build_apps.py
tools/check_kconfigs.py
tools/check_python_dependencies.py
tools/ci/apply_bot_filter.py
tools/ci/build_examples.sh
tools/ci/build_examples_cmake.sh
tools/ci/build_test_apps.sh
tools/ci/build_unit_test.sh
tools/ci/check-executable.sh
tools/ci/check-line-endings.sh
tools/ci/check_build_warnings.py
@ -50,6 +46,7 @@ tools/ci/check_ut_cmake_make.sh
tools/ci/checkout_project_ref.py
tools/ci/deploy_docs.py
tools/ci/envsubst.py
tools/ci/find_apps_build_apps.sh
tools/ci/fix_empty_prototypes.sh
tools/ci/get-full-sources.sh
tools/ci/get_supported_examples.sh

Wyświetl plik

@ -0,0 +1,172 @@
#!/usr/bin/env bash
#
# Find apps and build apps for example_test, custom_test, and unit_test
#
# Runs as part of CI process.
#
# -----------------------------------------------------------------------------
# Safety settings (see https://gist.github.com/ilg-ul/383869cbb01f61a51c4d).
if [[ -n ${DEBUG_SHELL} ]]; then
set -x # Activate the expand mode if DEBUG is anything but empty.
fi
if [ -z ${CI_NODE_TOTAL} ]; then
CI_NODE_TOTAL=1
echo "Assuming CI_NODE_TOTAL=${CI_NODE_TOTAL}"
fi
if [ -z ${CI_NODE_INDEX} ]; then
# Gitlab uses a 1-based index
CI_NODE_INDEX=1
echo "Assuming CI_NODE_INDEX=${CI_NODE_INDEX}"
fi
set -o errexit # Exit if command failed.
set -o pipefail # Exit if pipe failed.
set -o nounset # Exit if variable not set.
export PATH="$IDF_PATH/tools/ci:$IDF_PATH/tools:$PATH"
# -----------------------------------------------------------------------------
die() {
echo "${1:-"Unknown Error"}" 1>&2
exit 1
}
[ -d ${BUILD_PATH} ] || mkdir -p ${BUILD_PATH}
[ -d ${LOG_PATH} ] || mkdir -p ${LOG_PATH}
[ -f ${SIZE_INFO_LOCATION} ] && rm ${SIZE_INFO_LOCATION}
export REALPATH=realpath
if [ "$(uname -s)" = "Darwin" ]; then
export REALPATH=grealpath
fi
# Convert LOG_PATH and BUILD_PATH to relative, to make the json file less verbose.
BUILD_PATH=$(${REALPATH} --relative-to ${IDF_PATH} ${BUILD_PATH})
LOG_PATH=$(${REALPATH} --relative-to ${IDF_PATH} ${LOG_PATH})
ALL_BUILD_LIST_JSON="${BUILD_PATH}/list.json"
JOB_BUILD_LIST_JSON="${BUILD_PATH}/list_job_${CI_NODE_INDEX}.json"
# -----------------------------------------------------------------------------
# common variables, will specify special cases later
WORK_DIR="--work-dir ${BUILD_PATH}/@f/@w/@t"
BUILD_DIR="build"
BUILD_LOG="${LOG_PATH}/@f_@w.txt"
CONFIG="--config sdkconfig.ci=default
--config sdkconfig.ci.*=
--config =default"
export EXTRA_CFLAGS="${PEDANTIC_CFLAGS}"
export EXTRA_CXXFLAGS="${PEDANTIC_CXXFLAGS}"
# --config rules above explained:
# 1. If sdkconfig.ci exists, use it build the example with configuration name "default"
# 2. If sdkconfig.ci.* exists, use it to build the "*" configuration
# 3. If none of the above exist, build the default configuration under the name "default"
# --work-dir and --build-log above uses "placeholders" @x:
# - @f: full path to the test with slashes replaced with underscores
# - @w: wildcard used as config name
# - @t: target name
# so the workdir .../@f/@w/@t would expand to e.g. tools_test_apps_system_startup/default/esp32
# -----------------------------------------------------------------------------
# Example tests specific settings
if [ "${TEST_TYPE}" = "example_test" ]; then
export EXTRA_CFLAGS="${PEDANTIC_CFLAGS:-}"
export EXTRA_CXXFLAGS="${PEDANTIC_CXXFLAGS:-}"
EXTRA_ARGS="--app-list ${SCAN_TEST_JSON}"
# -----------------------------------------------------------------------------
# Custom tests specific settings
elif [ "${TEST_TYPE}" = "custom_test" ]; then
EXTRA_ARGS="--app-list ${SCAN_TEST_JSON}"
# -----------------------------------------------------------------------------
# Unit tests specific settings
elif [ "${TEST_TYPE}" = "unit_test" ]; then
ALL_BUILD_LIST_JSON="${BUILD_PATH}/${IDF_TARGET}/list.json"
JOB_BUILD_LIST_JSON="${BUILD_PATH}/${IDF_TARGET}/list_job_${CI_NODE_INDEX}.json"
mkdir -p ${BUILD_PATH}/${IDF_TARGET}
mkdir -p ${OUTPUT_PATH}/${IDF_TARGET}
WORK_DIR=""
BUILD_DIR="builds/@t/@w"
BUILD_LOG="${LOG_PATH}/@w.txt"
APP_FOLDER="tools/unit-test-app"
EXTRA_ARGS="
-p ${APP_FOLDER}
--build-system ${BUILD_SYSTEM}
--target ${IDF_TARGET}
--recursive
"
CONFIG="--config configs/*="
# -----------------------------------------------------------------------------
else
die "TEST_TYPE should only be one of {example_test, custom_test, unit_test}"
fi
echo "$TEST_TYPE running for target $IDF_TARGET"
cd ${IDF_PATH}
# This part of the script produces the same result for all the build jobs.
#
# It may be moved to a separate stage (pre-build) later, then the build jobs
# will receive ${BUILD_LIST_JSON} file as an artifact.
#
# If changing the work-dir or build-dir, remember to update the "artifacts" in
# gitlab-ci configs, and IDFApp.py.
${IDF_PATH}/tools/find_apps.py \
-vv \
--format json \
${WORK_DIR} \
--build-dir ${BUILD_DIR} \
--build-log ${BUILD_LOG} \
--output ${ALL_BUILD_LIST_JSON} \
${EXTRA_ARGS} \
${CONFIG}
# The part below is where the actual builds happen
${IDF_PATH}/tools/build_apps.py \
-vv \
--format json \
--keep-going \
--parallel-count ${CI_NODE_TOTAL} \
--parallel-index ${CI_NODE_INDEX} \
--output-build-list ${JOB_BUILD_LIST_JSON} \
--size-info ${SIZE_INFO_LOCATION} \
${ALL_BUILD_LIST_JSON}
# Check for build warnings
${IDF_PATH}/tools/ci/check_build_warnings.py -vv ${JOB_BUILD_LIST_JSON}
if [ "${TEST_TYPE}" = "unit_test" ]; then
# Copy build artifacts to output directory
build_names=$(
cd ${BUILD_PATH}/${IDF_TARGET}
find . -maxdepth 1 \! -name . -prune -type d | cut -c 3-
)
for build_name in $build_names; do
src=${BUILD_PATH}/${IDF_TARGET}/${build_name}
dst=${OUTPUT_PATH}/${IDF_TARGET}/${build_name}
echo "Copying artifacts from ${src} to ${dst}"
rm -rf ${dst}
mkdir -p ${dst}
cp ${src}/{*.bin,*.elf,*.map,sdkconfig,flasher_args.json} ${dst}/
mkdir -p ${dst}/bootloader
cp ${src}/bootloader/*.bin ${dst}/bootloader/
mkdir -p ${dst}/partition_table
cp ${src}/partition_table/*.bin ${dst}/partition_table/
done
fi

Wyświetl plik

@ -63,6 +63,7 @@ def local_test_check(decorator_target):
if os.getenv('CI_JOB_ID'): # Only auto-detect target when running locally
return idf_target
decorator_target = upper_list_or_str(decorator_target)
expected_json_path = os.path.join('build', 'config', 'sdkconfig.json')
if os.path.exists(expected_json_path):
sdkconfig = json.load(open(expected_json_path))
@ -262,3 +263,22 @@ def check_performance(item, value, target):
_check_perf(op, value)
# if no exception was thrown then the performance is met and no need to continue
break
MINIMUM_FREE_HEAP_SIZE_RE = re.compile(r'Minimum free heap size: (\d+) bytes')
def print_heap_size(app_name, config_name, target, minimum_free_heap_size):
"""
Do not change the print output in case you really need to.
The result is parsed by ci-dashboard project
"""
print('------ heap size info ------\n'
'[app_name] {}\n'
'[config_name] {}\n'
'[target] {}\n'
'[minimum_free_heap_size] {} Bytes\n'
'------ heap size end ------'.format(app_name,
'' if not config_name else config_name,
target,
minimum_free_heap_size))

Wyświetl plik

@ -1,14 +1,14 @@
import os
import sys
import subprocess
import logging
import shutil
import os
import re
import shutil
import subprocess
import sys
from .common import BuildSystem, BuildItem, BuildError
BUILD_SYSTEM_CMAKE = "cmake"
IDF_PY = "idf.py"
IDF_PY = os.path.join(os.environ["IDF_PATH"], "tools", "idf.py")
# While ESP-IDF component CMakeLists files can be identified by the presence of 'idf_component_register' string,
# there is no equivalent for the project CMakeLists files. This seems to be the best option...
@ -30,8 +30,7 @@ class CMakeBuildSystem(BuildSystem):
build_path, work_path, extra_cmakecache_items = cls.build_prepare(build_item)
# Prepare the build arguments
args = [
# Assume it is the responsibility of the caller to
# set up the environment (run . ./export.sh)
sys.executable,
IDF_PY,
"-B",
build_path,
@ -73,6 +72,7 @@ class CMakeBuildSystem(BuildSystem):
os.path.join(work_path, "sdkconfig"),
os.path.join(build_path, "sdkconfig"),
)
build_item.size_json_fp = build_item.get_size_json_fp()
finally:
if log_file:
log_file.close()

Wyświetl plik

@ -1,15 +1,18 @@
# coding=utf-8
import fnmatch
import json
import logging
import os
import re
import shutil
import subprocess
import sys
import os
from abc import abstractmethod
from collections import namedtuple
import logging
import json
import typing
from io import open
import typing
DEFAULT_TARGET = "esp32"
TARGET_PLACEHOLDER = "@t"
@ -18,6 +21,8 @@ NAME_PLACEHOLDER = "@n"
FULL_NAME_PLACEHOLDER = "@f"
INDEX_PLACEHOLDER = "@i"
IDF_SIZE_PY = os.path.join(os.environ["IDF_PATH"], "tools", "idf_size.py")
SDKCONFIG_LINE_REGEX = re.compile(r"^([^=]+)=\"?([^\"\n]*)\"?\n*$")
# If these keys are present in sdkconfig.defaults, they will be extracted and passed to CMake
@ -55,6 +60,14 @@ def config_rules_from_str(rule_strings): # type: (typing.List[str]) -> typing.L
return rules
def find_first_match(pattern, path):
for root, _, files in os.walk(path):
res = fnmatch.filter(files, pattern)
if res:
return os.path.join(root, res[0])
return None
class BuildItem(object):
"""
Instance of this class represents one build of an application.
@ -88,6 +101,7 @@ class BuildItem(object):
self.preserve = preserve_artifacts
self._app_name = os.path.basename(os.path.normpath(app_path))
self.size_json_fp = None
# Some miscellaneous build properties which are set later, at the build stage
self.index = None
@ -95,6 +109,14 @@ class BuildItem(object):
self.dry_run = False
self.keep_going = False
self.work_path = self.work_dir or self.app_dir
if not self.build_dir:
self.build_path = os.path.join(self.work_path, "build")
elif os.path.isabs(self.build_dir):
self.build_path = self.build_dir
else:
self.build_path = os.path.normpath(os.path.join(self.work_path, self.build_dir))
@property
def app_dir(self):
"""
@ -208,6 +230,39 @@ class BuildItem(object):
path = os.path.expandvars(path)
return path
def get_size_json_fp(self):
if self.size_json_fp and os.path.exists(self.size_json_fp):
return self.size_json_fp
assert os.path.exists(self.build_path)
assert os.path.exists(self.work_path)
map_file = find_first_match('*.map', self.build_path)
if not map_file:
raise ValueError('.map file not found under "{}"'.format(self.build_path))
size_json_fp = os.path.join(self.build_path, 'size.json')
idf_size_args = [
sys.executable,
IDF_SIZE_PY,
'--json',
'-o', size_json_fp,
map_file
]
subprocess.check_call(idf_size_args)
return size_json_fp
def write_size_info(self, size_info_fs):
if not self.size_json_fp or (not os.path.exists(self.size_json_fp)):
raise OSError('Run get_size_json_fp() for app {} after built binary'.format(self.app_dir))
size_info_dict = {
'app_name': self._app_name,
'config_name': self.config_name,
'target': self.target,
'path': self.size_json_fp,
}
size_info_fs.write(json.dumps(size_info_dict) + '\n')
class BuildSystem(object):
"""
@ -221,13 +276,8 @@ class BuildSystem(object):
@classmethod
def build_prepare(cls, build_item):
app_path = build_item.app_dir
work_path = build_item.work_dir or app_path
if not build_item.build_dir:
build_path = os.path.join(work_path, "build")
elif os.path.isabs(build_item.build_dir):
build_path = build_item.build_dir
else:
build_path = os.path.join(work_path, build_item.build_dir)
work_path = build_item.work_path
build_path = build_item.build_path
if work_path != app_path:
if os.path.exists(work_path):

Wyświetl plik

@ -48,6 +48,8 @@ class MakeBuildSystem(BuildSystem):
log_file.close()
raise BuildError("Build failed with exit code {}".format(e.returncode))
build_item.size_json_fp = build_item.get_size_json_fp()
@staticmethod
def is_app(path):
makefile_path = os.path.join(path, "Makefile")

Wyświetl plik

@ -10,18 +10,18 @@
/* utility functions */
static void die(const char* msg) __attribute__ ((noreturn));
static const char* get_test_name();
static const char* get_test_name(void);
/* functions which cause an exception/panic in different ways */
static void test_abort();
static void test_int_wdt();
static void test_task_wdt();
static void test_storeprohibited();
static void test_cache_error();
static void test_int_wdt_cache_disabled();
static void test_stack_overflow();
static void test_illegal_instruction();
static void test_instr_fetch_prohibited();
static void test_abort(void);
static void test_int_wdt(void);
static void test_task_wdt(void);
static void test_storeprohibited(void);
static void test_cache_error(void);
static void test_int_wdt_cache_disabled(void);
static void test_stack_overflow(void);
static void test_illegal_instruction(void);
static void test_instr_fetch_prohibited(void);
void app_main(void)
@ -60,12 +60,12 @@ void app_main(void)
/* implementations of the test functions */
static void test_abort()
static void test_abort(void)
{
abort();
}
static void test_int_wdt()
static void test_int_wdt(void)
{
portDISABLE_INTERRUPTS();
while (true) {
@ -73,25 +73,25 @@ static void test_int_wdt()
}
}
static void test_task_wdt()
static void test_task_wdt(void)
{
while (true) {
;
}
}
static void test_storeprohibited()
static void test_storeprohibited(void)
{
*(int*) 0x1 = 0;
}
static IRAM_ATTR void test_cache_error()
static IRAM_ATTR void test_cache_error(void)
{
esp_flash_default_chip->os_func->start(esp_flash_default_chip->os_func_data);
die("this should not be printed");
}
static void IRAM_ATTR test_int_wdt_cache_disabled()
static void IRAM_ATTR test_int_wdt_cache_disabled(void)
{
esp_flash_default_chip->os_func->start(esp_flash_default_chip->os_func_data);
portDISABLE_INTERRUPTS();
@ -100,7 +100,7 @@ static void IRAM_ATTR test_int_wdt_cache_disabled()
}
}
static void test_stack_overflow()
static void test_stack_overflow(void)
{
volatile uint8_t stuff[CONFIG_ESP_MAIN_TASK_STACK_SIZE * 2];
for (int i = 0; i < sizeof(stuff); ++i) {
@ -108,12 +108,12 @@ static void test_stack_overflow()
}
}
static void test_illegal_instruction()
static void test_illegal_instruction(void)
{
__asm__ __volatile__("ill");
}
static void test_instr_fetch_prohibited()
static void test_instr_fetch_prohibited(void)
{
typedef void (*fptr_t)(void);
volatile fptr_t fptr = (fptr_t) 0x4;
@ -124,7 +124,7 @@ static void test_instr_fetch_prohibited()
#define BOOT_CMD_MAX_LEN (128)
static const char* get_test_name()
static const char* get_test_name(void)
{
static char test_name_str[BOOT_CMD_MAX_LEN] = {0};

Wyświetl plik

@ -1,10 +1,12 @@
from __future__ import print_function
import argparse
import yaml
import os
import re
import shutil
import subprocess
import sys
from copy import deepcopy
import CreateSectionTable
@ -45,7 +47,6 @@ class Parser(object):
CONFIG_DEPENDENCY_FILE = os.path.join("tools", "unit-test-app", "tools", "ConfigDependency.yml")
MODULE_ARTIFACT_FILE = os.path.join("components", "idf_test", "ModuleDefinition.yml")
TEST_CASE_FILE_DIR = os.path.join("components", "idf_test", "unit_test")
UT_BIN_FOLDER = os.path.join("tools", "unit-test-app", "output")
UT_CONFIG_FOLDER = os.path.join("tools", "unit-test-app", "configs")
ELF_FILE = "unit-test-app.elf"
SDKCONFIG_FILE = "sdkconfig"
@ -55,12 +56,15 @@ class Parser(object):
"esp32s2": "xtensa-esp32s2-elf-",
}
def __init__(self, idf_path=os.getenv("IDF_PATH"), idf_target=os.getenv("IDF_TARGET")):
def __init__(self, binary_folder):
idf_path = os.getenv('IDF_PATH')
idf_target = os.getenv('IDF_TARGET')
self.test_env_tags = {}
self.unit_jobs = {}
self.file_name_cache = {}
self.idf_path = idf_path
self.idf_target = idf_target
self.ut_bin_folder = binary_folder
self.objdump = Parser.TOOLCHAIN_FOR_TARGET.get(idf_target, "") + "objdump"
self.tag_def = yaml.load(open(os.path.join(idf_path, self.TAG_DEF_FILE), "r"), Loader=Loader)
self.module_map = yaml.load(open(os.path.join(idf_path, self.MODULE_DEF_FILE), "r"), Loader=Loader)
@ -300,19 +304,19 @@ class Parser(object):
""" parse test cases from multiple built unit test apps """
test_cases = []
output_folder = os.path.join(self.idf_path, self.UT_BIN_FOLDER, self.idf_target)
output_folder = os.path.join(self.idf_path, self.ut_bin_folder, self.idf_target)
configs_folder = os.path.join(self.idf_path, self.UT_CONFIG_FOLDER)
test_configs = os.listdir(output_folder)
for config in test_configs:
config_output_folder = os.path.join(output_folder, config)
config_output_folder = os.path.join(output_folder, 'build', config)
if os.path.exists(config_output_folder):
test_cases.extend(self.parse_test_cases_for_one_config(configs_folder, config_output_folder, config))
test_cases.sort(key=lambda x: x["config"] + x["summary"])
self.dump_test_cases(test_cases)
def test_parser():
parser = Parser()
def test_parser(binary_folder):
parser = Parser(binary_folder)
# test parsing tags
# parsing module only and module in module list
prop = parser.parse_case_properities("[esp32]")
@ -353,20 +357,12 @@ def test_parser():
assert sorted(tags) == ['a', 'd', 'f'] # sorted is required for older Python3, e.g. 3.4.8
def main():
test_parser()
def main(binary_folder):
assert os.getenv('IDF_PATH'), 'IDF_PATH must be set to use this script'
assert os.getenv('IDF_TARGET'), 'IDF_TARGET must be set to use this script'
test_parser(binary_folder)
idf_path = os.getenv("IDF_PATH")
if not idf_path:
print("IDF_PATH must be set to use this script", file=sys.stderr)
raise SystemExit(1)
idf_target = os.getenv("IDF_TARGET")
if not idf_target:
print("IDF_TARGET must be set to use this script", file=sys.stderr)
raise SystemExit(1)
parser = Parser(idf_path, idf_target)
parser = Parser(binary_folder)
parser.parse_test_cases()
parser.copy_module_def_file()
if len(parser.parsing_errors) > 0:
@ -376,4 +372,7 @@ def main():
if __name__ == '__main__':
main()
parser = argparse.ArgumentParser()
parser.add_argument('bin_dir', help='Binary Folder')
args = parser.parse_args()
main(args.bin_dir)