✅ SerialPort performance
I'm doing some tests on the performance of serial communication and I'm geting a fair chunk of perforance loss. At a baud rate of 38400, with 7 data bits and 1 stop bit, then I can expect to get a maximum of 26kbps, but I received 120 bytes in just under 50 milliseconds which seems to be about 20 kbps. Anyone know what would be causing this?
43 Replies
Is there any handshaking? Rts/cts etc?
Not that I know of
I'm not specifying any handshaking
Just a baud rate of 38400, 7 data bits, one stop bits and even parity
Then it's just a dumb fire-and-forget protocol, so you'll get data as fast as the transmitting side is sending it
I guess maybe its CPU is trying to manage doing work with sending data then
Is it some embedded device?
Yeah
A PLC
One of those knockoff ones though
It's possible that it has all of the available to go at the start of the 50ms, and is DMAing it out, but it's not unusual to have little gaps as it does work, then transmits, etc
Get a logic analyser / scope on that line
I might give that a try
I definitely saw gaps though
Its clock might be a little off also, if it's just an rc oscillator
I did some rough timing (in debug mode though) using DateTime.Now, and found that I was basically receiving data 1 byte at a time which I guess is expected since my read function only used Thread.Yield(), sometimes the time between receiving bytes was less than a millisecond, sometimes it was maybe 2 milliseconds
The thread scheduling is normally only accurate to 3-5ms or something
So if you're reading one byte then sleeping the thread, it's normally at least 3ms until it'll be woken again
I guess I should just try and optimise when I read data and maybe even write too
(use a Stopwatch for that sort of timing, not DateTime also - much more accurate)
Yeah, read into a 1024 byte buffer or so
DateTime doesn't use the performance counter?
I don't think it does, no
Damn
(could be wrong)
You shouldn't need Thead.Yield in this sort of code
Just read a bunch of bytes from serial, and it'll block until some are available
I completely forgot the timeout functions work lol
I had it to no timeout I think
You normally don't even want timeouts in this sort of code
Well I mean, even for a short response from the PLC of maybe 6 bytes still takes about 10ms to receive for some reason
Maybe it was the yielding though, might test it again
Just do a single 1024 byte read or so
(and read all bytes that are returned, then do it again)
My buffer is 32 bytes since most messages won't be that big
It's using date time but a 6 byte response took 15ms to arrive fully, even after removing Thread.Yield()
Not sure exactly how you're processing it, but the normal strategy if you're receiving something like a length prefixed message is to allocate a buffer to hold the max message, do a read into the buffer for the size of the buffer, that'll return when 1 or more bytes are available, read your length, figure out how many more bytes you need, then keep doing reads of the remaining length until you get all of those bytes
My method is to check if the buffer contains a valid response, either it's an ACK/NAK or it has a checksum
I mean, at those sorts of times, scheduling times will likely dominate anything you're trying to measure
Each Read might sleep the thread if there are no bytes available etc
That'll be amortised out as you read larger chunks of data
Also, when did you start the timer?
At the start of the function, before infinitely looping until the message is fully received or my own timeout mechanism stops the loop
So you're potentially measuring a period before the plc starts sending its message?
Yeah
OK, that too then 😆
I write to the serial port and wait for a message to be received
Right, so you're also measuring the time taking to transmit the command, and the plc's processing time?
No just timing how long it takes to receive the response
But you said you start timing after you do the write?
(not after the first byte of the response is received or something)
https://github.com/AngryCarrot789/HslCommunication-Community/blob/HslCommunication/Serial/SerialBase.cs#L193
That's my function for sending a message and getting a response
The timing is only done in ReadMessageInternal
That's a 404 for me
Oops
double slash
Nevermind
Same with that fixed
GitHub
HslCommunication-Community/HslCommunication/Serial/SerialBase.cs at...
A library for communicating with common PLC devices. A open source and higher-performance edition of HslCommunication - AngryCarrot789/HslCommunication-Community
Right yes, after you queue the command for transmission
Actual sending of bytes will happen asynchronously. Then you've got the time for the plc to think about it
Hm I guess
Definitely put a scope on it
Look at the timing of your command, the plc's thinking time, and how long it takes the response to come back, start to end
$close
If you have no further questions, please use /close to mark the forum thread as answered