Page 1 of 2
High precision Delay (nano/micro second)
Posted: Wed Dec 20, 2023 11:43 am
by tatanas
Hi,
I would like to implement a high precision delay on Linux but it doesn't work as I want.
Here is 2 examples : one with nanosleep() function and the second one with clock_gettime()
Code: Select all
#CLOCK_MONOTONIC = 1
Structure timespec
Second.i
Nanosecond.i
EndStructure
ImportC "-lrt"
clock_gettime(ClockID.l, *TimeSpecA.TimeSpec)
EndImport
Structure Instance
StartCount.TimeSpec
EndCount.TimeSpec
EndStructure
Global Instance.Instance
Instance\StartCount\Second = 0
Instance\StartCount\NanoSecond = 0
Instance\EndCount\Second = 0
Instance\EndCount\NanoSecond = 0
Procedure DelayMicroSeconds(Time.q)
clock_gettime(#CLOCK_MONOTONIC, @Instance\StartCount)
Repeat
Delay(0)
clock_gettime(#CLOCK_MONOTONIC, @Instance\EndCount)
Until (Instance\EndCount\NanoSecond / 1000 - Instance\StartCount\NanoSecond / 1000) > Time
EndProcedure
a = ElapsedMilliseconds()
For n = 1 To 1000
DelayMicroSeconds(1)
Next
elapsedtime = ElapsedMilliseconds()-a
MessageRequester("debug", Str(elapsedtime) + "millisec") ; result should be 1 ms
Code: Select all
Structure timespec
Second.i
Nanosecond.i
EndStructure
Procedure NanoDelay(Nanoseconds.i)
Protected pause.timespec
If Nanoseconds > 0 And Nanoseconds <= 999999999
pause.timespec\Nanosecond = Nanoseconds
ProcedureReturn nanosleep_(@pause, #Null)
Else
ProcedureReturn -1
EndIf
EndProcedure
a = ElapsedMilliseconds()
For n = 1 To 1000
NanoDelay(1000) ; 1 microsec
Next
elapsedtime = ElapsedMilliseconds()-a
Debug Str(elapsedtime) + " millisec"
MessageRequester("debug", Str(elapsedtime) + " millisec") ; result should be 1 ms
Both return a elapsed time between 75 and 85 milliseconds instead of 1ms.
What am I doing wrong ?
Thanks for your time.
Re: High precision Delay (nano/micro second)
Posted: Wed Dec 20, 2023 1:15 pm
by NicTheQuick
Regarding the first example:
The biggest problem here is the `Delay(0)`. Although it should not make any delay at all, it will force the operating systems scheduler to switch contexts and give room for other processes. You will see a much better result if you straight up remove the `Delay(0)` completely and doing a busy wait. Also it might be better to multiply `Time` with 1000 beforehand instead of divide the `NanoSecond` field by 1000 on each iteration. I then get 3 ms consistently as a result.
Regarding the second example:
You can not achieve such a high precision on a multitasking operating system and with so much overhead.
You overhead consists of calling a function, doing conditions and other function calls inside that function, and then doing a for loop around all of that. Of course all of that needs additional time. Besides that your operating system will switch contexts multiple times a second if the priority of the process is not realtime.
One questions:
Why do you need this kind of precision? I can not think of anything but drivers that need this.
Re: High precision Delay (nano/micro second)
Posted: Wed Dec 20, 2023 2:51 pm
by tatanas
You're right, I don't need a 1 nanosecond precision. But I was expecting a bit better than 1 millisecond... like 500 microseconds.
I'm working on a tcp server. When I close it and restart it, all clients (350) that are waiting try to reconnect all at once. And with a delay(5) in the main loop, sometimes it crashes. Since I change the delay to 1, it's much better.
So I was looking for a smaller delay().
What is strange is I can't get a delay < 1 millisecond regardless of the function. It's never better than a delay(1)...
I even tryed with select_(0, #Null, #Null, #Null, @pause) instead of nanosleep(), which is much better but can't be inferior to 1 millisecond.
On Windows It works fine.
Re: High precision Delay (nano/micro second)
Posted: Wed Dec 20, 2023 2:56 pm
by NicTheQuick
What kind of crash do you have with the clients connecting all at once? 250 sounds not that much in my opinion. And what are you doing with the delays on the server side? Why do you not just handle all network events as fast as possible? You may want to give each connection it's own thread where the data is handled.
Re: High precision Delay (nano/micro second)
Posted: Wed Dec 20, 2023 3:46 pm
by Oso
I have also experienced network crashes and they have plagued my application development for some months, while I've worked at finally resolving them. Admittedly, mine have been on Windows though.
My main breakthroughs related to these areas —
1. Checking for a socket error, prior to sending any data
2. Making sure that I deal with incomplete buffer transmissions and re-sending, because PB functions don't do this for us. We have to look at the return byte counter and send the bytes that didn't get sent already.
3. Pausing before attempting to re-send (2) but if a timeout period is exceeded, drop the client and don't send more data. This has focused on the prevention of overloading the transmission, instead waiting a while, then sending a bit more data, otherwise it becomes overloaded.
4. Improving the checking that the client hadn't already disconnected. That hasn't been easy because I handle each client in its own thread.
Earlier in my project, I improved robustness by adding Delay(1) between sending blocks of data, similar to what you say, but I've since removed that altogether because it caused transmission to be too slow. I regarded it as a "sticking plaster", instead of a cure.
Re: High precision Delay (nano/micro second)
Posted: Wed Dec 20, 2023 3:48 pm
by tatanas
NicTheQuick
This is exactly what I do. Each time a client is connecting, I create a thread. This thread will handle all data and disconnection event.
I added a delay(1) in the main loop because I have a small GUI to display the connection/disconnection and count of online client, so I have to handle the WindowEvent().
I don't now what part of the code causing the crash. There is no line error specified.
Oso
You experienced almost the same as me but on Windows

.
I stoped using Send/ReceiveNetworkData/String() because as soon as the socket is closed, those functions crash. Instead I use recv_ and send_ API function.
Re: High precision Delay (nano/micro second)
Posted: Wed Dec 20, 2023 3:55 pm
by Oso
tatanas wrote: Wed Dec 20, 2023 3:48 pm
I don't now what part of the code causing the crash. There is no line error specified.
You could try the Purifier, that's how I resolved one of mine. It was the sending of data to a client that had already disconnected.
Re: High precision Delay (nano/micro second)
Posted: Wed Dec 20, 2023 3:58 pm
by tatanas
PurifierGranularity(1, 1, 1, 1)
Already done

Re: High precision Delay (nano/micro second)
Posted: Wed Dec 20, 2023 4:08 pm
by NicTheQuick
tatanas wrote: Wed Dec 20, 2023 3:48 pm
NicTheQuick
This is exactly what I do. Each time a client is connecting, I create a thread. This thread will handle all data and disconnection event.
I added a delay(1) in the main loop because I have a small GUI to display the connection/disconnection and count of online client, so I have to handle the WindowEvent().
Make sure you only do the `Delay(1)` if `WindowEvent()` returns 0.
Re: High precision Delay (nano/micro second)
Posted: Wed Dec 20, 2023 4:15 pm
by Oso
tatanas wrote: Wed Dec 20, 2023 3:58 pm
PurifierGranularity(1, 1, 1, 1)
Already done
How about your code, where you say that you handle all disconnection events in the thread. Normally, you would process the events at the server-side, as with the below.
How are you checking the event in the thread?
Code: Select all
termserverid.i = CreateNetworkServer(#PB_Any, termportno.i, #PB_Network_IPv4 | #PB_Network_TCP, "")
If termserverid.i
Repeat
termserverevent.i = NetworkServerEvent(termserverid.i) ; Check for server events (i.e. client terminals)
If termserverevent.i ; Process if there was an event
termclientid.i = EventClient() ; Obtain the terminal client id. if there was an event
Select termserverevent.i ; Check for event types
Case #PB_NetworkEvent_Connect
; **
Case #PB_NetworkEvent_Data
; **
; ** --- Thread is created here and from then onwards, it sends data back to the client
Case #PB_NetworkEvent_Disconnect
; **
; ** Client disconnected
EndSelect
EndIf
Delay(10)
Until quitprocess.b
Re: High precision Delay (nano/micro second)
Posted: Wed Dec 20, 2023 4:30 pm
by tatanas
My code was highly inspired by this post of RichAlgeni :
viewtopic.php?t=51072
Re: High precision Delay (nano/micro second)
Posted: Wed Dec 20, 2023 5:35 pm
by GG
This
>> post << I suppose (purebasic.com instead of purebasic.fr in your link).
Re: High precision Delay (nano/micro second)
Posted: Wed Dec 20, 2023 6:11 pm
by Oso
The linked code appears to be a receiving server only. Implementing the socket error check is only necessary at the point of sending data, because the destination might have gone away when you attempt to send data — that's what crashes PureBasic routines in my experience. You don't need it on the receiving end.
Incidentally, what is the client?
Re: High precision Delay (nano/micro second)
Posted: Wed Dec 20, 2023 9:13 pm
by mk-soft
Small tip ...
Move the delay to
Code: Select all
Case #PB_NetworkEvent_None
; Check lost clients
Delay(5)
And run the server within a thread and use PostEvent for GUI updates.
Furthermore, I fetch the receive data in the server thread and only then pass this complete data on to a thread for processing.
The server thread is fast enough to fetch all data from the receive buffers with only one delay in case #PB_NetworkEvent_None.
Re: High precision Delay (nano/micro second)
Posted: Thu Dec 21, 2023 9:38 am
by tatanas
This >> post << I suppose (purebasic.com instead of purebasic.fr in your link).
Yes GG.
Incidentally, what is the client?
Oso : The client is very conventional, classic Purebasic client. I've got no problem sending or receiving data with the server.
mk-soft : thanks I will try your tip.
We've changed the subject a bit. At the beginning I was looking for a working microsecond delay() for Linux.
