Skip to content

Commit

Permalink
Merge branch 'main' into thesobkiewicz/nifs/ets/refactor_insert
Browse files Browse the repository at this point in the history
  • Loading branch information
TheSobkiewicz authored Feb 11, 2025
2 parents 8103fe7 + 7396812 commit ac07f46
Show file tree
Hide file tree
Showing 24 changed files with 438 additions and 94 deletions.
15 changes: 11 additions & 4 deletions .github/workflows/build-and-test-on-freebsd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,17 @@ concurrency:

jobs:
build-and-test-on-freebsd:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
name: Build and test AtomVM on FreeBSD
env:
ATOMVM_EXAMPLE: "atomvm-example"

strategy:
fail-fast: false

matrix:
os_release: ["13.4", "14.2"]

steps:

- uses: actions/checkout@v4
Expand All @@ -47,17 +54,17 @@ jobs:
uses: vmactions/freebsd-vm@v1
timeout-minutes: 20
with:
release: 13.2
release: ${{ matrix.os_release }}
envs: 'ATOMVM_EXAMPLE'
usesh: true
sync: rsync
copyback: false

prepare: |
pkg install -y curl cmake gperf erlang elixir mbedtls
pkg install -y curl cmake gperf erlang elixir rebar3 mbedtls
run: |
set -e
echo "%%"
echo "%% System Info"
echo "%%"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build-and-test-other.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ jobs:
# Required for testing big endian archs
- arch: "s390x"
platform: "s390x"
tag: "bullseye"
tag: "bookworm"
cflags: "-O2"
cmake_opts: "-DAVM_WARNINGS_ARE_ERRORS=ON"

