Skip to contentSkip to conversation

Small optimizations for code using g_malloc0 + memset/memcpy

PATCH Applied Thomas Huth 5 participants 17 messages Oct 8, 2015 – Oct 9, 2015

v1 of 2 Applied Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover Small optimizations for code using g_malloc0 + memset/memcpy

There are a couple of spots in the QEMU code which use g_malloc0, directly followed by a memset or memcpy which fill the whole allocated buffer. In this case it either does not make sense to zero the buffer via g_malloc0 first (so g_malloc should be used instead), or if the second command is a memset(..., 0, ...), then the memset does not make much sense, of course, since the buffer has already been zeroed by the g_malloc0.

Thomas Huth (5):
hw/dma/pxa2xx: Remove superfluous memset hw/scsi/spapr_vscsi: Remove superfluous memset hw/input/tsc210x: Remove superfluous memset tests/i44fx-test: No need for zeroing memory before memset linux-user/syscall: Replace g_malloc0 + memcpy with g_memdup

 hw/dma/pxa2xx_dma.c   | 1 -
 hw/input/tsc210x.c    | 8 ++------
 hw/scsi/spapr_vscsi.c | 1 -
 linux-user/syscall.c  | 3 +--
 tests/i440fx-test.c   | 2 +-
 5 files changed, 4 insertions(+), 11 deletions(-)
Signature · 1 line
1.8.3.1
#1 lore raw

PATCH 1/5 hw/dma/pxa2xx: Remove superfluous memset

g_malloc0 already clears the memory, so no need for the additional memset here.

---
 hw/dma/pxa2xx_dma.c | 1 -
 1 file changed, 1 deletion(-)
hw/dma/pxa2xx_dma.c +0 -1
index d4501fb..3f0a720 100644
@@ -461,7 +461,6 @@ static int pxa2xx_dma_init(SysBusDevice *sbd)
 
     s->chan = g_malloc0(sizeof(PXA2xxDMAChannel) * s->channels);
 
-    memset(s->chan, 0, sizeof(PXA2xxDMAChannel) * s->channels);
     for (i = 0; i < s->channels; i ++)
         s->chan[i].state = DCSR_STOPINTR;
 
Signature · 1 line
1.8.3.1
#2 lore raw

Re: [Qemu-devel] [PATCH 1/5] hw/dma/pxa2xx: Remove superfluous memset

Quoted 13 lines · Thomas Huth

g_malloc0 already clears the memory, so no need for the additional memset here.

---
 hw/dma/pxa2xx_dma.c | 1 -
 1 file changed, 1 deletion(-)
hw/dma/pxa2xx_dma.c +0 -0
index d4501fb..3f0a720 100644

hw/dma/pxa2xx_dma.c static int pxa2xx_dma_init(SysBusDevice *sbd) · line 462

Quoted 2 lines
hw/dma/pxa2xx_dma.c +0 -0
@@ -461,7 +461,6 @@ static int pxa2xx_dma_init(SysBusDevice *sbd)
 
     s->chan = g_malloc0(sizeof(PXA2xxDMAChannel) * s->channels);

As long as we're here, this should probably be switched to g_new0(), in part to avoid any chance that the multiply can overflow.

hw/dma/pxa2xx_dma.c static int pxa2xx_dma_init(SysBusDevice *sbd) · line 464

Quoted 2 lines
hw/dma/pxa2xx_dma.c +0 -1
-    memset(s->chan, 0, sizeof(PXA2xxDMAChannel) * s->channels);

But this part is correct.

Signature · 2 lines
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org
#3 lore raw

Re: [Qemu-devel] [PATCH 1/5] hw/dma/pxa2xx: Remove superfluous memset

Quoted 15 lines · Eric Blake
Quoted 14 lines · Thomas Huth

g_malloc0 already clears the memory, so no need for the additional memset here.

---
 hw/dma/pxa2xx_dma.c | 1 -
 1 file changed, 1 deletion(-)
hw/dma/pxa2xx_dma.c +0 -0
index d4501fb..3f0a720 100644
@@ -461,7 +461,6 @@ static int pxa2xx_dma_init(SysBusDevice *sbd)
 
Quoted 4 lines

