Re: [PATCH] USB: f_mass_storage: dynamic buffers for better alignment

From: MichaÅ Nazarewicz
Date: Mon Mar 15 2010 - 15:20:19 EST


On Mon, Mar 15, 2010 at 11:09:55AM +0100, Michal Nazarewicz wrote:
"Static" buffers in fsg_buffhd structure (ie. fields which are arrays
rather then pointers to dynamically allocated memory) are not aligned
to any "big" power of two which may lead to poor DMA performance

On Mon, 15 Mar 2010 19:10:21 +0100, Felipe Balbi <me@xxxxxxxxxxxxxxx> wrote:
not so true as you can add __attribute__ ((aligned(32))) to those.

I admit, I haven't thought about that. Some fields rearrangement
could help avoid some padding but yes, it can be done.

However, there is one more thing I've had in mind. Each buffer
is 4 pages (16 KiB) and there are two such buffers in struct
fsg_common therefore the whole size of the structure is
9 pages (> 32 KiB).

I've been simply concerned about using kamlloc() for such big
structures so in the end decided to split it into 3 allocations.

Maybe I'm overeating though? Or maybe vmalloc() would solve those
problems? But then again, vmalloc() could degrade DMA performance
on systems w/o scatter-gather.

What do you think?

bh = common->buffhds;
- i = FSG_NUM_BUFFERS - 1;
- do {
+ i = FSG_NUM_BUFFERS;
+ for (i = FSG_NUM_BUFFERS;; ++bh) {

something like

for (i = 0; i < FSG_NUM_BUFFERS; i++, ++bh) {

wouldn't it do it ??

I admit I'm a bit addicted to "downwards to zero" loops and avoiding
checking of the condition prior to the first iteration. (As such I
often use do-while where others would use for.)

Besides counting to zero is not really an issue here. I didn't
particularly fancy the "bh[-1]" that have to be used if the break
is not inside the loop, ie:

bh = common->buffhds;
rc = -ENOMEM;
for (i = FSG_NUM_BUFFERS; i--; ++bh) {
bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL);
if (unlikely(!bh->buf))
goto error_release;
bh->next = bh + 1;
}
bh[-1].next = common->buffhds;

Note also that the last bh->next is assigned twice.

So personally I'd still stick with my version but since
readability is important how about:

bh = common->buffhds;
rc = -ENOMEM;
i = FSG_NUM_BUFFERS;
for(;;) {
bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL);
if (unlikely(!bh->buf))
goto error_release;
if (!--i)
break;
bh->next = bh + 1;
++bh;
}
bh->next = common->buffhds;

What do you think?

--
Best regards, _ _
.o. | Liege of Serenely Enlightened Majesty of o' \,=./ `o
..o | Computer Science, MichaÅ "mina86" Nazarewicz (o o)
ooo +---[mina86@xxxxxxxxxx]---[mina86@jabber.org]---ooO--(_)--Ooo--
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/