High precision Delay (nano/micro second)

Linux specific forum
tatanas
Enthusiast
Enthusiast
Posts: 204
Joined: Wed Nov 06, 2019 10:28 am
Location: France

High precision Delay (nano/micro second)

Post 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.
Windows 10 Pro x64
PureBasic 6.04 x64
User avatar
NicTheQuick
Addict
Addict
Posts: 1227
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: High precision Delay (nano/micro second)

Post 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.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
tatanas
Enthusiast
Enthusiast
Posts: 204
Joined: Wed Nov 06, 2019 10:28 am
Location: France

Re: High precision Delay (nano/micro second)

Post 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.
Windows 10 Pro x64
PureBasic 6.04 x64
User avatar
NicTheQuick
Addict
Addict
Posts: 1227
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: High precision Delay (nano/micro second)

Post 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.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
Oso
Enthusiast
Enthusiast
Posts: 595
Joined: Wed Jul 20, 2022 10:09 am

Re: High precision Delay (nano/micro second)

Post 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.
tatanas
Enthusiast
Enthusiast
Posts: 204
Joined: Wed Nov 06, 2019 10:28 am
Location: France

Re: High precision Delay (nano/micro second)

Post 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.
Last edited by tatanas on Wed Dec 20, 2023 3:55 pm, edited 1 time in total.
Windows 10 Pro x64
PureBasic 6.04 x64
Oso
Enthusiast
Enthusiast
Posts: 595
Joined: Wed Jul 20, 2022 10:09 am

Re: High precision Delay (nano/micro second)

Post 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.

Code: Select all

 PurifierGranularity(1, 1, 1, 1)
tatanas
Enthusiast
Enthusiast
Posts: 204
Joined: Wed Nov 06, 2019 10:28 am
Location: France

Re: High precision Delay (nano/micro second)

Post by tatanas »

PurifierGranularity(1, 1, 1, 1)
Already done :?
Windows 10 Pro x64
PureBasic 6.04 x64
User avatar
NicTheQuick
Addict
Addict
Posts: 1227
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: High precision Delay (nano/micro second)

Post 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.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
Oso
Enthusiast
Enthusiast
Posts: 595
Joined: Wed Jul 20, 2022 10:09 am

Re: High precision Delay (nano/micro second)

Post 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
tatanas
Enthusiast
Enthusiast
Posts: 204
Joined: Wed Nov 06, 2019 10:28 am
Location: France

Re: High precision Delay (nano/micro second)

Post by tatanas »

My code was highly inspired by this post of RichAlgeni : viewtopic.php?t=51072
Windows 10 Pro x64
PureBasic 6.04 x64
User avatar
GG
Enthusiast
Enthusiast
Posts: 258
Joined: Tue Jul 26, 2005 12:02 pm
Location: Lieusaint (77), France

Re: High precision Delay (nano/micro second)

Post by GG »

This >> post << I suppose (purebasic.com instead of purebasic.fr in your link).
Purebasic 6.04 64 bits - Windows 11 Pro 64 bits 23H2
Oso
Enthusiast
Enthusiast
Posts: 595
Joined: Wed Jul 20, 2022 10:09 am

Re: High precision Delay (nano/micro second)

Post 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?
User avatar
mk-soft
Always Here
Always Here
Posts: 5409
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: High precision Delay (nano/micro second)

Post 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.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
tatanas
Enthusiast
Enthusiast
Posts: 204
Joined: Wed Nov 06, 2019 10:28 am
Location: France

Re: High precision Delay (nano/micro second)

Post 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. :)
Windows 10 Pro x64
PureBasic 6.04 x64
Post Reply