hw/dma/pxa2xx_dma.c static int pxa2xx_dma_init(SysBusDevice *sbd) · line 462

Quoted 1 line
hw/dma/pxa2xx_dma.c +0 -0
     s->chan = g_malloc0(sizeof(PXA2xxDMAChannel) * s->channels);

As long as we're here, this should probably be switched to g_new0(), in part to avoid any chance that the multiply can overflow.

Ok, I doubt that we really get overflows here, but g_new0 is certainly nicer here, so I'll change my patch accordingly.

Thomas

#4 lore raw

PATCH 2/5 hw/scsi/spapr_vscsi: Remove superfluous memset

In reply to Thomas Huth

g_malloc0 already clears the memory, so no need for the additional memset here.

Cc Paolo Bonzini <[email protected]>
Cc David Gibson <[email protected]>
Cc Alexander Graf <[email protected]>
---
 hw/scsi/spapr_vscsi.c | 1 -
 1 file changed, 1 deletion(-)
hw/scsi/spapr_vscsi.c +0 -1
index 891424f..f4f5140 100644
@@ -750,7 +750,6 @@ static void vscsi_report_luns(VSCSIState *s, vscsi_req *req)
     len = n+8;
 
     resp_data = g_malloc0(len);
-    memset(resp_data, 0, len);
     stl_be_p(resp_data, n);
     i = found_lun0 ? 8 : 16;
     QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
Signature · 1 line
1.8.3.1
Reviewed-by on v1 2/5
#5 lore raw

Re: [Qemu-devel] [PATCH 2/5] hw/scsi/spapr_vscsi: Remove superfluous memset

Quoted 10 lines · Thomas Huth

g_malloc0 already clears the memory, so no need for the additional memset here.

Cc Paolo Bonzini <[email protected]>
Cc David Gibson <[email protected]>
Cc Alexander Graf <[email protected]>
---
 hw/scsi/spapr_vscsi.c | 1 -
 1 file changed, 1 deletion(-)
Signature · 2 lines
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org
Applied
#6 lore raw

Re: [Qemu-devel] [PATCH 2/5] hw/scsi/spapr_vscsi: Remove superfluous memset

In reply to Thomas Huth
Quoted 7 lines · Thomas Huth

g_malloc0 already clears the memory, so no need for the additional memset here.

Cc Paolo Bonzini <[email protected]>
Cc David Gibson <[email protected]>
Cc Alexander Graf <[email protected]>

Thanks, applied to spapr-next.

Signature · 4 lines
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson
#7 lore raw

PATCH 3/5 hw/input/tsc210x: Remove superfluous memset

In reply to Thomas Huth

g_malloc0 already clears the memory, so no need for additional memsets here. And while we're at it, let's also remove the superfluous typecasts for the return values of g_malloc0.

---
 hw/input/tsc210x.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)
hw/input/tsc210x.c +2 -6
index fae3385..92b076a 100644
@@ -1086,9 +1086,7 @@ uWireSlave *tsc2102_init(qemu_irq pint)
 {
     TSC210xState *s;
 
-    s = (TSC210xState *)
-            g_malloc0(sizeof(TSC210xState));
-    memset(s, 0, sizeof(TSC210xState));
+    s = g_malloc0(sizeof(TSC210xState));
     s->x = 160;
     s->y = 160;
     s->pressure = 0;
@@ -1135,9 +1133,7 @@ uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav)
 {
     TSC210xState *s;
 
-    s = (TSC210xState *)
-            g_malloc0(sizeof(TSC210xState));
-    memset(s, 0, sizeof(TSC210xState));
+    s = g_malloc0(sizeof(TSC210xState));
     s->x = 400;
     s->y = 240;
     s->pressure = 0;
Signature · 1 line
1.8.3.1
#8 lore raw

Re: [Qemu-devel] [PATCH 3/5] hw/input/tsc210x: Remove superfluous memset

Quoted 14 lines · Thomas Huth

g_malloc0 already clears the memory, so no need for additional memsets here. And while we're at it, let's also remove the superfluous typecasts for the return values of g_malloc0.

---
 hw/input/tsc210x.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)
hw/input/tsc210x.c +0 -0
index fae3385..92b076a 100644

hw/input/tsc210x.c uWireSlave *tsc2102_init(qemu_irq pint) · line 1089

