Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to place more .rodata in RAM for performance #2331

Merged
merged 7 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions esp-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Added
- A new config option `PLACE_SWITCH_TABLES_IN_RAM` to improve performance (especially for interrupts) at the cost of slightly more RAM usage (#2331)
- A new config option `PLACE_ANON_IN_RAM` to improve performance (especially for interrupts) at the cost of RAM usage (#2331)

### Changed

Expand Down
62 changes: 39 additions & 23 deletions esp-hal/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,53 @@ fn main() -> Result<(), Box<dyn Error>> {
// Define all necessary configuration symbols for the configured device:
config.define_symbols();

#[allow(unused_mut)]
let mut config_symbols = config.all().collect::<Vec<_>>();
#[cfg(feature = "flip-link")]
config_symbols.push("flip-link");

// Place all linker scripts in `OUT_DIR`, and instruct Cargo how to find these
// files:
let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
println!("cargo:rustc-link-search={}", out.display());

// emit config
let cfg = generate_config(
"esp_hal",
&[
(
"place-spi-driver-in-ram",
Value::Bool(false),
"Places the SPI driver in RAM for better performance",
),
(
"spi-address-workaround",
Value::Bool(true),
"(ESP32 only) Enables a workaround for the issue where SPI in half-duplex mode incorrectly transmits the address on a single line if the data buffer is empty.",
),
(
"place-switch-tables-in-ram",
Value::Bool(true),
"Places switch-tables, some lookup tables and constants related to interrupt handling into RAM - resulting in better performance but slightly more RAM consumption.",
),
(
"place-anon-in-ram",
Value::Bool(false),
"Places anonymous symbols into RAM - resulting in better performance at the cost of significant more RAM consumption. Best to be combined with `place-switch-tables-in-ram`.",
),
],
true,
);

// RISC-V and Xtensa devices each require some special handling and processing
// of linker scripts:

#[allow(unused_mut)]
let mut config_symbols = config.all().collect::<Vec<_>>();
#[cfg(feature = "flip-link")]
config_symbols.push("flip-link");

for (key, value) in &cfg {
if let Value::Bool(true) = value {
config_symbols.push(key);
}
}

if cfg!(feature = "esp32") || cfg!(feature = "esp32s2") || cfg!(feature = "esp32s3") {
// Xtensa devices:

Expand Down Expand Up @@ -125,24 +159,6 @@ fn main() -> Result<(), Box<dyn Error>> {
copy_dir_all(&config_symbols, "ld/sections", &out)?;
copy_dir_all(&config_symbols, format!("ld/{device_name}"), &out)?;

// emit config
generate_config(
"esp_hal",
&[
(
"place-spi-driver-in-ram",
Value::Bool(false),
"Places the SPI driver in RAM for better performance",
),
(
"spi-address-workaround",
Value::Bool(true),
"(ESP32 only) Enables a workaround for the issue where SPI in half-duplex mode incorrectly transmits the address on a single line if the data buffer is empty.",
),
],
true,
);

Ok(())
}

Expand Down
4 changes: 2 additions & 2 deletions esp-hal/ld/esp32/esp32.x
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ INCLUDE "fixups/rtc_fast_rwdata_dummy.x"
/* END ESP32 fixups */

/* Shared sections - ordering matters */
INCLUDE "text.x"
INCLUDE "rodata.x"
INCLUDE "rwtext.x"
INCLUDE "text.x"
INCLUDE "rwdata.x"
INCLUDE "rodata.x"
INCLUDE "rtc_fast.x"
INCLUDE "rtc_slow.x"
INCLUDE "stack.x"
Expand Down
4 changes: 2 additions & 2 deletions esp-hal/ld/esp32c2/esp32c2.x
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ PROVIDE(__global_pointer$ = _data_start + 0x800);
/* end of esp32c2 fixups */

/* Shared sections - ordering matters */
INCLUDE "text.x"
INCLUDE "rodata.x"
INCLUDE "rwtext.x"
INCLUDE "text.x"
INCLUDE "rwdata.x"
INCLUDE "rodata.x"
INCLUDE "stack.x"
INCLUDE "dram2.x"
/* End of Shared sections */
Expand Down
4 changes: 2 additions & 2 deletions esp-hal/ld/esp32c3/esp32c3.x
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ PROVIDE(__global_pointer$ = _data_start + 0x800);
/* end of esp32c3 fixups */

/* Shared sections - ordering matters */
INCLUDE "text.x"
INCLUDE "rodata.x"
INCLUDE "rwtext.x"
INCLUDE "text.x"
INCLUDE "rwdata.x"
INCLUDE "rodata.x"
INCLUDE "rtc_fast.x"
INCLUDE "stack.x"
INCLUDE "dram2.x"
Expand Down
4 changes: 2 additions & 2 deletions esp-hal/ld/esp32c6/esp32c6.x
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ INSERT BEFORE .rodata;
/* end of esp32c6 fixups */

/* Shared sections - ordering matters */
INCLUDE "text.x"
INCLUDE "rwtext.x"
INCLUDE "rodata.x"
INCLUDE "text.x"
INCLUDE "rwdata.x"
INCLUDE "rodata.x"
INCLUDE "rtc_fast.x"
INCLUDE "stack.x"
INCLUDE "dram2.x"
Expand Down
4 changes: 2 additions & 2 deletions esp-hal/ld/esp32h2/esp32h2.x
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ SECTIONS {
INSERT BEFORE .rodata;

/* Shared sections - ordering matters */
INCLUDE "text.x"
INCLUDE "rwtext.x"
INCLUDE "rodata.x"
INCLUDE "text.x"
INCLUDE "rwdata.x"
INCLUDE "rodata.x"
INCLUDE "rtc_fast.x"
INCLUDE "stack.x"
INCLUDE "dram2.x"
Expand Down
4 changes: 2 additions & 2 deletions esp-hal/ld/esp32s2/esp32s2.x
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ INCLUDE "fixups/rtc_fast_rwdata_dummy.x"
/* End of fixups for esp32s2 */

/* Shared sections - ordering matters */
INCLUDE "text.x"
INCLUDE "rodata.x"
INCLUDE "rwtext.x"
INCLUDE "text.x"
INCLUDE "rwdata.x"
INCLUDE "rodata.x"
INCLUDE "rtc_fast.x"
INCLUDE "rtc_slow.x"
INCLUDE "stack.x"
Expand Down
4 changes: 2 additions & 2 deletions esp-hal/ld/esp32s3/esp32s3.x
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ INCLUDE "fixups/rodata_dummy.x"
/* End of ESP32S3 fixups */

/* Shared sections - ordering matters */
INCLUDE "text.x"
INCLUDE "rodata.x"
INCLUDE "rwtext.x"
INCLUDE "text.x"
INCLUDE "rwdata.x"
INCLUDE "rodata.x"
INCLUDE "rtc_fast.x"
INCLUDE "rtc_slow.x"
INCLUDE "stack.x"
Expand Down
11 changes: 11 additions & 0 deletions esp-hal/ld/sections/rwdata.x
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ SECTIONS {
{
_data_start = ABSOLUTE(.);
. = ALIGN (4);

#IF ESP_HAL_PLACE_SWITCH_TABLES_IN_RAM
*(.rodata.*_esp_hal_internal_handler*)
*(.rodata..Lswitch.table.*)
*(.rodata.cst*)
#ENDIF

#IF ESP_HAL_PLACE_ANON_IN_RAM
*(.rodata..Lanon .rodata..Lanon.*)
#ENDIF

*(.sdata .sdata.* .sdata2 .sdata2.*);
*(.data .data.*);
*(.data1)
Expand Down
2 changes: 0 additions & 2 deletions esp-hal/ld/sections/rwtext.x
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@


SECTIONS {
.rwtext : ALIGN(4)
{
Expand Down
1 change: 1 addition & 0 deletions esp-hal/src/gpio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2475,6 +2475,7 @@ mod asynch {

use super::*;

#[ram]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this intentional? (Wondering if it was a temporary change for a local test)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one was intentionally - while the waker's internals are places in RAM the array was placed in flash otherwise

pub(super) static PIN_WAKERS: [AtomicWaker; NUM_PINS] =
[const { AtomicWaker::new() }; NUM_PINS];

Expand Down
27 changes: 18 additions & 9 deletions esp-hal/src/interrupt/riscv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ impl Priority {
}

/// The interrupts reserved by the HAL
pub const RESERVED_INTERRUPTS: &[usize] = INTERRUPT_TO_PRIORITY;
#[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")]
pub static RESERVED_INTERRUPTS: &[usize] = INTERRUPT_TO_PRIORITY;

/// # Safety
///
Expand Down Expand Up @@ -549,14 +550,18 @@ mod classic {
use super::{CpuInterrupt, InterruptKind, Priority};
use crate::Cpu;

pub(super) const DISABLED_CPU_INTERRUPT: u32 = 0;
#[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")]
pub(super) static DISABLED_CPU_INTERRUPT: u32 = 0;

pub(super) const EXTERNAL_INTERRUPT_OFFSET: u32 = 0;
#[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")]
pub(super) static EXTERNAL_INTERRUPT_OFFSET: u32 = 0;

pub(super) const PRIORITY_TO_INTERRUPT: &[usize] =
#[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")]
pub(super) static PRIORITY_TO_INTERRUPT: &[usize] =
&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];

pub(super) const INTERRUPT_TO_PRIORITY: &[usize] =
#[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")]
pub(super) static INTERRUPT_TO_PRIORITY: &[usize] =
&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];

/// Enable a CPU interrupt
Expand Down Expand Up @@ -667,17 +672,21 @@ mod plic {
use super::{CpuInterrupt, InterruptKind, Priority};
use crate::Cpu;

pub(super) const DISABLED_CPU_INTERRUPT: u32 = 31;
#[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")]
pub(super) static DISABLED_CPU_INTERRUPT: u32 = 31;

pub(super) const EXTERNAL_INTERRUPT_OFFSET: u32 = 0;
#[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")]
pub(super) static EXTERNAL_INTERRUPT_OFFSET: u32 = 0;

// don't use interrupts reserved for CLIC (0,3,4,7)
// for some reason also CPU interrupt 8 doesn't work by default since it's
// disabled after reset - so don't use that, too
pub(super) const PRIORITY_TO_INTERRUPT: &[usize] =
#[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")]
pub(super) static PRIORITY_TO_INTERRUPT: &[usize] =
&[1, 2, 5, 6, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19];

pub(super) const INTERRUPT_TO_PRIORITY: &[usize] = &[
#[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")]
pub(super) static INTERRUPT_TO_PRIORITY: &[usize] = &[
1, 2, 0, 0, 3, 4, 0, 0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
];

Expand Down
21 changes: 14 additions & 7 deletions esp-hal/src/interrupt/xtensa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ pub enum CpuInterrupt {
}

/// The interrupts reserved by the HAL
pub const RESERVED_INTERRUPTS: &[usize] = &[
#[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")]
pub static RESERVED_INTERRUPTS: &[usize] = &[
CpuInterrupt::Interrupt1LevelPriority1 as _,
CpuInterrupt::Interrupt19LevelPriority2 as _,
CpuInterrupt::Interrupt23LevelPriority3 as _,
Expand Down Expand Up @@ -447,7 +448,8 @@ mod vectored {
}

// TODO use CpuInterrupt::LevelX.mask() // TODO make it const
const CPU_INTERRUPT_LEVELS: [u32; 8] = [
#[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")]
static CPU_INTERRUPT_LEVELS: [u32; 8] = [
0b_0000_0000_0000_0000_0000_0000_0000_0000, // Dummy level 0
0b_0000_0000_0000_0110_0011_0111_1111_1111, // Level_1
0b_0000_0000_0011_1000_0000_0000_0000_0000, // Level 2
Expand All @@ -457,8 +459,10 @@ mod vectored {
0b_0000_0000_0000_0000_0000_0000_0000_0000, // Level 6
0b_0000_0000_0000_0000_0100_0000_0000_0000, // Level 7
];
const CPU_INTERRUPT_INTERNAL: u32 = 0b_0010_0000_0000_0001_1000_1000_1100_0000;
const CPU_INTERRUPT_EDGE: u32 = 0b_0111_0000_0100_0000_0000_1100_1000_0000;
#[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")]
static CPU_INTERRUPT_INTERNAL: u32 = 0b_0010_0000_0000_0001_1000_1000_1100_0000;
#[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")]
static CPU_INTERRUPT_EDGE: u32 = 0b_0111_0000_0100_0000_0000_1100_1000_0000;

#[inline]
fn cpu_interrupt_nr_to_cpu_interrupt_handler(
Expand Down Expand Up @@ -558,7 +562,8 @@ mod vectored {
#[cfg(esp32)]
mod chip_specific {
use super::*;
pub const INTERRUPT_EDGE: InterruptStatus = InterruptStatus::from(
#[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")]
pub static INTERRUPT_EDGE: InterruptStatus = InterruptStatus::from(
0b0000_0000_0000_0000_0000_0000_0000_0000,
0b1111_1100_0000_0000_0000_0000_0000_0000,
0b0000_0000_0000_0000_0000_0000_0000_0011,
Expand All @@ -583,7 +588,8 @@ mod vectored {
#[cfg(esp32s2)]
mod chip_specific {
use super::*;
pub const INTERRUPT_EDGE: InterruptStatus = InterruptStatus::from(
#[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")]
pub static INTERRUPT_EDGE: InterruptStatus = InterruptStatus::from(
0b0000_0000_0000_0000_0000_0000_0000_0000,
0b1100_0000_0000_0000_0000_0000_0000_0000,
0b0000_0000_0000_0000_0000_0011_1011_1111,
Expand Down Expand Up @@ -611,7 +617,8 @@ mod vectored {
#[cfg(esp32s3)]
mod chip_specific {
use super::*;
pub const INTERRUPT_EDGE: InterruptStatus = InterruptStatus::empty();
#[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")]
pub static INTERRUPT_EDGE: InterruptStatus = InterruptStatus::empty();
#[inline]
pub fn interrupt_is_edge(_interrupt: Interrupt) -> bool {
false
Expand Down