Re: [PATCH v2 dwarves 4/5] btf_encoder: make elf_functions.entry an elf_function list

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 2024-10-09 at 23:35 +0000, Ihor Solodrai wrote:
> btf_encoder__save_func() accumulates observations of DWARF functions,
> maintaining an elf_function per function name.
> 
> Part of this routine is a funcs_match() call, which requires access to
> BTF implicitly referenced by btf_encoder_func_state.  In case when
> elf_functions table is maintained for each btf_encoder this is not an
> issue, because every btf_encoder_func_state available to this encoder
> can only reference its own BTF. However, if elf_functions becomes
> shared, existing elf_function/btf_encoder_function_state structs can
> be produced by other encoders with their own BTFs. In this case
> funcs_match() can not be called unless BTFs are available and writes
> to them are synchronized in some manner (which is not desirable).

Nit: Something is missing in explanation at this point.
     In the paragraph above you describe why funcs_match()
     can't be called concurrently.

     I think a sentence is needed explaining that the solution is to
     forgo concurrent funcs_match() calls and simply accumulate info
     about all functions in DWARF.

> Accumulated states are later merged between encoders in
> btf_encoder__add_saved_funcs(). To enable sharing of the elf_functions
> table between encoders, two members are introduced to struct
> elf_function:
>   - elf_function *next - to enable linked-list
>   - btf_encoder *owner - to find elf_function corresponding to a
>     particular encoder in a list
> 
> Each element of elf_functions->entries is a head of a list that stores
> elf_function structs one for each encoder that searched for this
> function name at least once.
> 
> btf_encoder__find_function() is modified to perform the search on
> shared elf_functions table, and atomically update a corresponding list
> as necessary.
> 
> At this point each btf_encoder is still maintaining it's own
> elf_functions table, but the updated implementation is used.
> 
> Suggested-by: Eduard Zingerman <eddyz87@xxxxxxxxx>
> Signed-off-by: Ihor Solodrai <ihor.solodrai@xxxxx>
> ---

Aside from a few nits, I think the logic makes sense.
Not sure if it is worth it to separate patches #4 and #5.

>  btf_encoder.c | 117 +++++++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 93 insertions(+), 24 deletions(-)
> 
> diff --git a/btf_encoder.c b/btf_encoder.c
> index 9e05b56..f88c2e1 100644
> --- a/btf_encoder.c
> +++ b/btf_encoder.c
> @@ -86,10 +86,15 @@ struct btf_encoder_func_state {
>  };
>  
>  struct elf_function {
> +	// bsearch key
>  	const char	*name;
> -	char		*alias;
> -	bool		 generated;
> -	size_t		prefixlen;
> +	size_t		 prefixlen;
> +	// for list search
> +	struct elf_function *next;
> +	const struct btf_encoder *owner;

Nit: 'encoder' might be a better name for this field.

> +	// encoder-specific state
> +	char *alias;
> +	bool generated;
>  	struct btf_encoder_func_state state;
>  };
>  
> @@ -106,7 +111,7 @@ struct elf_functions {
>  	struct list_head node; // for elf_functions_list
>  	Elf *elf; // source ELF
>  	struct elf_symtab *symtab;
> -	struct elf_function *entries;
> +	struct elf_function *entries; // an array, each element is a head of a list
>  	int cnt;
>  	int suffix_cnt; /* number of .isra, .part etc */
>  };
> @@ -169,10 +174,29 @@ static struct elf_functions *elf_functions__get(Elf *elf)
>  	return NULL;
>  }
>  
> -static inline void elf_functions__delete(struct elf_functions *funcs)
> +static void __elf_functions__delete(struct elf_functions *funcs)
>  {
> +	for (int i = 0; i < funcs->cnt; i++) {
> +		// free all list elements except the head
> +		struct elf_function *func = funcs->entries[i].next;
> +
> +		while (func) {
> +			struct elf_function *next = func->next;
> +
> +			free(func->alias);
> +			zfree(&func->state.annots);
> +			zfree(&func->state.parms);
> +			free(func);
> +			func = next;
> +		}
> +	}
>  	free(funcs->entries);
>  	elf_symtab__delete(funcs->symtab);
> +}
> +
> +static inline void elf_functions__delete(struct elf_functions *funcs)
> +{
> +	__elf_functions__delete(funcs);
>  	list_del(&funcs->node);
>  	free(funcs);
>  }
> @@ -204,6 +228,7 @@ out_error:
>  	return NULL;
>  }
>  
> +

Nit: useless newline.

>  int btf_encoder__pre_cus__load_module(struct process_dwflmod_parms *parms, Dwfl_Module *mod, Dwarf *dw, Elf *elf)
>  {
>  	struct elf_functions *funcs = elf_functions__new(elf);
> @@ -1301,12 +1326,30 @@ static int32_t btf_encoder__add_func(struct btf_encoder *encoder, struct functio
>  	return 0;
>  }
>  
> +#define for_each_elf_function(func, head) \
> +	for (struct elf_function *func = head; func; func = func->next)
>
> +static inline struct elf_function *find_elf_function_in_list(struct elf_function *list_head,
> +							     const struct btf_encoder *encoder)

Nit: just 'find_elf_function'?

> +{
> +	for_each_elf_function(f, list_head) {
> +		if (f->owner == encoder)
> +			return f;
> +	}
> +
> +	return NULL;
> +}
> +
>  static int btf_encoder__add_saved_funcs(struct btf_encoder *encoder)
>  {
>  	int i;
>  
>  	for (i = 0; i < encoder->functions.cnt; i++) {
> -		struct elf_function *func = &encoder->functions.entries[i];
> +		struct elf_function *func = find_elf_function_in_list(&encoder->functions.entries[i], encoder);
> +
> +		if (!func)
> +			continue;
> +
>  		struct btf_encoder_func_state *state = &func->state;
>  		struct btf_encoder *other_encoder = NULL;
>  

[...]






[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux