[LAD] "enhanced event port" LV2 extension proposal

Krzysztof Foltman wdev at foltman.com
Sun Dec 2 21:46:42 UTC 2007


Dave Robillard wrote:
> We are definitely going to need some kind of shared data structure
> extension, so really massive message are probably stupid.  16/16 works
> and is un-weird.
>   
So, 16:16 it is.

> 64 bit will become the norm, sure, but does 64-bit alignment matter here
> anyway?  (I have no idea).
I've mentioned pointers. You don't see the use for storing pointers in 
payload?

>   We're probably not going to be firing around
> arrays of floats to do vectorizable things with here
>   
For SSE we'd need 128-bit alignment (4 floats). But I doubt our payload 
is going to be used for SSE and the likes. I'd be very surprised, actually.

> Life is easier and less problematic if we just pick absolute sizes and
> stick with them (so the buffer has a precisely defined format anywhere).
> I doubt this is a compelling enough reason to do otherwise.
>   
Well, usually APIs use pre-determined order, but not pre-determined 
sizes. ie. some fields are 32-bit on some platforms and 64-bit on other 
platforms, but the field ordering is always the same.

> Not really, just casting a char* pointer to a struct to make life easy.
>   
Yes, but... I mean... we'll end up casting to a struct pointer, not 
cherry-pick individual fields via pointer operations like this:

int size = *(int *)(buf + 4);

That's what I was talking about. Accessing a _single_ struct as a 
struct. The "running" pointer will probably be char *, right, but for 
processing of a particular event, it will be cast to a struct pointer.

What I was trying to say was "padding and field sizes - at least for 
some fields - should be platform-dependent". Not in header (because 
header works equally well on 32-bit and 64-bit). I don't want to vary 
field ordering on a per-platform basis either. That'd be a PITA. Just 
field sizes and alignment, and only when *really* needed, in payload. I 
hope you're OK with that. It's what other APIs do, for example, they may 
have a member of type 'size_t' in some structs, which is 32-bit on some 
platforms and 64-bit on others.

Anyway - I suppose at this stage it's a human language-related problem, 
not major differences in opinion.

> We are very precisely defining the layout of a byte array, period.
So, solution number 1. Just look at solution number 2, it might be more 
attractive anyway, even if I wasn't able to convince you by myself. You 
probably need to spend some time trying out your own ideas with both 
solutions. Perhaps I should have given some examples too, I don't know.
> What we have right now is this:
>
> /* 0       4       8       12      16
>  * |               |               |
>  * |       |       |       |       |
>  * | | | | | | | | | | | | | | | | |
>  * |FRAMES |SUBFRMS|TYP|LEN|DATA..
>  */
>
> On the plus side, 4 byte MIDI messages fit nicely in that 16 byte box,
> entire message is 2 64-bit words, 64-bit aligned, no wasted space.
>   
Yes, I got that. It's good and I want to keep it like that. In this 
situation (MIDI data or other data that look the same on all platforms), 
whether you use solution 1 or solution 2, you're fine.

The problems start when you need to put a pointer in an event (not a 
MIDI event; say, a "waveform pointer" event). Which will happen sooner 
than later, I hope.

On 32-bit platform, it will be fine (again, solution 1 and 2 give the 
same result here):

/* 0       4       8       12      16
 * |               |               |
 * |       |       |       |       |
 * | | | | | | | | | | | | | | | | |
 * |FRAMES |SUBFRMS|TYP|LEN|POINTER
 */

On 64 bit platform, though, we would have either:

a) misalignment (bad)

/* 0       4       8       12      16
 * |               |               |
 * |       |       |       |       |       |
 * | | | | | | | | | | | | | | | | | | | | |
 * |FRAMES |SUBFRMS|TYP|LEN| MISALIGNED PTR
 */


It corresponds to solution 1 ("in event type 
http://foltman.com/textpointer, the pointer is placed starting from byte 
0 of payload"). Field placement specified in terms of bytes, no matter 
which platform we're on.

b) padding (good-ish)

/* 0       4       8       12      16      20
 * |               |               |
 * |       |       |       |       |       |       |
 * | | | | | | | | | | | | | | | | | | | | | | | | |
 * |FRAMES |SUBFRMS|TYP|LEN|PADDING|POINTER........
 */

It corresponds to solution 2 ("in event type 
http://foltman.com/textpointer, the pointer is a 64-bit field that 
follows the len field, whatever its natural placement for given platform 
may be"). Ie. this:

struct LV2_WAVEFORM_EVENT {
  LV2_EVENT_HEADER hdr;
  // on 64-bit platforms, the compiler automatically puts 4 bytes of 
padding here
  void *some_ptr; // 4 bytes on x86, 8 bytes on x86-64
};

So, we have 0 bytes padding and offset 12 on x86 (etc) and 4 bytes 
padding and offset 16 on x86-64 (etc.).

Hope the difference between both solutions is clearly visible now.

If I understood correctly, you'd like to start from binary layout and 
*only then* make a C struct based on that design. Right?

I would do exactly the opposite way - design a C (or Pascal, or 
whatever) struct in a way that leads to acceptable in-memory layout at 
least on a typical 32-bit and 64-bit platform (which is easy!).

No, we don't need to do it for event *header* anymore (because the 
layout we pretty much agreed on is the same on 32-bit and 64-bit 
platform). We need to do it when creating new event types (ie. layout 
for payload). That's the part that might not be clear in what I wrote 
previously. I'm trying to imagine both header and typical situations in 
payload too. And from what I see, you seem to agree about the *payload* 
layouts being platform-dependent in some cases (which leads me to 
thinking that defining in terms of bytes is not the way to go for those 
cases).

> The data itself isn't 64-bit aligned, but I'd have to see some real
> reasons to care.
>   
Try reading a 8-byte pointer (64-bit platform) from offset 12. It will 
be equally slow or even crash-provoking as if you read it from offset 11 
on 32-bit platform.

Which doesn't mean that we should use 8-byte alignment for every 
platform. We might use sizeof(void *) alignment, whatever it is locally. 
Any contraindications?

(there is a contraindication, it seems; I've just written a short 
program to check reading/writing a buffer full of doubles from aligned 
and misaligned addresses, and ran it on my machine with crappy Pentium 4 
CPU - seems that reading a double from address misaligned by 4 bytes is 
about 2.6 times as slow than reading from an aligned address, doesn't 
surprise me at all)

Krzysztof




More information about the Linux-audio-dev mailing list