2022-03-24 20:43:33

by Jaewon Kim

[permalink] [raw]
Subject: [PATCH 0/8] memblock: introduce memsize showing reserved memory

Some of memory regions can be reserved for a specific purpose. They are
usually defined through reserved-memory in device tree. If only size
without address is specified in device tree, the address of the region
will be determined at boot time.

We may find the address of the memory regions through booting log, but
it does not show all. And it could be hard to catch the very beginning
log. The memblock_dump_all shows all memblock status but it does not
show region name and its information is difficult to summarize.

This patch introduce a debugfs node, memblock/memsize, to see reserved
memory easily.

Here's an example

$ cat debugfs/memblock/memsize
0x0f9000000-0x0fb000000 0x02000000 ( 32768 KB ) map reusable linux,cma
0x0b1900000-0x0b1b00000 0x00200000 ( 2048 KB ) nomap unusable test1
0x0b0200000-0x0b0400000 0x00200000 ( 2048 KB ) map unusable test2
(snipped)

Reserved : 746924 KB
.kernel : 137027 KB
.text : 28158 KB
.rwdata : 3238 KB
.rodata : 13468 KB
.bss : 12570 KB
.etc : 79593 KB
.unusable : 609897 KB
System : 3447380 KB
.common : 3152468 KB
.reusable : 294912 KB
Total : 4194304 KB ( 4096.00 MB )

Jaewon Kim (8):
memblock: introduce memsize showing reserved memory
memblock: detect hidden memory hole size
memblock: handle overlapped reserved memory region
memblock: track memblock changed at early param
memblock: track kernel size on memsize
memblock: recognize late free by checking PageReserved
memblock: print memsize summary information
memblock: print kernel internal size

drivers/of/fdt.c | 10 +
drivers/of/of_reserved_mem.c | 7 +-
include/linux/memblock.h | 21 ++
include/linux/mm.h | 3 +
init/main.c | 13 +-
kernel/dma/contiguous.c | 9 +-
mm/Kconfig | 7 +
mm/memblock.c | 434 ++++++++++++++++++++++++++++++++++-
mm/page_alloc.c | 15 +-
9 files changed, 506 insertions(+), 13 deletions(-)

--
2.17.1


2022-03-24 21:10:44

by Jaewon Kim

[permalink] [raw]
Subject: [PATCH 6/8] memblock: recognize late free by checking PageReserved

There are some cases in which reserved pages are freed late after the
initial memblock_free_all of mem_init. We'd like to recognize this
late free pages, and update the memsize information.

Because additional job is needed to a no-map or reusable region, the
late free is usually done to a map and unusable region. So only for map
and unusable region, check if some pages within the region is freed. The
freed pages can be recoginzed by checking if PageReserved flag is clear.
To be fast, let's skip other pages within 1 MB range. And this check is
done when a user wants to see the memsize information.

This is an example. If all pages are freed the region size will be 0.

Before
0x0a2300000-0x0a2400000 0x00100000 ( 1024 KB ) map unusable latefree

After
0x0a2300000-0x0a2300000 0x00000000 ( 0 KB ) map unusable latefree

Signed-off-by: Jaewon Kim <[email protected]>
---
mm/memblock.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)

diff --git a/mm/memblock.c b/mm/memblock.c
index aee22dbc2500..597ec7fb5bb2 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -2455,6 +2455,39 @@ static int memsize_rgn_cmp(const void *a, const void *b)
return 0;
}

+/* assume that freed size is always MB aligned */
+static inline void memblock_memsize_check_size(struct memsize_rgn_struct *rgn)
+{
+ phys_addr_t phy, end, freed = 0;
+ bool has_freed = false;
+ struct page *page;
+
+ if (rgn->reusable || rgn->nomap)
+ return;
+
+ /* check the first page of each 1 MB */
+ phy = rgn->base;
+ end = rgn->base + rgn->size;
+ while (phy < end) {
+ unsigned long pfn = __phys_to_pfn(phy);
+
+ if (!pfn_valid(pfn))
+ return;
+ page = pfn_to_page(pfn);
+ if (!has_freed && !PageReserved(page)) {
+ has_freed = true;
+ freed = phy;
+ } else if (has_freed && PageReserved(page)) {
+ has_freed = false;
+ memblock_memsize_free(freed, phy - freed);
+ }
+
+ if (has_freed && (phy + SZ_1M >= end))
+ memblock_memsize_free(freed, end - freed);
+ phy += SZ_1M;
+ }
+}
+
static int memblock_memsize_show(struct seq_file *m, void *private)
{
int i;
@@ -2468,6 +2501,7 @@ static int memblock_memsize_show(struct seq_file *m, void *private)
long size;

rgn = &memsize_rgn[i];
+ memblock_memsize_check_size(rgn);
base = rgn->base;
size = rgn->size;
end = base + size;
--
2.17.1

2022-03-24 21:16:08

by Jaewon Kim

[permalink] [raw]
Subject: [PATCH 8/8] memblock: print kernel internal size

Kernel internal size information is also useful to compare with other
binary. This patch print kernel text, rwdata, rodata, bss, and others.

Here's an example.

Reserved : 746924 KB
.kernel : 137027 KB
.text : 28158 KB
.rwdata : 3238 KB
.rodata : 13468 KB
.bss : 12570 KB
.etc : 79593 KB
.unusable : 609897 KB
System : 3447380 KB
.common : 3152468 KB
.reusable : 294912 KB
Total : 4194304 KB ( 4096.00 MB )

Signed-off-by: Jaewon Kim <[email protected]>
---
include/linux/mm.h | 3 +++
mm/memblock.c | 17 +++++++++++++++++
mm/page_alloc.c | 6 +++---
3 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 7a3dd7e617e4..6b874c602b3b 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -3387,4 +3387,7 @@ madvise_set_anon_name(struct mm_struct *mm, unsigned long start,
}
#endif

+extern unsigned long physpages, codesize, datasize, rosize, bss_size;
+extern unsigned long init_code_size, init_data_size;
+
#endif /* _LINUX_MM_H */
diff --git a/mm/memblock.c b/mm/memblock.c
index ef8cec6242d2..083d19b1d061 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -2494,6 +2494,13 @@ static int memblock_memsize_show(struct seq_file *m, void *private)
struct memsize_rgn_struct *rgn;
unsigned long reserved = 0, reusable = 0, total;
unsigned long system = totalram_pages() << PAGE_SHIFT;
+ unsigned long text, rw, ro, bss, etc;
+
+ text = codesize;
+ rw = datasize;
+ ro = rosize;
+ bss = bss_size;
+ etc = kernel_init_size - text - rw - ro - bss;

sort(memsize_rgn, memsize_rgn_count,
sizeof(memsize_rgn[0]), memsize_rgn_cmp, NULL);
@@ -2526,6 +2533,16 @@ static int memblock_memsize_show(struct seq_file *m, void *private)
DIV_ROUND_UP(kernel_init_size + reserved, SZ_1K));
seq_printf(m, " .kernel : %7lu KB\n",
DIV_ROUND_UP(kernel_init_size, SZ_1K));
+ seq_printf(m, " .text : %7lu KB\n"
+ " .rwdata : %7lu KB\n"
+ " .rodata : %7lu KB\n"
+ " .bss : %7lu KB\n"
+ " .etc : %7lu KB\n",
+ DIV_ROUND_UP(text, SZ_1K),
+ DIV_ROUND_UP(rw, SZ_1K),
+ DIV_ROUND_UP(ro, SZ_1K),
+ DIV_ROUND_UP(bss, SZ_1K),
+ DIV_ROUND_UP(etc, SZ_1K));
seq_printf(m, " .unusable : %7lu KB\n",
DIV_ROUND_UP(reserved, SZ_1K));
seq_printf(m, "System : %7lu KB\n",
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index bbbe314850b0..2bf75ba3c66d 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -8243,11 +8243,11 @@ unsigned long free_reserved_area(void *start, void *end, int poison, const char
return pages;
}

+unsigned long physpages, codesize, datasize, rosize, bss_size;
+unsigned long init_code_size, init_data_size;
+
void __init mem_init_print_info(void)
{
- unsigned long physpages, codesize, datasize, rosize, bss_size;
- unsigned long init_code_size, init_data_size;
-
physpages = get_num_physpages();
codesize = _etext - _stext;
datasize = _edata - _sdata;
--
2.17.1

2022-03-24 23:33:12

by Jaewon Kim

[permalink] [raw]
Subject: [PATCH 1/8] memblock: introduce memsize showing reserved memory

Some of memory regions can be reserved for a specific purpose. They are
usually defined through reserved-memory in device tree. If only size
without address is specified in device tree, the address of the region
will be determined at boot time.

We may find the address of the memory regions through booting log, but
it does not show all. And it could be hard to catch the very beginning
log. The memblock_dump_all shows all memblock status but it does not
show region name and its information is difficult to summarize.

This patch introduce a debugfs node, memblock/memsize, to see reserved
memory easily.

The first patch here will show the only reserved-memory in device tree
like following example. The next patches will show more information.

$ cat debugfs/memblock/memsize
0x0f9000000-0x0fb000000 0x02000000 ( 32768 KB ) map reusable linux,cma
0x0b1900000-0x0b1b00000 0x00200000 ( 2048 KB ) nomap unusable test1
0x0b0200000-0x0b0400000 0x00200000 ( 2048 KB ) map unusable test2

.unusable : 4096 KB
.reusable : 32768 KB

Signed-off-by: Jaewon Kim <[email protected]>
---
drivers/of/fdt.c | 2 +
drivers/of/of_reserved_mem.c | 7 ++-
include/linux/memblock.h | 9 +++
kernel/dma/contiguous.c | 2 +
mm/Kconfig | 7 +++
mm/memblock.c | 103 +++++++++++++++++++++++++++++++++++
6 files changed, 129 insertions(+), 1 deletion(-)

diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index ec315b060cd5..ec2f60a78f8f 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -619,6 +619,7 @@ static void __init fdt_reserve_elfcorehdr(void)
}

memblock_reserve(elfcorehdr_addr, elfcorehdr_size);
+ memblock_memsize_record("elfcorehdr", elfcorehdr_addr, size, false, false);

pr_info("Reserving %llu KiB of memory at 0x%llx for elfcorehdr\n",
elfcorehdr_size >> 10, elfcorehdr_addr);
@@ -645,6 +646,7 @@ void __init early_init_fdt_scan_reserved_mem(void)
if (!size)
break;
early_init_dt_reserve_memory_arch(base, size, false);
+ memblock_memsize_record("memreserve", base, size, false, false);
}

fdt_scan_reserved_mem();
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index 75caa6f5d36f..40323751efb2 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -261,9 +261,10 @@ void __init fdt_init_reserved_mem(void)
int len;
const __be32 *prop;
int err = 0;
- bool nomap;
+ bool nomap, reusable;

nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
+ reusable = of_get_flat_dt_prop(node, "reusable", NULL) != NULL;
prop = of_get_flat_dt_prop(node, "phandle", &len);
if (!prop)
prop = of_get_flat_dt_prop(node, "linux,phandle", &len);
@@ -283,6 +284,10 @@ void __init fdt_init_reserved_mem(void)
else
memblock_phys_free(rmem->base,
rmem->size);
+ } else {
+ memblock_memsize_record(rmem->name, rmem->base,
+ rmem->size, nomap,
+ reusable);
}
}
}
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index 50ad19662a32..468b016e179b 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -604,5 +604,14 @@ static inline void early_memtest(phys_addr_t start, phys_addr_t end)
}
#endif

+#ifdef CONFIG_MEMBLOCK_MEMSIZE
+extern void memblock_memsize_record(const char *name, phys_addr_t base,
+ phys_addr_t size, bool nomap,
+ bool reusable);
+#else
+static inline void memblock_memsize_record(const char *name, phys_addr_t base,
+ phys_addr_t size, bool nomap,
+ bool reusable) { }
+#endif

#endif /* _LINUX_MEMBLOCK_H */
diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c
index 6ea80ae42622..7415c1135afa 100644
--- a/kernel/dma/contiguous.c
+++ b/kernel/dma/contiguous.c
@@ -239,6 +239,8 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
dma_contiguous_early_fixup(cma_get_base(*res_cma),
cma_get_size(*res_cma));

+ memblock_memsize_record("dma_cma", cma_get_base(*res_cma),
+ cma_get_size(*res_cma), false, true);
return 0;
}

diff --git a/mm/Kconfig b/mm/Kconfig
index 761f5021ba51..e29f6cd8394e 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -96,6 +96,13 @@ config HAVE_FAST_GUP
depends on MMU
bool

+config MEMBLOCK_MEMSIZE
+ bool "memblock based reserved memory profiling"
+ default n
+ help
+ This patch introduce a debugfs node, memblock/memsize, to see reserved
+ memory easily.
+
# Don't discard allocated memory used to track "memory" and "reserved" memblocks
# after early boot, so it can still be used to test for validity of memory.
# Also, memblocks are updated with memory hot(un)plug.
diff --git a/mm/memblock.c b/mm/memblock.c
index b12a364f2766..8492757f7192 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -19,6 +19,7 @@

#include <asm/sections.h>
#include <linux/io.h>
+#include <linux/sort.h>

#include "internal.h"

@@ -1928,6 +1929,49 @@ static int __init early_memblock(char *p)
}
early_param("memblock", early_memblock);

+#ifdef CONFIG_MEMBLOCK_MEMSIZE
+
+#define NAME_SIZE 30
+struct memsize_rgn_struct {
+ phys_addr_t base;
+ long size;
+ bool nomap; /* 1/32 byte */
+ bool reusable; /* 1/32 byte */
+ char name[NAME_SIZE]; /* 30/32 byte */
+};
+
+#define MAX_MEMSIZE_RGN 64
+static struct memsize_rgn_struct memsize_rgn[MAX_MEMSIZE_RGN] __initdata_memblock;
+static int memsize_rgn_count __initdata_memblock;
+
+void __init_memblock memblock_memsize_record(const char *name, phys_addr_t base,
+ phys_addr_t size, bool nomap, bool reusable)
+{
+ struct memsize_rgn_struct *rgn;
+ phys_addr_t end;
+
+ if (memsize_rgn_count == MAX_MEMSIZE_RGN) {
+ pr_err("not enough space on memsize_rgn\n");
+ return;
+ }
+ rgn = &memsize_rgn[memsize_rgn_count++];
+ rgn->base = base;
+ rgn->size = size;
+ rgn->nomap = nomap;
+ rgn->reusable = reusable;
+
+ if (!name) {
+ strcpy(rgn->name, "unknown");
+ } else {
+ strncpy(rgn->name, name, NAME_SIZE - 1);
+ rgn->name[NAME_SIZE - 1] = '\0';
+ }
+ end = base + size - 1;
+ memblock_dbg("%s %pa..%pa nomap:%d reusable:%d\n",
+ __func__, &base, &end, nomap, reusable);
+}
+#endif /* MEMBLOCK_MEMSIZE */
+
static void __init free_memmap(unsigned long start_pfn, unsigned long end_pfn)
{
struct page *start_pg, *end_pg;
@@ -2138,6 +2182,61 @@ static int memblock_debug_show(struct seq_file *m, void *private)
}
DEFINE_SHOW_ATTRIBUTE(memblock_debug);

