Skip to content

Commit 8468307

Browse files
committed
Merge pull request atomvm#578 from pguyot/w20/fix-flappiness-of-esp32-qemu-tests
Fix flappiness of esp32 qemu tests ESP32 qemu tests were flappy because of a race condition in esp-idf that probably only occurs on qemu under heavy load (or within GitHub CI which doesn't really allocate two cores to actions) The fix consists in applying a patch against v4.4.4 The patch was also provided in espressif/esp-idf#11447 See discussion in espressif/esp-idf#11433 Also bump versions of pytest-embedded plugins Also optimize esp32 test by using espressif precompiled qemu binary These changes are made under both the "Apache 2.0" and the "GNU Lesser General Public License 2.1 or later" license terms (dual license). SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
2 parents e993754 + 8cb7c2b commit 8468307

File tree

4 files changed

+145
-64
lines changed

4 files changed

+145
-64
lines changed

.github/workflows/esp32-test-dockerfile

Lines changed: 0 additions & 44 deletions
This file was deleted.

.github/workflows/esp32-test.yaml

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,38 +27,65 @@ on:
2727
jobs:
2828
esp32-test:
2929
runs-on: ubuntu-latest
30+
container: espressif/idf:v4.4.4
3031

3132
strategy:
3233
fail-fast: false
3334

35+
defaults:
36+
run:
37+
shell: bash
38+
working-directory: ./src/platforms/esp32/test/
39+
3440
steps:
3541
- name: Checkout repo
3642
uses: actions/checkout@v2
3743

38-
- uses: actions/cache@v2
39-
id: cache
40-
with:
41-
path: esp32-test.tar
42-
key: ${{ hashFiles('.github/workflows/esp32-test-dockerfile') }}
44+
- name: Install dependencies to build host AtomVM and run qemu
45+
run: |
46+
set -eu
47+
apt update
48+
DEBIAN_FRONTEND=noninteractive apt install -y -q \
49+
doxygen erlang-base \
50+
libglib2.0-0 libpixman-1-0
51+
52+
- name: Install qemu binary from espressif/qemu
53+
run: |
54+
set -eu
55+
QEMU_VER=esp-develop-20220919
56+
QEMU_DIST=qemu-${QEMU_VER}.tar.bz2
57+
QEMU_SHA256=f6565d3f0d1e463a63a7f81aec94cce62df662bd42fc7606de4b4418ed55f870
58+
wget --no-verbose https://github.com/espressif/qemu/releases/download/${QEMU_VER}/${QEMU_DIST}
59+
echo "${QEMU_SHA256} *${QEMU_DIST}" | sha256sum --check --strict -
60+
tar -xf ${QEMU_DIST} -C /opt
4361
44-
- name: "Load cached docker image"
45-
if: steps.cache.outputs.cache-hit == 'true'
62+
- name: Install pytest and pytest-embedded plugins
4663
run: |
47-
sudo docker load -i esp32-test.tar
64+
set -e
65+
. $IDF_PATH/export.sh
66+
pip install pytest==7.0.1 \
67+
pytest-embedded==1.2.5 \
68+
pytest-embedded-serial-esp==1.2.5 \
69+
pytest-embedded-idf==1.2.5 \
70+
pytest-embedded-qemu==1.2.5
4871
49-
- name: "Build: customized esp-idf-v4.4 container"
50-
if: steps.cache.outputs.cache-hit != 'true'
51-
run: docker build -t atomvm/esp32-test -f esp32-test-dockerfile .
52-
working-directory: .github/workflows
72+
- name: Patch esp-idf to fix race condition that affects qemu under heavy load
73+
run: |
74+
set -e
75+
PATCH=$PWD/esp_ipc_isr.patch
76+
cd $IDF_PATH
77+
patch -p1 < $PATCH
5378
54-
- name: "Save custom docker image"
55-
if: steps.cache.outputs.cache-hit != 'true'
56-
run: docker save -o esp32-test.tar atomvm/esp32-test
79+
- name: Build ESP32 tests using idf.py
80+
run: |
81+
set -e
82+
. $IDF_PATH/export.sh
83+
idf.py build
5784
58-
- name: "Run ESP32 tests using qemu-system-xtensa on Docker"
85+
- name: Run ESP32 tests using qemu
5986
timeout-minutes: 10
6087
run: |
61-
docker run --rm -v $PWD:/atomvm -w /atomvm/src/platforms/esp32/test atomvm/esp32-test /bin/bash -c '
62-
idf.py build
88+
set -e
89+
. $IDF_PATH/export.sh
90+
export PATH=/opt/qemu/bin:${PATH}
6391
pytest --embedded-services=idf,qemu -s
64-
'
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#
2+
# This file is part of AtomVM.
3+
#
4+
# Copyright 2023 Paul Guyot <[email protected]>
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
19+
#
20+
21+
diff --git a/components/esp_ipc/src/esp_ipc_isr/esp_ipc_isr.c b/components/esp_ipc/src/esp_ipc_isr/esp_ipc_isr.c
22+
index dbdbe9027b..97025d5c65 100644
23+
--- a/components/esp_ipc/src/esp_ipc_isr/esp_ipc_isr.c
24+
+++ b/components/esp_ipc/src/esp_ipc_isr/esp_ipc_isr.c
25+
@@ -57,7 +57,7 @@ typedef enum {
26+
#define IPC_ISR_EXIT_CRITICAL() portEXIT_CRITICAL_SAFE(&s_ipc_isr_mux)
27+
28+
static void esp_ipc_isr_call_and_wait(esp_ipc_isr_func_t func, void* arg, esp_ipc_isr_wait_t wait_for);
29+
-
30+
+static void IRAM_ATTR esp_ipc_isr_wait_for_end();
31+
32+
/* Initializing IPC_ISR */
33+
34+
@@ -130,6 +130,8 @@ void IRAM_ATTR esp_ipc_isr_release_other_cpu(void)
35+
const uint32_t cpu_id = xPortGetCoreID();
36+
if (--s_count_of_nested_calls[cpu_id] == 0) {
37+
esp_ipc_isr_finish_cmd = 1;
38+
+ // Make sure end flag is cleared and esp_ipc_isr_waiting_for_finish_cmd is done.
39+
+ esp_ipc_isr_wait_for_end();
40+
IPC_ISR_EXIT_CRITICAL();
41+
portCLEAR_INTERRUPT_MASK_FROM_ISR(s_stored_interrupt_level);
42+
} else if (s_count_of_nested_calls[cpu_id] < 0) {
43+
@@ -174,7 +176,7 @@ static void IRAM_ATTR esp_ipc_isr_call_and_wait(esp_ipc_isr_func_t func, void* a
44+
const uint32_t cpu_id = xPortGetCoreID();
45+
46+
// waiting for the end of the previous call
47+
- while (!esp_ipc_isr_end_fl) {};
48+
+ esp_ipc_isr_wait_for_end();
49+
50+
esp_ipc_func = func;
51+
esp_ipc_func_arg = arg;
52+
@@ -196,8 +198,13 @@ static void IRAM_ATTR esp_ipc_isr_call_and_wait(esp_ipc_isr_func_t func, void* a
53+
while (!esp_ipc_isr_start_fl) {};
54+
} else {
55+
// IPC_ISR_WAIT_FOR_END
56+
- while (!esp_ipc_isr_end_fl) {};
57+
+ esp_ipc_isr_wait_for_end();
58+
}
59+
}
60+
61+
+static void IRAM_ATTR esp_ipc_isr_wait_for_end()
62+
+{
63+
+ while (!esp_ipc_isr_end_fl) {};
64+
+}
65+
+
66+
/* End private functions*/
67+
diff --git a/components/esp_ipc/src/esp_ipc_isr/esp_ipc_isr_handler.S b/components/esp_ipc/src/esp_ipc_isr/esp_ipc_isr_handler.S
68+
index 0fb4ae676a..20638a6895 100644
69+
--- a/components/esp_ipc/src/esp_ipc_isr/esp_ipc_isr_handler.S
70+
+++ b/components/esp_ipc/src/esp_ipc_isr/esp_ipc_isr_handler.S
71+
@@ -96,6 +96,7 @@ esp_ipc_isr_handler:
72+
73+
/* set the start flag */
74+
movi a0, esp_ipc_isr_start_fl
75+
+ memw
76+
s32i a0, a0, 0
77+
78+
/* Call the esp_ipc_function(void* arg) */
79+
@@ -113,6 +114,7 @@ esp_ipc_isr_handler:
80+
81+
/* set the end flag */
82+
movi a0, esp_ipc_isr_end_fl
83+
+ memw
84+
s32i a0, a0, 0
85+
86+
/* restore a0 */
87+
diff --git a/components/esp_ipc/src/esp_ipc_isr/esp_ipc_isr_routines.S b/components/esp_ipc/src/esp_ipc_isr/esp_ipc_isr_routines.S
88+
index 01ddf8b528..e947c3ed2f 100644
89+
--- a/components/esp_ipc/src/esp_ipc_isr/esp_ipc_isr_routines.S
90+
+++ b/components/esp_ipc/src/esp_ipc_isr/esp_ipc_isr_routines.S
91+
@@ -23,6 +23,7 @@
92+
esp_ipc_isr_waiting_for_finish_cmd:
93+
/* waiting for the finish command */
94+
.check_finish_cmd:
95+
+ memw
96+
l32i a3, a2, 0
97+
beqz a3, .check_finish_cmd
98+
ret

src/platforms/esp32/test/test_atomvm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
@pytest.mark.parametrize(
2525
'qemu_extra_args',
2626
[
27-
'"-nic user,model=open_eth"',
27+
'-nic user,model=open_eth',
2828
],
2929
indirect=True,
3030
)

0 commit comments

Comments
 (0)