[PATCH dwarves 6/6] btf_encoder: switch to shared elf_functions table

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

 



Do not collect functions from ELF for each new btf_encoder, and
instead set a pointer to a shared elf_functions table, built
beforehand by btf_encoder__pre_cus__load_module().

Add a mutex to elf_functions_entry for synchronization between
encoders. This way one encoder will wait for another only in an
unlikely situation when both process the same function name.

Change the algorithm of btf_encoder__add_saved_funcs(): traverse
elf_functions table once, merge function state for each
elf_functions_entry, and add each function to the BTF of the owner of
the first elf_function in this entry.

Do not call btf_encoder__add_saved_funcs() on every
btf_encoder__add_encoder(). Instead, introduce
btf_encoder__merge_encoders() function that does that.

Signed-off-by: Ihor Solodrai <ihor.solodrai@xxxxx>
---
 btf_encoder.c | 132 ++++++++++++++++++++++++--------------------------
 btf_encoder.h |   3 +-
 pahole.c      |  25 +++++-----
 3 files changed, 80 insertions(+), 80 deletions(-)

diff --git a/btf_encoder.c b/btf_encoder.c
index 33cd9eb..b230aee 100644
--- a/btf_encoder.c
+++ b/btf_encoder.c
@@ -111,6 +111,7 @@ struct elf_functions_entry {
 	const char *name;
 	size_t prefixlen;
 	struct elf_function *funcs; // list of elf_function
+	pthread_mutex_t mutex;
 };
 
 struct elf_functions {
@@ -155,7 +156,7 @@ struct btf_encoder {
 		int		allocated;
 		uint32_t	shndx;
 	} percpu;
-	struct elf_functions functions;
+	struct elf_functions *functions;
 };
 
 struct btf_func {
@@ -259,8 +260,6 @@ int btf_encoder__pre_cus__load_module(struct process_dwflmod_parms *parms, Dwfl_
 static LIST_HEAD(encoders);
 static pthread_mutex_t encoders__lock = PTHREAD_MUTEX_INITIALIZER;
 
-static int btf_encoder__add_saved_funcs(struct btf_encoder *encoder);
-
 /* mutex only needed for add/delete, as this can happen in multiple encoding
  * threads.  Traversal of the list is currently confined to thread collection.
  */
@@ -906,7 +905,7 @@ static int32_t btf_encoder__add_var_secinfo(struct btf_encoder *encoder, uint32_
 	return gobuffer__add(&encoder->percpu_secinfo, &si, sizeof(si));
 }
 
-int32_t btf_encoder__add_encoder(struct btf_encoder *encoder, struct btf_encoder *other)
+static int32_t btf_encoder__add_encoder(struct btf_encoder *encoder, struct btf_encoder *other)
 {
 	struct gobuffer *var_secinfo_buf = &other->percpu_secinfo;
 	size_t sz = gobuffer__size(var_secinfo_buf);
@@ -919,8 +918,6 @@ int32_t btf_encoder__add_encoder(struct btf_encoder *encoder, struct btf_encoder
 	if (encoder == other)
 		return 0;
 
-	btf_encoder__add_saved_funcs(other);
-
 	for (i = 0; i < nr_var_secinfo; i++) {
 		vsi = (struct btf_var_secinfo *)var_secinfo_buf->entries + i;
 		type_id = next_type_id + vsi->type - 1; /* Type ID starts from 1 */
@@ -932,6 +929,25 @@ int32_t btf_encoder__add_encoder(struct btf_encoder *encoder, struct btf_encoder
 	return btf__add_btf(encoder->btf, other->btf);
 }
 
+int btf_encoder__merge_encoders(struct btf_encoder *base_encoder, struct btf_encoder **encoders, int nr_encoders)
+{
+	int err;
+
+	err = btf_encoder__add_saved_funcs(base_encoder);
+	if (err < 0)
+		return err;
+
+	for (int i = 0; i < nr_encoders; i++) {
+		if (base_encoder == encoders[i])
+			continue;
+		err = btf_encoder__add_encoder(base_encoder, encoders[i]);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
 static int32_t btf_encoder__add_datasec(struct btf_encoder *encoder, const char *section_name)
 {
 	struct gobuffer *var_secinfo_buf = &encoder->percpu_secinfo;
@@ -997,7 +1013,7 @@ static int32_t btf_encoder__add_decl_tag(struct btf_encoder *encoder, const char
 	return id;
 }
 
-static void btf_encoder__log_func_skip(struct btf_encoder *encoder, struct elf_function *func,
+static void btf_encoder__log_func_skip(const struct btf_encoder *encoder, struct elf_function *func,
 				       const char *fmt, ...)
 {
 	va_list ap;
@@ -1033,7 +1049,7 @@ static int fwd__kind(const struct btf_type *t)
 	return btf_kind(t);
 }
 
-static bool types__match(struct btf_encoder *encoder,
+static bool types__match(const struct btf_encoder *encoder,
 			 struct btf *btf1, int type_id1,
 			 struct btf *btf2, int type_id2)
 {
@@ -1132,7 +1148,7 @@ static bool types__match(struct btf_encoder *encoder,
 	return false;
 }
 
-static bool funcs__match(struct btf_encoder *encoder, struct elf_function *func,
+static bool funcs__match(const struct btf_encoder *encoder, struct elf_function *func,
 			 struct btf *btf1, struct btf_encoder_func_state *s1,
 			 struct btf *btf2, struct btf_encoder_func_state *s2)
 {
@@ -1346,44 +1362,46 @@ static inline struct elf_function *find_elf_function_in_entry(struct elf_functio
 	return NULL;
 }
 
-static int btf_encoder__add_saved_funcs(struct btf_encoder *encoder)
+
+// Each elf_functions_entry contains a variable number of elf_function
+// structs, because not all encoders encountered a particular
+// function.  However each function encountered at least once needs to be
+// added to BTF _somewhere_. Here we traverse the entire elf_functions
+// table, and for each array of elf_function structs the function is
+// added to the BTF of the encoder of the first elf_function in the array.
+int btf_encoder__add_saved_funcs(struct btf_encoder *encoder)
 {
-	int i;
+	struct elf_functions *functions = encoder->functions;
 
-	for (i = 0; i < encoder->functions.cnt; i++) {
-		struct elf_function *func = find_elf_function_in_entry(&encoder->functions.entries[i], encoder);
+	for (int i = 0; i < functions->cnt; i++) {
+		struct elf_functions_entry *entry = &functions->entries[i];
 
-		if (!func)
+		if (!entry->funcs)
 			continue;
 
+		struct elf_function *func = entry->funcs;
 		struct btf_encoder_func_state *state = &func->state;
-		struct btf_encoder *other_encoder = NULL;
 
 		if (!state->initialized || state->processed)
 			continue;
-		/* merge optimized-out status across encoders; since each
-		 * encoder has the same elf symbol table we can use the
-		 * same index to access the same elf symbol.
-		 */
-		btf_encoders__for_each_encoder(other_encoder) {
-			struct elf_function *other_func;
-			struct btf_encoder_func_state *other_state;
-			uint8_t optimized, unexpected, inconsistent;
-			other_func = find_elf_function_in_entry(&other_encoder->functions.entries[i], other_encoder);
 
-			if (other_encoder == encoder || !other_func)
+		for_each_elf_function(other_func, entry) {
+			if (func == other_func)
 				continue;
 
-			other_state = &other_func->state;
-			if (!other_state->initialized)
+			struct btf_encoder_func_state *other_state = &other_func->state;
+			uint8_t optimized, unexpected, inconsistent;
+
+			if (!other_func || !other_state->initialized || other_state->processed)
 				continue;
+
 			optimized = state->optimized_parms | other_state->optimized_parms;
 			unexpected = state->unexpected_reg | other_state->unexpected_reg;
 			inconsistent = state->inconsistent_proto | other_state->inconsistent_proto;
 			if (!unexpected && !inconsistent &&
-			    !funcs__match(encoder, func,
-					  encoder->btf, state,
-					  other_encoder->btf, other_state))
+			    !funcs__match(func->owner, func,
+					  func->owner->btf, state,
+					  other_func->owner->btf, other_state))
 				inconsistent = 1;
 			state->optimized_parms = other_state->optimized_parms = optimized;
 			state->unexpected_reg = other_state->unexpected_reg = unexpected;
@@ -1397,7 +1415,7 @@ static int btf_encoder__add_saved_funcs(struct btf_encoder *encoder)
 		 * unexpected register use or multiple inconsistent prototypes.
 		 */
 		if (!state->unexpected_reg && !state->inconsistent_proto) {
-			if (btf_encoder__add_func(encoder, NULL, func))
+			if (btf_encoder__add_func((struct btf_encoder *)func->owner, NULL, func))
 				return -1;
 		}
 		state->processed = 1;
@@ -1466,6 +1484,7 @@ static int elf_functions__collect_function(struct elf_functions *functions, GElf
 		functions->suffix_cnt++;
 		entry->prefixlen = suffix - name;
 	}
+	pthread_mutex_init(&entry->mutex, NULL);
 	functions->cnt++;
 
 	return 0;
@@ -1477,11 +1496,12 @@ static struct elf_function *btf_encoder__find_function(const struct btf_encoder
 	struct elf_function *func = NULL;
 	struct elf_functions_entry key = { .name = name, .prefixlen = prefixlen };
 	struct elf_functions_entry *entry = bsearch(&key,
-						    encoder->functions.entries,
-						    encoder->functions.cnt,
+						    encoder->functions->entries,
+						    encoder->functions->cnt,
 						    sizeof(key),
 						    functions_cmp);
 	if (entry) {
+		pthread_mutex_lock(&entry->mutex);
 		// If entry is found then there is a name match.
 		func = find_elf_function_in_entry(entry, encoder);
 		// However if there is no elf_function for this encoder in the entry,
@@ -1495,6 +1515,7 @@ static struct elf_function *btf_encoder__find_function(const struct btf_encoder
 			func->next = entry->funcs;
 			entry->funcs = func;
 		}
+		pthread_mutex_unlock(&entry->mutex);
 	}
 
 	return func;
@@ -2184,9 +2205,6 @@ int btf_encoder__encode(struct btf_encoder *encoder)
 	bool should_tag_kfuncs;
 	int err;
 
-	/* for single-threaded case, saved funcs are added here */
-	btf_encoder__add_saved_funcs(encoder);
-
 	if (gobuffer__size(&encoder->percpu_secinfo) != 0)
 		btf_encoder__add_datasec(encoder, PERCPU_SECTION);
 
@@ -2236,11 +2254,8 @@ int btf_encoder__encode(struct btf_encoder *encoder)
 		err = btf_encoder__write_elf(encoder, encoder->btf, BTF_ELF_SEC);
 	}
 
-	// TODO: after moving encoders to shared elf_functions,
-	// replace elf_functions__get(encoder->functions.elf) here
-	// with encoder->functions
-	// The pointer to shared elf_functions will be set in btf_encoder__new
-	elf_functions__delete(elf_functions__get(encoder->functions.elf));
+	// Delete the shared elf_functions table, because we are done encoding
+	elf_functions__delete(encoder->functions);
 
 	return err;
 }
@@ -2372,25 +2387,6 @@ static int elf_functions__collect(struct elf_functions *functions)
 	return 0;
 }
 
-static int btf_encoder__collect_symbols(struct btf_encoder *encoder, bool collect_percpu_vars)
-{
-	int err;
-
-	err = elf_functions__collect(&encoder->functions);
-	if (err)
-		return err;
-	if (encoder->verbose)
-		printf("Found %d functions!\n", encoder->functions.cnt);
-
-	if (collect_percpu_vars) {
-		err = btf_encoder__collect_percpu_vars(encoder);
-		if (err)
-			return err;
-	}
-
-	return 0;
-}
-
 static bool ftype__has_arg_names(const struct ftype *ftype)
 {
 	struct parameter *param;
@@ -2584,8 +2580,7 @@ struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filenam
 				printf("%s: '%s' doesn't have symtab.\n", __func__, cu->filename);
 			goto out;
 		}
-		encoder->functions.symtab = encoder->symtab;
-		encoder->functions.elf = cu->elf;
+		encoder->functions = elf_functions__get(cu->elf);
 
 		/* index the ELF sections for later lookup */
 
@@ -2616,8 +2611,10 @@ struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filenam
 		if (!encoder->percpu.shndx && encoder->verbose)
 			printf("%s: '%s' doesn't have '%s' section\n", __func__, cu->filename, PERCPU_SECTION);
 
-		if (btf_encoder__collect_symbols(encoder, !encoder->skip_encoding_vars))
-			goto out_delete;
+		if (!encoder->skip_encoding_vars) {
+			if (btf_encoder__collect_percpu_vars(encoder))
+				goto out_delete;
+		}
 
 		if (encoder->verbose)
 			printf("File %s:\n", cu->filename);
@@ -2642,8 +2639,7 @@ void btf_encoder__delete(struct btf_encoder *encoder)
 	zfree(&encoder->source_filename);
 	btf__free(encoder->btf);
 	encoder->btf = NULL;
-
-	__elf_functions__delete(&encoder->functions);
+	elf_symtab__delete(encoder->symtab);
 
 	encoder->percpu.allocated = encoder->percpu.var_cnt = 0;
 	free(encoder->percpu.vars);
@@ -2746,7 +2742,7 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co
 			continue;
 		if (!ftype__has_arg_names(&fn->proto))
 			continue;
-		if (encoder->functions.cnt) {
+		if (encoder->functions->cnt) {
 			const char *name;
 
 			name = function__name(fn);
@@ -2762,7 +2758,7 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co
 					save = true;
 				else
 					func->generated = true;
-			} else if (encoder->functions.suffix_cnt &&
+			} else if (encoder->functions->suffix_cnt &&
 				   conf_load->btf_gen_optimized) {
 				/* falling back to name.isra.0 match if no exact
 				 * match is found; only bother if we found any
diff --git a/btf_encoder.h b/btf_encoder.h
index ee91444..859779f 100644
--- a/btf_encoder.h
+++ b/btf_encoder.h
@@ -25,7 +25,8 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co
 
 struct btf *btf_encoder__btf(struct btf_encoder *encoder);
 
-int btf_encoder__add_encoder(struct btf_encoder *encoder, struct btf_encoder *other);
+int btf_encoder__add_saved_funcs(struct btf_encoder *encoder);
+int btf_encoder__merge_encoders(struct btf_encoder *base_encoder, struct btf_encoder **encoders, int nr_encoders);
 
 int btf_encoder__pre_cus__load_module(struct process_dwflmod_parms *parms, Dwfl_Module *mod, Dwarf *dw, Elf *elf);
 
diff --git a/pahole.c b/pahole.c
index 239eb13..3251a5b 100644
--- a/pahole.c
+++ b/pahole.c
@@ -3265,23 +3265,23 @@ static int pahole_threads_collect(struct conf_load *conf, int nr_threads, void *
 				  int error)
 {
 	struct thread_data **threads = (struct thread_data **)thr_data;
+	struct btf_encoder *encoders[nr_threads];
 	int i;
 	int err = 0;
 
 	if (error)
 		goto out;
 
-	for (i = 0; i < nr_threads; i++) {
-		/*
-		 * Merge content of the btf instances of worker threads to the btf
-		 * instance of the primary btf_encoder.
-                */
-		if (!threads[i]->btf)
-			continue;
-		err = btf_encoder__add_encoder(btf_encoder, threads[i]->encoder);
-		if (err < 0)
-			goto out;
-	}
+	for (i = 0; i < nr_threads; i++)
+		encoders[i] = threads[i]->encoder;
+
+	/*
+	 * Merge content of the btf instances of worker threads to the btf
+	 * instance of the primary btf_encoder.
+	 */
+	err = btf_encoder__merge_encoders(btf_encoder, encoders, nr_threads);
+	if (err < 0)
+		goto out;
 	err = 0;
 
 out:
@@ -3924,6 +3924,9 @@ try_sole_arg_as_class_names:
 			exit(1);
 		}
 
+		if (conf_load.nr_jobs <= 1 || conf_load.reproducible_build)
+			btf_encoder__add_saved_funcs(btf_encoder);
+
 		err = btf_encoder__encode(btf_encoder);
 		if (err) {
 			fputs("Failed to encode BTF\n", stderr);
-- 
2.34.1







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

  Powered by Linux