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

Excessive use of BSS by certain static objects #283

Open
lyusupov opened this issue Mar 22, 2024 · 3 comments
Open

Excessive use of BSS by certain static objects #283

lyusupov opened this issue Mar 22, 2024 · 3 comments
Labels
topic: code Related to content of the project itself type: imperfection Perceived defect in any part of project

Comments

@lyusupov
Copy link

Core version: 1.1.0
Variant: UNO R4 WIFI

Let's take this simple sketch and built it for UNO R4 Wi-Fi target:

extern "C" void * _sbrk   (int);

static uint32_t RA4M1_getFreeHeap()
{
  char top;
  return &top - reinterpret_cast<char*>(_sbrk(0));
}

void setup()
{
  Serial.begin(38400);
  for (int i=0; i < 20; i++) {if (Serial) break; else delay(100);}

  Serial.print("Free Heap = "); Serial.println(RA4M1_getFreeHeap());
  Serial.flush();
}
void loop() { }

These are the static objects of the sketch that consume most of RAM space:

$ arm-none-eabi-nm -n --size-sort sketch.elf | grep ' B ' | tail -12

00000010 B g_external_irq1_ctrl
00000014 B SerialUSB
00000018 B _ZN7arduino11IN6ADDR_ANYE
00000018 B _ZN7arduino11INADDR_NONEE
00000028 B _ZN4UART7g_uartsE
00000038 B _ZN4Tone10tone_timerE
0000003c B _dac12
00000040 B g_bsp_group_irq_sources
00000080 B gp_renesas_isr_context
000004ac B _UART1_
000004ac B _UART2_
000004ac B _UART3_

2 of 3 UARTs are not in use by the sketch itself but they consume 1+ KByte each.

When we execute the sketch - it makes a report of free heap available:

Free Heap = 25635

Let's alter the sketch by adding #include <Wire.h> line:

#include <Wire.h>

extern "C" void * _sbrk   (int);

static uint32_t RA4M1_getFreeHeap()
{
  char top;
  return &top - reinterpret_cast<char*>(_sbrk(0));
}

void setup()
{
  Serial.begin(38400);
  for (int i=0; i < 20; i++) {if (Serial) break; else delay(100);}

  Serial.print("Free Heap = "); Serial.println(RA4M1_getFreeHeap());
  Serial.flush();
}
void loop() { }
$ arm-none-eabi-nm -n --size-sort sketch.elf | grep ' B ' | tail -12

00000018 B _ZN7arduino11INADDR_NONEE
00000028 B _ZN4UART7g_uartsE
00000028 B _ZN7TwoWire10g_I2CWiresE
00000038 B _ZN4Tone10tone_timerE
0000003c B _dac12
00000040 B g_bsp_group_irq_sources
00000080 B gp_renesas_isr_context
00000448 B Wire
00000448 B Wire1
000004ac B _UART1_
000004ac B _UART2_
000004ac B _UART3_

We can see now that 2 more (Wire and Wire1) objects consume 1+ Kbyte of RAM each. Both of these objects are actually not in use by the sketch.

Let's execute the sketch as well:

Free Heap = 23395

We can see that this 'hello world' kind of sketch consumes 9 KBytes out of 32 KBytes RAM available in the Renesas RA4M1 MCU.

Let's build and execute the sketch on Arduino Zero/M0 (SAMD21) target:

There are the results when Wire.h is not included:

00000004 B _usbSetInterface
00000008 B sercom0
00000008 B sercom1
00000008 B sercom2
00000008 B sercom3
00000008 B sercom4
00000008 B sercom5
00000028 B EndPoints
0000003c B SerialUSB
00000100 B _pack_buffer
00000104 B usbd
00000244 B Serial1

Free Heap = 30063

And this one is taken with Wire.h:

00000008 B sercom0
00000008 B sercom1
00000008 B sercom2
00000008 B sercom3
00000008 B sercom4
00000008 B sercom5
00000028 B EndPoints
0000003c B SerialUSB
00000100 B _pack_buffer
00000104 B usbd
0000023c B Wire
00000244 B Serial1

Free Heap = 29487

Summary

