I am finally trying to get my successful app (Find Any File) to use true multitasking by employing a Helper app (as a Console build).
I am using Xojo’s IPCSocket to communicate between my Host app and the Helper. The Helper uses Threads to perform its tasks.
And while this all works, the Host app (and not the Helper) then goes into a state where it gets > 1000 wakeups per second (as seen in Activity Monitor.app) and soon OS X interjects and invokes a Spindump and does more bad stuff which I need to prevent.
The Console logs this then:
process Find Any File.de caught causing excessive wakeups. Observed wakeups rate (per sec): 896; Maximum permitted wakeups rate (per sec): 150; Observation period: 300 seconds; Task lifetime number of wakeups: 45596
Does anyone know what’s going on here and how to avoid this? Is it the IPCSocket that’s buggy, perhaps?
There’s a Plist setting to keep an App from using AppNap. Perhaps that’s the first place to start? If Find Any File is really just waiting for the helper app then perhaps you keep it from going to ‘sleep’ in the first place.
Joe, the latest I’ve tried is 2015r2.2
Do I need 2015r3 to make this work?
It appears that it’s indeed caused by the IPCSocket as a process sampling shows that it’s running into related code.
I would like to be able to have more control over this - I am already using Timers to manage wakeups of my app, so I’d like to turn off the automatic wakeups the the Socket appears to perform to look for new data all the time. Is there a way, especially with older Xojo versions (I’d like to get this working with 2013r3.3 as that’s what I use to build FAF in order to keep supporting 10.6)?
Bob, the only way to not letting it going to sleep would be to block the event handling, i.e. never return from the event of the Button.Push handler that starts the whole process. But that would not only lead to 100% CPU use by this app but would also soon lead to the msg that the app is not responding (including the spinning beach ball). So, that’s not an option.
Threads got a big overhaul in 2015r3 and 2015r3.1 that reduced the number of spurious wakes. If FaF itself isn’t using threads and it truly is the IPCSocket overhead, there’s not much that can be done about it without fixes on the framework side.
@Joe Ranieri, I just tried it with 2015r3.1 - same problem. > 1000 wakeups per second (and CPU usage below 10%) as long as I keep the IPCSocket open, even if there’s no data send or received over it.
And the app is not running any Threads either (it used to initially, but when it’s done, it’s not running any, and does no other processing either - it’s just sitting there idling, but with high CPU usage around 10% due to the wakeups).
As soon as I dispose of the IPCSocket, wakeups go back to normal (below a 100/s). Damn.
Looks like I’ll have to implement my own IPCSocket then.
Joe, could you give a few pointers what kind of APIs are used by the Xojo implementation? I had already tried it with BSD sockets but that didn’t work out well because of the difficulty to use the select() command in Xojo without pre-emptive threads.
Okay, after some long digging I found the culprit.
It’s actually not caused by using IPCSocket but by using the Shell class (which I use to invoke the helper program).
What Xojo does is that it installs a polling timer using CFRunLoopTimerCreate with a period 1ms. That’s clearly too frequent. I’ve also found out how to change that value. So I’ve changed it to 10ms and all is good now.
Huh, what does you surprise about this now? Wasn’t that clear from my and other people’s previous descriptions that this is happening? Why else would we all get 1000 wakeups / second? I just spent two days digging into this because I had the impression I wasn’t taken seriously.
Ah, but I thought it would have been easy to search the source code for the few calls where a timer is set, and it would have been obvious that there must be at least one that requests this short period. It took me two days, most of it looking in the wrong part of the code until I finally found that it’s related to the Shell. Had I had the source code, this would have been a search of a few minutes.
On the plus side, I’ve learned a bit more about Hopper, gdb and lldb, and I can now fix this in existing libs, keeping my code working on 10.6.8
Marco, in my case it was due to using a Shell in Async mode, plus using IPCSockets, though I am not sure if it’s also happening without IPCSockets.
If you want to work around it - Xojo Inc doesn’t allow us to patch the bug in the framework, although that would have been easy. So I’ve filed a bug report in hope it gets fixed soon: <https://xojo.com/issue/41687>
If you want to fix this yourself, you’d have to somehow intercept invocations to the OS X function CFRunLoopTimerCreate and modify the period value from 0.001 to 0.01 or something higher. That won’t violate the EULA because it’s not patching the code nor does it require RE’ing the framework because simply observing the calls to the OS is all it takes, and it was pretty clear to me from the beginning that this is a timer issue, and there’s only one Timer function for that, i.e. CFRunLoopTimerCreate.
Unfortunately, I haven’t figured out how to intercept OS X function calls, yet. I know how to intercept Cocoa ObjC functions (using OS X “objc_runtime” calls), but this is a Core Foundation C-like function and I haven’t tried intercepting those yet (or it’s so long ago that I don’t remember). Does anyone here know how to hook into a CF function in Xojo code?
Only when the terms of the EULA are violated to do so
Norman - huh? Do you mean there are exceptions? Are there cases where we are allowed to patch a bug in the framework that do not violate the EULA? The EULA, as I know it, simply state that we may not modify the framework in any case. Please elaborate.