+#ifdef CONFIG_MEMBLOCK_MEMSIZE
+
+static int memsize_rgn_cmp(const void *a, const void *b)
+{
+ const struct memsize_rgn_struct *ra = a, *rb = b;
+
+ if (ra->base > rb->base)
+ return -1;
+
+ if (ra->base < rb->base)
+ return 1;
+
+ return 0;
+}
+
+static int memblock_memsize_show(struct seq_file *m, void *private)
+{
+ int i;
+ struct memsize_rgn_struct *rgn;
+ unsigned long reserved = 0, reusable = 0;
+
+ sort(memsize_rgn, memsize_rgn_count,
+ sizeof(memsize_rgn[0]), memsize_rgn_cmp, NULL);
+ for (i = 0; i < memsize_rgn_count; i++) {
+ phys_addr_t base, end;
+ long size;
+
+ rgn = &memsize_rgn[i];
+ base = rgn->base;
+ size = rgn->size;
+ end = base + size;
+
+ seq_printf(m, "0x%09lx-0x%09lx 0x%08lx ( %7lu KB ) %s %s %s\n",
+ &base, &end,
+ size, DIV_ROUND_UP(size, SZ_1K),
+ rgn->nomap ? "nomap" : " map",
+ rgn->reusable ? "reusable" : "unusable",
+ rgn->name);
+ if (rgn->reusable)
+ reusable += (unsigned long)rgn->size;
+ else
+ reserved += (unsigned long)rgn->size;
+ }
+
+ seq_printf(m, "\n");
+ seq_printf(m, " .unusable : %7lu KB\n",
+ DIV_ROUND_UP(reserved, SZ_1K));
+ seq_printf(m, " .reusable : %7lu KB\n",
+ DIV_ROUND_UP(reusable, SZ_1K));
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(memblock_memsize);
+#endif
+
static int __init memblock_init_debugfs(void)
{
struct dentry *root = debugfs_create_dir("memblock", NULL);
@@ -2150,6 +2249,10 @@ static int __init memblock_init_debugfs(void)
debugfs_create_file("physmem", 0444, root, &physmem,
&memblock_debug_fops);
#endif
+#ifdef CONFIG_MEMBLOCK_MEMSIZE
+ debugfs_create_file("memsize", 0444, root,
+ NULL, &memblock_memsize_fops);
+#endif

return 0;
}
--
2.17.1

2022-03-25 17:42:39

by Mike Rapoport

[permalink] [raw]
Subject: Re: [PATCH 0/8] memblock: introduce memsize showing reserved memory

Hi,

On Thu, Mar 24, 2022 at 04:01:50PM +0900, Jaewon Kim wrote:
> Some of memory regions can be reserved for a specific purpose. They are
> usually defined through reserved-memory in device tree. If only size
> without address is specified in device tree, the address of the region
> will be determined at boot time.
>
> We may find the address of the memory regions through booting log, but
> it does not show all. And it could be hard to catch the very beginning
> log. The memblock_dump_all shows all memblock status but it does not
> show region name and its information is difficult to summarize.
>
> This patch introduce a debugfs node, memblock/memsize, to see reserved
> memory easily.
>
> Here's an example
>
> $ cat debugfs/memblock/memsize
> 0x0f9000000-0x0fb000000 0x02000000 ( 32768 KB ) map reusable linux,cma
> 0x0b1900000-0x0b1b00000 0x00200000 ( 2048 KB ) nomap unusable test1
> 0x0b0200000-0x0b0400000 0x00200000 ( 2048 KB ) map unusable test2
> (snipped)
>
> Reserved : 746924 KB
> .kernel : 137027 KB
> .text : 28158 KB
> .rwdata : 3238 KB
> .rodata : 13468 KB
> .bss : 12570 KB
> .etc : 79593 KB
> .unusable : 609897 KB
> System : 3447380 KB
> .common : 3152468 KB
> .reusable : 294912 KB
> Total : 4194304 KB ( 4096.00 MB )

Most of this information information is already available at various
places, like the existing memblock debugfs, /proc/iomem and DT sysfs.

I don't see why we need yet another debugfs file to expose it.

> Jaewon Kim (8):
> memblock: introduce memsize showing reserved memory
> memblock: detect hidden memory hole size
> memblock: handle overlapped reserved memory region
> memblock: track memblock changed at early param
> memblock: track kernel size on memsize
> memblock: recognize late free by checking PageReserved
> memblock: print memsize summary information
> memblock: print kernel internal size
>
> drivers/of/fdt.c | 10 +
> drivers/of/of_reserved_mem.c | 7 +-
> include/linux/memblock.h | 21 ++
> include/linux/mm.h | 3 +
> init/main.c | 13 +-
> kernel/dma/contiguous.c | 9 +-
> mm/Kconfig | 7 +
> mm/memblock.c | 434 ++++++++++++++++++++++++++++++++++-
> mm/page_alloc.c | 15 +-
> 9 files changed, 506 insertions(+), 13 deletions(-)
>
> --
> 2.17.1
>

--
Sincerely yours,
Mike.

2022-03-25 17:57:13

by Jaewon Kim

[permalink] [raw]
Subject: [PATCH 7/8] memblock: print memsize summary information

With the previous patches, now we can print summary information.

Here's an example of 4GB DRAM device.

Reserved : 746924 KB
.kernel : 137027 KB
.unusable : 609897 KB
System : 3447380 KB
.common : 3152468 KB
.reusable : 294912 KB
Total : 4194304 KB ( 4096.00 MB )

Signed-off-by: Jaewon Kim <[email protected]>
---
mm/memblock.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/mm/memblock.c b/mm/memblock.c
index 597ec7fb5bb2..ef8cec6242d2 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -2492,7 +2492,8 @@ static int memblock_memsize_show(struct seq_file *m, void *private)
{
int i;
struct memsize_rgn_struct *rgn;
- unsigned long reserved = 0, reusable = 0;
+ unsigned long reserved = 0, reusable = 0, total;
+ unsigned long system = totalram_pages() << PAGE_SHIFT;

sort(memsize_rgn, memsize_rgn_count,
sizeof(memsize_rgn[0]), memsize_rgn_cmp, NULL);
@@ -2518,13 +2519,24 @@ static int memblock_memsize_show(struct seq_file *m, void *private)
reserved += (unsigned long)rgn->size;
}

+ total = kernel_init_size + reserved + system;
+
seq_printf(m, "\n");
+ seq_printf(m, "Reserved : %7lu KB\n",
+ DIV_ROUND_UP(kernel_init_size + reserved, SZ_1K));
seq_printf(m, " .kernel : %7lu KB\n",
DIV_ROUND_UP(kernel_init_size, SZ_1K));
seq_printf(m, " .unusable : %7lu KB\n",
DIV_ROUND_UP(reserved, SZ_1K));
+ seq_printf(m, "System : %7lu KB\n",
+ DIV_ROUND_UP(system, SZ_1K));
+ seq_printf(m, " .common : %7lu KB\n",
+ DIV_ROUND_UP(system - reusable, SZ_1K));
seq_printf(m, " .reusable : %7lu KB\n",
DIV_ROUND_UP(reusable, SZ_1K));
+ seq_printf(m, "Total : %7lu KB ( %5lu.%02lu MB )\n",
+ DIV_ROUND_UP(total, SZ_1K),
+ total >> 20, ((total % SZ_1M) * 100) >> 20);
return 0;
}

--
2.17.1

2022-03-25 18:42:59

by Jaewon Kim

[permalink] [raw]
Subject: [PATCH 2/8] memblock: detect hidden memory hole size

Bootloader knows the actual memory size, but bootloader may reserve some
memory for a specific purpose and pass the only remaining memory region
to kernel.

