Console helper app eating up one CPU core

So I’ve got those nice new console helper apps for device interaction, now built without IPCSockets, running an asynchronous shells.
They are mainly running a thread to watch for shell input, watching the connection status and mostly idling around.
Which they are on Windows where Resource Monitor tells me they cause about 0% CPU.
Not so on macOS, where every sleepcurrentthread or doevents seems to be ignored, and I am up to about 99% CPU load.
Any hints what I should change? MBS to the rescue?

So App.DoEvents(500) is not making it slow down?

Then you may have a tight loop -one that’s not in a thread- that’s causing this ?

One thing for sure is that Xojo builds are always more efficient on windows, on my experience by on average by about 80%.
Xojo builds on mac use ALOT more CPU, but a console app doing is one i’ve never seen unless i do App.DoEvents(5) or even lower.

Our Windows builds run at about 2-40% cpu (% of one core) and our Mac builds run about 25-80% cpu while being the same code.

No. There is only the main loop and the input thread. Here’s the main loop’s Mac look that causes 99% load:

[code]Dim GetInputThread As New thread
AddHandler GetInputThread.Run, WeakAddressOf InputThreadHandler
GetInputThread.Run

Dim DeviceFound, DeviceConnected As Boolean
#If TargetMacOS
Dim device As HIDAPIDeviceMBS
Do
Dim DeviceInfo As HIDAPIDeviceInfoMBS = HIDAPIDeviceMBS.Enumerate(vendor, productID)
If DeviceInfo <> Nil Then
If Not DeviceFound Then
DeviceFound = True
Device = HIDAPIDeviceMBS.Open(Vendor, ProductID)
If device <> Nil Then
Print “Connected”
DeviceConnected = True
Else
//Print “Failed to open 2D Barcode Reader”
End If
End If
If DeviceConnected Then
Dim Result As MemoryBlock = device.ReadTimeOut(100, 1000)
If result <> Nil Then
Dim ReportID As Integer = result.UInt8Value(0)
Dim Length As Integer = result.UInt8Value(1)-1
Dim Output As String = DefineEncoding(result.StringValue(2,Length), Encodings.utf8)
Print "Data " + output
End If
Else
Device = HIDAPIDeviceMBS.OpenPath(DeviceInfo.path)
If device <> Nil Then
Print “Connected”
DeviceConnected = True
Else
System.DebugLog HIDAPIDeviceMBS.LoadError
End If
End If
Else
If DeviceConnected Or DeviceFound Then
Print “Disconnected”
device = Nil
DeviceConnected = False
DeviceFound = False
End If
End If
app.DoEvents(500)
Loop Until app.quitapp[/code]

But DelayMBS instead of DoEvents or SleepCurrentThread brings it down to under 2% …
(and with a bit of fine-tuning below 1%. But why? Rather why not: Shouldn’t the Xojo methods do something very similar?)

[quote=429614:@Ulrich Bogun]But DelayMBS instead of DoEvents or SleepCurrentThread brings it down to under 2% …
(and with a bit of fine-tuning below 1%. But why? Rather why not: Shouldn’t the Xojo methods do something very similar?)[/quote]

DelayMbS blocks your loop, so that explains the lower percentage.

There is no event based system you can use?

No, this class is not event-driven. Anyway, it’s working nicely now, and DelayMBS has some yielding options, so that is no problem.

you could combine doEvents and calls to DelayMBS.

Instead of 500ms for doEvents, better do a loop and count from 1 to 5 and do

for I as integer = 1 to 5 app.DoEvents(0) DelayMBS 0.1 next

Thank you, @Christian!
Do you know if the difference in console doevents (which I don’t have always, but in this case maybe because there is an input read thread that runs in parallel to the main loop) could have something to do with the Mac in this case just changing to the thread context in each doevents call whereby Windows is not that fast and sleeps most of the time? Or similar?

(Because that would be the answer to this thread, while your approach is the solution – and because on the other hand I would disagree that Window code is more efficient. My findings (which may be caused by my Parallels setup solely) are usually rather contrary to Derk’s statement above.)

When building a console app that will run for a while, you MUST create your own main event loop. Something like

While Not Done App.DoEvents(10) Wend
Now you may also want to put the ms parameter in a property and only have it run fast (10ms) when the app is doing something and slow (500-1000ms) when it’s not. Whatever you do, the slow value becomes the maximum delay for the helper to spin up and start processing, so keep that in mind.

About Windows… the threshold of what Windows considers “not responding” is very different here and seems to very between versions of Windows, although I’ve never measured by how much. I tend to use 20-50ms just to keep the process responsive.

[quote=429767:@Greg O’Lone]When building a console app that will run for a while, you MUST create your own main event loop. Something like

While Not Done App.DoEvents(10) Wend
Now you may also want to put the ms parameter in a property and only have it run fast (10ms) when the app is doing something and slow (500-1000ms) when it’s not. Whatever you do, the slow value becomes the maximum delay for the helper to spin up and start processing, so keep that in mind.

About Windows… the threshold of what Windows considers “not responding” is very different here and seems to very between versions of Windows, although I’ve never measured by how much. I tend to use 20-50ms just to keep the process responsive.[/quote]

This is what we do alot, since it’s a very powerfull feature to speedup or slow down a process effectively good for a Raspberry Pi where a battery powered device does intensive processing, after it App.DoEvents(1000) to run the loop only once per second. If it needs more processing we use App.DoEvents(10) or App.DoEvents(25) depending on what it does.

For example a Mailing daemon wants to check for sending emails every 10 seconds you’d have a loop like this:

'Console app run event
'MilliSecondsToSystem is an inteter property in app with default set to 10

While Not Done
    MainLoop() 'A method that is the actual mainloop.
    App.DoEvents(MilliSecondsToSystem)
Wend

Return 0 'Returns the errorcode (0 for success)

In MainLoop() you’d wanna check if a mail in in a queue and send it setting MilliSecondsToSystem = 10 untill the SMTPSocket’s mailsent event fires, there you set App.MilliSecondsToSystem back to 10000 (10 seconds)