[PATCH 0/3] malloc: Reduce size by initializing data at runtime

In my efforts to get SPL to fit into flash after some changes I made, I noticed that av_ is one of the largest variables in SPL. As it turns out, we can generate it at runtime, and the code is already there. This has the potential to save 1-2k across the board, for some minor boot time increase.
Sean Anderson (3): malloc: Don't use ifdefs for SYS_MALLOC_DEFAULT_TO_INIT malloc: Don't statically initialize av_ if using malloc_init malloc: Enable SYS_MALLOC_RUNTIME_INIT by default in SPL
Kconfig | 27 +++++++++++++++++---------- common/dlmalloc.c | 16 ++++++++-------- 2 files changed, 25 insertions(+), 18 deletions(-)

With CONFIG_IS_ENABLED we can eliminate some ifdefs.
Signed-off-by: Sean Anderson sean.anderson@seco.com ---
common/dlmalloc.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/common/dlmalloc.c b/common/dlmalloc.c index 0f9b7262d5..30c78ae976 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -588,9 +588,7 @@ static void malloc_bin_reloc(void) static inline void malloc_bin_reloc(void) {} #endif
-#ifdef CONFIG_SYS_MALLOC_DEFAULT_TO_INIT static void malloc_init(void); -#endif
ulong mem_malloc_start = 0; ulong mem_malloc_end = 0; @@ -625,9 +623,8 @@ void mem_malloc_init(ulong start, ulong size) mem_malloc_end = start + size; mem_malloc_brk = start;
-#ifdef CONFIG_SYS_MALLOC_DEFAULT_TO_INIT - malloc_init(); -#endif + if (CONFIG_IS_ENABLED(SYS_MALLOC_DEFAULT_TO_INIT)) + malloc_init();
debug("using memory %#lx-%#lx for malloc()\n", mem_malloc_start, mem_malloc_end); @@ -733,7 +730,6 @@ static unsigned int max_n_mmaps = 0; static unsigned long max_mmapped_mem = 0; #endif
-#ifdef CONFIG_SYS_MALLOC_DEFAULT_TO_INIT static void malloc_init(void) { int i, j; @@ -762,7 +758,6 @@ static void malloc_init(void) memset((void *)¤t_mallinfo, 0, sizeof(struct mallinfo)); #endif } -#endif
/* Debugging support

On 8/1/23 00:33, Sean Anderson wrote:
With CONFIG_IS_ENABLED we can eliminate some ifdefs.
Signed-off-by: Sean Anderson sean.anderson@seco.com
Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de
common/dlmalloc.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/common/dlmalloc.c b/common/dlmalloc.c index 0f9b7262d5..30c78ae976 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -588,9 +588,7 @@ static void malloc_bin_reloc(void) static inline void malloc_bin_reloc(void) {} #endif
-#ifdef CONFIG_SYS_MALLOC_DEFAULT_TO_INIT static void malloc_init(void); -#endif
ulong mem_malloc_start = 0; ulong mem_malloc_end = 0; @@ -625,9 +623,8 @@ void mem_malloc_init(ulong start, ulong size) mem_malloc_end = start + size; mem_malloc_brk = start;
-#ifdef CONFIG_SYS_MALLOC_DEFAULT_TO_INIT
- malloc_init();
-#endif
if (CONFIG_IS_ENABLED(SYS_MALLOC_DEFAULT_TO_INIT))
malloc_init();
debug("using memory %#lx-%#lx for malloc()\n", mem_malloc_start, mem_malloc_end);
@@ -733,7 +730,6 @@ static unsigned int max_n_mmaps = 0; static unsigned long max_mmapped_mem = 0; #endif
-#ifdef CONFIG_SYS_MALLOC_DEFAULT_TO_INIT static void malloc_init(void) { int i, j; @@ -762,7 +758,6 @@ static void malloc_init(void) memset((void *)¤t_mallinfo, 0, sizeof(struct mallinfo)); #endif } -#endif
/* Debugging support

On Mon, 31 Jul 2023 at 23:24, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 8/1/23 00:33, Sean Anderson wrote:
With CONFIG_IS_ENABLED we can eliminate some ifdefs.
Signed-off-by: Sean Anderson sean.anderson@seco.com
Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de
Reviewed-by: Simon Glass sjg@chromium.org

When we enable malloc_init, there is no need to statically initialize av_, since we are going to do it manually. This lets us move av_ to .bss, saving around 1-2k of data (depending on the pointer size).
cALLOc must be adjusted to not access top before malloc_init.
While we're at it, rename/reword the Kconfig to better describe what this option does.
Signed-off-by: Sean Anderson sean.anderson@seco.com ---
Kconfig | 18 +++++++----------- common/dlmalloc.c | 9 +++++++-- 2 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/Kconfig b/Kconfig index 70efb41cc6..4b32286b69 100644 --- a/Kconfig +++ b/Kconfig @@ -372,18 +372,14 @@ if EXPERT When disabling this, please check if malloc calls, maybe should be replaced by calloc - if one expects zeroed memory.
-config SYS_MALLOC_DEFAULT_TO_INIT - bool "Default malloc to init while reserving the memory for it" +config SYS_MALLOC_RUNTIME_INIT + bool "Initialize malloc's internal data at runtime" help - It may happen that one needs to move the dynamic allocation - from one to another memory range, eg. when moving the malloc - from the limited static to a potentially large dynamic (DDR) - memory. - - If so then on top of setting the updated memory aside one - needs to bring the malloc init. - - If such a scenario is sought choose yes. + Initialize malloc's internal data structures at runtime, rather than + at compile-time. This is necessary if relocating the malloc arena + from a smaller static memory to a large DDR memory. It can also + reduce the size of U-Boot by letting malloc's data reside in .bss + instead of .data.
config TOOLS_DEBUG bool "Enable debug information for tools" diff --git a/common/dlmalloc.c b/common/dlmalloc.c index 30c78ae976..8a1daae5ec 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -556,6 +556,7 @@ typedef struct malloc_chunk* mbinptr; #define IAV(i) bin_at(i), bin_at(i)
static mbinptr av_[NAV * 2 + 2] = { +#if !CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) NULL, NULL, IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7), IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15), @@ -573,6 +574,7 @@ static mbinptr av_[NAV * 2 + 2] = { IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111), IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119), IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127) +#endif };
#ifdef CONFIG_NEEDS_MANUAL_RELOC @@ -623,7 +625,7 @@ void mem_malloc_init(ulong start, ulong size) mem_malloc_end = start + size; mem_malloc_brk = start;
- if (CONFIG_IS_ENABLED(SYS_MALLOC_DEFAULT_TO_INIT)) + if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT)) malloc_init();
debug("using memory %#lx-%#lx for malloc()\n", mem_malloc_start, @@ -2151,7 +2153,10 @@ Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size; #ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT #if MORECORE_CLEARS mchunkptr oldtop = top; - INTERNAL_SIZE_T oldtopsize = chunksize(top); + INTERNAL_SIZE_T oldtopsize; + if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) && + !(gd->flags & GD_FLG_FULL_MALLOC_INIT)) + oldtopsize = chunksize(top); #endif #endif Void_t* mem = mALLOc (sz);

On 8/1/23 00:33, Sean Anderson wrote:
When we enable malloc_init, there is no need to statically initialize av_, since we are going to do it manually. This lets us move av_ to .bss, saving around 1-2k of data (depending on the pointer size).
cALLOc must be adjusted to not access top before malloc_init.
While we're at it, rename/reword the Kconfig to better describe what this option does.
Signed-off-by: Sean Anderson sean.anderson@seco.com
Kconfig | 18 +++++++----------- common/dlmalloc.c | 9 +++++++-- 2 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/Kconfig b/Kconfig index 70efb41cc6..4b32286b69 100644 --- a/Kconfig +++ b/Kconfig @@ -372,18 +372,14 @@ if EXPERT When disabling this, please check if malloc calls, maybe should be replaced by calloc - if one expects zeroed memory.
-config SYS_MALLOC_DEFAULT_TO_INIT
- bool "Default malloc to init while reserving the memory for it"
+config SYS_MALLOC_RUNTIME_INIT
- bool "Initialize malloc's internal data at runtime" help
It may happen that one needs to move the dynamic allocation
from one to another memory range, eg. when moving the malloc
from the limited static to a potentially large dynamic (DDR)
memory.
If so then on top of setting the updated memory aside one
needs to bring the malloc init.
If such a scenario is sought choose yes.
Initialize malloc's internal data structures at runtime, rather than
at compile-time. This is necessary if relocating the malloc arena
from a smaller static memory to a large DDR memory. It can also
reduce the size of U-Boot by letting malloc's data reside in .bss
instead of .data.
config TOOLS_DEBUG bool "Enable debug information for tools"
diff --git a/common/dlmalloc.c b/common/dlmalloc.c index 30c78ae976..8a1daae5ec 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -556,6 +556,7 @@ typedef struct malloc_chunk* mbinptr; #define IAV(i) bin_at(i), bin_at(i)
static mbinptr av_[NAV * 2 + 2] = { +#if !CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) NULL, NULL, IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7), IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15), @@ -573,6 +574,7 @@ static mbinptr av_[NAV * 2 + 2] = { IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111), IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119), IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127) +#endif };
With this patch booting qemu-riscv64_spl_defconfig with SYS_MALLOC_RUNTIME_INIT=y fails without output from main U-Boot.
After removing the #if above, main U-Boot output provides some output but driver binding fails.
Without this patch and with SYS_MALLOC_DEFAULT_TO_INIT=y booting succeeds.
#ifdef CONFIG_NEEDS_MANUAL_RELOC @@ -623,7 +625,7 @@ void mem_malloc_init(ulong start, ulong size) mem_malloc_end = start + size; mem_malloc_brk = start;
- if (CONFIG_IS_ENABLED(SYS_MALLOC_DEFAULT_TO_INIT))
if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT)) malloc_init();
debug("using memory %#lx-%#lx for malloc()\n", mem_malloc_start,
@@ -2151,7 +2153,10 @@ Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size; #ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT #if MORECORE_CLEARS mchunkptr oldtop = top;
- INTERNAL_SIZE_T oldtopsize = chunksize(top);
- INTERNAL_SIZE_T oldtopsize;
- if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) &&
!(gd->flags & GD_FLG_FULL_MALLOC_INIT))
- oldtopsize = chunksize(top);
malloc_simple needs a value for oldtopsize and this is before GD_FLG_FULL_MALLOC_INIT is set.
This change worked for me:
#ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT #if MORECORE_CLEARS mchunkptr oldtop = top; if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) && !(gd->flags & GD_FLG_FULL_MALLOC_INIT)) malloc_init(); INTERNAL_SIZE_T oldtopsize = chunksize(top); #endif #endif
You don't want to call malloc_init() twice. So some flag should be added indicating if malloc_init() has been invoked.
Best regards
Heinrich
#endif #endif Void_t* mem = mALLOc (sz);

On 8/1/23 03:04, Heinrich Schuchardt wrote:
On 8/1/23 00:33, Sean Anderson wrote:
When we enable malloc_init, there is no need to statically initialize av_, since we are going to do it manually. This lets us move av_ to .bss, saving around 1-2k of data (depending on the pointer size).
cALLOc must be adjusted to not access top before malloc_init.
While we're at it, rename/reword the Kconfig to better describe what this option does.
Signed-off-by: Sean Anderson sean.anderson@seco.com
Kconfig | 18 +++++++----------- common/dlmalloc.c | 9 +++++++-- 2 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/Kconfig b/Kconfig index 70efb41cc6..4b32286b69 100644 --- a/Kconfig +++ b/Kconfig @@ -372,18 +372,14 @@ if EXPERT When disabling this, please check if malloc calls, maybe should be replaced by calloc - if one expects zeroed memory. -config SYS_MALLOC_DEFAULT_TO_INIT
- bool "Default malloc to init while reserving the memory for it"
+config SYS_MALLOC_RUNTIME_INIT
- bool "Initialize malloc's internal data at runtime" help
It may happen that one needs to move the dynamic allocation
from one to another memory range, eg. when moving the malloc
from the limited static to a potentially large dynamic (DDR)
memory.
If so then on top of setting the updated memory aside one
needs to bring the malloc init.
If such a scenario is sought choose yes.
Initialize malloc's internal data structures at runtime,
rather than
at compile-time. This is necessary if relocating the malloc
arena
from a smaller static memory to a large DDR memory. It can also
reduce the size of U-Boot by letting malloc's data reside in
.bss
config TOOLS_DEBUG bool "Enable debug information for tools"instead of .data.
diff --git a/common/dlmalloc.c b/common/dlmalloc.c index 30c78ae976..8a1daae5ec 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -556,6 +556,7 @@ typedef struct malloc_chunk* mbinptr; #define IAV(i) bin_at(i), bin_at(i) static mbinptr av_[NAV * 2 + 2] = { +#if !CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) NULL, NULL, IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7), IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15), @@ -573,6 +574,7 @@ static mbinptr av_[NAV * 2 + 2] = { IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111), IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119), IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127) +#endif };
With this patch booting qemu-riscv64_spl_defconfig with SYS_MALLOC_RUNTIME_INIT=y fails without output from main U-Boot.
After removing the #if above, main U-Boot output provides some output but driver binding fails.
Without this patch and with SYS_MALLOC_DEFAULT_TO_INIT=y booting succeeds.
#ifdef CONFIG_NEEDS_MANUAL_RELOC @@ -623,7 +625,7 @@ void mem_malloc_init(ulong start, ulong size) mem_malloc_end = start + size; mem_malloc_brk = start;
- if (CONFIG_IS_ENABLED(SYS_MALLOC_DEFAULT_TO_INIT))
- if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT)) malloc_init(); debug("using memory %#lx-%#lx for malloc()\n", mem_malloc_start,
@@ -2151,7 +2153,10 @@ Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size; #ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT #if MORECORE_CLEARS mchunkptr oldtop = top;
- INTERNAL_SIZE_T oldtopsize = chunksize(top);
- INTERNAL_SIZE_T oldtopsize;
- if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) &&
!(gd->flags & GD_FLG_FULL_MALLOC_INIT))
- oldtopsize = chunksize(top);
malloc_simple needs a value for oldtopsize and this is before GD_FLG_FULL_MALLOC_INIT is set.
This change worked for me:
#ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT #if MORECORE_CLEARS mchunkptr oldtop = top; if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) && !(gd->flags & GD_FLG_FULL_MALLOC_INIT)) malloc_init(); INTERNAL_SIZE_T oldtopsize = chunksize(top); #endif #endif
You don't want to call malloc_init() twice. So some flag should be added indicating if malloc_init() has been invoked.
Actually, I think the original condition was just backwards. It should be
if (!CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) && (gd->flags & GD_FLG_FULL_MALLOC_INIT))
although this still doesn't match the malloc_simple condition. So maybe the condition to remove the initialization should be
#if !CONFIG_VAL(SYS_MALLOC_F_LEN) && \ !CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT)
or perhaps RUNTIME_INIT should depend on F_LEN? I don't see anyone using for other purposes, so I think adding this dependency should be fine.
--Sean

On 01.08.23 18:02, Sean Anderson wrote:
On 8/1/23 03:04, Heinrich Schuchardt wrote:
On 8/1/23 00:33, Sean Anderson wrote:
When we enable malloc_init, there is no need to statically initialize av_, since we are going to do it manually. This lets us move av_ to .bss, saving around 1-2k of data (depending on the pointer size).
cALLOc must be adjusted to not access top before malloc_init.
While we're at it, rename/reword the Kconfig to better describe what this option does.
Signed-off-by: Sean Anderson sean.anderson@seco.com
Kconfig | 18 +++++++----------- common/dlmalloc.c | 9 +++++++-- 2 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/Kconfig b/Kconfig index 70efb41cc6..4b32286b69 100644 --- a/Kconfig +++ b/Kconfig @@ -372,18 +372,14 @@ if EXPERT When disabling this, please check if malloc calls, maybe should be replaced by calloc - if one expects zeroed memory. -config SYS_MALLOC_DEFAULT_TO_INIT - bool "Default malloc to init while reserving the memory for it" +config SYS_MALLOC_RUNTIME_INIT + bool "Initialize malloc's internal data at runtime" help - It may happen that one needs to move the dynamic allocation - from one to another memory range, eg. when moving the malloc - from the limited static to a potentially large dynamic (DDR) - memory.
- If so then on top of setting the updated memory aside one - needs to bring the malloc init.
- If such a scenario is sought choose yes. + Initialize malloc's internal data structures at runtime, rather than + at compile-time. This is necessary if relocating the malloc arena + from a smaller static memory to a large DDR memory. It can also + reduce the size of U-Boot by letting malloc's data reside in .bss + instead of .data. config TOOLS_DEBUG bool "Enable debug information for tools" diff --git a/common/dlmalloc.c b/common/dlmalloc.c index 30c78ae976..8a1daae5ec 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -556,6 +556,7 @@ typedef struct malloc_chunk* mbinptr; #define IAV(i) bin_at(i), bin_at(i) static mbinptr av_[NAV * 2 + 2] = { +#if !CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) NULL, NULL, IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7), IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15), @@ -573,6 +574,7 @@ static mbinptr av_[NAV * 2 + 2] = { IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111), IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119), IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127) +#endif };
With this patch booting qemu-riscv64_spl_defconfig with SYS_MALLOC_RUNTIME_INIT=y fails without output from main U-Boot.
After removing the #if above, main U-Boot output provides some output but driver binding fails.
Without this patch and with SYS_MALLOC_DEFAULT_TO_INIT=y booting succeeds.
#ifdef CONFIG_NEEDS_MANUAL_RELOC @@ -623,7 +625,7 @@ void mem_malloc_init(ulong start, ulong size) mem_malloc_end = start + size; mem_malloc_brk = start; - if (CONFIG_IS_ENABLED(SYS_MALLOC_DEFAULT_TO_INIT)) + if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT)) malloc_init(); debug("using memory %#lx-%#lx for malloc()\n", mem_malloc_start, @@ -2151,7 +2153,10 @@ Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size; #ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT #if MORECORE_CLEARS mchunkptr oldtop = top; - INTERNAL_SIZE_T oldtopsize = chunksize(top); + INTERNAL_SIZE_T oldtopsize; + if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) && + !(gd->flags & GD_FLG_FULL_MALLOC_INIT)) + oldtopsize = chunksize(top);
malloc_simple needs a value for oldtopsize and this is before GD_FLG_FULL_MALLOC_INIT is set.
This change worked for me:
#ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT #if MORECORE_CLEARS mchunkptr oldtop = top; if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) && !(gd->flags & GD_FLG_FULL_MALLOC_INIT)) malloc_init(); INTERNAL_SIZE_T oldtopsize = chunksize(top); #endif #endif
You don't want to call malloc_init() twice. So some flag should be added indicating if malloc_init() has been invoked.
Actually, I think the original condition was just backwards. It should be
if (!CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) && (gd->flags & GD_FLG_FULL_MALLOC_INIT))
This does not work either.
oldtopsize is needed in calloc() both w/ and w/o GD_FLG_FULL_MALLOC_INIT and w/ and w/o SYS_MALLOC_RUNTIME_INIT to define the memory area to zero out for calloc(). You must set it to the correct value irrespective of these conditions.
Why don't you want to call malloc_init() here?
Best regards
Heinrich
although this still doesn't match the malloc_simple condition. So maybe the condition to remove the initialization should be
#if !CONFIG_VAL(SYS_MALLOC_F_LEN) && \ !CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT)
or perhaps RUNTIME_INIT should depend on F_LEN? I don't see anyone using for other purposes, so I think adding this dependency should be fine.
--Sean

On 8/1/23 12:23, Heinrich Schuchardt wrote:
On 01.08.23 18:02, Sean Anderson wrote:
On 8/1/23 03:04, Heinrich Schuchardt wrote:
On 8/1/23 00:33, Sean Anderson wrote:
When we enable malloc_init, there is no need to statically initialize av_, since we are going to do it manually. This lets us move av_ to .bss, saving around 1-2k of data (depending on the pointer size).
cALLOc must be adjusted to not access top before malloc_init.
While we're at it, rename/reword the Kconfig to better describe what this option does.
Signed-off-by: Sean Anderson sean.anderson@seco.com
Kconfig | 18 +++++++----------- common/dlmalloc.c | 9 +++++++-- 2 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/Kconfig b/Kconfig index 70efb41cc6..4b32286b69 100644 --- a/Kconfig +++ b/Kconfig @@ -372,18 +372,14 @@ if EXPERT When disabling this, please check if malloc calls, maybe should be replaced by calloc - if one expects zeroed memory. -config SYS_MALLOC_DEFAULT_TO_INIT
- bool "Default malloc to init while reserving the memory for it"
+config SYS_MALLOC_RUNTIME_INIT
- bool "Initialize malloc's internal data at runtime" help
It may happen that one needs to move the dynamic allocation
from one to another memory range, eg. when moving the malloc
from the limited static to a potentially large dynamic (DDR)
memory.
If so then on top of setting the updated memory aside one
needs to bring the malloc init.
If such a scenario is sought choose yes.
Initialize malloc's internal data structures at runtime,
rather than
at compile-time. This is necessary if relocating the
malloc arena
from a smaller static memory to a large DDR memory. It can
also
reduce the size of U-Boot by letting malloc's data reside
in .bss
config TOOLS_DEBUG bool "Enable debug information for tools"instead of .data.
diff --git a/common/dlmalloc.c b/common/dlmalloc.c index 30c78ae976..8a1daae5ec 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -556,6 +556,7 @@ typedef struct malloc_chunk* mbinptr; #define IAV(i) bin_at(i), bin_at(i) static mbinptr av_[NAV * 2 + 2] = { +#if !CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) NULL, NULL, IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7), IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15), @@ -573,6 +574,7 @@ static mbinptr av_[NAV * 2 + 2] = { IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111), IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119), IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127) +#endif };
With this patch booting qemu-riscv64_spl_defconfig with SYS_MALLOC_RUNTIME_INIT=y fails without output from main U-Boot.
After removing the #if above, main U-Boot output provides some output but driver binding fails.
Without this patch and with SYS_MALLOC_DEFAULT_TO_INIT=y booting succeeds.
#ifdef CONFIG_NEEDS_MANUAL_RELOC @@ -623,7 +625,7 @@ void mem_malloc_init(ulong start, ulong size) mem_malloc_end = start + size; mem_malloc_brk = start;
- if (CONFIG_IS_ENABLED(SYS_MALLOC_DEFAULT_TO_INIT))
- if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT)) malloc_init(); debug("using memory %#lx-%#lx for malloc()\n", mem_malloc_start,
@@ -2151,7 +2153,10 @@ Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size; #ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT #if MORECORE_CLEARS mchunkptr oldtop = top;
- INTERNAL_SIZE_T oldtopsize = chunksize(top);
- INTERNAL_SIZE_T oldtopsize;
- if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) &&
!(gd->flags & GD_FLG_FULL_MALLOC_INIT))
- oldtopsize = chunksize(top);
malloc_simple needs a value for oldtopsize and this is before GD_FLG_FULL_MALLOC_INIT is set.
This change worked for me:
#ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT #if MORECORE_CLEARS mchunkptr oldtop = top; if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) && !(gd->flags & GD_FLG_FULL_MALLOC_INIT)) malloc_init(); INTERNAL_SIZE_T oldtopsize = chunksize(top); #endif #endif
You don't want to call malloc_init() twice. So some flag should be added indicating if malloc_init() has been invoked.
Actually, I think the original condition was just backwards. It should be
if (!CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) && (gd->flags & GD_FLG_FULL_MALLOC_INIT))
This does not work either.
oldtopsize is needed in calloc() both w/ and w/o GD_FLG_FULL_MALLOC_INIT and w/ and w/o SYS_MALLOC_RUNTIME_INIT to define the memory area to zero out for calloc(). You must set it to the correct value irrespective of these conditions.
No it's not.
if (mem == NULL) return NULL; else { #if CONFIG_VAL(SYS_MALLOC_F_LEN) if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT)) { memset(mem, 0, sz); return mem; } #endif
There's no reference to oldtopsize here.
Why don't you want to call malloc_init() here?
Why not just lazily call malloc_init and skip the whole malloc_simple thing?
--Sean
Best regards
Heinrich
although this still doesn't match the malloc_simple condition. So maybe the condition to remove the initialization should be
#if !CONFIG_VAL(SYS_MALLOC_F_LEN) && \ !CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT)
or perhaps RUNTIME_INIT should depend on F_LEN? I don't see anyone using for other purposes, so I think adding this dependency should be fine.
--Sean

On 01.08.23 18:27, Sean Anderson wrote:
On 8/1/23 12:23, Heinrich Schuchardt wrote:
On 01.08.23 18:02, Sean Anderson wrote:
On 8/1/23 03:04, Heinrich Schuchardt wrote:
On 8/1/23 00:33, Sean Anderson wrote:
When we enable malloc_init, there is no need to statically initialize av_, since we are going to do it manually. This lets us move av_ to .bss, saving around 1-2k of data (depending on the pointer size).
cALLOc must be adjusted to not access top before malloc_init.
While we're at it, rename/reword the Kconfig to better describe what this option does.
Signed-off-by: Sean Anderson sean.anderson@seco.com
Kconfig | 18 +++++++----------- common/dlmalloc.c | 9 +++++++-- 2 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/Kconfig b/Kconfig index 70efb41cc6..4b32286b69 100644 --- a/Kconfig +++ b/Kconfig @@ -372,18 +372,14 @@ if EXPERT When disabling this, please check if malloc calls, maybe should be replaced by calloc - if one expects zeroed memory. -config SYS_MALLOC_DEFAULT_TO_INIT - bool "Default malloc to init while reserving the memory for it" +config SYS_MALLOC_RUNTIME_INIT + bool "Initialize malloc's internal data at runtime" help - It may happen that one needs to move the dynamic allocation - from one to another memory range, eg. when moving the malloc - from the limited static to a potentially large dynamic (DDR) - memory.
- If so then on top of setting the updated memory aside one - needs to bring the malloc init.
- If such a scenario is sought choose yes. + Initialize malloc's internal data structures at runtime, rather than + at compile-time. This is necessary if relocating the malloc arena + from a smaller static memory to a large DDR memory. It can also + reduce the size of U-Boot by letting malloc's data reside in .bss + instead of .data. config TOOLS_DEBUG bool "Enable debug information for tools" diff --git a/common/dlmalloc.c b/common/dlmalloc.c index 30c78ae976..8a1daae5ec 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -556,6 +556,7 @@ typedef struct malloc_chunk* mbinptr; #define IAV(i) bin_at(i), bin_at(i) static mbinptr av_[NAV * 2 + 2] = { +#if !CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) NULL, NULL, IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7), IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15), @@ -573,6 +574,7 @@ static mbinptr av_[NAV * 2 + 2] = { IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111), IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119), IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127) +#endif };
With this patch booting qemu-riscv64_spl_defconfig with SYS_MALLOC_RUNTIME_INIT=y fails without output from main U-Boot.
After removing the #if above, main U-Boot output provides some output but driver binding fails.
Without this patch and with SYS_MALLOC_DEFAULT_TO_INIT=y booting succeeds.
#ifdef CONFIG_NEEDS_MANUAL_RELOC @@ -623,7 +625,7 @@ void mem_malloc_init(ulong start, ulong size) mem_malloc_end = start + size; mem_malloc_brk = start; - if (CONFIG_IS_ENABLED(SYS_MALLOC_DEFAULT_TO_INIT)) + if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT)) malloc_init(); debug("using memory %#lx-%#lx for malloc()\n", mem_malloc_start, @@ -2151,7 +2153,10 @@ Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size; #ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT #if MORECORE_CLEARS mchunkptr oldtop = top; - INTERNAL_SIZE_T oldtopsize = chunksize(top); + INTERNAL_SIZE_T oldtopsize; + if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) && + !(gd->flags & GD_FLG_FULL_MALLOC_INIT)) + oldtopsize = chunksize(top);
malloc_simple needs a value for oldtopsize and this is before GD_FLG_FULL_MALLOC_INIT is set.
This change worked for me:
#ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT #if MORECORE_CLEARS mchunkptr oldtop = top; if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) && !(gd->flags & GD_FLG_FULL_MALLOC_INIT)) malloc_init(); INTERNAL_SIZE_T oldtopsize = chunksize(top); #endif #endif
You don't want to call malloc_init() twice. So some flag should be added indicating if malloc_init() has been invoked.
Actually, I think the original condition was just backwards. It should be
if (!CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) && (gd->flags & GD_FLG_FULL_MALLOC_INIT))
GD_FLG_FULL_MALLOC_INIT is set in initr_reloc().
*Thereafter*
mem_malloc_init is called in initr_malloc().
See init_sequence_r[].
This explains why calling malloc_init() here helped me.
Best regards
Heinrich

On 8/1/23 12:56, Heinrich Schuchardt wrote:
On 01.08.23 18:27, Sean Anderson wrote:
On 8/1/23 12:23, Heinrich Schuchardt wrote:
On 01.08.23 18:02, Sean Anderson wrote:
On 8/1/23 03:04, Heinrich Schuchardt wrote:
On 8/1/23 00:33, Sean Anderson wrote:
When we enable malloc_init, there is no need to statically initialize av_, since we are going to do it manually. This lets us move av_ to .bss, saving around 1-2k of data (depending on the pointer size).
cALLOc must be adjusted to not access top before malloc_init.
While we're at it, rename/reword the Kconfig to better describe what this option does.
Signed-off-by: Sean Anderson sean.anderson@seco.com
Kconfig | 18 +++++++----------- common/dlmalloc.c | 9 +++++++-- 2 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/Kconfig b/Kconfig index 70efb41cc6..4b32286b69 100644 --- a/Kconfig +++ b/Kconfig @@ -372,18 +372,14 @@ if EXPERT When disabling this, please check if malloc calls, maybe should be replaced by calloc - if one expects zeroed memory. -config SYS_MALLOC_DEFAULT_TO_INIT
- bool "Default malloc to init while reserving the memory for it"
+config SYS_MALLOC_RUNTIME_INIT
- bool "Initialize malloc's internal data at runtime" help
It may happen that one needs to move the dynamic allocation
from one to another memory range, eg. when moving the malloc
from the limited static to a potentially large dynamic (DDR)
memory.
If so then on top of setting the updated memory aside one
needs to bring the malloc init.
If such a scenario is sought choose yes.
Initialize malloc's internal data structures at runtime,
rather than
at compile-time. This is necessary if relocating the
malloc arena
from a smaller static memory to a large DDR memory. It
can also
reduce the size of U-Boot by letting malloc's data
reside in .bss
config TOOLS_DEBUG bool "Enable debug information for tools"instead of .data.
diff --git a/common/dlmalloc.c b/common/dlmalloc.c index 30c78ae976..8a1daae5ec 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -556,6 +556,7 @@ typedef struct malloc_chunk* mbinptr; #define IAV(i) bin_at(i), bin_at(i) static mbinptr av_[NAV * 2 + 2] = { +#if !CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) NULL, NULL, IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7), IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15), @@ -573,6 +574,7 @@ static mbinptr av_[NAV * 2 + 2] = { IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111), IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119), IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127) +#endif };
With this patch booting qemu-riscv64_spl_defconfig with SYS_MALLOC_RUNTIME_INIT=y fails without output from main U-Boot.
After removing the #if above, main U-Boot output provides some output but driver binding fails.
Without this patch and with SYS_MALLOC_DEFAULT_TO_INIT=y booting succeeds.
#ifdef CONFIG_NEEDS_MANUAL_RELOC @@ -623,7 +625,7 @@ void mem_malloc_init(ulong start, ulong size) mem_malloc_end = start + size; mem_malloc_brk = start;
- if (CONFIG_IS_ENABLED(SYS_MALLOC_DEFAULT_TO_INIT))
- if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT)) malloc_init(); debug("using memory %#lx-%#lx for malloc()\n",
mem_malloc_start, @@ -2151,7 +2153,10 @@ Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size; #ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT #if MORECORE_CLEARS mchunkptr oldtop = top;
- INTERNAL_SIZE_T oldtopsize = chunksize(top);
- INTERNAL_SIZE_T oldtopsize;
- if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) &&
!(gd->flags & GD_FLG_FULL_MALLOC_INIT))
- oldtopsize = chunksize(top);
malloc_simple needs a value for oldtopsize and this is before GD_FLG_FULL_MALLOC_INIT is set.
This change worked for me:
#ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT #if MORECORE_CLEARS mchunkptr oldtop = top; if (CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) && !(gd->flags & GD_FLG_FULL_MALLOC_INIT)) malloc_init(); INTERNAL_SIZE_T oldtopsize = chunksize(top); #endif #endif
You don't want to call malloc_init() twice. So some flag should be added indicating if malloc_init() has been invoked.
Actually, I think the original condition was just backwards. It should be
if (!CONFIG_IS_ENABLED(SYS_MALLOC_RUNTIME_INIT) && (gd->flags & GD_FLG_FULL_MALLOC_INIT))
GD_FLG_FULL_MALLOC_INIT is set in initr_reloc().
*Thereafter*
mem_malloc_init is called in initr_malloc().
See init_sequence_r[].
This explains why calling malloc_init() here helped me.
Ah. So maybe we should set this flag in malloc_init. This is what SPL does (see board_init_r).
--Sean

On boards with size restrictions, 1-2k can be a significant fraction of the binary size. Add a new SPL version of SYS_MALLOC_RUNTIME_INIT and enable it by default.
Signed-off-by: Sean Anderson sean.anderson@seco.com ---
Kconfig | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/Kconfig b/Kconfig index 4b32286b69..3cb31a9346 100644 --- a/Kconfig +++ b/Kconfig @@ -381,6 +381,17 @@ config SYS_MALLOC_RUNTIME_INIT reduce the size of U-Boot by letting malloc's data reside in .bss instead of .data.
+config SPL_SYS_MALLOC_RUNTIME_INIT + bool "Initialize malloc's internal data at runtime in SPL" + default y + depends on SPL + help + Initialize malloc's internal data structures at SPL runtime, rather + than at compile-time. This is necessary if relocating the malloc arena + from a smaller static memory to a large DDR memory. It can also reduce + the size of U-Boot by letting malloc's data reside in .bss instead of + .data. + config TOOLS_DEBUG bool "Enable debug information for tools" help

On Mon, Jul 31, 2023 at 06:33:27PM -0400, Sean Anderson wrote:
On boards with size restrictions, 1-2k can be a significant fraction of the binary size. Add a new SPL version of SYS_MALLOC_RUNTIME_INIT and enable it by default.
Signed-off-by: Sean Anderson sean.anderson@seco.com
Kconfig | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/Kconfig b/Kconfig index 4b32286b69..3cb31a9346 100644 --- a/Kconfig +++ b/Kconfig @@ -381,6 +381,17 @@ config SYS_MALLOC_RUNTIME_INIT reduce the size of U-Boot by letting malloc's data reside in .bss instead of .data.
+config SPL_SYS_MALLOC_RUNTIME_INIT
- bool "Initialize malloc's internal data at runtime in SPL"
- default y
- depends on SPL
- help
Initialize malloc's internal data structures at SPL runtime, rather
than at compile-time. This is necessary if relocating the malloc arena
from a smaller static memory to a large DDR memory. It can also reduce
the size of U-Boot by letting malloc's data reside in .bss instead of
.data.
config TOOLS_DEBUG bool "Enable debug information for tools" help
Can you use something like grabserial (or other tooling) to quantify the change on a platform or two?

On 8/1/23 11:25, Tom Rini wrote:
On Mon, Jul 31, 2023 at 06:33:27PM -0400, Sean Anderson wrote:
On boards with size restrictions, 1-2k can be a significant fraction of the binary size. Add a new SPL version of SYS_MALLOC_RUNTIME_INIT and enable it by default.
Signed-off-by: Sean Anderson sean.anderson@seco.com
Kconfig | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/Kconfig b/Kconfig index 4b32286b69..3cb31a9346 100644 --- a/Kconfig +++ b/Kconfig @@ -381,6 +381,17 @@ config SYS_MALLOC_RUNTIME_INIT reduce the size of U-Boot by letting malloc's data reside in .bss instead of .data.
+config SPL_SYS_MALLOC_RUNTIME_INIT
- bool "Initialize malloc's internal data at runtime in SPL"
- default y
- depends on SPL
- help
Initialize malloc's internal data structures at SPL runtime, rather
than at compile-time. This is necessary if relocating the malloc arena
from a smaller static memory to a large DDR memory. It can also reduce
the size of U-Boot by letting malloc's data reside in .bss instead of
.data.
config TOOLS_DEBUG bool "Enable debug information for tools" help
Can you use something like grabserial (or other tooling) to quantify the change on a platform or two?
I had a ZynqMP board roughly based on xilinx_zynqmp_virt_defconfig lying around. On this board, serial is not initialized until after malloc, so I used the internal timer and printed the times later. DEBUG_UART would probably be better but I didn't get it working.
diff --git a/common/board_r.c b/common/board_r.c index d798c00a80a..d7aee85e5b1 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -194,6 +194,7 @@ static int initr_barrier(void) return 0; }
+static ulong malloc_begin, malloc_end; static int initr_malloc(void) { ulong malloc_start; @@ -208,8 +209,10 @@ static int initr_malloc(void) * reserve_noncached(). */ malloc_start = gd->relocaddr - TOTAL_MALLOC_LEN; + malloc_begin = timer_get_boot_us(); mem_malloc_init((ulong)map_sysmem(malloc_start, TOTAL_MALLOC_LEN), TOTAL_MALLOC_LEN); + malloc_end = timer_get_boot_us(); return 0; }
@@ -569,6 +572,7 @@ static int dm_announce(void)
static int run_main_loop(void) { + printf("malloc_init took %luus (%lu %lu)\n", malloc_end - malloc_begin, malloc_begin, malloc_end); #ifdef CONFIG_SANDBOX sandbox_main_loop_init(); #endif diff --git a/common/spl/spl.c b/common/spl/spl.c index d74acec10b5..09abcc74442 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -755,7 +755,9 @@ void board_init_r(gd_t *dummy1, ulong dummy2) spl_set_bd();
#if defined(CONFIG_SYS_SPL_MALLOC) + ulong malloc_begin = timer_get_boot_us(); mem_malloc_init(SYS_SPL_MALLOC_START, CONFIG_SYS_SPL_MALLOC_SIZE); + ulong malloc_end = timer_get_boot_us(); gd->flags |= GD_FLG_FULL_MALLOC_INIT; #endif if (!(gd->flags & GD_FLG_SPL_INIT)) { @@ -817,6 +819,7 @@ void board_init_r(gd_t *dummy1, ulong dummy2) spl_image.boot_device = BOOT_DEVICE_NONE; board_boot_order(spl_boot_list);
+ printf("malloc_init took %luus (%lu %lu)\n", malloc_end - malloc_begin, malloc_begin, malloc_end); ret = boot_from_devices(&spl_image, spl_boot_list, ARRAY_SIZE(spl_boot_list)); if (ret) {
I recorded times (in us) from five boots. The value of (SPL_)SYS_MALLOC_RUNTIME_INIT is in parentheses:
SPL (n) U-Boot (n) SPL (y) U-Boot (y) ======= ========== ======= ========== 192975 47557 135027 47557 192940 47557 135059 47557 193006 47557 134722 47558 193015 47556 135055 47557 193987 47557 134790 47557
So SPL took 60 ms shorter (?!) and U-Boot was mostly unaffected. Not sure how that happened. The raw values for begin/end look reasonable:
malloc_init took 47557us (6778108 6825665) malloc_init took 47557us (6779290 6826847) malloc_init took 47558us (6780379 6827937)
etc. but to be honest I don't really see how SPL can spend 190ms setting some variables and clearing the arena.
--Sean

On Tue, Aug 01, 2023 at 07:51:20PM -0400, Sean Anderson wrote:
On 8/1/23 11:25, Tom Rini wrote:
On Mon, Jul 31, 2023 at 06:33:27PM -0400, Sean Anderson wrote:
On boards with size restrictions, 1-2k can be a significant fraction of the binary size. Add a new SPL version of SYS_MALLOC_RUNTIME_INIT and enable it by default.
Signed-off-by: Sean Anderson sean.anderson@seco.com
Kconfig | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/Kconfig b/Kconfig index 4b32286b69..3cb31a9346 100644 --- a/Kconfig +++ b/Kconfig @@ -381,6 +381,17 @@ config SYS_MALLOC_RUNTIME_INIT reduce the size of U-Boot by letting malloc's data reside in .bss instead of .data.
+config SPL_SYS_MALLOC_RUNTIME_INIT
- bool "Initialize malloc's internal data at runtime in SPL"
- default y
- depends on SPL
- help
Initialize malloc's internal data structures at SPL runtime, rather
than at compile-time. This is necessary if relocating the malloc arena
from a smaller static memory to a large DDR memory. It can also reduce
the size of U-Boot by letting malloc's data reside in .bss instead of
.data.
config TOOLS_DEBUG bool "Enable debug information for tools" help
Can you use something like grabserial (or other tooling) to quantify the change on a platform or two?
I had a ZynqMP board roughly based on xilinx_zynqmp_virt_defconfig lying around. On this board, serial is not initialized until after malloc, so I used the internal timer and printed the times later. DEBUG_UART would probably be better but I didn't get it working.
diff --git a/common/board_r.c b/common/board_r.c index d798c00a80a..d7aee85e5b1 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -194,6 +194,7 @@ static int initr_barrier(void) return 0; }
+static ulong malloc_begin, malloc_end; static int initr_malloc(void) { ulong malloc_start; @@ -208,8 +209,10 @@ static int initr_malloc(void) * reserve_noncached(). */ malloc_start = gd->relocaddr - TOTAL_MALLOC_LEN;
malloc_begin = timer_get_boot_us(); mem_malloc_init((ulong)map_sysmem(malloc_start, TOTAL_MALLOC_LEN), TOTAL_MALLOC_LEN);
malloc_end = timer_get_boot_us(); return 0;
}
@@ -569,6 +572,7 @@ static int dm_announce(void)
static int run_main_loop(void) {
printf("malloc_init took %luus (%lu %lu)\n", malloc_end - malloc_begin, malloc_begin, malloc_end);
#ifdef CONFIG_SANDBOX sandbox_main_loop_init(); #endif diff --git a/common/spl/spl.c b/common/spl/spl.c index d74acec10b5..09abcc74442 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -755,7 +755,9 @@ void board_init_r(gd_t *dummy1, ulong dummy2) spl_set_bd();
#if defined(CONFIG_SYS_SPL_MALLOC)
ulong malloc_begin = timer_get_boot_us(); mem_malloc_init(SYS_SPL_MALLOC_START, CONFIG_SYS_SPL_MALLOC_SIZE);
ulong malloc_end = timer_get_boot_us(); gd->flags |= GD_FLG_FULL_MALLOC_INIT;
#endif if (!(gd->flags & GD_FLG_SPL_INIT)) { @@ -817,6 +819,7 @@ void board_init_r(gd_t *dummy1, ulong dummy2) spl_image.boot_device = BOOT_DEVICE_NONE; board_boot_order(spl_boot_list);
printf("malloc_init took %luus (%lu %lu)\n", malloc_end - malloc_begin, malloc_begin, malloc_end); ret = boot_from_devices(&spl_image, spl_boot_list, ARRAY_SIZE(spl_boot_list)); if (ret) {
I recorded times (in us) from five boots. The value of (SPL_)SYS_MALLOC_RUNTIME_INIT is in parentheses:
SPL (n) U-Boot (n) SPL (y) U-Boot (y) ======= ========== ======= ========== 192975 47557 135027 47557 192940 47557 135059 47557 193006 47557 134722 47558 193015 47556 135055 47557 193987 47557 134790 47557
So SPL took 60 ms shorter (?!) and U-Boot was mostly unaffected. Not sure how that happened. The raw values for begin/end look reasonable:
malloc_init took 47557us (6778108 6825665) malloc_init took 47557us (6779290 6826847) malloc_init took 47558us (6780379 6827937)
etc. but to be honest I don't really see how SPL can spend 190ms setting some variables and clearing the arena.
OK. Please repeat this for v2 and assuming that once again the timing change is marginal, I think we can emphasize it's generally a wash.
participants (5)
-
Heinrich Schuchardt
-
Heinrich Schuchardt
-
Sean Anderson
-
Simon Glass
-
Tom Rini