Even though kernel does not know what it is, we need to detect those
regions to sum up all reserved memory. Let me call it memory hole. To
expect the hole size, this patch assume two things. One is that each
physical memory has 1GB aligned size and address. And the hole is less
than 1GB. For the hole, let it be shown as unknown in memsize logic.

This is an example.
0x0bf000000-0x0c0000000 0x01000000 ( 16384 KB ) nomap unusable unknown

Signed-off-by: Jaewon Kim <[email protected]>
---
drivers/of/fdt.c | 2 ++
include/linux/memblock.h | 2 ++
mm/memblock.c | 45 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 49 insertions(+)

diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index ec2f60a78f8f..9721a3d7b7ae 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -1294,6 +1294,8 @@ void __init early_init_dt_scan_nodes(void)

/* Handle linux,usable-memory-range property */
early_init_dt_check_for_usable_mem_range();
+
+ memblock_memsize_detect_hole();
}

bool __init early_init_dt_scan(void *params)
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index 468b016e179b..201f8723dfd8 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -608,10 +608,12 @@ static inline void early_memtest(phys_addr_t start, phys_addr_t end)
extern void memblock_memsize_record(const char *name, phys_addr_t base,
phys_addr_t size, bool nomap,
bool reusable);
+extern void memblock_memsize_detect_hole(void);
#else
static inline void memblock_memsize_record(const char *name, phys_addr_t base,
phys_addr_t size, bool nomap,
bool reusable) { }
+static inline void memblock_memsize_detect_hole(void) { }
#endif

#endif /* _LINUX_MEMBLOCK_H */
diff --git a/mm/memblock.c b/mm/memblock.c
index 8492757f7192..8e032f44eb57 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -1970,6 +1970,51 @@ void __init_memblock memblock_memsize_record(const char *name, phys_addr_t base,
memblock_dbg("%s %pa..%pa nomap:%d reusable:%d\n",
__func__, &base, &end, nomap, reusable);
}
+
+/* This function will be called to by early_init_dt_scan_nodes */
+void __init memblock_memsize_detect_hole(void)
+{
+ phys_addr_t base, end;
+ phys_addr_t prev_end, hole_sz;
+ int idx;
+ struct memblock_region *rgn;
+ int memblock_cnt = (int)memblock.memory.cnt;
+
+ /* assume that the hole size is less than 1 GB */
+ for_each_memblock_type(idx, (&memblock.memory), rgn) {
+ prev_end = (idx == 0) ? round_down(rgn->base, SZ_1G) : end;
+ base = rgn->base;
+ end = rgn->base + rgn->size;
+
+ /* only for the last region, check a hole after the region */
+ if (idx + 1 == memblock_cnt) {
+ hole_sz = round_up(end, SZ_1G) - end;
+ if (hole_sz)
+ memblock_memsize_record(NULL, end, hole_sz,
+ true, false);
+ }
+
+ /* for each region, check a hole prior to the region */
+ hole_sz = base - prev_end;
+ if (!hole_sz)
+ continue;
+ if (hole_sz < SZ_1G) {
+ memblock_memsize_record(NULL, prev_end, hole_sz, true,
+ false);
+ } else {
+ phys_addr_t hole_sz1, hole_sz2;
+
+ hole_sz1 = round_up(prev_end, SZ_1G) - prev_end;
+ if (hole_sz1)
+ memblock_memsize_record(NULL, prev_end,
+ hole_sz1, true, false);
+ hole_sz2 = base % SZ_1G;
+ if (hole_sz2)
+ memblock_memsize_record(NULL, base - hole_sz2,
+ hole_sz2, true, false);
+ }
+ }
+}
#endif /* MEMBLOCK_MEMSIZE */

static void __init free_memmap(unsigned long start_pfn, unsigned long end_pfn)
--
2.17.1

2022-03-25 19:07:49

by Jaewon Kim

[permalink] [raw]
Subject: RE: [PATCH 0/8] memblock: introduce memsize showing reserved memory

>
>
>--------- Original Message ---------
>Sender : Mike Rapoport <[email protected]>
>Date : 2022-03-25 16:46 (GMT+9)
>Title : Re: [PATCH 0/8] memblock: introduce memsize showing reserved memory
>
>Hi,
>
>On Thu, Mar 24, 2022 at 04:01:50PM +0900, Jaewon Kim wrote:
>> Some of memory regions can be reserved for a specific purpose. They are
>> usually defined through reserved-memory in device tree. If only size
>> without address is specified in device tree, the address of the region
>> will be determined at boot time.
>>
>> We may find the address of the memory regions through booting log, but
>> it does not show all. And it could be hard to catch the very beginning
>> log. The memblock_dump_all shows all memblock status but it does not
>> show region name and its information is difficult to summarize.
>>
>> This patch introduce a debugfs node, memblock/memsize, to see reserved
>> memory easily.
>>
>> Here's an example
>>
>> $ cat debugfs/memblock/memsize
>> 0x0f9000000-0x0fb000000 0x02000000 ( 32768 KB ) map reusable linux,cma
>> 0x0b1900000-0x0b1b00000 0x00200000 ( 2048 KB ) nomap unusable test1
>> 0x0b0200000-0x0b0400000 0x00200000 ( 2048 KB ) map unusable test2
>> (snipped)
>>
>> Reserved : 746924 KB
>> .kernel : 137027 KB
>> .text : 28158 KB
>> .rwdata : 3238 KB
>> .rodata : 13468 KB
>> .bss : 12570 KB
>> .etc : 79593 KB
>> .unusable : 609897 KB
>> System : 3447380 KB
>> .common : 3152468 KB
>> .reusable : 294912 KB
>> Total : 4194304 KB ( 4096.00 MB )
>
>Most of this information information is already available at various
>places, like the existing memblock debugfs, /proc/iomem and DT sysfs.
>
>I don't see why we need yet another debugfs file to expose it.

Hi.
Thank you for your reply.

I don't think existing memblock debugfs or /proc/iomem shows information I want.
They don't show name and actually allocated address and size. And it does not
handle pages freed to buddy allocator after boot.

And which DT sysfs do you mean? If it is /proc/device-tree/reserved-memory, it
shows name and size, but it does not show address for only size defined regions.
It does not recognize the freed pages, either.

Especially I'd like to create a node showing all reserved memory status, their
total size is same as the physical memory size. This was very useful when I
compare reserved memory and kernel init time memory between different chipsets,
or between different sw release versions.

Thank you
Jaewon Kim

>
>> Jaewon Kim (8):
>> memblock: introduce memsize showing reserved memory
>> memblock: detect hidden memory hole size
>> memblock: handle overlapped reserved memory region
>> memblock: track memblock changed at early param
>> memblock: track kernel size on memsize
>> memblock: recognize late free by checking PageReserved
>> memblock: print memsize summary information
>> memblock: print kernel internal size
>>
>> drivers/of/fdt.c | 10 +
>> drivers/of/of_reserved_mem.c | 7 +-
>> include/linux/memblock.h | 21 ++
>> include/linux/mm.h | 3 +
>> init/main.c | 13 +-
>> kernel/dma/contiguous.c | 9 +-
>> mm/Kconfig | 7 +
>> mm/memblock.c | 434 ++++++++++++++++++++++++++++++++++-
>> mm/page_alloc.c | 15 +-
>> 9 files changed, 506 insertions(+), 13 deletions(-)
>>
>> --
>> 2.17.1
>>
>
>--
>Sincerely yours,
>Mike.
>

2022-03-25 19:11:24

by Jaewon Kim

[permalink] [raw]
Subject: [PATCH 4/8] memblock: track memblock changed at early param