Quoted 7 lines
hw/input/tsc210x.c +1 -3
@@ -1086,9 +1086,7 @@ uWireSlave *tsc2102_init(qemu_irq pint)
 {
     TSC210xState *s;
 
-    s = (TSC210xState *)
-            g_malloc0(sizeof(TSC210xState));
-    memset(s, 0, sizeof(TSC210xState));
+    s = g_malloc0(sizeof(TSC210xState));

This should probably be g_new0(TSC210xState, 1), consistent with Markus' recent cleanup patches.

hw/input/tsc210x.c uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav) · line 1136

Quoted 11 lines
hw/input/tsc210x.c +1 -3
     s->x = 160;
     s->y = 160;
     s->pressure = 0;
@@ -1135,9 +1133,7 @@ uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav)
 {
     TSC210xState *s;
 
-    s = (TSC210xState *)
-            g_malloc0(sizeof(TSC210xState));
-    memset(s, 0, sizeof(TSC210xState));
+    s = g_malloc0(sizeof(TSC210xState));

Likewise.

Signature · 2 lines
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org
#9 lore raw

Re: [Qemu-devel] [PATCH 3/5] hw/input/tsc210x: Remove superfluous memset

Quoted 18 lines · Eric Blake
Quoted 17 lines · Thomas Huth

g_malloc0 already clears the memory, so no need for additional memsets here. And while we're at it, let's also remove the superfluous typecasts for the return values of g_malloc0.

---
 hw/input/tsc210x.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)
