Vec<u8> or array for a buffer?

I'm working on a UDP service that will pretty much use the whole max size of 65,507 bytes per datagram. What I'm wondering is whether to use a Vec.with_capacity(65_507), or a [u8; 65_507] as my buffer.

Is there a difference in performance of reads and writes between a vector and an array if the vector is created with the capacity I need before hand?

Thanks,
Jeramy

Vec will allocate buffer on the heap, [u8; N] will allocate it on the stack (unless static). Taking a 64K chunk of stack seems, to me, slightly excessive.

But performancewise they are both just blocks of RAM. Unless you're on a very special architecture accessing the stack and heap is ~the same.

Is that even possible?

Generally people suggest much small packets to get through ethernet and/or the internet:
https://jvns.ca/blog/2017/02/07/mtu/

It probably doesn't matter, but my instinct would be to use a Vec.

My reasoning is that a CPU has a limited size Level 1 cache, and you want the stack to be in that cache for high performance, sticking a 64KB buffer on the stack is liable to "mess up" the L1 caching. Keep the stack for small data items. Whether my reasoning is correct, I do not know, but that's my instinct.

Thanks to fragmentation you can send UDP packets larger than an Ethernet frame. If you read the "what's the maximum packet size for UDP?" discussions carefully you'll see that the argument boils down to "fragmenting is bad, so you want to avoid that" [implied: fragmenting is a thing, but it's not a good thing].

For a local service large UDP packets will tend to work, as long as you don't have complicated network equipment. That said, I still try to fit all my UDP packets within a frame.

That is how I understand it. But surely then all the fragments can arrive out of order and/or get dropped. How would one ever know how to reassemble the parts and fill the holes?

This won't be UDP over a normal network so my MTU is much higher.

I think there are some misconceptions about UDP due to how much emphasis we put on how UDP is not guaranteed delivery and may arrive out-of-order. In practice when you use UDP within a local and reliable network, you'll find that UDP is surprisingly reliable. That is to say, you should never assume it is (see, I'm doing this thing myself, even while I'm trying to say we've been indoctrinated to exaggerate the implications of it) -- but if you empirically test it on a reliable network, it's far more "reliable" than we've been taught.

Many years ago I did some tests sending UDP packets between a server in Sweden and a server in Florida in various configurations, and I was genuinely surprised at how rarely packets were lost, and it got to the point where I started thinking that packet reordering was a myth. Eventually it did happen, though. (I've been told it's much easier today due to how much more dynamic routes are on the Internet, but I have no idea if this is accurate or not).

Philosophically we should assume that UDP packets are always dropped, and of those 0 packets that actually go through, 109.7% of them arrive in the maximally wrong order. In practice there's no reason for engineers to randomly scramble packet ordering or drop packets. These things only happen if there's reason for it, and such reasons are far fewer than one might imagine.

One can prove a point and use network emulator to create a network which will maximally ruin UDP, and the point will have been proven very well. But at the same time, on real local networks UDP will work surprisingly well (at least compared to what we've been taught about it).

With all that said; I spent a few weeks benchmarking raw ethernet and UDP for a project and I have some very nasty words to say about cheap on-board network chips. If you're sending data at a sustained high rate, then reliability quickly drops to 0%, unless you use something like I350 NICs.

Anyway, this is waay off-topic.

Never assume UDP is reliable. Also, in practice, on normal hardware, it's far more reliable than you've been taught. But don't assume it is. Even if it is. :grimacing:

That's big enough that you might as well just use a Vec, especially if you can re-use the buffer. And it'll make it way easier to safely write it without needing to initialize the whole thing first.

(I'd say definitely don't use an array. Probably don't use an ArrayVec in arrayvec - Rust either, but if you find the allocation is a problem in a profile you could consider it.)

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.