From 2fab8fbc0c4f1c4cbe889de4cead5f7457a19f77 Mon Sep 17 00:00:00 2001 From: Tao Liu Date: Sat, 16 Oct 2021 13:21:11 +0800 Subject: [PATCH 1/9] symbols: Implement install and remove operations for mod_symname_hash Currently the sequence for symbol_search to search a symbol is: 1) kernel symname hash table, 2) iterate all kernel symbols, 3) iterate all kernel modules and their symbols. In the worst case, if a non-exist symbol been searched, all 3 stages will be went through. The time consuming status for each stage is like: stage 1 stage 2 stage 3 0.007000(ms) 0.593000(ms) 2.421000(ms) stage 3 takes too much time when comparing to stage 1. This patch series introduces a symname hash table for kernel modules, to improve the performance of symbol searching. Functions symbol_search() and symbol_exists() are fundamental and widely used by other crash functions, thus the benefit of performance improvement can get accumulated. For example, "ps -m" and "irq" commands, which call the functions many times, will become faster with the patch series. This patch indroduces mod_symname_hash, and its install/remove operations. Since symbol_search() has to return the lowest address symbol and symbol_search_next() returns the next lowest symbol, thus the installation should be sorted ascendingly. In mod_symname_hash_install_range() scenario, spn are already arranged ascendingly, so for mod_symname_hash_install(): Install spn previous to sp: If sp is the start of bucket, or 1) spn->value is smaller than sp->value. Install spn next to sp: 1) sp->name_hash_next is NULL, or 2) sp->name_hash_next->value is larger than spn->value spn->value is the kernel address of the symbol and will not change. So we use it mainly to determine the sequence. When spn->value equals sp->value, they must be symbols within a kernel module. Signed-off-by: Tao Liu --- defs.h | 1 + symbols.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/defs.h b/defs.h index cbd45e52f9da..bbdca799f72d 100644 --- a/defs.h +++ b/defs.h @@ -2755,6 +2755,7 @@ struct symbol_table_data { double val_hash_searches; double val_hash_iterations; struct syment *symname_hash[SYMNAME_HASH]; + struct syment *mod_symname_hash[SYMNAME_HASH]; struct symbol_namespace kernel_namespace; struct syment *ext_module_symtable; struct syment *ext_module_symend; diff --git a/symbols.c b/symbols.c index 69dccdb09d5f..ad12d1c22225 100644 --- a/symbols.c +++ b/symbols.c @@ -1157,6 +1157,79 @@ symname_hash_install(struct syment *spn) } } +/* + * Install a single kernel module symbol into the mod_symname_hash. + */ +static void +mod_symname_hash_install(struct syment *spn) +{ + struct syment *sp; + int index; + + if (!spn) + return; + + index = SYMNAME_HASH_INDEX(spn->name); + + sp = st->mod_symname_hash[index]; + + if (!sp || (spn->value < sp->value)) { + st->mod_symname_hash[index] = spn; + spn->name_hash_next = sp; + return; + } + for (; sp; sp = sp->name_hash_next) { + if (!sp->name_hash_next || + spn->value < sp->name_hash_next->value) { + spn->name_hash_next = sp->name_hash_next; + sp->name_hash_next = spn; + return; + } + } +} + +static void +mod_symname_hash_remove(struct syment *spn) +{ + struct syment *sp; + int index; + + if (!spn) + return; + + index = SYMNAME_HASH_INDEX(spn->name); + + if (st->mod_symname_hash[index] == spn) { + st->mod_symname_hash[index] = spn->name_hash_next; + return; + } + + for (sp = st->mod_symname_hash[index]; sp; sp = sp->name_hash_next) { + if (sp->name_hash_next == spn) { + sp->name_hash_next = spn->name_hash_next; + return; + } + } +} + +static void +mod_symtable_hash_install_range(struct syment *from, struct syment *to) +{ + struct syment *sp; + + for (sp = from; sp <= to; sp++) + mod_symname_hash_install(sp); +} + +static void +mod_symtable_hash_remove_range(struct syment *from, struct syment *to) +{ + struct syment *sp; + + for (sp = from; sp <= to; sp++) + mod_symname_hash_remove(sp); +} + /* * Static kernel symbol value search */ -- 2.30.2