From: David Laight <david.laight.linux@gmail.com>
To: Petr Mladek <pmladek@suse.com>, Kees Cook <kees@kernel.org>,
David Laight <david.laight.linux@gmail.com>,
linux-kernel@vger.kernel.org, linux-kbuild@vger.kernel.org,
bpf@vger.kernel.org, Jim Cromie <jim.cromie@gmail.com>,
Lorenzo Stoakes <ljs@kernel.org>
Cc: Luis Chamberlain <mcgrof@kernel.org>,
Andrey Grodzovsky <andrey.grodzovsky@crowdstrike.com>,
Steven Rostedt <rostedt@goodmis.org>,
Andrii Nakryiko <andrii@kernel.org>,
Samuel Wu <wusamuel@google.com>,
linux-kselftest@vger.kernel.org
Subject: [PATCH v3 next 12/13] scripts/kallsyms: Reuse tokens that have no references
Date: Wed, 11 Nov 2026 11:59:10 +0000 [thread overview]
Message-ID: <20261111115911.1142000-13-david.laight.linux@gmail.com> (raw)
In-Reply-To: <20261111115911.1142000-1-david.laight.linux@gmail.com>
Keep track of the number of times each compression token is used.
If the count becomes zero (eg if the only x are in axb and y is
substituted for xb giving ay) then x can be reused.
This means that a token can refer to a long string without needing
tokens for all the shorter strings.
Output the counts in comments in the output file.
For my normal kernel build four tokens get reused saving 8.5k of data.
The savings may be greater if there are symbols with long matching prefix.
Signed-off-by: David Laight <david.laight.linux@gmail.com>
--
v3: Formally patch 13, rebased on 7.4-rc1
scripts/kallsyms.c | 72 ++++++++++++++++++++++++++++++++++++----------
1 file changed, 57 insertions(+), 15 deletions(-)
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 4da613e8e728..2f517873e9b4 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -91,6 +91,7 @@ static struct sym_arr token_syms[NR_TOKENS];
static struct best_table {
char *str; /* Full expansion, '\0' terminated */
unsigned short len; /* Length of str */
+ unsigned int refs; /* Number of times used in a symbol */
} best_table[256];
static void stamp(const char *where)
@@ -423,7 +424,8 @@ static void write_src(void)
for (i = 0; i < 256; i++) {
best_idx[i] = off;
off += best_table[i].len + 1;
- printf("\t.asciz\t\"%s\"\n", best_table[i].str);
+ printf("\t.asciz\t\"%s\"\t/* %u: refs %u */\n",
+ best_table[i].str, i, best_table[i].refs);
}
printf(".size kallsyms_token_table, . - kallsyms_token_table\n");
printf("\n");
@@ -641,12 +643,14 @@ static void check_tables(void)
unsigned int refs;
unsigned int idx;
} tok_info[NR_TOKENS], *ti;
+ unsigned int tok_refs[256];
unsigned int sym_idx, token;
unsigned char *cp, *end;
struct sym_arr *sa;
unsigned int i, idx;
memset(&tok_info, 0, sizeof(tok_info));
+ memset(&tok_refs, 0, sizeof(tok_refs));
/* Check that token_syms[]->sym_indexes is correctly sorted. */
for (token = 0; token < NR_TOKENS; token++) {
@@ -665,8 +669,10 @@ static void check_tables(void)
for (sym_idx = 0; sym_idx < table_cnt; sym_idx++) {
cp = table[sym_idx]->sym;
end = cp + table[sym_idx]->len;
+ tok_refs[*cp]++;
/* Scan all pairs */
while (++cp < end) {
+ tok_refs[*cp]++;
token = token_index(cp[-1], cp[0]);
ti = tok_info + token;
ti->refs++;
@@ -690,6 +696,12 @@ static void check_tables(void)
}
/* Check the reference counts for all tokens. */
+ for (i = 0; i < 256; i++) {
+ if (tok_refs[i] != best_table[i].refs)
+ errx(EXIT_FAILURE, "token reference error for %u (%s) %u != %u",
+ i, best_table[i].str, best_table[i].refs, tok_refs[i]);
+ }
+
for (idx = 0; idx < NR_TOKENS; idx++) {
if (tok_info[idx].refs != token_profit[idx]) {
errx(EXIT_FAILURE, "profit error for %x (%s/%s) discrepency %u != %u",
@@ -698,6 +710,7 @@ static void check_tables(void)
tok_info[idx].refs, token_profit[idx]);
}
}
+
}
/* count all the possible tokens in a symbol */
@@ -720,6 +733,19 @@ static void token_add_symbol(unsigned int token_idx, unsigned int sym_idx)
sym_arr_add(arr, sym_idx);
}
+static unsigned int sym_arr_free_all(unsigned int ch)
+{
+ unsigned int i;
+
+ /* Just zero the counts, the entries are about to be reused. */
+ for (i = 0; i < 256; i++) {
+ token_syms[token_index(i, ch)].cnt = 0;
+ token_syms[token_index(ch, i)].cnt = 0;
+ }
+
+ return ch;
+}
+
static void symbol_index_all_tokens(const unsigned char *symbol, int len,
unsigned int sym_idx)
{
@@ -785,11 +811,11 @@ static unsigned char *find_token(unsigned char *str, unsigned char *end,
/* replace a given token in all the valid symbols. Use the sampled symbols
* to update the counts.
* Marked noinline to help register allocation. */
-static __attribute__((noinline)) void
+static __attribute__((noinline)) unsigned int
compress_symbols(unsigned int token_idx, int compressed_chr)
{
struct sym_arr *arr = &token_syms[token_idx];
- unsigned int sym_idx, j, len;
+ unsigned int sym_idx, j, len, subs;
unsigned char *sym, *p, *end;
struct sym_entry *se;
@@ -817,8 +843,11 @@ compress_symbols(unsigned int token_idx, int compressed_chr)
}
/* No symbol contains this token any more. */
+ subs = token_profit[token_idx];
token_profit[token_idx] = 0;
sym_arr_free(arr);
+
+ return subs;
}
/* search the token with the maximum profit */
@@ -842,28 +871,40 @@ static int find_best_token(void)
static void optimize_result(void)
{
struct best_table *bt, *first, *second;
- unsigned int len;
+ unsigned char to_process[256];
+ unsigned int idx, len, refs;
int i, best;
char *str;
- /* Use the '\0' symbol last so the output is unchanged */
- for (i = 255; i >= 0; i--) {
- bt = best_table + i;
- /* Ignore tokens used for the original character codes. */
- if (bt->len)
- continue;
+ /* Generate a list of the unused tokens. */
+ for (i = 0, idx = 0; i < 256; i++) {
+ if (!best_table[i].len)
+ to_process[idx++] = i;
+ }
- /* Find the token that appears most often. */
+ while (idx) {
+ /* find the token that appears most often */
best = find_best_token();
if (best < 0)
break;
+ i = to_process[--idx];
/* Replace this token in all the valid symbols. */
- compress_symbols(best, i);
+ refs = compress_symbols(best, i);
- /* Generate the full name for this token ... */
+ bt = best_table + i;
first = best_table + token_first(best);
second = best_table + token_second(best);
+
+ /* Update the number of times each token is used. */
+ bt->refs += refs;
+ if (!(first->refs -= refs) && first->len > 1)
+ /* There are no references left, reuse the token. */
+ to_process[idx++] = sym_arr_free_all(token_first(best));
+ if (!(second->refs -= refs) && second->len > 1)
+ to_process[idx++] = sym_arr_free_all(token_second(best));
+
+ /* Generate the full name for this token ... */
len = first->len + second->len;
str = xmalloc(len + 1);
str[len] = 0;
@@ -885,13 +926,14 @@ static void insert_real_symbols_in_table(void)
for (i = 0; i < table_cnt; i++) {
for (j = 0; j < table[i]->len; j++) {
c = table[i]->sym[j];
- best_table[c].len = 1;
+ best_table[c].refs++;
}
}
for (i = 0; i <= 255; i++) {
best_table[i].str = xmalloc(2);
- best_table[i].str[0] = best_table[i].len ? i : 0;
+ best_table[i].len = best_table[i].refs ? 1 : 0;
+ best_table[i].str[0] = best_table[i].refs ? i : 0;
best_table[i].str[1] = 0;
}
}
--
2.39.5
next prev parent reply other threads:[~2026-11-11 11:59 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-11 11:58 [PATCH v3 next 00/13] kallsyms: optimise symbol search by name David Laight
2026-11-11 11:58 ` [PATCH v3 next 01/13] scripts/kallsyms: Avoid overrunning on-stack buffer David Laight
2026-11-11 11:59 ` [PATCH v3 next 02/13] scripts/kallsyms: Improve error reporting David Laight
2026-11-11 11:59 ` [PATCH v3 next 03/13] scripts/elf-parse: add elf_map_big_endian() helper David Laight
2026-11-11 11:59 ` [PATCH v3 next 04/13] scripts/kallsyms: make use of binary data output optional David Laight
2026-11-11 11:59 ` [PATCH v3 next 05/13] kallsyms: Fix selftest startup delay David Laight
2026-11-11 11:59 ` [PATCH v3 next 06/13] kallsyms: Improve selftest test_perf_kallsyms_lookup_name() output David Laight
2026-11-11 11:59 ` [PATCH v3 next 07/13] kallsyms: Match compressed tokens on the fly during binary search David Laight
2026-11-11 11:59 ` [PATCH v3 next 08/13] kallsyms: Optimise symbol name search David Laight
2026-11-11 11:59 ` [PATCH v3 next 09/13] kallsyms: Add a kernel parameter to change the kallsyms_markers[] density David Laight
2026-11-11 11:59 ` [PATCH v3 next 10/13] scripts/kallsyms: Keep full expansion of tokens David Laight
2026-11-11 11:59 ` [PATCH v3 next 11/13] scripts/kallsyms: Optimise compress_symbols() David Laight
2026-11-11 11:59 ` David Laight [this message]
2026-11-11 11:59 ` [PATCH v3 next 13/13] scripts/kallsyms: Reuse little-used compression tokens David Laight
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261111115911.1142000-13-david.laight.linux@gmail.com \
--to=david.laight.linux@gmail.com \
--cc=andrey.grodzovsky@crowdstrike.com \
--cc=andrii@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=jim.cromie@gmail.com \
--cc=kees@kernel.org \
--cc=linux-kbuild@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=ljs@kernel.org \
--cc=mcgrof@kernel.org \
--cc=pmladek@suse.com \
--cc=rostedt@goodmis.org \
--cc=wusamuel@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®