In addition to reserved-memory in device tree, an option in cmdline may
result in memblock allocation. This patch tries to distinguish memblock
changes done at early param.

A region in memsize will be created with name as the param string. And
the region size will be updated during the param function.

Signed-off-by: Jaewon Kim <[email protected]>
---
include/linux/memblock.h | 4 ++
init/main.c | 13 ++++-
mm/memblock.c | 101 +++++++++++++++++++++++++++++++++++++--
3 files changed, 112 insertions(+), 6 deletions(-)

diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index 201f8723dfd8..4be4e0e6baf4 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -609,11 +609,15 @@ extern void memblock_memsize_record(const char *name, phys_addr_t base,
phys_addr_t size, bool nomap,
bool reusable);
extern void memblock_memsize_detect_hole(void);
+extern void memblock_memsize_set_name(const char *name);
+extern void memblock_memsize_unset_name(void);
#else
static inline void memblock_memsize_record(const char *name, phys_addr_t base,
phys_addr_t size, bool nomap,
bool reusable) { }
static inline void memblock_memsize_detect_hole(void) { }
+static inline void memblock_memsize_set_name(const char *name) { }
+static inline void memblock_memsize_unset_name(void) { }
#endif

#endif /* _LINUX_MEMBLOCK_H */
diff --git a/init/main.c b/init/main.c
index 560f45c27ffe..ce59521b5ae5 100644
--- a/init/main.c
+++ b/init/main.c
@@ -214,8 +214,15 @@ static bool __init obsolete_checksetup(char *line)
pr_warn("Parameter %s is obsolete, ignored\n",
p->str);
return true;
- } else if (p->setup_func(line + n))
- return true;
+ } else {
+ int ret;
+
+ memblock_memsize_set_name(p->str);
+ ret = p->setup_func(line + n);
+ memblock_memsize_unset_name();
+ if (ret)
+ return true;
+ }
}
p++;
} while (p < __setup_end);
@@ -736,8 +743,10 @@ static int __init do_early_param(char *param, char *val,
(strcmp(param, "console") == 0 &&
strcmp(p->str, "earlycon") == 0)
) {
+ memblock_memsize_set_name(p->str);
if (p->setup_func(val) != 0)
pr_warn("Malformed early option '%s'\n", param);
+ memblock_memsize_unset_name();
}
}
/* We accept everything at this stage. */
diff --git a/mm/memblock.c b/mm/memblock.c
index 9195a51bfa5d..4f21b596687e 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -169,6 +169,18 @@ static inline phys_addr_t memblock_cap_size(phys_addr_t base, phys_addr_t *size)
return *size = min(*size, PHYS_ADDR_MAX - base);
}

+#ifdef CONFIG_MEMBLOCK_MEMSIZE
+static void memblock_memsize_record_add(struct memblock_type *type,
+ phys_addr_t base, phys_addr_t size);
+static void memblock_memsize_record_remove(struct memblock_type *type,
+ phys_addr_t base, phys_addr_t size);
+#else
+static inline void memblock_memsize_record_add(struct memblock_type *type,
+ phys_addr_t base, phys_addr_t size) { }
+static inline void memblock_memsize_record_remove(struct memblock_type *type,
+ phys_addr_t base, phys_addr_t size) { }
+#endif /* CONFIG_MEMBLOCK_MEMSIZE */
+
/*
* Address comparison utilities
*/
@@ -578,6 +590,7 @@ static int __init_memblock memblock_add_range(struct memblock_type *type,
bool insert = false;
phys_addr_t obase = base;
phys_addr_t end = base + memblock_cap_size(base, &size);
+ phys_addr_t new_size = 0;
int idx, nr_new;
struct memblock_region *rgn;

@@ -592,7 +605,8 @@ static int __init_memblock memblock_add_range(struct memblock_type *type,
type->regions[0].flags = flags;
memblock_set_region_node(&type->regions[0], nid);
type->total_size = size;
- return 0;
+ new_size = size;
+ goto done;
}
repeat:
/*
@@ -621,10 +635,12 @@ static int __init_memblock memblock_add_range(struct memblock_type *type,
#endif
WARN_ON(flags != rgn->flags);
nr_new++;
- if (insert)
+ if (insert) {
memblock_insert_region(type, idx++, base,
rbase - base, nid,
flags);
+ new_size += rbase - base;
+ }
}
/* area below @rend is dealt with, forget about it */
base = min(rend, end);
@@ -633,9 +649,11 @@ static int __init_memblock memblock_add_range(struct memblock_type *type,
/* insert the remaining portion */
if (base < end) {
nr_new++;
- if (insert)
+ if (insert) {
memblock_insert_region(type, idx, base, end - base,
nid, flags);
+ new_size += end - base;
+ }
}

if (!nr_new)
@@ -653,8 +671,11 @@ static int __init_memblock memblock_add_range(struct memblock_type *type,
goto repeat;
} else {
memblock_merge_regions(type);
- return 0;
}
+done:
+ if (new_size == size)
+ memblock_memsize_record_add(type, obase, size);
+ return 0;
}

/**
@@ -790,6 +811,7 @@ static int __init_memblock memblock_remove_range(struct memblock_type *type,

for (i = end_rgn - 1; i >= start_rgn; i--)
memblock_remove_region(type, i);
+ memblock_memsize_record_remove(type, base, size);
return 0;
}

@@ -2091,6 +2113,77 @@ void __init memblock_memsize_detect_hole(void)
}
}
}
+
+/* assume that freeing region is NOT bigger than the previous region */
+static void __init_memblock memblock_memsize_free(phys_addr_t free_base,
+ phys_addr_t free_size)
+{
+ int i;
+ struct memsize_rgn_struct *rgn;
+ phys_addr_t free_end, end;
+
+ free_end = free_base + free_size - 1;
+ memblock_dbg("%s %pa..%pa\n",
+ __func__, &free_base, &free_end);
+
+ for (i = 0; i < memsize_rgn_count; i++) {
+ rgn = &memsize_rgn[i];
+
+ end = rgn->base + rgn->size;
+ if (free_base < rgn->base ||
+ free_base >= end)
+ continue;
+
+ free_end = free_base + free_size;
+ if (free_base == rgn->base) {
+ rgn->size -= free_size;
+ if (rgn->size != 0)
+ rgn->base += free_size;
+ } else if (free_end == end) {
+ rgn->size -= free_size;
+ } else {
+ memblock_memsize_record(rgn->name, free_end,
+ end - free_end, rgn->nomap, rgn->reusable);
+ rgn->size = free_base - rgn->base;
+ }
+ }
+}
+
+static const char *memblock_memsize_name;
+
+void __init memblock_memsize_set_name(const char *name)
+{
+ memblock_memsize_name = name;
+}
+
+void __init memblock_memsize_unset_name(void)
+{
+ memblock_memsize_name = NULL;
+}
+
+static void __init_memblock memblock_memsize_record_add(struct memblock_type *type,
+ phys_addr_t base, phys_addr_t size)
+{
+ if (memblock_memsize_name) {
+ if (type == &memblock.reserved)
+ memblock_memsize_record(memblock_memsize_name,
+ base, size, false, false);
+ else if (type == &memblock.memory)
+ memblock_memsize_free(base, size);
+ }
+}
+
+static void __init_memblock memblock_memsize_record_remove(struct memblock_type *type,
+ phys_addr_t base, phys_addr_t size)
+{
+ if (memblock_memsize_name) {
+ if (type == &memblock.reserved)
+ memblock_memsize_free(base, size);
+ else if (type == &memblock.memory)
+ memblock_memsize_record(memblock_memsize_name,
+ base, size, true, false);
+ }
+}
#endif /* MEMBLOCK_MEMSIZE */

static void __init free_memmap(unsigned long start_pfn, unsigned long end_pfn)
--
2.17.1

2022-03-25 19:52:24

by Jaewon Kim

[permalink] [raw]
Subject: [PATCH 5/8] memblock: track kernel size on memsize

Some memory regions are already being tracked by previous patches. But
there are many memory allocations from memblock and frees to memblock
during the boot time.

This patch tracks the memblock size used for the common kernel. To to
this, tracking memblock size is disabled for some memory handling logics
like early param, device tree, and default cma size.

For precise kernel size, this patch counts not actually freed size to
buddy at boot time, and does not count freed size from ramdisk and init
section.

Additionally this patch does one important thing. This patch blocks
memblock_add_range of memblock_remove_range not to update memsize if
free pages were already released to the buddy allocator.

This is an example. The kernel size is newly added by this patch.

.kernel : 135137 KB
.unusable : 788073 KB
.reusable : 294912 KB

Signed-off-by: Jaewon Kim <[email protected]>
---
drivers/of/fdt.c | 6 ++++++
include/linux/memblock.h | 6 ++++++
kernel/dma/contiguous.c | 7 ++++--
mm/memblock.c | 46 ++++++++++++++++++++++++++++++++++++++++
mm/page_alloc.c | 9 +++++++-
5 files changed, 71 insertions(+), 3 deletions(-)

diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 9721a3d7b7ae..8d38d1499d71 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -640,6 +640,8 @@ void __init early_init_fdt_scan_reserved_mem(void)
if (!initial_boot_params)
return;

+ memblock_memsize_disable_tracking();
+
/* Process header /memreserve/ fields */
for (n = 0; ; n++) {
fdt_get_mem_rsv(initial_boot_params, n, &base, &size);
@@ -652,6 +654,7 @@ void __init early_init_fdt_scan_reserved_mem(void)
fdt_scan_reserved_mem();
fdt_reserve_elfcorehdr();
fdt_init_reserved_mem();
+ memblock_memsize_enable_tracking();
}

/**
@@ -1289,12 +1292,15 @@ void __init early_init_dt_scan_nodes(void)
if (rc)
pr_warn("No chosen node found, continuing without\n");

+ memblock_memsize_disable_tracking();
+
/* Setup memory, calling early_init_dt_add_memory_arch */
early_init_dt_scan_memory();

/* Handle linux,usable-memory-range property */
early_init_dt_check_for_usable_mem_range();

+ memblock_memsize_enable_tracking();
memblock_memsize_detect_hole();
}

diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index 4be4e0e6baf4..6d59c6e68467 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -611,6 +611,9 @@ extern void memblock_memsize_record(const char *name, phys_addr_t base,
extern void memblock_memsize_detect_hole(void);
extern void memblock_memsize_set_name(const char *name);
extern void memblock_memsize_unset_name(void);
+extern void memblock_memsize_enable_tracking(void);
+extern void memblock_memsize_disable_tracking(void);
+extern void memblock_memsize_mod_kernel_size(long size);
#else
static inline void memblock_memsize_record(const char *name, phys_addr_t base,
phys_addr_t size, bool nomap,
@@ -618,6 +621,9 @@ static inline void memblock_memsize_record(const char *name, phys_addr_t base,
static inline void memblock_memsize_detect_hole(void) { }
static inline void memblock_memsize_set_name(const char *name) { }
static inline void memblock_memsize_unset_name(void) { }
+static inline void memblock_memsize_enable_tracking(void){ }
+static inline void memblock_memsize_disable_tracking(void){ }
+static inline void memblock_memsize_mod_kernel_size(long size) { }
#endif

#endif /* _LINUX_MEMBLOCK_H */
diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c
index 7415c1135afa..2a3ecf6a6b22 100644
--- a/kernel/dma/contiguous.c
+++ b/kernel/dma/contiguous.c
@@ -230,10 +230,11 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
{
int ret;

+ memblock_memsize_disable_tracking();
ret = cma_declare_contiguous(base, size, limit, 0, 0, fixed,
"reserved", res_cma);
if (ret)
- return ret;
+ goto out;

/* Architecture specific contiguous memory fixup. */
dma_contiguous_early_fixup(cma_get_base(*res_cma),
@@ -241,7 +242,9 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,

memblock_memsize_record("dma_cma", cma_get_base(*res_cma),
cma_get_size(*res_cma), false, true);
- return 0;
+out:
+ memblock_memsize_enable_tracking();
+ return ret;
}

/**
diff --git a/mm/memblock.c b/mm/memblock.c
index 4f21b596687e..aee22dbc2500 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -1965,6 +1965,23 @@ struct memsize_rgn_struct {
#define MAX_MEMSIZE_RGN 64
static struct memsize_rgn_struct memsize_rgn[MAX_MEMSIZE_RGN] __initdata_memblock;
static int memsize_rgn_count __initdata_memblock;
+static long kernel_init_size;
+static bool do_memsize __initdata_memblock = true;
+
+void __init memblock_memsize_enable_tracking(void)
+{
+ do_memsize = true;
+}
+
+void __init memblock_memsize_disable_tracking(void)
+{
+ do_memsize = false;
+}
+
+void memblock_memsize_mod_kernel_size(long size)
+{
+ kernel_init_size += size;
+}

static inline struct memsize_rgn_struct * __init_memblock memsize_get_new_rgn(void)
{
@@ -2170,6 +2187,12 @@ static void __init_memblock memblock_memsize_record_add(struct memblock_type *ty
base, size, false, false);
else if (type == &memblock.memory)
memblock_memsize_free(base, size);
+ } else if (do_memsize) {
+ if (type == &memblock.reserved) {
+ memblock_dbg("%s: kernel %lu %+ld\n", __func__,
+ kernel_init_size, (unsigned long)size);
+ kernel_init_size += size;
+ }
}
}

@@ -2182,6 +2205,12 @@ static void __init_memblock memblock_memsize_record_remove(struct memblock_type
else if (type == &memblock.memory)
memblock_memsize_record(memblock_memsize_name,
base, size, true, false);
+ } else if (do_memsize) {
+ if (type == &memblock.reserved) {
+ memblock_dbg("%s: kernel %lu %+ld\n", __func__,
+ kernel_init_size, (unsigned long)size);
+ kernel_init_size -= size;
+ }
}
}
#endif /* MEMBLOCK_MEMSIZE */
@@ -2289,6 +2318,19 @@ static unsigned long __init __free_memory_core(phys_addr_t start,
unsigned long end_pfn = min_t(unsigned long,
PFN_DOWN(end), max_low_pfn);

+#ifdef CONFIG_MEMBLOCK_MEMSIZE
+ unsigned long start_align_up = PFN_ALIGN(start);
+ unsigned long end_align_down = PFN_PHYS(end_pfn);
+
+ if (start_pfn >= end_pfn) {
+ memblock_memsize_mod_kernel_size(end - start);
+ } else {
+ if (start_align_up > start)
+ memblock_memsize_mod_kernel_size(start_align_up - start);
+ if (end_pfn != max_low_pfn && end_align_down < end)
+ memblock_memsize_mod_kernel_size(end - end_align_down);
+ }
+#endif
if (start_pfn >= end_pfn)
return 0;

@@ -2374,6 +2416,8 @@ void __init memblock_free_all(void)

pages = free_low_memory_core_early();
totalram_pages_add(pages);
+
+ memblock_memsize_disable_tracking();
}

#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_ARCH_KEEP_MEMBLOCK)
@@ -2441,6 +2485,8 @@ static int memblock_memsize_show(struct seq_file *m, void *private)
}

seq_printf(m, "\n");
+ seq_printf(m, " .kernel : %7lu KB\n",
+ DIV_ROUND_UP(kernel_init_size, SZ_1K));
seq_printf(m, " .unusable : %7lu KB\n",
DIV_ROUND_UP(reserved, SZ_1K));
seq_printf(m, " .reusable : %7lu KB\n",
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 6e0b4596cde9..bbbe314850b0 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -8230,8 +8230,15 @@ unsigned long free_reserved_area(void *start, void *end, int poison, const char
free_reserved_page(page);
}

- if (pages && s)
+ if (pages && s) {
pr_info("Freeing %s memory: %ldK\n", s, K(pages));
+ if (!strcmp(s, "initrd") || !strcmp(s, "unused kernel")) {
+ long size;
+
+ size = -1 * (long)(pages << PAGE_SHIFT);
+ memblock_memsize_mod_kernel_size(size);
+ }
+ }

return pages;
}
--
2.17.1

2022-03-27 19:31:24

by Mike Rapoport

[permalink] [raw]
Subject: Re: [PATCH 0/8] memblock: introduce memsize showing reserved memory

Hi,

On Fri, Mar 25, 2022 at 05:38:46PM +0900, Jaewon Kim wrote:

> >--------- Original Message ---------
> >Sender : Mike Rapoport <[email protected]>
> >Date : 2022-03-25 16:46 (GMT+9)
> >Title : Re: [PATCH 0/8] memblock: introduce memsize showing reserved memory
> >
> >Hi,
> >
> >On Thu, Mar 24, 2022 at 04:01:50PM +0900, Jaewon Kim wrote:
> >> Some of memory regions can be reserved for a specific purpose. They are
> >> usually defined through reserved-memory in device tree. If only size
> >> without address is specified in device tree, the address of the region
> >> will be determined at boot time.
> >>
> >> We may find the address of the memory regions through booting log, but
> >> it does not show all. And it could be hard to catch the very beginning
> >> log. The memblock_dump_all shows all memblock status but it does not
> >> show region name and its information is difficult to summarize.
> >>
> >> This patch introduce a debugfs node, memblock/memsize, to see reserved
> >> memory easily.
> >>
> >> Here's an example
> >>
> >> $ cat debugfs/memblock/memsize
> >> 0x0f9000000-0x0fb000000 0x02000000 ( 32768 KB ) map reusable linux,cma
> >> 0x0b1900000-0x0b1b00000 0x00200000 ( 2048 KB ) nomap unusable test1
> >> 0x0b0200000-0x0b0400000 0x00200000 ( 2048 KB ) map unusable test2
> >> (snipped)
> >>
> >> Reserved : 746924 KB
> >> .kernel : 137027 KB
> >> .text : 28158 KB
> >> .rwdata : 3238 KB
> >> .rodata : 13468 KB
> >> .bss : 12570 KB
> >> .etc : 79593 KB
> >> .unusable : 609897 KB
> >> System : 3447380 KB
> >> .common : 3152468 KB
> >> .reusable : 294912 KB
> >> Total : 4194304 KB ( 4096.00 MB )
> >
> >Most of this information information is already available at various
> >places, like the existing memblock debugfs, /proc/iomem and DT sysfs.
> >
> >I don't see why we need yet another debugfs file to expose it.
>
> Hi.
> Thank you for your reply.
>
> Especially I'd like to create a node showing all reserved memory status, their
> total size is same as the physical memory size. This was very useful when I
> compare reserved memory and kernel init time memory between different chipsets,
> or between different sw release versions.

I'm still not following. The reserved region sizes are available in the
existing memblock debugfs.
Why the names are important? What is the value of having names for *some*
of the reserved regions?

> Thank you
> Jaewon Kim

--
Sincerely yours,
Mike.

2022-03-28 11:44:35

by Mike Rapoport

[permalink] [raw]
Subject: Re: [PATCH 0/8] memblock: introduce memsize showing reserved memory

On Sun, Mar 27, 2022 at 10:53:47PM +0900, Jaewon Kim wrote:
> >
> >--------- Original Message ---------
> >Sender : Mike Rapoport <[email protected]>
> >Date : 2022-03-27 16:40 (GMT+9)
> >Title : Re: [PATCH 0/8] memblock: introduce memsize showing reserved memory
> >
> >
> >I'm still not following. The reserved region sizes are available in the
> >existing memblock debugfs.
> >Why the names are important? What is the value of having names for *some*
> >of the reserved regions?
>
> Hi
>
> There are many memory regions in memblock debugfs memory/reserved, and some might
> be splited or merged with other region. Among regions in debugfs, we can't find
> the one we defined in device tree. Especially it is difficult to find the region we
> described size only without start address.
>
> On mobile environment, memory is used by not only CPU but also GPU, Camera, Secure
> world, Audio, ETC. To support them, there are many reserved regions described in
> device tree. So the name is quite important to recognize a region. And with thename
> we can compare reserved memory map with other map.

You still didn't describe your use case. What is the problem your patches
are trying to solve? Why is it important to know what is the use of particular
reserved region?

You propose complex mechanism that seems to fit very particular scenario
and sprinkle some calls to this mechanism at random places because you need
to "compare reserved memory map with other map".

Does not sound convincing to me, sorry.

> Thank you
> Jaewon Kim

--
Sincerely yours,
Mike.

2022-03-28 22:24:52

by Jaewon Kim

[permalink] [raw]
Subject: RE: [PATCH 0/8] memblock: introduce memsize showing reserved memory

>
>
>--------- Original Message ---------
>Sender : Mike Rapoport <[email protected]>
>Date : 2022-03-27 16:40 (GMT+9)
>Title : Re: [PATCH 0/8] memblock: introduce memsize showing reserved memory
>
>Hi,
>
>On Fri, Mar 25, 2022 at 05:38:46PM +0900, Jaewon Kim wrote:
>
>> >--------- Original Message ---------
>> >Sender : Mike Rapoport <[email protected]>
>> >Date : 2022-03-25 16:46 (GMT+9)
>> >Title : Re: [PATCH 0/8] memblock: introduce memsize showing reserved memory
>> >
>> >Hi,
>> >
>> >On Thu, Mar 24, 2022 at 04:01:50PM +0900, Jaewon Kim wrote:
>> >> Some of memory regions can be reserved for a specific purpose. They are
>> >> usually defined through reserved-memory in device tree. If only size
>> >> without address is specified in device tree, the address of the region
>> >> will be determined at boot time.
>> >>
>> >> We may find the address of the memory regions through booting log, but
>> >> it does not show all. And it could be hard to catch the very beginning
>> >> log. The memblock_dump_all shows all memblock status but it does not
>> >> show region name and its information is difficult to summarize.
>> >>
>> >> This patch introduce a debugfs node, memblock/memsize, to see reserved
>> >> memory easily.
>> >>
>> >> Here's an example
>> >>
>> >> $ cat debugfs/memblock/memsize
>> >> 0x0f9000000-0x0fb000000 0x02000000 ( 32768 KB ) map reusable linux,cma
>> >> 0x0b1900000-0x0b1b00000 0x00200000 ( 2048 KB ) nomap unusable test1
>> >> 0x0b0200000-0x0b0400000 0x00200000 ( 2048 KB ) map unusable test2
>> >> (snipped)
>> >>
>> >> Reserved : 746924 KB
>> >> .kernel : 137027 KB
>> >> .text : 28158 KB
>> >> .rwdata : 3238 KB
>> >> .rodata : 13468 KB
>> >> .bss : 12570 KB
>> >> .etc : 79593 KB
>> >> .unusable : 609897 KB
>> >> System : 3447380 KB
>> >> .common : 3152468 KB
>> >> .reusable : 294912 KB
>> >> Total : 4194304 KB ( 4096.00 MB )
>> >
>> >Most of this information information is already available at various
>> >places, like the existing memblock debugfs, /proc/iomem and DT sysfs.
>> >
>> >I don't see why we need yet another debugfs file to expose it.
>>
>> Hi.
>> Thank you for your reply.
>>
>> I don't think existing memblock debugfs or /proc/iomem shows information I want.
>> They don't show name and actually allocated address and size. And it does not
>> handle pages freed to buddy allocator after boot.
>>
>> And which DT sysfs do you mean? If it is /proc/device-tree/reserved-memory, it
>> shows name and size, but it does not show address for only size defined regions.
>> It does not recognize the freed pages, either.
>>
>> Especially I'd like to create a node showing all reserved memory status, their
>> total size is same as the physical memory size. This was very useful when I
>> compare reserved memory and kernel init time memory between different chipsets,
>> or between different sw release versions.
>
>I'm still not following. The reserved region sizes are available in the
>existing memblock debugfs.
>Why the names are important? What is the value of having names for *some*
>of the reserved regions?

Hi

There are many memory regions in memblock debugfs memory/reserved, and some might
be splited or merged with other region. Among regions in debugfs, we can't find
the one we defined in device tree. Especially it is difficult to find the region we
described size only without start address.

On mobile environment, memory is used by not only CPU but also GPU, Camera, Secure
world, Audio, ETC. To support them, there are many reserved regions described in
device tree. So the name is quite important to recognize a region. And with thename
we can compare reserved memory map with other map.

Additionally as I said, we need one simple knob to look overall reservecd memory
status.

Thank you
Jaewon Kim

>
>> Thank you
>> Jaewon Kim
>
>--
>Sincerely yours,
>Mike.
>

2022-03-29 08:00:54

by Jaewon Kim

[permalink] [raw]
Subject: RE: [PATCH 0/8] memblock: introduce memsize showing reserved memory

>> >
>> >--------- Original Message ---------
>> >Sender : Mike Rapoport <[email protected]>
>> >Date : 2022-03-27 16:40 (GMT+9)
>> >Title : Re: [PATCH 0/8] memblock: introduce memsize showing reserved memory
>> >
>> >
>> >I'm still not following. The reserved region sizes are available in the
>> >existing memblock debugfs.
>> >Why the names are important? What is the value of having names for *some*
>> >of the reserved regions?
>>
>> Hi
>>
>> There are many memory regions in memblock debugfs memory/reserved, and some might
>> be splited or merged with other region. Among regions in debugfs, we can't find
>> the one we defined in device tree. Especially it is difficult to find the region we
>> described size only without start address.
>>
>> On mobile environment, memory is used by not only CPU but also GPU, Camera, Secure
>> world, Audio, ETC. To support them, there are many reserved regions described in
>> device tree. So the name is quite important to recognize a region. And with thename
>> we can compare reserved memory map with other map.
>
>You still didn't describe your use case. What is the problem your patches
>are trying to solve? Why is it important to know what is the use of particular
>reserved region?
>
>You propose complex mechanism that seems to fit very particular scenario
>and sprinkle some calls to this mechanism at random places because you need
>to "compare reserved memory map with other map".
>
>Does not sound convincing to me, sorry.

As I said serveral times, I want a simple knob showing all reserved memory status.
The current debugfs, device tree do not show all those information I want. I think you also know that.
i.e. late freed pages, splited or merged memblock, address defined at boot time, kernel size, ETC.

Anyway I think I touched too many points to do this. Let me drop this.

>
>> Thank you
>> Jaewon Kim
>
>--
>Sincerely yours,
>Mike.
>

2022-03-30 23:59:49

by Mike Rapoport

[permalink] [raw]
Subject: Re: [PATCH 0/8] memblock: introduce memsize showing reserved memory

Hi,

On Tue, Mar 29, 2022 at 11:46:20AM +0900, Jaewon Kim wrote:
> >> >
> >> >I'm still not following. The reserved region sizes are available in the
> >> >existing memblock debugfs.
> >> >Why the names are important? What is the value of having names for *some*
> >> >of the reserved regions?
> >>
> >> Hi
> >>
> >> There are many memory regions in memblock debugfs memory/reserved, and some might
> >> be splited or merged with other region. Among regions in debugfs, we can't find
> >> the one we defined in device tree. Especially it is difficult to find the region we
> >> described size only without start address.
> >>
> >> On mobile environment, memory is used by not only CPU but also GPU, Camera, Secure
> >> world, Audio, ETC. To support them, there are many reserved regions described in
> >> device tree. So the name is quite important to recognize a region. And with thename
> >> we can compare reserved memory map with other map.
> >
> >You still didn't describe your use case. What is the problem your patches
> >are trying to solve? Why is it important to know what is the use of particular
> >reserved region?
> >
> >You propose complex mechanism that seems to fit very particular scenario
> >and sprinkle some calls to this mechanism at random places because you need
> >to "compare reserved memory map with other map".
> >
> >Does not sound convincing to me, sorry.
>
> As I said serveral times, I want a simple knob showing all reserved
> memory status. The current debugfs, device tree do not show all those
> information I want. I think you also know that. i.e. late freed pages,
> splited or merged memblock, address defined at boot time, kernel size,
> ETC.

I know that there is not much information about reserved memory exposed and
I understand *what* are you trying to achieve. But you never provided
details about *why* you want this information exposed.

I don't mind providing more visibility into reserved memory attributes in
general, but I'd like to see something way more simple and localized.

--
Sincerely yours,
Mike.

2022-03-31 01:56:08

by Jaewon Kim

[permalink] [raw]
Subject: RE: [PATCH 0/8] memblock: introduce memsize showing reserved memory

>Hi,
>
>On Tue, Mar 29, 2022 at 11:46:20AM +0900, Jaewon Kim wrote:
>> >> >
>> >> >I'm still not following. The reserved region sizes are available in the
>> >> >existing memblock debugfs.
>> >> >Why the names are important? What is the value of having names for *some*
>> >> >of the reserved regions?
>> >>
>> >> Hi
>> >>
>> >> There are many memory regions in memblock debugfs memory/reserved, and some might
>> >> be splited or merged with other region. Among regions in debugfs, we can't find
>> >> the one we defined in device tree. Especially it is difficult to find the region we
>> >> described size only without start address.
>> >>
>> >> On mobile environment, memory is used by not only CPU but also GPU, Camera, Secure
>> >> world, Audio, ETC. To support them, there are many reserved regions described in
>> >> device tree. So the name is quite important to recognize a region. And with thename
>> >> we can compare reserved memory map with other map.
>> >
>> >You still didn't describe your use case. What is the problem your patches
>> >are trying to solve? Why is it important to know what is the use of particular
>> >reserved region?
>> >
>> >You propose complex mechanism that seems to fit very particular scenario
>> >and sprinkle some calls to this mechanism at random places because you need
>> >to "compare reserved memory map with other map".
>> >
>> >Does not sound convincing to me, sorry.
>>
>> As I said serveral times, I want a simple knob showing all reserved
>> memory status. The current debugfs, device tree do not show all those
>> information I want. I think you also know that. i.e. late freed pages,
>> splited or merged memblock, address defined at boot time, kernel size,
>> ETC.
>
>I know that there is not much information about reserved memory exposed and
>I understand *what* are you trying to achieve. But you never provided
>details about *why* you want this information exposed.
>
>I don't mind providing more visibility into reserved memory attributes in
>general, but I'd like to see something way more simple and localized.
>

I think the "what" is same as "why".
I want to look at all reservced memory status simply in a knob.

I also want to make in more simple and localized way, but there seems be
several ways to change reserved memory such as cmdline way, freeing after
boot, etc. I wanted to cover all those things.

That's OK. I hope someone later to try this again to show all the info.

>--
>Sincerely yours,
>Mike.