Skip to content

CI

CI #4144

Workflow file for this run

name: CI
on:
push:
pull_request:
schedule:
- cron: '0 8 * * *'
workflow_dispatch:
jobs:
clang-format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: DoozyX/clang-format-lint-action@v0.15
with:
source: './app ./include ./src ./test'
build-linux:
strategy:
matrix:
include:
- build_type: DEBUG
- build_type: RELEASE
stats: false
- build_type: RELEASE
stats: true
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Set binary paths
id: set_binaries
run: |
echo "ACC_BINARY=build/bin/ACC" >> $GITHUB_OUTPUT
- name: Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ccache-${{ github.job }}-${{ matrix.build_type }}
max-size: 2G
- name: Build
run: |
cmake -S . -B build -G Ninja \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
-DOPENCV_PATH=build/3rdparty/opencv_build \
${{ matrix.stats && '-DENABLE_STATISTIC_TENSORS=ON' || '' }} \
${{ matrix.stats && '-DENABLE_STATISTIC_TIME=ON' || '' }} \
${{ matrix.stats && '-DENABLE_STATISTIC_WEIGHTS=ON' || '' }}
cmake --build build --parallel
env:
CTEST_OUTPUT_ON_FAILURE: 1
- name: Prepare ALL libs
run: |
mkdir -p build/bin/all_libs
cp -a build/3rdparty/opencv_build/lib/* build/bin/all_libs/ 2>/dev/null || true
ldd build/bin/ACC | grep "=> /" | awk '{print $3}' | xargs -I {} cp {} build/bin/all_libs/ 2>/dev/null || true
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: mnist-${{ matrix.build_type }}${{ matrix.stats && '-stats' || '' }}
path: |
${{ steps.set_binaries.outputs.ACC_BINARY }}
build/bin/all_libs/*
build/bin/opencv_libs/*
build/setenv.sh
- name: Test
run: cmake --build build -t test
env:
CTEST_OUTPUT_ON_FAILURE: 1
- name: Test (valgrind)
run: |
sudo apt-get update
sudo apt-get install -y valgrind
valgrind cmake --build build -t test
env:
CTEST_OUTPUT_ON_FAILURE: 1
build-linux-clang:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install prerequisites
run: |
sudo apt install clang libomp-dev
- name: Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ccache-${{ github.job }}
- name: Build
run: |
cmake -S . -B build -G Ninja \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++
cmake --build build --parallel
- name: Test
run: cmake --build build -t test
env:
CTEST_OUTPUT_ON_FAILURE: 1
- name: Test (valgrind)
run: |
sudo apt-get update
sudo apt-get install -y valgrind
valgrind cmake --build build -t test
env:
CTEST_OUTPUT_ON_FAILURE: 1
build-macos:
runs-on: macos-15
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install prerequisites
run: |
brew install libomp ninja
brew link libomp --overwrite --force
- name: Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ccache-${{ github.job }}
- name: Build
run: |
OPENMP_PATH=$(brew --prefix libomp)
echo "OpenMP path: $OPENMP_PATH"
cmake -S . -B build -G Ninja \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_PREFIX_PATH=$OPENMP_PATH \
-DCMAKE_INCLUDE_PATH=$OPENMP_PATH/include \
-DCMAKE_LIBRARY_PATH=$OPENMP_PATH/lib \
-DOpenMP_C_FLAGS="-Xclang -fopenmp -I$OPENMP_PATH/include" \
-DOpenMP_CXX_FLAGS="-Xclang -fopenmp -I$OPENMP_PATH/include" \
-DOpenMP_C_LIB_NAMES="omp" \
-DOpenMP_CXX_LIB_NAMES="omp" \
-DOpenMP_omp_LIBRARY="$OPENMP_PATH/lib/libomp.dylib" \
-DCMAKE_EXE_LINKER_FLAGS="-L$OPENMP_PATH/lib -lomp" \
-DCMAKE_SHARED_LINKER_FLAGS="-L$OPENMP_PATH/lib -lomp"
cmake --build build --parallel
env:
LDFLAGS: "-L$(brew --prefix libomp)/lib -lomp"
CPPFLAGS: "-I$(brew --prefix libomp)/include"
- name: Test
run: cmake --build build -t test
env:
CTEST_OUTPUT_ON_FAILURE: 1
build-windows:
runs-on: windows-2025
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v2
with:
vs-version: 'latest'
- name: Setup ccache
uses: Chocobo1/setup-ccache-action@v1
with:
windows_compile_environment: msvc
- name: Setup ninja
uses: seanmiddleditch/gha-setup-ninja@v6
- name: Setup MSVC for Ninja again
uses: ilammy/msvc-dev-cmd@v1
- name: Build
run: |
cmake -S . -B build -G Ninja -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel --config Release
- name: Test
run: |
cd build
ctest --output-on-failure
build-linux-arm64:
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install prerequisites
run: sudo apt-get update && sudo apt-get install -y libomp-dev build-essential cmake
- name: Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ccache-${{ github.job }}
- name: Build and Test
run: |
cmake -S . -B build -G Ninja \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel
cmake --build build -t test
env:
CTEST_OUTPUT_ON_FAILURE: 1
codecov:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y gcovr
- name: Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ccache-${{ github.job }}-${{ matrix.build_type }}
max-size: 2G
- name: Build
run: |
cmake -S . -B build -G Ninja \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="--coverage" \
-DCMAKE_CXX_FLAGS="--coverage" \
-DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build build --parallel
- name: Test
run: cmake --build build -t test
env:
CTEST_OUTPUT_ON_FAILURE: 1
- name: Generate Coverage Data
run: gcovr -r . --xml -o coverage.xml --gcov-ignore-parse-errors
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4.0.1
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: embedded-dev-research/ITLabAI
evaluate-model-alexnet:
runs-on: ubuntu-latest
needs: [build-linux]
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download binary and libs
uses: actions/download-artifact@v4
with:
name: mnist-RELEASE
path: build/
- name: Set binary path
id: set_eval_binary
run: |
echo "EVAL_BINARY=build/bin/ACC" >> $GITHUB_OUTPUT
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-0 libtbb12 libjpeg-dev libpng-dev libtiff-dev libopenjp2-7 libdnnl3
sudo ldconfig
- name: Generate model JSON
run: |
cd docs && mkdir -p jsons
cd ..
cd app/Converters
pip install -r requirements.txt
python parser.py
cd ../..
- name: Cache MNIST test dataset
id: cache-mnist
uses: actions/cache@v4
with:
path: docs/mnist/mnist/test
key: mnist-dataset-e2d09c892023700f68bfa9f30ac91a4dffaa23b151deeaca627101b3d73ef83d
- name: Download MNIST test dataset
if: steps.cache-mnist.outputs.cache-hit != 'true'
run: |
mkdir -p docs/mnist/mnist/test
wget -q https://github.com/DeepTrackAI/MNIST_dataset/archive/main.zip -O main.zip
unzip -q main.zip
cp MNIST_dataset-main/mnist/test/*.png docs/mnist/mnist/test/
rm -rf main.zip MNIST_dataset-main
- name: Prepare environment
run: |
chmod +x "${{ steps.set_eval_binary.outputs.EVAL_BINARY }}"
export LD_LIBRARY_PATH=$PWD/build/bin/all_libs:/usr/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH
- name: Run evaluation
run: |
export LD_LIBRARY_PATH=$PWD/build/bin/all_libs:/usr/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH
"${{ steps.set_eval_binary.outputs.EVAL_BINARY }}" --model alexnet_mnist > accuracy.txt 2>&1
if [ $? -ne 0 ]; then
exit 1
fi
- name: Extract accuracy value
run: |
ACCURACY=$(grep -oE '[0-9]+\.?[0-9]*%' accuracy.txt | head -1 || echo "0%")
echo "$ACCURACY" > accuracy_value.txt
- name: Update README (main only)
run: |
ACCURACY=$(sed 's/%//g' accuracy_value.txt)
CURRENT_ACCURACY=$(sed -nE 's/.*<!--ACCURACY_PLACEHOLDER-->Accuracy: ([0-9]+(\.[0-9]+)?)% \(updated: [0-9-]+\)<!--END_ACCURACY-->.*/\1/p' README.md | head -n1)
if [ -n "$CURRENT_ACCURACY" ] && [ "$CURRENT_ACCURACY" = "$ACCURACY" ]; then
echo "Accuracy unchanged; keeping existing README update date"
exit 0
fi
DATE=$(date '+%Y-%m-%d')
UPDATE_TEXT="<!--ACCURACY_PLACEHOLDER-->Accuracy: ${ACCURACY}% (updated: ${DATE})<!--END_ACCURACY-->"
ESCAPED_UPDATE_TEXT=$(printf '%s\n' "$UPDATE_TEXT" | sed 's/[&|\\]/\\&/g')
sed -i "s|<!--ACCURACY_PLACEHOLDER-->.*<!--END_ACCURACY-->|${ESCAPED_UPDATE_TEXT}|" README.md
- name: Commit and push changes (main only)
if: github.ref == 'refs/heads/main' && github.repository == 'embedded-dev-research/itlab_2023'
run: |
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
git add README.md
if git diff --cached --quiet; then
echo "No changes to commit"
else
git commit -m "[CI] Update accuracy: $(cat accuracy_value.txt)"
for attempt in 1 2 3 4 5; do
git pull --rebase origin main && git push origin HEAD:main && break
git rebase --abort || true
[ "$attempt" -eq 5 ] && { echo "Failed to push README update after ${attempt} attempts"; exit 1; }
sleep 5
done
fi
download-dataset:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Cache ImageNet-Paste dataset
id: cache-imagenet
uses: actions/cache@v4
with:
path: docs/ImageNet
key: imagenet-paste-v1
restore-keys: |
imagenet-paste-v1-
imagenet-paste-
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install Python dependencies from requirements.txt
run: |
cd app/Converters
pip install -r requirements.txt
cd ../..
- name: Download ImageNet-Paste dataset
if: steps.cache-imagenet.outputs.cache-hit != 'true'
env:
HF_TOKEN: ${{ secrets.HF_TOKEN }}
run: |
mkdir -p docs/ImageNet/test
cd app/Converters
python download_imagenet.py
cd ../..
- name: Save ImageNet-Paste dataset
uses: actions/cache/save@v4
with:
path: docs/ImageNet
key: imagenet-paste-v1
evaluate-models-onnx:
runs-on: ubuntu-latest
needs: [build-linux, download-dataset]
permissions:
contents: write
strategy:
fail-fast: false
matrix:
model: [googlenet, densenet, resnet, yolo]
include:
- model: googlenet
parser: parser_onnx.py
model_file: GoogLeNet.onnx
model_path: docs/models/GoogLeNet.onnx
model_url: ''
extra_args: "--onednn 10000"
- model: densenet
parser: parser_onnx.py
model_file: densenet121_Opset16.onnx
model_url: https://github.com/onnx/models/raw/refs/heads/main/Computer_Vision/densenet121_Opset16_timm/densenet121_Opset16.onnx?download=
extra_args: "--onednn 10000"
- model: resnet
parser: parser_onnx.py
model_file: resnest101e_Opset16.onnx
model_url: https://github.com/onnx/models/raw/refs/heads/main/Computer_Vision/resnest101e_Opset16_timm/resnest101e_Opset16.onnx?download=
extra_args: "--onednn 10000"
- model: yolo
parser: parser_onnx.py
model_file: yolo11x-cls.pt
model_url: https://github.com/ultralytics/assets/releases/download/v8.4.0/yolo11x-cls.pt
extra_args: "--onednn 10000"
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download binary and libs
uses: actions/download-artifact@v4
with:
name: mnist-RELEASE
path: build/
- name: Set binary path
id: set_eval_binary
run: |
echo "EVAL_BINARY=build/bin/ACC" >> $GITHUB_OUTPUT
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-0 libtbb12 libjpeg-dev libpng-dev libtiff-dev libopenjp2-7 libdnnl3
sudo ldconfig
- name: Download model (if URL provided)
if: matrix.model_url != ''
run: |
mkdir -p docs/models
wget -O docs/models/${{ matrix.model_file }} ${{ matrix.model_url }}
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install Python dependencies from requirements.txt
run: |
cd app/Converters
pip install -r requirements.txt
cd ../..
- name: Cache model JSON files
id: cache-model-json
uses: actions/cache@v4
with:
path: docs/jsons
key: model-json-${{ matrix.model }}-${{ hashFiles('app/Converters/parser_onnx.py', 'app/Converters/requirements.txt') }}
restore-keys: |
model-json-${{ matrix.model }}-
model-json-
- name: Generate model JSON
if: steps.cache-model-json.outputs.cache-hit != 'true'
run: |
mkdir -p docs/jsons
cd app/Converters
python ${{ matrix.parser }} ${{ matrix.model }}
cd ../..
- name: Restore ImageNet-Paste dataset
id: cache-imagenet
uses: actions/cache/restore@v4
with:
path: docs/ImageNet
key: imagenet-paste-v1
restore-keys: |
imagenet-paste-v1-
imagenet-paste-
- name: Prepare environment
run: |
chmod +x "${{ steps.set_eval_binary.outputs.EVAL_BINARY }}"
echo "LD_LIBRARY_PATH=$PWD/build/bin/all_libs:/usr/lib/x86_64-linux-gnu" >> $GITHUB_ENV
- name: Run evaluation
run: |
DATASET_PATH="docs/ImageNet/test"
MODEL="${{ matrix.model }}"
EXTRA_ARGS="${{ matrix.extra_args }}"
"${{ steps.set_eval_binary.outputs.EVAL_BINARY }}" \
--model $MODEL \
$EXTRA_ARGS > accuracy_$MODEL.txt 2>&1
if [ $? -ne 0 ]; then
echo "Ошибка при оценке модели $MODEL"
cat accuracy_$MODEL.txt
exit 1
fi
echo "Результат оценки:"
cat accuracy_$MODEL.txt
- name: Extract accuracy value
run: |
ACCURACY=$(grep -oE '[0-9]+\.?[0-9]*%' accuracy_${{ matrix.model }}.txt | head -1 || echo "0%")
echo "$ACCURACY" > accuracy_value_${{ matrix.model }}.txt
echo "Accuracy for ${{ matrix.model }}: $ACCURACY"
- name: Upload accuracy artifacts
uses: actions/upload-artifact@v4
with:
name: accuracy-${{ matrix.model }}
path: |
accuracy_${{ matrix.model }}.txt
accuracy_value_${{ matrix.model }}.txt
- name: Update README for model
run: |
TOP1_ACC=$(sed -nE 's/^Top-1 Accuracy: ([0-9]+(\.[0-9]+)?)%$/\1/p' accuracy_${{ matrix.model }}.txt | head -n1)
TOP5_ACC=$(sed -nE 's/^Top-5 Accuracy: ([0-9]+(\.[0-9]+)?)%$/\1/p' accuracy_${{ matrix.model }}.txt | head -n1)
if [ -z "$TOP1_ACC" ] || [ -z "$TOP5_ACC" ]; then
echo "Ошибка: Не удалось извлечь точность из файла accuracy_${{ matrix.model }}.txt"
cat accuracy_${{ matrix.model }}.txt
exit 1
fi
CURRENT_TOP1=$(sed -nE "s/.*<!--ACCURACY_${{ matrix.model }}_PLACEHOLDER-->Accuracy: Top-1: ([0-9]+(\\.[0-9]+)?)% \\| Top-5: ([0-9]+(\\.[0-9]+)?)% \\(updated: [0-9-]+\\)<!--END_ACCURACY_${{ matrix.model }}-->.*/\\1/p" README.md | head -n1)
CURRENT_TOP5=$(sed -nE "s/.*<!--ACCURACY_${{ matrix.model }}_PLACEHOLDER-->Accuracy: Top-1: ([0-9]+(\\.[0-9]+)?)% \\| Top-5: ([0-9]+(\\.[0-9]+)?)% \\(updated: [0-9-]+\\)<!--END_ACCURACY_${{ matrix.model }}-->.*/\\3/p" README.md | head -n1)
if [ -n "$CURRENT_TOP1" ] && [ -n "$CURRENT_TOP5" ] && \
[ "$CURRENT_TOP1" = "$TOP1_ACC" ] && [ "$CURRENT_TOP5" = "$TOP5_ACC" ]; then
echo "Accuracy for ${{ matrix.model }} unchanged; keeping existing README update date"
exit 0
fi
DATE=$(date '+%Y-%m-%d')
UPDATE_TEXT="<!--ACCURACY_${{ matrix.model }}_PLACEHOLDER-->Accuracy: Top-1: ${TOP1_ACC}% | Top-5: ${TOP5_ACC}% (updated: ${DATE})<!--END_ACCURACY_${{ matrix.model }}-->"
ESCAPED_UPDATE_TEXT=$(printf '%s\n' "$UPDATE_TEXT" | sed 's/[&|\\]/\\&/g')
if grep -q "<!--ACCURACY_${{ matrix.model }}_PLACEHOLDER-->" README.md; then
sed -i "s|<!--ACCURACY_${{ matrix.model }}_PLACEHOLDER-->.*<!--END_ACCURACY_${{ matrix.model }}-->|${ESCAPED_UPDATE_TEXT}|" README.md
else
echo "Ошибка: Плейсхолдер <!--ACCURACY_${{ matrix.model }}_PLACEHOLDER--> не найден в README.md"
echo "Содержимое README.md:"
cat README.md
exit 1
fi
- name: Commit and push changes (main only)
if: github.ref == 'refs/heads/main' && github.repository == 'embedded-dev-research/ITLabAI'
run: |
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
git add README.md
if git diff --cached --quiet; then
echo "No changes to commit"
else
git commit -m "[CI] Update accuracy for ${{ matrix.model }}: $(cat accuracy_value_${{ matrix.model }}.txt)"
for attempt in 1 2 3 4 5; do
git pull --rebase origin main && git push origin HEAD:main && break
git rebase --abort || true
[ "$attempt" -eq 5 ] && { echo "Failed to push README update after ${attempt} attempts"; exit 1; }
sleep 5
done
fi