Both RA4M1 and SAMD21 have 32 Kbytes of RAM available.
However, the Arduino Core for Renesas MCUs consumes a lot more RAM space for unused static objects rather than Arduino Core for SAMD does.

@JAndrassy
Copy link
Contributor

you build with Arduino IDE or Arduino CLI? (not with platformio or Sloeber)

@lyusupov
Copy link
Author

lyusupov commented Mar 22, 2024

@JAndrassy

you build with Arduino IDE or Arduino CLI?

$ arduino-cli  core install arduino:renesas_uno
$ arduino-cli  core install arduino:samd
$ export BOARD=arduino:renesas_uno:unor4wifi
$ arduino-cli  compile -v --build-path=/tmp/arduino_renesas -b "$BOARD" <path-to-sketch-folder>
$ export BOARD=arduino:samd:mkrzero
$ arduino-cli  compile -v --build-path=/tmp/arduino_samd -b "$BOARD" <path-to-sketch-folder>

@facchinm
Copy link
Member

Double checked and it's true indeed 🤔 The issue was once "bypassed" by moving every instance to their own file (so they become independent compilation units and the linker can strip the unused bits).
Enabling LTO with this patch

diff --git a/platform.txt b/platform.txt
index 22e6cae7..05be7cb0 100644
--- a/platform.txt
+++ b/platform.txt
@@ -20,13 +20,13 @@ compiler.optimization_flags.debug=-Og
 
 compiler.path={build.compiler_path}
 compiler.c.cmd={build.crossprefix}gcc
-compiler.c.flags=-c {compiler.warning_flags} {compiler.optimization_flags} -g3 -nostdlib {build.defines} -MMD -std=gnu11 -mcpu={build.mcu} {build.float-abi} {build.fpu} -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -fmessage-length=0 -fno-builtin
+compiler.c.flags=-c {compiler.warning_flags} {compiler.optimization_flags} -g3 -nostdlib {build.defines} -MMD -std=gnu11 -mcpu={build.mcu} {build.float-abi} {build.fpu} -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -fmessage-length=0 -fno-builtin -flto -fuse-linker-plugin
 compiler.c.elf.cmd={build.crossprefix}g++
-compiler.c.elf.flags=-Wl,--gc-sections --specs=nosys.specs {compiler.warning_flags} -mcpu={build.mcu} {build.float-abi} {build.fpu}
+compiler.c.elf.flags=-Wl,--gc-sections --specs=nosys.specs {compiler.warning_flags} -mcpu={build.mcu} {build.float-abi} {build.fpu} -flto
 compiler.S.cmd={build.crossprefix}g++
 compiler.S.flags=-c -g -x assembler-with-cpp {compiler.optimization_flags} -mcpu={build.mcu} {build.float-abi} {build.fpu} -fsigned-char -ffunction-sections -fdata-sections
 compiler.cpp.cmd={build.crossprefix}g++
-compiler.cpp.flags=-c {compiler.warning_flags} {compiler.optimization_flags} -g3 -fno-use-cxa-atexit -fno-rtti -fno-exceptions -MMD -nostdlib {build.defines} -MMD -std=gnu++17 -mcpu={build.mcu} {build.float-abi} {build.fpu} -fsigned-char -ffunction-sections -fdata-sections -fmessage-length=0 -fno-builtin
+compiler.cpp.flags=-c {compiler.warning_flags} {compiler.optimization_flags} -g3 -fno-use-cxa-atexit -fno-rtti -fno-exceptions -MMD -nostdlib {build.defines} -MMD -std=gnu++17 -mcpu={build.mcu} {build.float-abi} {build.fpu} -fsigned-char -ffunction-sections -fdata-sections -fmessage-length=0 -fno-builtin -flto -fuse-linker-plugin
 compiler.ar.cmd={build.crossprefix}ar
 compiler.ar.flags=rcs
 compiler.ar.extra_flags=

removes the unused objects but it could have side effects. I'm checking now why the original optimization doesn't work anymore...
Thanks for the heads up!

@per1234 per1234 added type: imperfection Perceived defect in any part of project topic: code Related to content of the project itself labels Mar 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: code Related to content of the project itself type: imperfection Perceived defect in any part of project
Projects
None yet
Development

No branches or pull requests

4 participants