hw/input/tsc210x.c +0 -0
index fae3385..92b076a 100644
@@ -1086,9 +1086,7 @@ uWireSlave *tsc2102_init(qemu_irq pint)
 {
     TSC210xState *s;
 
Quoted 7 lines

hw/input/tsc210x.c uWireSlave *tsc2102_init(qemu_irq pint) · line 1089

Quoted 4 lines
hw/input/tsc210x.c +1 -3
-    s = (TSC210xState *)
-            g_malloc0(sizeof(TSC210xState));
-    memset(s, 0, sizeof(TSC210xState));
+    s = g_malloc0(sizeof(TSC210xState));

This should probably be g_new0(TSC210xState, 1), consistent with Markus' recent cleanup patches.

Ok, I'll change my patch.

Thomas

#10 lore raw

PATCH 4/5 tests/i44fx-test: No need for zeroing memory before memset

In reply to Thomas Huth

Change a g_malloc0 into g_malloc since the following memset fills the whole buffer anyway.

---
 tests/i440fx-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tests/i440fx-test.c +1 -1
index d0bc8de..7fa1709 100644
@@ -191,7 +191,7 @@ static void write_area(uint32_t start, uint32_t end, uint8_t value)
     uint32_t size = end - start + 1;
     uint8_t *data;
 
-    data = g_malloc0(size);
+    data = g_malloc(size);
     memset(data, value, size);
     memwrite(start, data, size);
 
Signature · 1 line
1.8.3.1
#11 lore raw

Re: [Qemu-devel] [PATCH 4/5] tests/i44fx-test: No need for zeroing memory before memset

Quoted 15 lines · Thomas Huth

Change a g_malloc0 into g_malloc since the following memset fills the whole buffer anyway.

---
 tests/i440fx-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tests/i440fx-test.c +0 -0
index d0bc8de..7fa1709 100644

tests/i440fx-test.c static void write_area(uint32_t start, uint32_t end, uint8_t value) · line 197

Quoted 8 lines
tests/i440fx-test.c +1 -1
@@ -191,7 +191,7 @@ static void write_area(uint32_t start, uint32_t end, uint8_t value)
     uint32_t size = end - start + 1;
     uint8_t *data;
 
-    data = g_malloc0(size);
+    data = g_malloc(size);
     memset(data, value, size);
     memwrite(start, data, size);
 

Technically you are right of course, but I remember some historical mess around this, in this file.

Plus I vaguely recall g_new[0]() being the most recent preference.

https://developer.gnome.org/glib/stable/glib-Memory-Allocation.html#g-new

See e.g. commit 97f3ad3551. Markus?

Thanks
Laszlo

#12 lore raw

Re: [Qemu-devel] [PATCH 4/5] tests/i44fx-test: No need for zeroing memory before memset

Quoted 28 lines · Laszlo Ersek
Quoted 15 lines · Thomas Huth

Change a g_malloc0 into g_malloc since the following memset fills the whole buffer anyway.

---
 tests/i440fx-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tests/i440fx-test.c +0 -0
index d0bc8de..7fa1709 100644

tests/i440fx-test.c static void write_area(uint32_t start, uint32_t end, uint8_t value) · line 197

Quoted 8 lines
tests/i440fx-test.c +1 -1
@@ -191,7 +191,7 @@ static void write_area(uint32_t start, uint32_t end, uint8_t value)
     uint32_t size = end - start + 1;
     uint8_t *data;
 
-    data = g_malloc0(size);
+    data = g_malloc(size);
     memset(data, value, size);
     memwrite(start, data, size);
 

Technically you are right of course, but I remember some historical mess around this, in this file.

Quoted 5 lines

Plus I vaguely recall g_new[0]() being the most recent preference.

https://developer.gnome.org/glib/stable/glib-Memory-Allocation.html#g-new

See e.g. commit 97f3ad3551. Markus?

g_new IMHO only makes sense when you try to allocate the memory for a struct or something similar - for allocating byte arrays, g_malloc is the better choice. So I think this patch should be fine.

Thomas

#13 lore raw

Re: [Qemu-devel] [PATCH 4/5] tests/i44fx-test: No need for zeroing memory before memset

In reply to Laszlo Ersek
Quoted 28 lines · Laszlo Ersek
Quoted 15 lines · Thomas Huth

Change a g_malloc0 into g_malloc since the following memset fills the whole buffer anyway.

---
 tests/i440fx-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tests/i440fx-test.c +0 -0
index d0bc8de..7fa1709 100644

tests/i440fx-test.c static void write_area(uint32_t start, uint32_t end, uint8_t value) · line 197

Quoted 8 lines
tests/i440fx-test.c +1 -1
@@ -191,7 +191,7 @@ static void write_area(uint32_t start, uint32_t end, uint8_t value)
     uint32_t size = end - start + 1;
     uint8_t *data;
 
-    data = g_malloc0(size);
+    data = g_malloc(size);
     memset(data, value, size);
     memwrite(start, data, size);
 

Technically you are right of course, but I remember some historical mess around this, in this file.

Quoted 5 lines

Plus I vaguely recall g_new[0]() being the most recent preference.

https://developer.gnome.org/glib/stable/glib-Memory-Allocation.html#g-new

See e.g. commit 97f3ad3551. Markus?

TL;DR: the patch is fine.

The argument of g_malloc() isn't always the size of a type. But when it is, you should be using g_new() instead. The commit message explains:

g_new(T, n) is neater than g_malloc(sizeof(T) * n). It's also safer, for two reasons. One, it catches multiplication overflowing size_t. Two, it returns T * rather than void *, which lets the compiler catch more type errors.

The multiplication argument applies only when n != 1.

The type checking argument applies regardless of n. That's why the commit also transfroms patterns like g_malloc(sizeof(T)).

When the argument isn't written as sizeof a type, but could be, we enter "matter of taste" territory. For instance, some may perefer the idiomatic T *p = g_malloc(sizeof(*p)) to the more tightly typed p = g_new(T, 1). I therefore leave them alone. Commit messsage again:

This commit only touches allocations with size arguments of the form sizeof(T).

A separate issue is a zeroing memset() after allocation. Please use a zeroing allocator instead, because that's more concise. Precedence:
commit 0bd0adb.

Now let's apply this to the patch.

The memset() isn't zeroing, so "use a zeroing allocator instead" doesn't apply. Before the patch, the code uses one additionally, which is wasteful. The patch stops the waste.

The size argument is not the size of any type. You could still write

    data = g_new(uint8_t, size);

but the extra verbosity pretty clearly outweighs what we could gain from type checking here.

Reviewed-by
#14 lore raw

Re: [Qemu-devel] [PATCH 4/5] tests/i44fx-test: No need for zeroing memory before memset

Quoted 69 lines · Markus Armbruster
Quoted 28 lines · Laszlo Ersek
Quoted 15 lines · Thomas Huth

Change a g_malloc0 into g_malloc since the following memset fills the whole buffer anyway.

---
 tests/i440fx-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tests/i440fx-test.c +0 -0
index d0bc8de..7fa1709 100644

tests/i440fx-test.c static void write_area(uint32_t start, uint32_t end, uint8_t value) · line 197

Quoted 8 lines
tests/i440fx-test.c +1 -1
@@ -191,7 +191,7 @@ static void write_area(uint32_t start, uint32_t end, uint8_t value)
     uint32_t size = end - start + 1;
     uint8_t *data;
 
-    data = g_malloc0(size);
+    data = g_malloc(size);
     memset(data, value, size);
     memwrite(start, data, size);
 

Technically you are right of course, but I remember some historical mess around this, in this file.

Quoted 5 lines

Plus I vaguely recall g_new[0]() being the most recent preference.

https://developer.gnome.org/glib/stable/glib-Memory-Allocation.html#g-new

See e.g. commit 97f3ad3551. Markus?

TL;DR: the patch is fine.

The argument of g_malloc() isn't always the size of a type. But when it is, you should be using g_new() instead. The commit message explains:

g_new(T, n) is neater than g_malloc(sizeof(T) * n). It's also safer, for two reasons. One, it catches multiplication overflowing size_t. Two, it returns T * rather than void *, which lets the compiler catch more type errors.

The multiplication argument applies only when n != 1.

The type checking argument applies regardless of n. That's why the commit also transfroms patterns like g_malloc(sizeof(T)).

When the argument isn't written as sizeof a type, but could be, we enter "matter of taste" territory. For instance, some may perefer the idiomatic T *p = g_malloc(sizeof(*p)) to the more tightly typed p = g_new(T, 1). I therefore leave them alone. Commit messsage again:

This commit only touches allocations with size arguments of the form sizeof(T).

A separate issue is a zeroing memset() after allocation. Please use a zeroing allocator instead, because that's more concise. Precedence:
commit 0bd0adb.

Now let's apply this to the patch.

The memset() isn't zeroing, so "use a zeroing allocator instead" doesn't apply. Before the patch, the code uses one additionally, which is wasteful. The patch stops the waste.

Quoted 7 lines

The size argument is not the size of any type. You could still write

    data = g_new(uint8_t, size);

but the extra verbosity pretty clearly outweighs what we could gain from type checking here.

Okay, thanks!

Cheers
Laszlo

#15 lore raw

PATCH 5/5 linux-user/syscall: Replace g_malloc0 + memcpy with g_memdup

In reply to Thomas Huth

No need to use g_malloc0 to zero the memory if we memcpy to the whole buffer afterwards anyway. Actually, there is even a function which combines both steps, g_memdup, so let's use this function here instead.

---
 linux-user/syscall.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
linux-user/syscall.c +1 -2
index 98b5766..f2ada0a 100644
@@ -5325,8 +5325,7 @@ static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
         return -TARGET_EFAULT;
     }
 
-    fh = g_malloc0(total_size);
-    memcpy(fh, target_fh, total_size);
+    fh = g_memdup(target_fh, total_size);
     fh->handle_bytes = size;
     fh->handle_type = tswap32(target_fh->handle_type);
 
Signature · 1 line
1.8.3.1
Reviewed-by on v1 5/5
#16 lore raw

Re: [Qemu-devel] [PATCH 5/5] linux-user/syscall: Replace g_malloc0 + memcpy with g_memdup

Quoted 10 lines · Thomas Huth

No need to use g_malloc0 to zero the memory if we memcpy to the whole buffer afterwards anyway. Actually, there is even a function which combines both steps, g_memdup, so let's use this function here instead.

---
 linux-user/syscall.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
Quoted 16 lines
linux-user/syscall.c +1 -2
index 98b5766..f2ada0a 100644
@@ -5325,8 +5325,7 @@ static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
         return -TARGET_EFAULT;
     }
 
-    fh = g_malloc0(total_size);
-    memcpy(fh, target_fh, total_size);
+    fh = g_memdup(target_fh, total_size);
     fh->handle_bytes = size;
     fh->handle_type = tswap32(target_fh->handle_type);
 
Signature · 2 lines
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org