[PATCH] symbols: use non-debug BFD to retrieve .rodata
by Jiri Slaby
When running crash on openSUSE, get_linux_banner_from_vmlinux() returns
success but fill the target buffer with all zero bytes (`\0`).
This happens because `st->bfd` is initially opened for the main binary
(`vmlinux`), but is later overwritten with the debuginfo file
(`vmlinux.debug`) in `check_gnu_debuglink()`. In separate debug files,
`.rodata` has no content, so is marked only as `ALLOC` without
`SEC_HAS_CONTENTS`.
When `bfd_get_section_contents()` is called on a section without
`SEC_HAS_CONTENTS`, BFD clears the buffer to zeros and returns TRUE. As
a result, `get_linux_banner_from_vmlinux()` thinks it successfully read
the banner, while it actually received zeroed bytes.
Fix this by caching the original main executable's BFD (into
`st->bfd_orig`) before `st->bfd` gets swapped for the debuginfo file.
`get_linux_banner_from_vmlinux()` will then fall back to `st->bfd_orig`
if present, ensuring `.rodata` contents are read from the binary that
actually contains the raw section data.
Fixes #232.
Signed-off-by: Jiri Slaby <jirislaby(a)gmail.com>
Cc: Dave Young <yangrr.2009(a)tsinghua.org.cn>
Cc: <ltao(a)redhat.com>
Cc: <mpilaniy(a)redhat.com>
---
defs.h | 1 +
kernel.c | 5 +++--
symbols.c | 1 +
3 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/defs.h b/defs.h
index e3027e2b9141..e82af5bd5ed0 100644
--- a/defs.h
+++ b/defs.h
@@ -2920,6 +2920,7 @@ struct symbol_table_data {
#ifdef GDB_5_3
struct _bfd *bfd;
#else
+ struct bfd *bfd_orig;
struct bfd *bfd;
#endif
struct sec *sections;
diff --git a/kernel.c b/kernel.c
index e53038d5d8db..521cdf5664ef 100644
--- a/kernel.c
+++ b/kernel.c
@@ -12145,6 +12145,7 @@ check_vmcoreinfo(void)
static
int get_linux_banner_from_vmlinux(char *buf, size_t size)
{
+ struct bfd *bfd = st->bfd_orig ? : st->bfd;
struct bfd_section *sect;
long offset;
ulong start_rodata;
@@ -12156,7 +12157,7 @@ int get_linux_banner_from_vmlinux(char *buf, size_t size)
else
return FALSE;
- sect = bfd_get_section_by_name(st->bfd, ".rodata");
+ sect = bfd_get_section_by_name(bfd, ".rodata");
if (!sect)
return FALSE;
@@ -12168,7 +12169,7 @@ int get_linux_banner_from_vmlinux(char *buf, size_t size)
*/
offset = symbol_value("linux_banner") - start_rodata;
- if (!bfd_get_section_contents(st->bfd,
+ if (!bfd_get_section_contents(bfd,
sect,
buf,
offset,
diff --git a/symbols.c b/symbols.c
index a7ccdb101033..4b5585d62dba 100644
--- a/symbols.c
+++ b/symbols.c
@@ -444,6 +444,7 @@ check_gnu_debuglink(bfd *bfd)
return FALSE;
reset_bfd:
+ st->bfd_orig = st->bfd;
if ((st->bfd = bfd_openr(pc->debuginfo_file, NULL)) == NULL)
error(FATAL, "cannot open object file: %s\n",
--
2.55.0
2 months
[PATCH V2] Refactor kernel version checking code
by Ruirui Yang
In case linux banner can not be found in vmlinux for some reason.
The fallback checking of "Linux version" failed for kernel 7.x with
below error msg:
WARNING: kernel version inconsistency between vmlinux and dumpfile
crash: incompatible arguments: vmlinux is not SMP -- vmcore is SMP
Jiri's case is OpenSUSE uses separate vmlinux.debug file, details see
https://github.com/crash-utility/crash/issues/232
But update the kernel version number in kernel sanity checking code
does workaround the issue. Let's fix this separately.
A few improvements to the sanity checking including:
- Replace hardcoded version checks (2.x through 6.x) with a unified
kernel_version_str_sanity_check() function
- Extend support to Linux 7.x kernels
- Add proper bounds checking and null pointer validation
- Ensure minor version number is numeric for stricter validation
- Reduce code duplication in verify_namelist() and debug_kernel_version()
Reported-by: Jiri Slaby <jirislaby(a)gmail.com>
Signed-off-by: Dave Young <yangrr.2009(a)tsinghua.org.cn>
---
[V1->V2]: refactore the code; address comments from Mukesh
kernel.c | 39 +++++++++++++++++++++++++++++----------
1 file changed, 29 insertions(+), 10 deletions(-)
Index: crash/kernel.c
===================================================================
--- crash.orig/kernel.c 2026-08-14 11:21:39.972971968 +0800
+++ crash/kernel.c 2026-08-14 11:21:42.371976057 +0800
@@ -29,6 +29,9 @@
#endif
#include "bfd.h"
+#define KERNEL_VERSION_MIN '2'
+#define KERNEL_VERSION_MAX '7' /* latest linux mainline kernel major number */
+
static void do_module_cmd(ulong, char *, ulong, char *, char *);
static void show_module_taint(void);
static char *find_module_objfile(char *, char *, char *);
@@ -104,6 +107,30 @@
static int is_pvops_xen(void);
static int get_linux_banner_from_vmlinux(char *, size_t);
+static bool kernel_version_str_sanity_check(char *buf)
+{
+ int n;
+ char *p;
+
+ if (!buf)
+ return FALSE;
+
+ p = strstr(buf, "Linux version ");
+ if (!p)
+ return FALSE;
+
+ n = strlen(p);
+
+ if (n < 17) /* "Linux version " (14) + "x.y" (3) = 17 */
+ return FALSE;
+
+ if (p[14] >= KERNEL_VERSION_MIN && p[14] <= KERNEL_VERSION_MAX
+ && p[15] == '.' && p[16] >= '0' && p[16] <= '9')
+ return TRUE;
+
+ return FALSE;
+}
+
/*
* popuplate the global kernel table (kt) with kernel version
* information parsed from UTSNAME/OSRELEASE string
@@ -1396,11 +1423,7 @@
found = FALSE;
sprintf(buffer3, "(unknown)");
while (fgets(buffer, (BUFSIZE/2)-1, pipe)) {
- if (!strstr(buffer, "Linux version 2.") &&
- !strstr(buffer, "Linux version 3.") &&
- !strstr(buffer, "Linux version 4.") &&
- !strstr(buffer, "Linux version 5.") &&
- !strstr(buffer, "Linux version 6."))
+ if (!kernel_version_str_sanity_check(buffer))
continue;
if (strstr(buffer, kt->proc_version)) {
@@ -5987,11 +6010,7 @@
argc = 0;
while (fgets(buf, BUFSIZE-1, pipe)) {
- if (!strstr(buf, "Linux version 2.") &&
- !strstr(buf, "Linux version 3.") &&
- !strstr(buf, "Linux version 4.") &&
- !strstr(buf, "Linux version 5.") &&
- !strstr(buf, "Linux version 6."))
+ if (!kernel_version_str_sanity_check(buf))
continue;
argc = parse_line(buf, arglist);
2 months
[PATCH] Fix compound_head() and "bt -F" option on Linux 7.1 and later
by HAGIO KAZUHITO(萩尾 一仁)
From: Kazuhito Hagio <k-hagio-ab(a)nec.com>
Kernel commit d50569612c29 ("mm: rename the 'compound_head' field in the
'struct page' to 'compound_info'") and related patches [1] changed the
field name and its value.
Without the patch, crash prints the following warning during startup,
WARNING: SLUB: cannot determine how compound pages are linked
and "bt -F" option fails with the following error.
crash> bt -F
bt: invalid structure member offset: page_first_page
FILE: memory.c LINE: 20238 FUNCTION: compound_head()
[1] https://lore.kernel.org/all/20260227194302.274384-1-kas@kernel.org/
Signed-off-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
---
defs.h | 1 +
memory.c | 44 ++++++++++++++++++++++++++++++++++++--------
symbols.c | 1 +
3 files changed, 38 insertions(+), 8 deletions(-)
diff --git a/defs.h b/defs.h
index e3027e2b9141..88b7bbeb2372 100644
--- a/defs.h
+++ b/defs.h
@@ -2295,6 +2295,7 @@ struct offset_table { /* stash of commonly-used offsets */
long page_compound_order;
long folio__folio_order;
long folio__flags_1;
+ long page_compound_info;
};
struct size_table { /* stash of commonly-used sizes */
diff --git a/memory.c b/memory.c
index 3f3aa274ab5a..7102e951f1d5 100644
--- a/memory.c
+++ b/memory.c
@@ -414,6 +414,7 @@ mem_init(void)
#define FOLIO_ORDER_V2 2
#define FOLIO_ORDER_V3 3
static int folio_order_version;
+static int compound_info_has_mask = FALSE;
/*
* Stash a few popular offsets and some basic kernel virtual memory
@@ -547,6 +548,7 @@ vm_init(void)
MEMBER_OFFSET_INIT(page_compound_head, "page", "compound_head");
if (INVALID_MEMBER(page_compound_head))
ANON_MEMBER_OFFSET_INIT(page_compound_head, "page", "compound_head");
+ MEMBER_OFFSET_INIT(page_compound_info, "page", "compound_info");
MEMBER_OFFSET_INIT(page_private, "page", "private");
MEMBER_OFFSET_INIT(page_freelist, "page", "freelist");
MEMBER_OFFSET_INIT(page_page_type, "page", "page_type");
@@ -1352,6 +1354,17 @@ vm_init(void)
} else if (CRASHDEBUG(1))
error(NOTE, "page_hash_table does not exist in this kernel\n");
+ /*
+ * on Linux 7.1 and later, zone.vmemmap_tails is defined only when
+ * CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP is enabled.
+ */
+#define is_power_of_2(n) (n - 1 < (n ^ (n - 1)))
+ if (VALID_MEMBER(page_compound_info) &&
+ is_power_of_2(SIZE(page)) && MEMBER_EXISTS("zone", "vmemmap_tails"))
+ compound_info_has_mask = TRUE;
+ if (CRASHDEBUG(1))
+ error(NOTE, "compound_info_has_mask = %d\n", compound_info_has_mask);
+
kmem_cache_init();
page_flags_init();
@@ -5642,10 +5655,11 @@ PG_slab_flag_init(void)
}
}
- if (VALID_MEMBER(page_compound_head)) {
+ if (VALID_MEMBER(page_compound_head) || VALID_MEMBER(page_compound_info)) {
if (CRASHDEBUG(2))
fprintf(fp,
- "PG_head_tail_mask: (UNUSED): page.compound_head exists!\n");
+ "PG_head_tail_mask: (UNUSED): page.compound_head or "
+ "page.compound_info exists!\n");
} else if (vt->flags & KMALLOC_SLUB) {
/*
* PG_slab and the following are hardwired for
@@ -9858,7 +9872,8 @@ vaddr_to_kmem_cache(ulong vaddr, char *buf, int verbose)
&page_flags, sizeof(ulong), "page.flags",
FAULT_ON_ERROR);
if (!page_slab(page, page_flags)) {
- if (((vt->flags & KMALLOC_SLUB) || VALID_MEMBER(page_compound_head)) ||
+ if (((vt->flags & KMALLOC_SLUB) || VALID_MEMBER(page_compound_head) ||
+ VALID_MEMBER(page_compound_info)) ||
((vt->flags & KMALLOC_COMMON) &&
VALID_MEMBER(page_slab) && VALID_MEMBER(page_first_page))) {
readmem(compound_head(page)+OFFSET(page_flags), KVADDR,
@@ -9873,7 +9888,8 @@ vaddr_to_kmem_cache(ulong vaddr, char *buf, int verbose)
if ((vt->flags & KMALLOC_SLUB) ||
((vt->flags & KMALLOC_COMMON) && VALID_MEMBER(page_slab) &&
- (VALID_MEMBER(page_compound_head) || VALID_MEMBER(page_first_page)))) {
+ (VALID_MEMBER(page_compound_head) || VALID_MEMBER(page_compound_info) ||
+ VALID_MEMBER(page_first_page)))) {
readmem(compound_head(page)+OFFSET(page_slab),
KVADDR, &cache, sizeof(void *),
"page.slab", FAULT_ON_ERROR);
@@ -9904,7 +9920,8 @@ is_slab_overload_page(ulong vaddr, ulong *page_head, char *buf)
if ((vt->flags & SLAB_OVERLOAD_PAGE) &&
is_page_ptr(vaddr, NULL) && VALID_MEMBER(page_slab) &&
- (VALID_MEMBER(page_compound_head) || VALID_MEMBER(page_first_page))) {
+ (VALID_MEMBER(page_compound_head) || VALID_MEMBER(page_compound_info) ||
+ VALID_MEMBER(page_first_page))) {
readmem(compound_head(vaddr)+OFFSET(page_slab),
KVADDR, &cache, sizeof(void *),
"page.slab", FAULT_ON_ERROR);
@@ -9944,7 +9961,8 @@ vaddr_to_slab(ulong vaddr)
slab = 0;
- if ((vt->flags & KMALLOC_SLUB) || VALID_MEMBER(page_compound_head))
+ if ((vt->flags & KMALLOC_SLUB) || VALID_MEMBER(page_compound_head) ||
+ VALID_MEMBER(page_compound_info))
slab = compound_head(page);
else if (vt->flags & SLAB_OVERLOAD_PAGE)
slab = compound_head(page);
@@ -20222,11 +20240,21 @@ get_kmem_cache_child_list(ulong **cache_buf, ulong root)
static ulong
compound_head(ulong page)
{
- ulong flags, first_page, compound_head;
+ ulong flags, first_page, compound_head, info, mask;
first_page = page;
- if (VALID_MEMBER(page_compound_head)) {
+ if (VALID_MEMBER(page_compound_info)) {
+ if (readmem(page + OFFSET(page_compound_info), KVADDR, &info,
+ sizeof(ulong), "page.compound_info", RETURN_ON_ERROR)) {
+ if (compound_info_has_mask) {
+ mask = (info & 1) - 1;
+ mask |= info;
+ first_page = page & mask;
+ } else if (info & 1)
+ first_page = info - 1;
+ }
+ } else if (VALID_MEMBER(page_compound_head)) {
if (readmem(page+OFFSET(page_compound_head), KVADDR, &compound_head,
sizeof(ulong), "page.compound_head", RETURN_ON_ERROR)) {
if (compound_head & 1)
diff --git a/symbols.c b/symbols.c
index 03511c8cbe8c..2071bdf77819 100644
--- a/symbols.c
+++ b/symbols.c
@@ -10504,6 +10504,7 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(page_active));
fprintf(fp, " page_compound_head: %ld\n",
OFFSET(page_compound_head));
+ fprintf(fp, " page_compound_info: %ld\n", OFFSET(page_compound_info));
fprintf(fp, " page_private: %ld\n", OFFSET(page_private));
fprintf(fp, " page_page_type: %ld\n",
OFFSET(page_page_type));
--
2.31.1
2 months
[PATCH] Add linux version 7.x in verify_namelist
by Dave Young
In case linux banner can not be found in vmlinux for some reason.
The fallback chcking of "Linux version" failed for kernel 7.x with
below error msg:
WARNING: kernel version inconsistency between vmlinux and dumpfile
crash: incompatible arguments: vmlinux is not SMP -- vmcore is SMP
Not sure how to reproduce, tested by forcing get_linux_banner_from_vmlinux to return false.
Add "Linux version 7" to fix it.
Fixes: https://github.com/crash-utility/crash/issues/232
Reported-by: Jiri Slaby <jirislaby(a)gmail.com>
Signed-off-by: Dave Young <yangrr.2009(a)tsinghua.org.cn>
---
kernel.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
Index: crash/kernel.c
===================================================================
--- crash.orig/kernel.c 2026-08-13 13:26:26.858739906 +0800
+++ crash/kernel.c 2026-08-13 13:27:30.450848208 +0800
@@ -1400,7 +1400,8 @@
!strstr(buffer, "Linux version 3.") &&
!strstr(buffer, "Linux version 4.") &&
!strstr(buffer, "Linux version 5.") &&
- !strstr(buffer, "Linux version 6."))
+ !strstr(buffer, "Linux version 6.") &&
+ !strstr(buffer, "Linux version 7."))
continue;
if (strstr(buffer, kt->proc_version)) {
2 months
Laos Visa for Business Travellers
by Edgar Sullivan
The Laos eVisa for Business Travellers is a topic of interest for professionals planning meetings, conferences, networking activities, or commercial visits in Laos. However, travelers should not assume that the standard Laos eVisa covers all business-related activities. The appropriate visa category depends on the purpose, duration, and nature of the planned stay. Business visitors may need a separate business visa or additional authorization from the relevant Lao authorities. Before submitting an application, travelers should confirm the correct visa type and prepare any required business documentation, such as an invitation or company-related information. Checking current Lao immigration rules, fees, processing times, and entry requirements is recommended before travel.
website: https://lao-evisa.com/laos-visa-for-business-travelers/
2 months, 1 week
Application Process For A Laos eVisa
by Edgar Sullivan
The <a href="https://lao-evisa.com/application-process-for-laos-e-visa/">Application Process for a Laos eVisa</a> begins with checking whether the traveler and intended trip meet the current eligibility conditions. Eligible applicants can complete the online form by entering their personal details, passport information, contact details, and travel plans. A recent photograph and a digital copy of the passport may be required during submission. After completing the form, applicants should carefully verify all information before paying the applicable fee and submitting the request. The application is then reviewed by the relevant authorities. If approved, the eVisa document is provided electronically. Travelers should save or print the approval and confirm the latest entry requirements before traveling to Laos.
2 months, 1 week
[PATCH v3] symbols: optimize symval_hash_init with O(1) tail insertion
by Rui Qi
Replace the O(n) tail traversal with O(1) tail insertion using a
dynamically-allocated per-bucket tail tracking array. The original code
traversed the entire linked list on every insert to find the tail,
resulting in O(n^2) complexity for hash table initialization.
This reduces hash table initialization from O(n^2) to O(n).
Benchmark on an x86_64 machine (kernel 5.10.135, ~112k symbols):
Before: 5.54 s (mean, n=6, sigma=0.12)
After: 5.31 s (mean, n=6, sigma=0.12)
Speedup: 1.04x (-4.1%)
Benchmark on an ARM64 Neoverse-N2 machine (kernel 5.15.152 arm64,
~132k nm symbols):
Before: 3.4113 s (mean, n=48, sigma=0.0698)
After: 2.5073 s (mean, n=48, sigma=0.0394)
Speedup: 1.36x (-26.5%), with improved consistency.
User CPU: 4.1706 s -> 3.2768 s (-21.4%).
Benchmark retest on a RISC-V machine (kernel
6.12.13 riscv64, ~198k nm symbols):
$ printf 'q\n' | ./crash vmlinux /proc/kcore
Before: 11.934 s (mean, n=3, sigma=0.880; samples: 12.921, 11.231, 11.651)
After: 10.255 s (mean, n=3, sigma=0.835; samples: 11.131, 9.467, 10.168)
Speedup: 1.16x (-14.1%)
Signed-off-by: Rui Qi <qirui.001(a)bytedance.com>
Reviewed-by: Dave Young <yangrr.2009(a)tsinghua.org.cn>
---
Changes since v2:
- Fix the comment to reference the dynamically-allocated tails[]
array instead of val_hash_last (suggested by Dave Young)
- Use malloc/free for the tails[] array instead of stack allocation
(suggested by Dave Young)
Changes from V1 [1]:
- Use a separate local tails[] array for tail tracking instead of reusing
val_hash_last, to preserve its original semantics as a last-visited-entry
cache for symval_hash_search(). (Dave Young, Tao Liu)
- Add benchmarks on x86_64 and ARM64 in addition to RISC-V. (Tao Liu)
symbols.c | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/symbols.c b/symbols.c
index 03511c8cbe8c..2859afa7f6e0 100644
--- a/symbols.c
+++ b/symbols.c
@@ -1085,12 +1085,18 @@ symbol_value_from_proc_kallsyms(char *symname)
/*
* Install all static kernel symbol values into the symval_hash.
+ * Uses a dynamically-allocated tails[] array for O(1) tail insertion.
*/
static void
symval_hash_init(void)
{
int index;
- struct syment *sp, *sph;
+ struct syment *sp, **tails;
+
+ tails = (struct syment **)malloc(SYMVAL_HASH * sizeof(struct syment *));
+ if (tails == NULL)
+ error(FATAL, "symval_hash_init tails malloc: %s\n", strerror(errno));
+ BZERO(tails, SYMVAL_HASH * sizeof(struct syment *));
for (sp = st->symtable; sp < st->symend; sp++) {
index = SYMVAL_HASH_INDEX(sp->value);
@@ -1098,15 +1104,12 @@ symval_hash_init(void)
if (st->symval_hash[index].val_hash_head == NULL) {
st->symval_hash[index].val_hash_head = sp;
st->symval_hash[index].val_hash_last = sp;
- continue;
- }
-
- sph = st->symval_hash[index].val_hash_head;
- while (sph->val_hash_next)
- sph = sph->val_hash_next;
-
- sph->val_hash_next = sp;
+ } else
+ tails[index]->val_hash_next = sp;
+ tails[index] = sp;
}
+
+ free(tails);
}
/*
--
2.20.1
2 months, 1 week
[PATCH v3] x86_64: Make ORC_REG_SP and ORC_REG_PREV_SP independent from kernel version
by Tao Liu
Previously ORC_REG_SP and ORC_REG_PREV_SP will depend on kernel version
for their value, however this is fragile since distributions will
backport the upstream patch to a lower kernel version, thus break the
version assumption.
This patch fixes by checking the value of ORC_REG_PREV_SP, which can be
get from orc_fp_entry. ORC_REG_PREV_SP's value can work as the indicator
of whether the current kernel have applied the upstream patch 1735858caa4b
("objtool/x86: Reorder ORC register numbering").
Fixes: d0ee428664f9 ("x86_64: Fix "bt" command to use correct ORC register
values on Linux 7.1 and later")
Signed-off-by: Tao Liu <ltao(a)redhat.com>
---
v3 -> v2: Remove data type query of orc_fp_entry, just use kernel_orc_entry_6_4
which already contained in crash utility for bp_reg offset resolving.
---
x86_64.c | 32 +++++++++++++++++++++++++-------
1 file changed, 25 insertions(+), 7 deletions(-)
diff --git a/x86_64.c b/x86_64.c
index 55648697baf3..d192f3bcdd20 100644
--- a/x86_64.c
+++ b/x86_64.c
@@ -6661,6 +6661,9 @@ x86_64_ORC_init(void)
NULL
};
struct ORC_data *orc;
+ struct gnu_request request, *req;
+ ulong value = 0;
+ req = &request;
MEMBER_OFFSET_INIT(inactive_task_frame_bp, "inactive_task_frame", "bp");
MEMBER_OFFSET_INIT(inactive_task_frame_ret_addr, "inactive_task_frame", "ret_addr");
@@ -6736,13 +6739,28 @@ x86_64_ORC_init(void)
if (orc->has_signal && !orc->has_end)
machdep->flags |= ORC_6_4;
- /* See kernel commit 1735858caa4b */
- if (THIS_KERNEL_VERSION >= LINUX(7,1,0)) {
- ORC_REG_SP = 3;
- ORC_REG_PREV_SP = 8;
- } else {
- ORC_REG_SP = 5;
- ORC_REG_PREV_SP = 1;
+ /* Try get ORC_REG_(PREV)_SP */
+ ORC_REG_SP = 5;
+ ORC_REG_PREV_SP = 1;
+
+ if (kernel_symbol_exists("orc_fp_entry")) {
+ /*
+ * kernel_orc_entry_6_4 & kernel_orc_entry have the same
+ * offset of bp_reg.
+ */
+ kernel_orc_entry_6_4 entry = {0};
+ if (try_get_symbol_data("orc_fp_entry", sizeof(entry), &entry)) {
+ /*
+ * orc_fp_entry.bp_reg = ORC_REG_PREV_SP
+ * See kernel commit 1735858caa4b. Use ORC_REG_PREV_SP
+ * as the indicator of the commit.
+ */
+ if (entry.bp_reg == 8) {
+ ORC_REG_SP = 3;
+ ORC_REG_PREV_SP = 8;
+ }
+ } else
+ error(WARNING, "Cannot get orc_fp_entry.bp_reg info");
}
machdep->flags |= ORC;
--
2.54.0
2 months, 1 week
[PATCH v2] symbols: optimize symval_hash_init with O(1) tail insertion
by 启瑞
From: Rui Qi <qirui.001(a)bytedance.com>
Replace the O(n) tail traversal with O(1) tail insertion using a local
per-bucket tail tracking array. The original code traversed the entire
linked list on every insert to find the tail, resulting in O(n^2)
complexity for hash table initialization.
This reduces hash table initialization from O(n^2) to O(n).
Benchmark on an x86_64 machine (kernel 5.10.135, ~112k symbols):
Before: 5.54 s (mean, n=6, sigma=0.12)
After: 5.31 s (mean, n=6, sigma=0.12)
Speedup: 1.04x (-4.1%)
Benchmark on an ARM64 Neoverse-N2 machine (kernel 5.15.152.bsk.4-arm64,
~132k nm symbols):
Before: 3.4113 s (mean, n=48, sigma=0.0698)
After: 2.5073 s (mean, n=48, sigma=0.0394)
Speedup: 1.36x (-26.5%), with improved consistency.
User CPU: 4.1706 s -> 3.2768 s (-21.4%).
Benchmark retest on a RISC-V machine (kernel
6.12.13.bsk.1-rc14-riscv64, ~198k nm symbols):
$ printf 'q\n' | ./crash vmlinux /proc/kcore
Before: 11.934 s (mean, n=3, sigma=0.880; samples: 12.921, 11.231, 11.651)
After: 10.255 s (mean, n=3, sigma=0.835; samples: 11.131, 9.467, 10.168)
Speedup: 1.16x (-14.1%)
Signed-off-by: Rui Qi <qirui.001(a)bytedance.com>
Changes from V1 [1]:
- Use a separate local tails[] array for tail tracking instead of reusing
val_hash_last, to preserve its original semantics as a last-visited-entry
cache for symval_hash_search(). (Dave Young, Tao Liu)
- Add benchmarks on x86_64 and ARM64 in addition to RISC-V. (Tao Liu)
[1] https://lists.crash-utility.osci.io/archives/list/devel@lists.crash-utili...
---
symbols.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/symbols.c b/symbols.c
index 03511c8cbe8c..42e0058a102e 100644
--- a/symbols.c
+++ b/symbols.c
@@ -1085,12 +1085,16 @@ symbol_value_from_proc_kallsyms(char *symname)
/*
* Install all static kernel symbol values into the symval_hash.
+ * Uses val_hash_last for O(1) tail insertion.
*/
static void
symval_hash_init(void)
{
int index;
- struct syment *sp, *sph;
+ struct syment *sp;
+ struct syment *tails[SYMVAL_HASH];
+
+ BZERO(tails, sizeof(tails));
for (sp = st->symtable; sp < st->symend; sp++) {
index = SYMVAL_HASH_INDEX(sp->value);
@@ -1098,14 +1102,9 @@ symval_hash_init(void)
if (st->symval_hash[index].val_hash_head == NULL) {
st->symval_hash[index].val_hash_head = sp;
st->symval_hash[index].val_hash_last = sp;
- continue;
- }
-
- sph = st->symval_hash[index].val_hash_head;
- while (sph->val_hash_next)
- sph = sph->val_hash_next;
-
- sph->val_hash_next = sp;
+ } else
+ tails[index]->val_hash_next = sp;
+ tails[index] = sp;
}
}
--
2.20.1
2 months, 1 week
[RFC PATCH 1/2] add cpu_to_nid function
by Huang Shijie
Add cpu_to_nid function which we can use to get the NUMA node id
by the cpu id.
Signed-off-by: Huang Shijie <huangsj(a)hygon.cn>
---
defs.h | 2 ++
kernel.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
main.c | 1 +
3 files changed, 49 insertions(+)
diff --git a/defs.h b/defs.h
index a4f70b7..98a149b 100644
--- a/defs.h
+++ b/defs.h
@@ -6040,6 +6040,8 @@ ulong do_maple_tree(ulong, int, struct list_pair *);
void help_init(void);
void cmd_usage(char *, int);
void display_version(void);
+int cpu_to_nid(int cpu);
+void numa_init(void);
void display_help_screen(char *);
#ifdef ARM
#define dump_machdep_table(X) arm_dump_machdep_table(X)
diff --git a/kernel.c b/kernel.c
index eb9754c..15254a4 100644
--- a/kernel.c
+++ b/kernel.c
@@ -12207,3 +12207,49 @@ out:
pc->error_fp = error_fp_save;
}
#endif
+
+static int *cpu_to_nid_map;
+
+int
+cpu_to_nid(int cpu)
+{
+ if (!cpu_to_nid_map || cpu < 0 || cpu >= kt->cpus)
+ return -1;
+ if (vt->numnodes == 1)
+ return 0;
+ return cpu_to_nid_map[cpu];
+}
+
+static void
+cpu_to_nid_init(void)
+{
+ int i, j;
+ int fd;
+ char buf[64];
+
+ cpu_to_nid_map = malloc(kt->cpus * sizeof(int));
+ if (vt->numnodes == 1)
+ return;
+
+ memset(cpu_to_nid_map, -1, kt->cpus * sizeof(int));
+
+ for (i = 0; i < kt->cpus; i++) {
+ for (j = 0; j < vt->numnodes; j++) {
+ memset(buf, 0, sizeof(buf));
+ sprintf(buf, "/sys/devices/system/cpu/cpu%d/node%d", i, j);
+
+ fd = open(buf, O_RDONLY);
+ if (fd > 0) {
+ cpu_to_nid_map[i] = j;
+ close(fd);
+ break;
+ }
+ }
+ }
+}
+
+void
+numa_init(void)
+{
+ cpu_to_nid_init();
+}
diff --git a/main.c b/main.c
index d5f8486..a8c77f8 100644
--- a/main.c
+++ b/main.c
@@ -793,6 +793,7 @@ main_loop(void)
kernel_init();
machdep_init(POST_GDB);
vm_init();
+ numa_init();
machdep_init(POST_VM);
module_init();
help_init();
--
2.53.0
2 months, 1 week