diff mbox series

[dwarves,v4] btf_encoder: switch func_states from a list to an array

Message ID 20250107190855.2312210-11-ihor.solodrai@pm.me (mailing list archive)
State New
Headers show
Series [dwarves,v4] btf_encoder: switch func_states from a list to an array | expand

Checks

Context Check Description
netdev/tree_selection success Not a local patch

Commit Message

Ihor Solodrai Jan. 7, 2025, 7:09 p.m. UTC
With only a single encoder, it's now easier to acummulate function
states into an array, and then sort it before merging the states and
adding the functions to BTF.

Previously a list (per encoder) was collected, and because the sorting
is required, the lists had to be converted into a temporary array in a
separate step.

Signed-off-by: Ihor Solodrai <ihor.solodrai@pm.me>
---
 btf_encoder.c | 95 ++++++++++++++++++++++++++++++---------------------
 1 file changed, 57 insertions(+), 38 deletions(-)
diff mbox series

Patch

diff --git a/btf_encoder.c b/btf_encoder.c
index da99fbb..78efd70 100644
--- a/btf_encoder.c
+++ b/btf_encoder.c
@@ -72,7 +72,6 @@  struct btf_encoder_func_annot {
 
 /* state used to do later encoding of saved functions */
 struct btf_encoder_func_state {
-	struct list_head node;
 	struct btf_encoder *encoder;
 	struct elf_function *elf;
 	uint32_t type_id_off;
@@ -134,7 +133,11 @@  struct btf_encoder {
 	struct elf_secinfo *secinfo;
 	size_t             seccnt;
 	int                encode_vars;
-	struct list_head   func_states;
+	struct {
+		struct btf_encoder_func_state *array;
+		int cnt;
+		int cap;
+	} func_states;
 	/* This is a list of elf_functions tables, one per ELF.
 	 * Multiple ELF modules can be processed in one pahole run,
 	 * so we have to store elf_functions tables per ELF.
@@ -1078,9 +1081,31 @@  static bool funcs__match(struct btf_encoder_func_state *s1,
 	return true;
 }
 
+static struct btf_encoder_func_state *btf_encoder__alloc_func_state(struct btf_encoder *encoder)
+{
+	struct btf_encoder_func_state *tmp;
+
+	if (encoder->func_states.cnt >= encoder->func_states.cap) {
+
+		/* We only need to grow to accommodate duplicate
+		 * function declarations across different CUs, so the
+		 * rate of the array growth shouldn't be high.
+		 */
+		encoder->func_states.cap += 64;
+
+		tmp = realloc(encoder->func_states.array, sizeof(*tmp) * encoder->func_states.cap);
+		if (!tmp)
+			return NULL;
+
+		encoder->func_states.array = tmp;
+	}
+
+	return &encoder->func_states.array[encoder->func_states.cnt++];
+}
+
 static int32_t btf_encoder__save_func(struct btf_encoder *encoder, struct function *fn, struct elf_function *func)
 {
-	struct btf_encoder_func_state *state = zalloc(sizeof(*state));
+	struct btf_encoder_func_state *state = btf_encoder__alloc_func_state(encoder);
 	struct ftype *ftype = &fn->proto;
 	struct btf *btf = encoder->btf;
 	struct llvm_annotation *annot;
@@ -1142,7 +1167,6 @@  static int32_t btf_encoder__save_func(struct btf_encoder *encoder, struct functi
 			idx++;
 		}
 	}
-	list_add_tail(&state->node, &encoder->func_states);
 	return 0;
 out:
 	zfree(&state->annots);
@@ -1219,17 +1243,15 @@  static int functions_cmp(const void *_a, const void *_b)
 
 static int saved_functions_cmp(const void *_a, const void *_b)
 {
-	struct btf_encoder_func_state * const *a = _a;
-	struct btf_encoder_func_state * const *b = _b;
+	const struct btf_encoder_func_state *a = _a;
+	const struct btf_encoder_func_state *b = _b;
 
-	return functions_cmp((*a)->elf, (*b)->elf);
+	return functions_cmp(a->elf, b->elf);
 }
 
-static int saved_functions_combine(void *_a, void *_b)
+static int saved_functions_combine(struct btf_encoder_func_state *a, struct btf_encoder_func_state *b)
 {
 	uint8_t optimized, unexpected, inconsistent;
-	struct btf_encoder_func_state *a = _a;
-	struct btf_encoder_func_state *b = _b;
 	int ret;
 
 	ret = strncmp(a->elf->name, b->elf->name,
@@ -1250,44 +1272,37 @@  static int saved_functions_combine(void *_a, void *_b)
 
 static void btf_encoder__delete_saved_funcs(struct btf_encoder *encoder)
 {
-	struct btf_encoder_func_state *pos, *s;
+	struct btf_encoder_func_state *state;
 
-	list_for_each_entry_safe(pos, s, &encoder->func_states, node) {
-		list_del(&pos->node);
-		free(pos->parms);
-		free(pos->annots);
-		free(pos);
+	for (int i = 0; i < encoder->func_states.cnt; i++) {
+		state = &encoder->func_states.array[i];
+		free(state->parms);
+		free(state->annots);
 	}
+
+	free(encoder->func_states.array);
+
+	encoder->func_states.array = NULL;
+	encoder->func_states.cnt = 0;
+	encoder->func_states.cap = 0;
 }
 
 static int btf_encoder__add_saved_funcs(struct btf_encoder *encoder, bool skip_encoding_inconsistent_proto)
 {
-	struct btf_encoder_func_state **saved_fns = NULL, *s;
-	int err = 0, i = 0, j, nr_saved_fns = 0;
-
-	/* Retrieve function states from the encoder, combine them
-	 * and sort by name, addr.
-	 */
-	list_for_each_entry(s, &encoder->func_states, node) {
-		nr_saved_fns++;
-	}
+	struct btf_encoder_func_state *saved_fns = encoder->func_states.array;
+	int nr_saved_fns = encoder->func_states.cnt;
+	int err = 0, i = 0, j;
 
 	if (nr_saved_fns == 0)
 		goto out;
 
-	saved_fns = calloc(nr_saved_fns, sizeof(*saved_fns));
-	if (!saved_fns) {
-		err = -ENOMEM;
-		goto out;
-	}
-
-	list_for_each_entry(s, &encoder->func_states, node) {
-		saved_fns[i++] = s;
-	}
+	/* Sort the saved_fns so that we can merge multiple states of
+	 * the "same" function into one, before adding it to the BTF.
+	 */
 	qsort(saved_fns, nr_saved_fns, sizeof(*saved_fns), saved_functions_cmp);
 
 	for (i = 0; i < nr_saved_fns; i = j) {
-		struct btf_encoder_func_state *state = saved_fns[i];
+		struct btf_encoder_func_state *state = &saved_fns[i];
 		bool add_to_btf = !skip_encoding_inconsistent_proto;
 
 		/* Compare across sorted functions that match by name/prefix;
@@ -1295,7 +1310,7 @@  static int btf_encoder__add_saved_funcs(struct btf_encoder *encoder, bool skip_e
 		 */
 		j = i + 1;
 
-		while (j < nr_saved_fns && saved_functions_combine(saved_fns[i], saved_fns[j]) == 0)
+		while (j < nr_saved_fns && saved_functions_combine(&saved_fns[i], &saved_fns[j]) == 0)
 			j++;
 
 		/* do not exclude functions with optimized-out parameters; they
@@ -1313,7 +1328,6 @@  static int btf_encoder__add_saved_funcs(struct btf_encoder *encoder, bool skip_e
 	}
 
 out:
-	free(saved_fns);
 	btf_encoder__delete_saved_funcs(encoder);
 
 	return err;
@@ -2404,7 +2418,7 @@  struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filenam
 		encoder->need_index_type = false;
 		encoder->array_index_id  = 0;
 		encoder->encode_vars = 0;
-		INIT_LIST_HEAD(&encoder->func_states);
+
 		if (!conf_load->skip_encoding_btf_vars)
 			encoder->encode_vars |= BTF_VAR_PERCPU;
 		if (conf_load->encode_btf_global_vars)
@@ -2417,6 +2431,11 @@  struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filenam
 
 		encoder->symtab = funcs->symtab;
 
+		/* Start with funcs->cnt. The array may grow in btf_encoder__alloc_func_state() */
+		encoder->func_states.array = zalloc(sizeof(*encoder->func_states.array) * funcs->cnt);
+		encoder->func_states.cap = funcs->cnt;
+		encoder->func_states.cnt = 0;
+
 		GElf_Ehdr ehdr;
 
 		if (gelf_getehdr(cu->elf, &ehdr) == NULL) {