diff mbox series

core/device: Remove redundant malloc

Message ID 20190219052750.10694-1-jniethe5@gmail.com
State Superseded
Headers show
Series core/device: Remove redundant malloc | expand

Checks

Context Check Description
snowpatch_ozlabs/apply_patch success master/apply_patch Successfully applied
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot fail Test snowpatch/job/snowpatch-skiboot on branch master

Commit Message

Jordan Niethe Feb. 19, 2019, 5:27 a.m. UTC
From: jordan <jpn@pasglop.ozlabs.ibm.com>

Currently dt_new_addr() / dt_new_2addr() malloc a scatch buffer for the
node name. This is then duplicated in new_node(). This makes the initial
allocation redundant. To address this the allocation was removed from
dt_new_addr() / dt_new_2addr() and new_node() was changed to a varadic
function to accomodate the different name format.

Ideally vsnprintf() would be used to calculate the length of the
resulting name so a buffer could be dynamically allocated.
This would then be filled with another call to vsnprintf(). However the
implemenation of vsnprintf() does not behave correctly when called with
a size of 0 so this is not possible.
Instead a statically allocated buffer is used. This assumes a maximum
length for a name.
The optimization for ro memory names in take_name() is no longer
peformed. This is because the arguements to new_node() are intended for
vsnprintf() and can not be readly checked using is_rodata().
This does not significantly impact memory usage.

Signed-off-by: Jordan Niethe <jniethe5@gmail.com>
---
 core/device.c | 41 ++++++++++++++++++++---------------------
 1 file changed, 20 insertions(+), 21 deletions(-)

Comments

Oliver O'Halloran Feb. 19, 2019, 5:42 a.m. UTC | #1
On Tue, Feb 19, 2019 at 4:28 PM Jordan Niethe <jniethe5@gmail.com> wrote:
>
> From: jordan <jpn@pasglop.ozlabs.ibm.com>
>
> Currently dt_new_addr() / dt_new_2addr() malloc a scatch buffer for the
> node name. This is then duplicated in new_node(). This makes the initial
> allocation redundant. To address this the allocation was removed from
> dt_new_addr() / dt_new_2addr() and new_node() was changed to a varadic
> function to accomodate the different name format.
>
> Ideally vsnprintf() would be used to calculate the length of the
> resulting name so a buffer could be dynamically allocated.
> This would then be filled with another call to vsnprintf(). However the
> implemenation of vsnprintf() does not behave correctly when called with
> a size of 0 so this is not possible.
> Instead a statically allocated buffer is used. This assumes a maximum
> length for a name.

> The optimization for ro memory names in take_name() is no longer
> peformed. This is because the arguements to new_node() are intended for
> vsnprintf() and can not be readly checked using is_rodata().
> This does not significantly impact memory usage.

So on P9 systems we have a lot of cores and each core has a seperate
DT node which is populated with static strings. It might be worth
looking into how this affects memory usage there.

Also, we could check if there is a format string indicator (the %) in
the name and still do the rodata trick if we can be sure that it's a
static string.

