Hi Tao Liu,
 
 -----Original Message-----
 > Currently the sequence for crash searching 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)
 
 Just to clarify, which parts of code are meant by the stage 1 and 2?
 
 Do you have a result with the patch?
 
 > 
 > stage 3 takes too much time when comparing to stage 1. So let's introduce a
 > symname hash table for kernel modules to improve the performance of symbol
 > searching.
 
 I see that 3) is relatively time-consuming, but I have not had a delay
 due to the symbol search.  Which command did you observe a delay? 
Hello Kazu,
The target function is symbols.c:symbol_search. The code involved in the 3 stages are:
1) sp_hashed = symname_hash_search(s);
2) for (sp = sp_hashed ? sp_hashed : st->symtable; sp < st->symend; sp++) {
                 if (STREQ(s, sp->name)) 
                         return(sp);
3) for (i = 0; i < st->mods_installed; i++) {
                 lm = &st->load_modules[i];
                 ....
   }
I measured each stage's time by adding the following code to symbol_search:
        struct load_module *lm;
        int pseudos, search_init;
+       double T1, T2, T3;
+       clock_t start, end;
 
+       start = clock();
        sp_hashed = symname_hash_search(s);
+       end = clock();
+       T1 = (double)(end - start) * 1000.0 / CLOCKS_PER_SEC;
 
+       start = clock();
         for (sp = sp_hashed ? sp_hashed : st->symtable; sp < st->symend; sp++)
{
                 if (STREQ(s, sp->name)) 
                         return(sp);
         }
+        end = clock();
+        T2 = (double)(end - start) * 1000.0 / CLOCKS_PER_SEC;
 
        pseudos = (strstr(s, "_MODULE_START_") || strstr(s,
"_MODULE_END_"));
        search_init = FALSE;
 
+       start = clock();
         for (i = 0; i < st->mods_installed; i++) {
                 lm = &st->load_modules[i];
                if (lm->mod_flags & MOD_INIT)
         ....
                                return(sp);
                 }
         }
+        end = clock();
+        T3 = (double)(end - start) * 1000.0 / CLOCKS_PER_SEC;
+       printf("%lf %lf %lf\n", T1, T2, T3);
 
        if (!search_init)
                return((struct syment *)NULL);
crash> sym blah
T1:0.008000 T2:0.562000 T3:2.435000
symbol not found: blah
possible alternatives:
  (none found)
With the v2 patch applied and the time measurement code added:
crash> sym blah
T1:0.003000 T2:0.545000 T3:0.017000
symbol not found: blah
possible alternatives:
  (none found)
