From nobody Wed Apr 8 14:46:53 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AD4C0ECAAA1 for ; Fri, 9 Sep 2022 13:04:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229599AbiIINES (ORCPT ); Fri, 9 Sep 2022 09:04:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37140 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231304AbiIINDV (ORCPT ); Fri, 9 Sep 2022 09:03:21 -0400 Received: from szxga01-in.huawei.com (szxga01-in.huawei.com [45.249.212.187]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 212E0B8F1E; Fri, 9 Sep 2022 06:03:20 -0700 (PDT) Received: from dggpemm500021.china.huawei.com (unknown [172.30.72.54]) by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4MPGKV3mW2zlVqb; Fri, 9 Sep 2022 20:59:26 +0800 (CST) Received: from dggpemm500006.china.huawei.com (7.185.36.236) by dggpemm500021.china.huawei.com (7.185.36.109) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Fri, 9 Sep 2022 21:03:18 +0800 Received: from thunder-town.china.huawei.com (10.174.178.55) by dggpemm500006.china.huawei.com (7.185.36.236) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Fri, 9 Sep 2022 21:03:17 +0800 From: Zhen Lei To: Josh Poimboeuf , Jiri Kosina , Miroslav Benes , Petr Mladek , Joe Lawrence , , , Masahiro Yamada , Alexei Starovoitov , Jiri Olsa , Kees Cook , Andrew Morton , "Luis Chamberlain" , CC: Zhen Lei Subject: [PATCH v2 8/8] kallsyms: Add self-test facility Date: Fri, 9 Sep 2022 21:00:16 +0800 Message-ID: <20220909130016.727-9-thunder.leizhen@huawei.com> X-Mailer: git-send-email 2.26.0.windows.1 In-Reply-To: <20220909130016.727-1-thunder.leizhen@huawei.com> References: <20220909130016.727-1-thunder.leizhen@huawei.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Originating-IP: [10.174.178.55] X-ClientProxiedBy: dggems704-chm.china.huawei.com (10.3.19.181) To dggpemm500006.china.huawei.com (7.185.36.236) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add some test cases to test the function and performance of some kallsyms interfaces, such as kallsyms_lookup_name. It also calculates the compression rate of the kallsyms compression algorithm for the current symbol set. Start self-test automatically after system startup. Example of output content: (prefix 'kallsyms_selftest:' is omitted) start There are 174101 symbols in total: -------------------------------------------------------------- | | compressed size | original size | ratio(%) | |--------------------------------------------------------------| | no '\0' | 1785569 | 3750649 | 47.60 | | with '\0' | 1959670 | 3924750 | 49.93 | -------------------------------------------------------------- kallsyms_lookup_name() looked up 174101 symbols The time spent on each symbol is (ns): min=3D5350, max=3D985150, avg=3D2955= 17 kallsyms_on_each_symbol() lookup vmap: 15806120 ns kallsyms_on_each_symbol() traverse vmap: 15817140 ns kallsyms_on_each_match_symbol() lookup vmap: 32840 ns kallsyms_on_each_match_symbol() traverse vmap: 567370 ns Signed-off-by: Zhen Lei --- init/Kconfig | 13 ++ kernel/Makefile | 1 + kernel/kallsyms_selftest.c | 243 +++++++++++++++++++++++++++++++++++++ 3 files changed, 257 insertions(+) create mode 100644 kernel/kallsyms_selftest.c diff --git a/init/Kconfig b/init/Kconfig index 532362fcfe31fd3..2fcace3b9f063bf 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1716,6 +1716,19 @@ config KALLSYMS symbolic stack backtraces. This increases the size of the kernel somewhat, as all symbols have to be loaded into the kernel image. =20 +config KALLSYMS_SELFTEST + bool "Test the function and performance of some interfaces in kallsyms" + depends on KALLSYMS + default n + help + Test the function and performance of some interfaces, such as + kallsyms_lookup_name. It also calculates the compression rate of the + kallsyms compression algorithm for the current symbol set. + + Start self-test automatically after system startup. Suggest executing + "dmesg | grep kallsyms_selftest" to collect test results. "finish" is + displayed in the last line, indicating that the test is complete. + config KALLSYMS_ALL bool "Include all symbols in kallsyms" depends on DEBUG_KERNEL && KALLSYMS diff --git a/kernel/Makefile b/kernel/Makefile index 318789c728d3290..122a5fed457bd98 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -68,6 +68,7 @@ endif obj-$(CONFIG_UID16) +=3D uid16.o obj-$(CONFIG_MODULE_SIG_FORMAT) +=3D module_signature.o obj-$(CONFIG_KALLSYMS) +=3D kallsyms.o +obj-$(CONFIG_KALLSYMS_SELFTEST) +=3D kallsyms_selftest.o obj-$(CONFIG_BSD_PROCESS_ACCT) +=3D acct.o obj-$(CONFIG_CRASH_CORE) +=3D crash_core.o obj-$(CONFIG_KEXEC_CORE) +=3D kexec_core.o diff --git a/kernel/kallsyms_selftest.c b/kernel/kallsyms_selftest.c new file mode 100644 index 000000000000000..d89d6b2f5dd763e --- /dev/null +++ b/kernel/kallsyms_selftest.c @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Test the function and performance of kallsyms + * + * Copyright (C) Huawei Technologies Co., Ltd., 2022 + * + * Authors: Zhen Lei Huawei + */ + +#define pr_fmt(fmt) "kallsyms_selftest: " fmt + +#include +#include +#include +#include +#include +#include + +#include "kallsyms_internal.h" + + +struct test_stat { + int min; + int max; + int cnt; + u64 sum; + unsigned long addr; +}; + + +static int match_symbol(void *data, unsigned long addr) +{ + struct test_stat *stat =3D (struct test_stat *)data; + + stat->cnt++; + stat->addr =3D addr; + + if (stat->cnt =3D=3D stat->max) + return 1; + + return 0; +} + +static void test_kallsyms_on_each_match_symbol(void) +{ + u64 t0, t1; + unsigned long flags; + struct test_stat stat; + + stat.cnt =3D 0; + stat.max =3D 1; + stat.addr =3D 0; + local_irq_save(flags); + t0 =3D sched_clock(); + kallsyms_on_each_match_symbol(match_symbol, "vmap", &stat); + t1 =3D sched_clock(); + local_irq_restore(flags); + if (stat.addr !=3D (unsigned long)vmap || stat.cnt !=3D 1) { + pr_info("kallsyms_on_each_match_symbol() test failed\n"); + return; + } + pr_info("kallsyms_on_each_match_symbol() lookup vmap: %lld ns\n", t1 - t0= ); + + stat.cnt =3D 0; + stat.max =3D INT_MAX; + stat.addr =3D 0; + local_irq_save(flags); + t0 =3D sched_clock(); + kallsyms_on_each_match_symbol(match_symbol, "vmap", &stat); + t1 =3D sched_clock(); + local_irq_restore(flags); + if (stat.addr !=3D (unsigned long)vmap || stat.cnt !=3D 1) { + pr_info("kallsyms_on_each_match_symbol() test failed\n"); + return; + } + pr_info("kallsyms_on_each_match_symbol() traverse vmap: %lld ns\n", t1 - = t0); +} + +static int find_symbol(void *data, const char *name, + struct module *mod, unsigned long addr) +{ + struct test_stat *stat =3D (struct test_stat *)data; + + if (strcmp(name, "vmap") =3D=3D 0) { + stat->cnt++; + stat->addr =3D addr; + } + + if (stat->cnt =3D=3D stat->max) + return 1; + + return 0; +} + +static void test_kallsyms_on_each_symbol(void) +{ + u64 t0, t1; + unsigned long flags; + struct test_stat stat; + + stat.cnt =3D 0; + stat.sum =3D 1; + stat.addr =3D 0; + local_irq_save(flags); + t0 =3D sched_clock(); + kallsyms_on_each_symbol(find_symbol, &stat); + t1 =3D sched_clock(); + local_irq_restore(flags); + if (stat.addr !=3D (unsigned long)vmap || stat.cnt !=3D 1) { + pr_info("kallsyms_on_each_symbol() test failed\n"); + return; + } + pr_info("kallsyms_on_each_symbol() lookup vmap: %lld ns\n", t1 - t0); + + stat.cnt =3D 0; + stat.max =3D INT_MAX; + stat.addr =3D 0; + local_irq_save(flags); + t0 =3D sched_clock(); + kallsyms_on_each_symbol(find_symbol, &stat); + t1 =3D sched_clock(); + local_irq_restore(flags); + if (stat.addr !=3D (unsigned long)vmap || stat.cnt !=3D 1) { + pr_info("kallsyms_on_each_symbol() test failed\n"); + return; + } + pr_info("kallsyms_on_each_symbol() traverse vmap: %lld ns\n", t1 - t0); +} + +static int lookup_name(void *data, const char *name, struct module *mod, u= nsigned long addr) +{ + u64 t0, t1, t; + unsigned long flags; + struct test_stat *stat =3D (struct test_stat *)data; + + local_irq_save(flags); + t0 =3D sched_clock(); + (void)kallsyms_lookup_name(name); + t1 =3D sched_clock(); + local_irq_restore(flags); + + t =3D t1 - t0; + if (t < stat->min) + stat->min =3D t; + + if (t > stat->max) + stat->max =3D t; + + stat->cnt++; + stat->sum +=3D t; + + return 0; +} + +static void test_kallsyms_lookup_name(void) +{ + struct test_stat stat; + + stat.min =3D INT_MAX; + stat.max =3D 0; + stat.cnt =3D 0; + stat.sum =3D 0; + kallsyms_on_each_symbol(lookup_name, &stat); + pr_info("kallsyms_lookup_name() looked up %d symbols\n", stat.cnt); + pr_info("The time spent on each symbol is (ns): min=3D%d, max=3D%d, avg= =3D%lld\n", + stat.min, stat.max, stat.sum / stat.cnt); + + stat.addr =3D kallsyms_lookup_name("vmap"); + if (stat.addr !=3D (unsigned long)vmap) + pr_info("kallsyms_lookup_name() test failed\n"); +} + +static int stat_symbol_len(void *data, const char *name, + struct module *mod, unsigned long addr) +{ + *(u32 *)data +=3D strlen(name); + + return 0; +} + +static void test_kallsyms_compression_ratio(void) +{ + int i; + const u8 *name; + u32 pos; + u32 ratio, total_size, total_len =3D 0; + + kallsyms_on_each_symbol(stat_symbol_len, &total_len); + + pos =3D kallsyms_num_syms - 1; + name =3D &kallsyms_names[kallsyms_markers[pos >> 8]]; + for (i =3D 0; i <=3D (pos & 0xff); i++) + name =3D name + (*name) + 1; + + /* The length and string terminator are not counted */ + total_size =3D (name - kallsyms_names) - (kallsyms_num_syms * 2); + pr_info("There are %d symbols in total:\n", kallsyms_num_syms); + pr_info(" --------------------------------------------------------------\= n"); + pr_info("| | compressed size | original size | ratio(%%) = |\n"); + pr_info("|--------------------------------------------------------------|= \n"); + ratio =3D 10000ULL * total_size / total_len; + pr_info("| no '\\0' | %10d | %10d | %2d.%-2d |\n", + total_size, total_len, ratio / 100, ratio % 100); + total_size +=3D kallsyms_num_syms; + total_len +=3D kallsyms_num_syms; + ratio =3D 10000ULL * total_size / total_len; + pr_info("| with '\\0' | %10d | %10d | %2d.%-2d |\n", + total_size, total_len, ratio / 100, ratio % 100); + pr_info(" --------------------------------------------------------------\= n"); + pr_info("\n"); +} + +static int test_entry(void *p) +{ + do { + schedule_timeout(5 * HZ); + } while (system_state !=3D SYSTEM_RUNNING); + + pr_info("start\n"); + test_kallsyms_compression_ratio(); + test_kallsyms_lookup_name(); + test_kallsyms_on_each_symbol(); + test_kallsyms_on_each_match_symbol(); + pr_info("finish\n"); + + return 0; +} + +static int __init kallsyms_test_init(void) +{ + struct task_struct *t; + + t =3D kthread_create(test_entry, NULL, "kallsyms_test"); + if (IS_ERR(t)) { + pr_info("Create kallsyms selftest task failed\n"); + return PTR_ERR(t); + } + kthread_bind(t, 0); + wake_up_process(t); + + return 0; +} +late_initcall(kallsyms_test_init); --=20 2.25.1