>
> Signed-off-by: Jordan Niethe <jniethe5@gmail.com>
> ---
>  core/device.c | 41 ++++++++++++++++++++---------------------
>  1 file changed, 20 insertions(+), 21 deletions(-)
>
> diff --git a/core/device.c b/core/device.c
> index 6364a60e93ec..7f8bb929a184 100644
> --- a/core/device.c
> +++ b/core/device.c
> @@ -44,15 +44,31 @@ static void free_name(const char *name)
>                 free((char *)name);
>  }
>
> -static struct dt_node *new_node(const char *name)
> +static struct dt_node *new_node(const char *fmt, ...)
>  {
> +       const size_t max_name = 256;

you can drop this and use sizeof(name) as the param for vsnprintf()

> +       char name[max_name];

bring this down one line for REVERSE-CHRISTMAS-TREE variable declarations

>         struct dt_node *node = malloc(sizeof *node);
> +       size_t len = 0;
> +       va_list args;
> +
>         if (!node) {
>                 prerror("Failed to allocate node\n");
>                 abort();
>         }
>
> -       node->name = take_name(name);
> +       va_start(args, fmt);
> +       len = vsnprintf(name, max_name, fmt, args);
> +       va_end(args);
> +
> +       len++;

is len being used at all here?

> +
> +       node->name = strdup(name);
> +       if (!node->name) {
> +               prerror("Failed to allocate copy of name");
> +               abort();
> +       }
> +
>         node->parent = NULL;
>         list_head_init(&node->properties);
>         list_head_init(&node->children);
> @@ -208,18 +224,10 @@ struct dt_node *dt_find_by_name_addr(struct dt_node *parent, const char *name,
>  struct dt_node *dt_new_addr(struct dt_node *parent, const char *name,
>                             uint64_t addr)
>  {
> -       char *lname;
>         struct dt_node *new;
> -       size_t len;
>
>         assert(parent);
> -       len = strlen(name) + STR_MAX_CHARS(addr) + 2;
> -       lname = malloc(len);
> -       if (!lname)
> -               return NULL;
> -       snprintf(lname, len, "%s@%llx", name, (long long)addr);
> -       new = new_node(lname);
> -       free(lname);
> +       new = new_node("%s@%llx", name, (long long)addr);
>         if (!dt_attach_root(parent, new)) {
>                 dt_destroy(new);
>                 return NULL;
> @@ -230,19 +238,10 @@ struct dt_node *dt_new_addr(struct dt_node *parent, const char *name,
>  struct dt_node *dt_new_2addr(struct dt_node *parent, const char *name,
>                              uint64_t addr0, uint64_t addr1)
>  {
> -       char *lname;
>         struct dt_node *new;
> -       size_t len;
>         assert(parent);
>
> -       len = strlen(name) + 2*STR_MAX_CHARS(addr0) + 3;
> -       lname = malloc(len);
> -       if (!lname)
> -               return NULL;
> -       snprintf(lname, len, "%s@%llx,%llx",
> -                name, (long long)addr0, (long long)addr1);
> -       new = new_node(lname);
> -       free(lname);
> +       new = new_node("%s@%llx,%llx", name, (long long)addr0, (long long)addr1);
>         if (!dt_attach_root(parent, new)) {
>                 dt_destroy(new);
>                 return NULL;
> --
> 2.19.1
>
diff mbox series

Patch

diff --git a/core/device.c b/core/device.c
index 6364a60e93ec..7f8bb929a184 100644
--- a/core/device.c
+++ b/core/device.c
@@ -44,15 +44,31 @@  static void free_name(const char *name)
 		free((char *)name);
 }
 
-static struct dt_node *new_node(const char *name)
+static struct dt_node *new_node(const char *fmt, ...)
 {
+	const size_t max_name = 256;
+	char name[max_name];
 	struct dt_node *node = malloc(sizeof *node);
+	size_t len = 0;
+	va_list args;
+
 	if (!node) {
 		prerror("Failed to allocate node\n");
 		abort();
 	}
 
-	node->name = take_name(name);
+	va_start(args, fmt);
+	len = vsnprintf(name, max_name, fmt, args);
+	va_end(args);
+
+	len++;
+
+	node->name = strdup(name);
+	if (!node->name) {
+		prerror("Failed to allocate copy of name");
+		abort();
+	}
+
 	node->parent = NULL;
 	list_head_init(&node->properties);
 	list_head_init(&node->children);
@@ -208,18 +224,10 @@  struct dt_node *dt_find_by_name_addr(struct dt_node *parent, const char *name,
 struct dt_node *dt_new_addr(struct dt_node *parent, const char *name,
 			    uint64_t addr)
 {
-	char *lname;
 	struct dt_node *new;
-	size_t len;
 
 	assert(parent);
-	len = strlen(name) + STR_MAX_CHARS(addr) + 2;
-	lname = malloc(len);
-	if (!lname)
-		return NULL;
-	snprintf(lname, len, "%s@%llx", name, (long long)addr);
-	new = new_node(lname);
-	free(lname);
+	new = new_node("%s@%llx", name, (long long)addr);
 	if (!dt_attach_root(parent, new)) {
 		dt_destroy(new);
 		return NULL;
@@ -230,19 +238,10 @@  struct dt_node *dt_new_addr(struct dt_node *parent, const char *name,
 struct dt_node *dt_new_2addr(struct dt_node *parent, const char *name,
 			     uint64_t addr0, uint64_t addr1)
 {
-	char *lname;
 	struct dt_node *new;
-	size_t len;
 	assert(parent);
 
-	len = strlen(name) + 2*STR_MAX_CHARS(addr0) + 3;
-	lname = malloc(len);
-	if (!lname)
-		return NULL;
-	snprintf(lname, len, "%s@%llx,%llx",
-		 name, (long long)addr0, (long long)addr1);
-	new = new_node(lname);
-	free(lname);
+	new = new_node("%s@%llx,%llx", name, (long long)addr0, (long long)addr1);
 	if (!dt_attach_root(parent, new)) {
 		dt_destroy(new);
 		return NULL;