My code sends out UDP and TCP Packets of varying lengths depending on the situation. The packet / buffer size varies from 10 bytes to 150 bytes.
As of now I dynamically initialize a uint8_t send_buffer[10] or uint8_t send_buffer[150] and fill them up with the data that I want to send within a function.
Since I know that the max size of any buffer is 150 bytes, is it better to have a global buffer initialized right at the beginning with a fixed size of 150 bytes and use the same buffer for all situations OR have the buffers created dynamically as I need them?
Example:
uint8_t global_send_buffer[150];
// need to send out 10 bytes
udp.write(global_send_buffer, 10);
// need to send out 150
udp.write(global_send_buffer, 150);
I can’t tell if you are using automatic variables (often called stack allocated) in a function or if you are doing something like
uint8_t * buf;
buf = new uint8_t[10];
//or later
buf = new uint8_t[150];
If you are calling new then I think you will eventually run out of memory. The garbage collector will not be able to completely de-fragment this over time and it doesn’t take too many holes to run you out of RAM
I would think that a static 150 byte array that you manage would be much better in the long run, but as @ScruffR said it depends a lot on the lifetime of your data. Also, if a portion of the data is the same every time, you can probably optimize that further.
@bko Here’s my simple use case. The code is similar to what I actually use. When I receive a udp packet, I decode it and send an appropriate response (send_function()) back. I have about 10 different / unique send_functions() each with a different buffer size.
A very clever compiler could figure out via variable lifetime analysis that all of your send_buffer automatic variables could share storage, but in the real world the analysis is not always perfect. It might to some sharing, you would have to check the compiler output (compiling on your local machine) carefully.
I think you would be better off in general to have one global send_buffer[150] and use it in all three functions. Using strcpy or memcpy you can put the different preambles into the buffer in each function.
Edit: @bko beat me again, with a completely differen view of the matter
@nitred, since I can’t see any functional difference in your functions I’d go for only one function, that’ll take parameters (e.g. category (=recv) or category plus buffsize) inside the fn you’d use a local (automatic) buffer which can be sized for the max size (which I’d #define rather than hardcode inside the fn) and then use the parameters to choose between different behaviours.
This way you safe space twice. Local variables don’t take up any space until the fn is called and will vanish once the fn finishes and you safe space since the “shared” code does not exist multiple times as it would do with different functions.
Advantage of Brians version is, that your buffer is created once and for all and so is better performance wise.
And if it happened that the fn gets called recursifly, you will not run out of stack, as you would with my suggestion.
@bko Thank you so much. I can only see a positive outcome moving in this direction.
@ScruffR The actual functions in my code are pretty unique in functionality and do get called recursively, I just made them simple here. I’m looking for absolute stability so I think I’ll have to go with @bko’s suggestions here Thanks a lot though!