Expand Down
42 changes: 42 additions & 0 deletions .github/workflows/build-and-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -367,60 +367,69 @@ jobs:
timeout-minutes: 15
working-directory: build
run: |
ulimit -c unlimited
./tests/test-erlang -s prime_smp
valgrind ./tests/test-erlang -s prime_smp
- name: "Test: test-enif"
working-directory: build
run: |
ulimit -c unlimited
./tests/test-enif
valgrind ./tests/test-enif
- name: "Test: test-mailbox"
working-directory: build
run: |
ulimit -c unlimited
./tests/test-mailbox
valgrind ./tests/test-mailbox
- name: "Test: test-structs"
timeout-minutes: 10
working-directory: build
run: |
ulimit -c unlimited
./tests/test-structs
valgrind ./tests/test-structs
- name: "Test: test_etest.avm"
timeout-minutes: 5
working-directory: build
run: |
ulimit -c unlimited
./src/AtomVM ./tests/libs/etest/test_etest.avm
valgrind ./src/AtomVM ./tests/libs/etest/test_etest.avm
- name: "Test: test_estdlib.avm"
timeout-minutes: 5
working-directory: build
run: |
ulimit -c unlimited
./src/AtomVM ./tests/libs/estdlib/test_estdlib.avm
valgrind ./src/AtomVM ./tests/libs/estdlib/test_estdlib.avm
- name: "Test: test_eavmlib.avm"
timeout-minutes: 10
working-directory: build
run: |
ulimit -c unlimited
./src/AtomVM ./tests/libs/eavmlib/test_eavmlib.avm
valgrind ./src/AtomVM ./tests/libs/eavmlib/test_eavmlib.avm
- name: "Test: test_alisp.avm"
timeout-minutes: 10
working-directory: build
run: |
ulimit -c unlimited
./src/AtomVM ./tests/libs/alisp/test_alisp.avm
valgrind ./src/AtomVM ./tests/libs/alisp/test_alisp.avm
- name: "Test: Tests.avm (Elixir)"
timeout-minutes: 10
working-directory: build
run: |
ulimit -c unlimited
if command -v elixirc &> /dev/null
then
./src/AtomVM ./tests/libs/exavmlib/Tests.avm
Expand All @@ -430,7 +439,40 @@ jobs:
- name: "Install and smoke test"
working-directory: build
run: |
ulimit -c unlimited
sudo PATH=${PATH} make install
atomvm examples/erlang/hello_world.avm
atomvm -v
atomvm -h
- name: "Run coredumpctl info"
if: ${{ failure() }}
run: |
# Wait until systemd-coredump finished
while ps x | grep -cE 'systemd-[c]oredump'; do
echo systemd-coredump is still running
sleep 1
done
# info works on all versions of ubuntu
coredumpctl info || true
# The following only works on recent versions of ubuntu
coredumpctl debug --debugger-arguments="-batch -ex 'info all-registers'" || true
coredumpctl debug --debugger-arguments="-batch -ex 'info threads'" || true
coredumpctl debug --debugger-arguments="-batch -ex 'thread apply all bt full'" || true
coredumpctl debug --debugger-arguments='-batch -ex "display /10i $pc"' || true
coredumpctl dump -o core.dump || true
if [ -e core.dump ]; then
mkdir core
mv core.dump core/
cp build/src/AtomVM core/
cp build/tests/test-* core/
fi
- name: "Upload any dumped core"
uses: actions/upload-artifact@v4
if: ${{ failure() }}
with:
name: core-${{ matrix.os }}-${{ matrix.cc }}-${{ matrix.otp }}-${{ github.run_id }}-${{ github.run_attempt }}
path: |
core/*
retention-days: 5
2 changes: 1 addition & 1 deletion .github/workflows/esp32-mkimage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
elixir_version: ["1.17"]
rebar3_version: ["3.24.0"]
compiler_pkgs: ["clang-14"]
soc: ["esp32", "esp32c2", "esp32c3", "esp32s2", "esp32s3", "esp32c6", "esp32h2"]
soc: ["esp32", "esp32c2", "esp32c3", "esp32s2", "esp32s3", "esp32c6", "esp32h2", "esp32p4"]
flavor: ["", "-elixir"]

env:
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/esp32-simtest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ jobs:
runs-on: ubuntu-24.04
if: needs.cli_token.outputs.token_check == 'true'
container: espressif/idf:${{ matrix.idf-version }}
services:
wokwi-ci-server:
image: wokwi/wokwi-ci-server
ports:
- 3000:3000

strategy:
fail-fast: false
# focus on device diversity.
Expand Down Expand Up @@ -120,6 +126,10 @@ jobs:
idf.py -DSDKCONFIG_DEFAULTS='sdkconfig.ci.wokwi' set-target ${{matrix.esp-idf-target}}
idf.py build
- name: Configure Wokwi environment
run: |
echo "WOKWI_CLI_SERVER=ws://wokwi-ci-server:3000" >> $GITHUB_ENV
- name: Run ESP32-sim tests using Wokwi CI
working-directory: ./src/platforms/esp32/test/
env:
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added `net:gethostname/0` on platforms with gethostname(3).
- Added `socket:getopt/2`
- Added `supervisor:terminate_child/2`, `supervisor:restart_child/2` and `supervisor:delete_child/2`
- Added `esp:partition_read/3`, and documentation for `esp:partition_erase_range/2/3` and `esp:partition_write/3`
- Added support for list insertion in 'ets:insert/2'.

### Fixed
- ESP32: improved sntp sync speed from a cold boot.
- Utilize reserved `phy_init` partition on ESP32 to store wifi calibration for faster connections.

## [0.6.6] - Unreleased

### Added

- Added the ability to run beams from the CLI for Generic Unix platform (it was already possible with nodejs and emscripten).
- Added support for 'erlang:--/2'.
- Added preliminary support for ESP32P4 (no networking support yet).

### Fixed

Expand All @@ -47,6 +50,9 @@ certain VM instructions are used.
- Fixed a race condition affecting multi-core MCUs where a timeout would not be properly cleared
- Fixed a double free when esp32 uart driver was closed, yielding an assert abort
- Fixed compilation with latest debian gcc-arm-none-eabi
- Fix `network:stop/0` on ESP32 so the network can be started again
- Fix matching of binaries on unaligned boundaries for code compiled with older versions of OTP
- Fix a memory corruption caused by `binary:split/2,3`

## [0.6.5] - 2024-10-15

Expand Down
57 changes: 57 additions & 0 deletions doc/src/build-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,63 @@ $ pytest --embedded-services=idf,qemu -s

ESP32 tests are erlang modules located in `src/platforms/esp32/test/main/test_erl_sources/` and executed from `src/platforms/esp32/test/main/test_main.c`.

### Performance and Power

AtomVM comes with conservative defaults for broad compatibility with different ESP32 boards, and a reasonable performance/power/longevity tradeoff.

You may want to change these settings to optimize for your specific application's performance and power needs.

Factors like heat dissipation should also be considered, and the effect on overall longevity of components.

#### CPU frequency

Use `idf.py menuconfig` in `src/platforms/esp32`
`Component config ---> ESP System Settings ---> CPU frequency (160 MHz) --->`

You can increase or decrease the CPU frequency, this is a tradeoff against power usage.
Eg. 160 MHz is the conservative default for the ESP32, but you can increase it to 240 MHz or decrease it to 80 MHz. The higher the frequency, the more power is consumed. The lower the frequency, the less power is consumed.

#### Flash mode and speed

Use `idf.py menuconfig` in `src/platforms/esp32`
`Serial flasher config ---> Flash SPI mode (DIO) --->`
You can change the mode of the SPI flash. QIO is the fastest mode, but not all flash chips support it.

`Serial flasher config ---> Flash SPI speed (40 MHz) --->`
You can change the speed of the SPI flash. The higher the speed, the faster the flash will be, at the cost of higher power usage, but not all flash chips support higher speeds.

See external docs: [ESP-IDF flash modes](https://docs.espressif.com/projects/esptool/en/latest/esp32/advanced-topics/spi-flash-modes.html)

#### PSRAM speed

Use `idf.py menuconfig` in `src/platforms/esp32`
`Component config ---> ESP PSRAM ---> SPI RAM config --->`

If your board has PSRAM and it's enabled, you can configure the SPI RAM settings here.
`Set RAM clock speed (40MHz clock speed) --->`
You can increase or decrease the clock speed of the PSRAM.

```{warning}
You may have to increase "Flash SPI speed" (see above) before you can increase PSRAM speed.
```

The higher the speed, the faster the PSRAM will be, at the cost of higher power usage, but not all PSRAM chips support higher speeds.

#### Sleep mode - Deep sleep

For low power applications, you should use the [deep sleep functionality](./programmers-guide.md#restart-and-deep-sleep) of the ESP32.

This will put the ESP32 into a very low power state, and it will consume very little power.
You can wake the ESP32 from deep sleep using a timer, or an interrupt etc.

Make sure your board is suitable for low power deep sleep, some boards have voltage regulators and/or LEDs constantly draining power, also make sure sensors are powered down or in low power mode when the ESP32 is in deep sleep.

For persisting small amounts of data during deep sleep, you can use the [RTC memory](./programmers-guide.md#rtc-memory) of the ESP32, which is preserved during deep sleep.

#### Sleep mode - Light sleep

Usage of light sleep is untested, and no support for controlling light sleep is currently implemented. Reach out if you do any experiments and measurements.

### Flash Layout

The AtomVM Flash memory is partitioned to include areas for the above binary artifacts created from the build, as well areas for runtime information used by the ESP32 and compiled Erlang/Elixir code.
Expand Down
73 changes: 73 additions & 0 deletions libs/eavmlib/src/esp.erl
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@
nvs_erase_key/1, nvs_erase_key/2,
nvs_erase_all/0, nvs_erase_all/1,
nvs_reformat/0,
partition_erase_range/2, partition_erase_range/3,
partition_list/0,
partition_read/3,
partition_write/3,
rtc_slow_get_binary/0,
rtc_slow_set_binary/1,
freq_hz/0,
Expand Down Expand Up @@ -469,6 +472,42 @@ nvs_erase_all(Namespace) when is_atom(Namespace) ->
nvs_reformat() ->
erlang:nif_error(undefined).

%%-----------------------------------------------------------------------------
%% @param partition_id The id of the partition to erase eg. "main.avm"
%% @param offset Starting offset in bytes where to begin erasing
%% @returns ok on success, error on failure
%% @doc Erases a range in the specified partition. The range starts at the given
%% offset and continues to the end of the partition. This is equivalent to
%% calling partition_erase_range/3 with size set to the remaining partition
%% size from the offset.
%%
%% Note: Erasing sets all bits in the erased range to 1s. This operation
%% is irreversible.
%% @end
%%-----------------------------------------------------------------------------
-spec partition_erase_range(Partition_id :: binary(), Offset :: non_neg_integer()) -> ok | error.
partition_erase_range(Partition_id, Offset) ->
erlang:nif_error(undefined).

%%-----------------------------------------------------------------------------
%% @param partition_id The id of the partition to erase eg. "main.avm"
%% @param offset Starting offset in bytes where to begin erasing
%% @param size Number of bytes to erase
%% @returns ok on success, error on failure
%% @doc Erases a range of the specified size in the partition, starting at the
%% given offset. The size must not exceed the partition's boundaries.
%%
%% Note: Erasing sets all bits in the erased range to 1s. This operation
%% is irreversible. Make sure the offset and size parameters are valid for
%% the target partition to avoid errors.
%% @end
%%-----------------------------------------------------------------------------
-spec partition_erase_range(
Partition_id :: binary(), Offset :: non_neg_integer(), Size :: pos_integer()
) -> ok | error.
partition_erase_range(Partition_id, Offset, Size) ->
erlang:nif_error(undefined).

%%-----------------------------------------------------------------------------
%% @returns List of partitions
%% @doc Gets the list of partitions as tuples, such as {name, type, subtype,
Expand All @@ -480,6 +519,40 @@ nvs_reformat() ->
partition_list() ->
erlang:nif_error(undefined).

%%-----------------------------------------------------------------------------
%% @param partition_id The id of the partition to read from eg. "main.avm"
%% @param offset Starting offset in bytes where to begin reading
%% @param read_size Number of bytes to read
%% @returns {ok, data} on success, error on failure
%% @doc Read binary data from a specific partition at the given offset.
%%
%% @end
%%-----------------------------------------------------------------------------
-spec partition_read(
Partition_id :: binary(), Offset :: non_neg_integer(), Read_size :: non_neg_integer()
) -> {ok, binary()} | error.
partition_read(Partition_id, Offset, Read_size) ->
erlang:nif_error(undefined).

%%-----------------------------------------------------------------------------
%% @param partition_id The id of the partition to write to eg. "main.avm"
%% @param offset Starting offset in bytes where to begin writing
%% @param data Binary data to write to the partition
%% @returns ok on success, error on failure
%% @doc Writes binary data to a specific partition at the given offset.
%%
%% This function allows writing data to ESP32 flash partitions. Care must be
%% taken when using this function as improper writes can corrupt the partition
%% table or system firmware. Make sure the offset and data size do not exceed
%% the partition's boundaries.
%%
%% @end
%%-----------------------------------------------------------------------------
-spec partition_write(Partition_id :: binary(), Offset :: non_neg_integer(), Data :: binary()) ->
ok | error.
partition_write(Partition_id, Offset, Data) ->
erlang:nif_error(undefined).

%%-----------------------------------------------------------------------------
%% @returns the currently stored binary in RTC slow memory.
%% @doc Get the binary currently stored in RTC slow memory. Must not be
Expand Down
1 change: 1 addition & 0 deletions libs/estdlib/src/erlang.erl
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ process_info(_Pid, _Key) ->
%% <li><b>esp32_free_heap_size</b> the number of (noncontiguous) free bytes in the ESP32 heap (integer)</li>
%% <li><b>esp32_largest_free_block</b> the number of the largest contiguous free bytes in the ESP32 heap (integer)</li>
%% <li><b>esp32_minimum_free_size</b> the smallest number of free bytes in the ESP32 heap since boot (integer)</li>
%% <li><b>esp32_chip_info</b> Details about the model and capabilities of the ESP32 device (map)</li>
%% </ul>
%%
%% Additional keys may be supported on some platforms that are not documented here.
Expand Down
Loading

0 comments on commit ac07f46

Please sign in to comment.