Maintain process / timer priority when display sleeps

I am writing a data acquisition and control application which needs to continuously sample data from devices, perfom calculations, and output results to devices (the hardware is either serial or ethernet). This app will run typically for days at a time, 24 hours a day, with very little user interaction. I am using timer callbacks, which works fine as long as there is user activity and the screen is not in sleep or screen saver. However, when there is no user activity and the screen sleeps, I find my callbacks are not occuring with good frequency. Now, I'm not doing any high speed sampling here- I'm in the range of 10's of samples / second, not hundreds or thousands, but I would like it to be consistent. I am finding when the display sleeps, there may be several seconds gap in samples.


I have tried putting:


myActivityRef = [[NSProcessInfo processInfo] beginActivityWithOptions:NSActivityLatencyCritical reason:@"DAQC Processing"];


but am still seeing sample frequency drop off when there is no user activity.


Testing on OS X 10.14.6, sleep set to never, display sleep set to 1 hour, screen saver set to 30 minutes.

Accepted Reply

First, you're keeping a strong reference to myActivityRef for the duration, right?


Next, I'd try using NSActivityBackground instead of, or perhaps in addition to, NSActivityLatencyCritical. (The latter is documented to say very few apps really need it.) The bit mask values for those two options do not overlap. It's conceivable that NSActivityLatencyCritical without NSActivityBackground is interpreted as only needing lowest latency when in the foreground.


If that doesn't do it, try NSActivityUserInitiated.

Replies

UPDATE: I found an error, which fixed part of the problem: My timers were in NSRunLoopDefaultMode. Putting them in NSRunLoopCommonModes seems to have fixed the latency problem with the screensaver active. However with display sleep active the latency still occurs (Added some diagnostic messages and am seeing time intervals from about 4 to about 20 seconds for a timer set to repeat every 0.5 seconds.

First, you're keeping a strong reference to myActivityRef for the duration, right?


Next, I'd try using NSActivityBackground instead of, or perhaps in addition to, NSActivityLatencyCritical. (The latter is documented to say very few apps really need it.) The bit mask values for those two options do not overlap. It's conceivable that NSActivityLatencyCritical without NSActivityBackground is interpreted as only needing lowest latency when in the foreground.


If that doesn't do it, try NSActivityUserInitiated.

Yes, I do keep the reference to the returned activity object. Indeed, your suggestion of using NSActivityBackground option solved the problem. using NSActivityUserInitiated also works and (as confirmed in ActivityMonitor) also makes the app prevent sleeping, so I don't have to disable sleep system wide.


I found this document, which I think explains what was happening (the system was putting it in App Nap which, as stated, reduces timer firing frequency) https://developer.apple.com/library/archive/documentation/Performance/Conceptual/power_efficiency_guidelines_osx/AppNap.html#//apple_ref/doc/uid/TP40013929-CH2-SW1


I am still seeing some odd extra latency, for example, when choosing a menu item that opens a window I get a callback times in the range of ~0.8 - 1.1 seconds (the timer interval is 0.5 seconds). I can probably live with this, but it seems like it should do better. Weirdly, when the app is in the background it works BETTER- almost never throws a time over 0.6 seconds (I have it set to log a message if it is over this time). even when choosing menus in the other app, moving windows around, etc.

Is your timer firing on the main thread? If on a background thread, does the timer callback interact with the main thread? Either of those might explain why GUI operations might interfere with the timer.

Right Again! detached a new thread to run the timer and now not seeing any latency from user actions. Much better stability overall on the timing accuracy.