We can see T3 performs better.
Thanks,
Tao Liu
 
 Thanks,
 Kazu
 
 
 > 
 > Signed-off-by: Tao Liu <ltao(a)redhat.com>
 > ---
 > v1 -> v2:
 > - Removed unused variables within the modified functions.
 > 
 > ---
 >  defs.h    |   1 +
 >  kernel.c  |   1 +
 >  symbols.c | 189 +++++++++++++++++++++++++++++++-----------------------
 >  3 files changed, 111 insertions(+), 80 deletions(-)
 > 
 > diff --git a/defs.h b/defs.h
 > index eb1c71b..58b8546 100644
 > --- a/defs.h
 > +++ b/defs.h
 > @@ -2751,6 +2751,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/kernel.c b/kernel.c
 > index 36fdea2..c56cc34 100644
 > --- a/kernel.c
 > +++ b/kernel.c
 > @@ -4663,6 +4663,7 @@ reinit_modules(void)
 >          kt->mods_installed = 0;
 >  	clear_text_value_cache();
 > 
 > +	memset(st->mod_symname_hash, 0, sizeof(st->mod_symname_hash));
 >          module_init();
 >  }
 > 
 > diff --git a/symbols.c b/symbols.c
 > index bf6d94d..9b64734 100644
 > --- a/symbols.c
 > +++ b/symbols.c
 > @@ -64,8 +64,9 @@ static int namespace_ctl(int, struct symbol_namespace *, void *,
void *);
 >  static void symval_hash_init(void);
 >  static struct syment *symval_hash_search(ulong);
 >  static void symname_hash_init(void);
 > -static void symname_hash_install(struct syment *);
 > -static struct syment *symname_hash_search(char *);
 > +static void symname_hash_install(struct syment *[], struct syment *);
 > +static void symname_hash_remove(struct syment *[], struct syment *);
 > +static struct syment *symname_hash_search(struct syment *[], char *, int (*)(struct
syment *, char *));
 >  static void gnu_qsort(bfd *, void *, long, unsigned int, asymbol *, asymbol *);
 >  static int check_gnu_debuglink(bfd *);
 >  static int separate_debug_file_exists(const char *, unsigned long, int *);
 > @@ -1119,7 +1120,7 @@ symname_hash_init(void)
 >          struct syment *sp;
 > 
 >          for (sp = st->symtable; sp < st->symend; sp++)
 > -		symname_hash_install(sp);
 > +		symname_hash_install(st->symname_hash, sp);
 > 
 >  	if ((sp = symbol_search("__per_cpu_start")))
 >  		st->__per_cpu_start = sp->value;
 > @@ -1127,21 +1128,48 @@ symname_hash_init(void)
 >  		st->__per_cpu_end = sp->value;
 >  }
 > 
 > +static void
 > +mod_symtable_hash_install_range(struct syment *from, struct syment *to)
 > +{
 > +        struct syment *sp;
 > +
 > +	for (sp = from; sp <= to; sp++) {
 > +		if (sp != NULL) {
 > +			symname_hash_install(st->mod_symname_hash, sp);
 > +		}
 > +	}
 > +}
 > +
 > +static void
 > +mod_symtable_hash_remove_range(struct syment *from, struct syment *to)
 > +{
 > +        struct syment *sp;
 > +
 > +	for (sp = from; sp <= to; sp++) {
 > +		if (sp != NULL) {
 > +			symname_hash_remove(st->mod_symname_hash, sp);
 > +		}
 > +	}
 > +}
 > +
 >  /*
 >   *  Install a single static kernel symbol into the symname_hash.
 >   */
 >  static void
 > -symname_hash_install(struct syment *spn)
 > +symname_hash_install(struct syment *table[], struct syment *spn)
 >  {
 >  	struct syment *sp;
 >          int index;
 > 
 >          index = SYMNAME_HASH_INDEX(spn->name);
 > +	index = index > 0 ? index : -index;
 > +
 >  	spn->cnt = 1;
 > 
 > -        if ((sp = st->symname_hash[index]) == NULL)
 > -        	st->symname_hash[index] = spn;
 > -	else {
 > +        if ((sp = table[index]) == NULL) {
 > +		table[index] = spn;
 > +		spn->name_hash_next = NULL;
 > +	} else {
 >  		while (sp) {
 >  	        	if (STREQ(sp->name, spn->name)) {
 >  	                	sp->cnt++;
 > @@ -1151,23 +1179,67 @@ symname_hash_install(struct syment *spn)
 >  				sp = sp->name_hash_next;
 >  			else {
 >  				sp->name_hash_next = spn;
 > +				spn->name_hash_next = NULL;
 >  				break;
 >  			}
 >  		}
 >  	}
 >  }
 > 
 > +static void
 > +symname_hash_remove(struct syment *table[], struct syment *spn)
 > +{
 > +	struct syment *sp, **tmp;
 > +        int index, first_encounter = 1;
 > +
 > +        index = SYMNAME_HASH_INDEX(spn->name);
 > +	index = index > 0 ? index : -index;
 > +
 > +        if ((sp = table[index]) == NULL)
 > +		return;
 > +
 > +	for (tmp = &table[index], sp = table[index]; sp; ) {
 > +		if (STREQ(sp->name, spn->name)) {
 > +			if (sp != spn) {
 > +				sp->cnt--;
 > +				spn->cnt--;
 > +			} else if (!first_encounter) {
 > +				sp->cnt--;
 > +			} else {
 > +				*tmp = sp->name_hash_next;
 > +				first_encounter = 0;
 > +
 > +				tmp = &(*tmp)->name_hash_next;
 > +				sp = sp->name_hash_next;
 > +				spn->name_hash_next = NULL;
 > +				continue;
 > +			}
 > +		}
 > +		tmp = &sp->name_hash_next;
 > +		sp = sp->name_hash_next;
 > +	}
 > +}
 > +
 >  /*
 >   *  Static kernel symbol value search
 >   */
 >  static struct syment *
 > -symname_hash_search(char *name)
 > +symname_hash_search(struct syment *table[], char *name,
 > +		int (*skip_condition)(struct syment *, char *))
 >  {
 >  	struct syment *sp;
 > +	int index;
 > 
 > -        sp = st->symname_hash[SYMNAME_HASH_INDEX(name)];
 > +	index = SYMNAME_HASH_INDEX(name);
 > +	index = index > 0 ? index : -index;
 > +        sp = table[index];
 > 
 >  	while (sp) {
 > +		if (skip_condition && skip_condition(sp, name)) {
 > +			sp = sp->name_hash_next;
 > +			continue;
 > +		}
 > +
 >  		if (STREQ(sp->name, name))
 >  			return sp;
 >  		sp = sp->name_hash_next;
 > @@ -1595,6 +1667,7 @@ store_module_symbols_v1(ulong total, int mods_installed)
 >  				lm->mod_symend = sp;
 >  			}
 >  		}
 > +		mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend);
 >  	}
 > 
 >  	st->flags |= MODULE_SYMS;
 > @@ -2075,6 +2148,8 @@ store_module_symbols_v2(ulong total, int mods_installed)
 >  				lm->mod_init_symend = sp;
 >  			}
 >  		}
 > +		mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend);
 > +		mod_symtable_hash_install_range(lm->mod_init_symtable,
lm->mod_init_symend);
 >  	}
 > 
 >  	st->flags |= MODULE_SYMS;
 > @@ -4482,6 +4557,16 @@ symbol_query(char *s, char *print_pad, struct syment **spp)
 >  	return(cnt);
 >  }
 > 
 > +static int
 > +skip_symbols(struct syment *sp, char *s)
 > +{
 > +	int pseudos, skip = 0;
 > +	pseudos = (strstr(s, "_MODULE_START_") || strstr(s,
"_MODULE_END_") ||
 > +		strstr(s, "_MODULE_INIT_START_") || strstr(s,
"_MODULE_INIT_END_"));
 > +	if (!pseudos && MODULE_PSEUDO_SYMBOL(sp))
 > +		skip = 1;
 > +	return skip;
 > +}
 > 
 >  /*
 >   *  Return the syment of a symbol.
 > @@ -4489,58 +4574,16 @@ symbol_query(char *s, char *print_pad, struct syment **spp)
 >  struct syment *
 >  symbol_search(char *s)
 >  {
 > -	int i;
 > -        struct syment *sp_hashed, *sp, *sp_end;
 > -	struct load_module *lm;
 > -	int pseudos, search_init;
 > +        struct syment *sp_hashed, *sp;
 > 
 > -	sp_hashed = symname_hash_search(s);
 > +	sp_hashed = symname_hash_search(st->symname_hash, s, NULL);
 > 
 >          for (sp = sp_hashed ? sp_hashed : st->symtable; sp < st->symend;
sp++) {
 >                  if (STREQ(s, sp->name))
 >                          return(sp);
 >          }
 > 
 > -	pseudos = (strstr(s, "_MODULE_START_") || strstr(s,
"_MODULE_END_"));
 > -	search_init = FALSE;
 > -
 > -        for (i = 0; i < st->mods_installed; i++) {
 > -                lm = &st->load_modules[i];
 > -		if (lm->mod_flags & MOD_INIT)
 > -			search_init = TRUE;
 > -		sp = lm->mod_symtable;
 > -                sp_end = lm->mod_symend;
 > -
 > -                for ( ; sp <= sp_end; sp++) {
 > -                	if (!pseudos && MODULE_PSEUDO_SYMBOL(sp))
 > -                        	continue;
 > -                	if (STREQ(s, sp->name))
 > -                        	return(sp);
 > -                }
 > -        }
 > -
 > -	if (!search_init)
 > -		return((struct syment *)NULL);
 > -
 > -	pseudos = (strstr(s, "_MODULE_INIT_START_") || strstr(s,
"_MODULE_INIT_END_"));
 > -
 > -	for (i = 0; i < st->mods_installed; i++) {
 > -		lm = &st->load_modules[i];
 > -		if (!lm->mod_init_symtable)
 > -			continue;
 > -		sp = lm->mod_init_symtable;
 > -		sp_end = lm->mod_init_symend;
 > -
 > -		for ( ; sp < sp_end; sp++) {
 > -			if (!pseudos && MODULE_PSEUDO_SYMBOL(sp))
 > -				continue;
 > -
 > -			if (STREQ(s, sp->name))
 > -				return(sp);
 > -		}
 > -	}
 > -
 > -        return((struct syment *)NULL);
 > +	return symname_hash_search(st->mod_symname_hash, s, skip_symbols);
 >  }
 > 
 >  /*
 > @@ -5432,33 +5475,13 @@ value_symbol(ulong value)
 >  int
 >  symbol_exists(char *symbol)
 >  {
 > -	int i;
 > -        struct syment *sp, *sp_end;
 > -	struct load_module *lm;
 > +        struct syment *sp;
 > 
 > -	if ((sp = symname_hash_search(symbol)))
 > +	if ((sp = symname_hash_search(st->symname_hash, symbol, NULL)))
 >  		return TRUE;
 > 
 > -        for (i = 0; i < st->mods_installed; i++) {
 > -                lm = &st->load_modules[i];
 > -		sp = lm->mod_symtable;
 > -                sp_end = lm->mod_symend;
 > -
 > -                for ( ; sp < sp_end; sp++) {
 > -                	if (STREQ(symbol, sp->name))
 > -                        	return(TRUE);
 > -                }
 > -
 > -		if (lm->mod_init_symtable) {
 > -			sp = lm->mod_init_symtable;
 > -			sp_end = lm->mod_init_symend;
 > -
 > -			for ( ; sp < sp_end; sp++) {
 > -				if (STREQ(symbol, sp->name))
 > -					return(TRUE);
 > -			}
 > -		}
 > -	}
 > +	if ((sp = symname_hash_search(st->mod_symname_hash, symbol, NULL)))
 > +		return TRUE;
 > 
 >          return(FALSE);
 >  }
 > @@ -5515,7 +5538,7 @@ kernel_symbol_exists(char *symbol)
 >  {
 >  	struct syment *sp;
 > 
 > -        if ((sp = symname_hash_search(symbol)))
 > +        if ((sp = symname_hash_search(st->symname_hash, symbol, NULL)))
 >                  return TRUE;
 >  	else
 >          	return FALSE;
 > @@ -5527,7 +5550,7 @@ kernel_symbol_exists(char *symbol)
 >  struct syment *
 >  kernel_symbol_search(char *symbol)
 >  {
 > -	return symname_hash_search(symbol);
 > +	return symname_hash_search(st->symname_hash, symbol, NULL);
 >  }
 > 
 >  /*
 > @@ -12464,8 +12487,10 @@ store_load_module_symbols(bfd *bfd, int dynamic, void
*minisyms,
 >  		error(INFO, "%s: last symbol: %s is not _MODULE_END_%s?\n",
 >  			lm->mod_name, lm->mod_load_symend->name, lm->mod_name);
 > 
 > +	mod_symtable_hash_remove_range(lm->mod_symtable, lm->mod_symend);
 >          lm->mod_symtable = lm->mod_load_symtable;
 >          lm->mod_symend = lm->mod_load_symend;
 > +	mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend);
 > 
 >  	lm->mod_flags &= ~MOD_EXT_SYMS;
 >  	lm->mod_flags |= MOD_LOAD_SYMS;
 > @@ -12495,6 +12520,7 @@ delete_load_module(ulong base_addr)
 >          			req->name = lm->mod_namelist;
 >          			gdb_interface(req);
 >  			}
 > +			mod_symtable_hash_remove_range(lm->mod_symtable, lm->mod_symend);
 >  			if (lm->mod_load_symtable) {
 >                          	free(lm->mod_load_symtable);
 >                                  namespace_ctl(NAMESPACE_FREE,
 > @@ -12504,6 +12530,7 @@ delete_load_module(ulong base_addr)
 >  				unlink_module(lm);
 >  			lm->mod_symtable = lm->mod_ext_symtable;
 >  			lm->mod_symend = lm->mod_ext_symend;
 > +			mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend);
 >  			lm->mod_flags &= ~(MOD_LOAD_SYMS|MOD_REMOTE|MOD_NOPATCH);
 >  			lm->mod_flags |= MOD_EXT_SYMS;
 >  			lm->mod_load_symtable = NULL;
 > @@ -12532,6 +12559,7 @@ delete_load_module(ulong base_addr)
 >                          	req->name = lm->mod_namelist;
 >                          	gdb_interface(req);
 >  			}
 > +			mod_symtable_hash_remove_range(lm->mod_symtable, lm->mod_symend);
 >  			if (lm->mod_load_symtable) {
 >                          	free(lm->mod_load_symtable);
 >  				namespace_ctl(NAMESPACE_FREE,
 > @@ -12541,6 +12569,7 @@ delete_load_module(ulong base_addr)
 >  				unlink_module(lm);
 >  			lm->mod_symtable = lm->mod_ext_symtable;
 >  			lm->mod_symend = lm->mod_ext_symend;
 > +			mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend);
 >                          lm->mod_flags &=
~(MOD_LOAD_SYMS|MOD_REMOTE|MOD_NOPATCH);
 >                          lm->mod_flags |= MOD_EXT_SYMS;
 >                          lm->mod_load_symtable = NULL;
 > --
 > 2.29.2
 > 
 > --
 > Crash-utility mailing list
 > Crash-utility(a)redhat.com
 > 
https://listman.redhat.com/mailman/listinfo/crash-utility
 
 
 --
 Crash-utility mailing list
 Crash-utility(a)redhat.com
 
https://listman.redhat.com/mailman/listinfo/crash-utility