Most Accurate Timer on MacOS












3















I have an app that reads environmental data from a USB sensor connected to a Mac. Users are able to configure how often the app samples data and how often the app averages those samples and logs the average to a file.



I first used NSTimer but that was wildly inaccurate, especially when the display went to sleep. I am now using a DispatchSourceTimer but it is still losing 1 millisecond about every 21-23 seconds which is about 1 second every 6 hours or so. I'd ideally like that to be less than 1 second per day.



Any ideas how I can tune in the timer to be a little more accurate?



func setupTimer() -> DispatchSourceTimer {
let timer = DispatchSource.makeTimerSource(flags: .strict, queue: nil)
let repeatInterval = DispatchTimeInterval.seconds(samplingInterval)
let deadline : DispatchTime = .now() + repeatInterval
timer.schedule(deadline: deadline, repeating: repeatInterval, leeway: .nanoseconds(0))
timer.setEventHandler(handler: self.collectPlotAndLogDatapoint)
return timer
}

func collectPlotAndLogDatapoint() {
samplingIntervalCount += 1
let dataPoint : Float = softwareLoggingDelegate?.getCurrentCalibratedOutput() ?? 0
accumulatedTotal += dataPoint
if samplingIntervalCount == loggingInterval / samplingInterval{
let average = self.accumulatedTotal/Float(self.samplingIntervalCount)
DispatchQueue.global().async {
self.logDataPoint(data: average)
self.chartControls.addPointsToLineChart([Double(average)], Date().timeIntervalSince1970)
self.samplingIntervalCount = 0
self.accumulatedTotal = 0
}
}
}









share|improve this question




















  • 1





    What about comparing the time in your event handler to the system time as got from DispatchTime.now() and adjusting the firing interval accordingly when the drift gets unacceptably large?

    – JeremyP
    Nov 20 '18 at 16:41








  • 2





    Just in case, make sure you disable App Nap.

    – Ken Thomases
    Nov 20 '18 at 17:05











  • @KenThomases I'm surprised I haven't seen this yet with all my searching how to fix this. Thanks for commenting. It is now disabled while logging is active.

    – jgramse
    Nov 20 '18 at 17:29











  • @JeremyP I think that is probably going to be the best approach and it should work well. I was hoping the timer would auto-calibrate itself in some way but I guess that's just wishful thinking.

    – jgramse
    Nov 20 '18 at 17:29
















3















I have an app that reads environmental data from a USB sensor connected to a Mac. Users are able to configure how often the app samples data and how often the app averages those samples and logs the average to a file.



I first used NSTimer but that was wildly inaccurate, especially when the display went to sleep. I am now using a DispatchSourceTimer but it is still losing 1 millisecond about every 21-23 seconds which is about 1 second every 6 hours or so. I'd ideally like that to be less than 1 second per day.



Any ideas how I can tune in the timer to be a little more accurate?



func setupTimer() -> DispatchSourceTimer {
let timer = DispatchSource.makeTimerSource(flags: .strict, queue: nil)
let repeatInterval = DispatchTimeInterval.seconds(samplingInterval)
let deadline : DispatchTime = .now() + repeatInterval
timer.schedule(deadline: deadline, repeating: repeatInterval, leeway: .nanoseconds(0))
timer.setEventHandler(handler: self.collectPlotAndLogDatapoint)
return timer
}

func collectPlotAndLogDatapoint() {
samplingIntervalCount += 1
let dataPoint : Float = softwareLoggingDelegate?.getCurrentCalibratedOutput() ?? 0
accumulatedTotal += dataPoint
if samplingIntervalCount == loggingInterval / samplingInterval{
let average = self.accumulatedTotal/Float(self.samplingIntervalCount)
DispatchQueue.global().async {
self.logDataPoint(data: average)
self.chartControls.addPointsToLineChart([Double(average)], Date().timeIntervalSince1970)
self.samplingIntervalCount = 0
self.accumulatedTotal = 0
}
}
}









share|improve this question




















  • 1





    What about comparing the time in your event handler to the system time as got from DispatchTime.now() and adjusting the firing interval accordingly when the drift gets unacceptably large?

    – JeremyP
    Nov 20 '18 at 16:41








  • 2





    Just in case, make sure you disable App Nap.

    – Ken Thomases
    Nov 20 '18 at 17:05











  • @KenThomases I'm surprised I haven't seen this yet with all my searching how to fix this. Thanks for commenting. It is now disabled while logging is active.

    – jgramse
    Nov 20 '18 at 17:29











  • @JeremyP I think that is probably going to be the best approach and it should work well. I was hoping the timer would auto-calibrate itself in some way but I guess that's just wishful thinking.

    – jgramse
    Nov 20 '18 at 17:29














3












3








3








I have an app that reads environmental data from a USB sensor connected to a Mac. Users are able to configure how often the app samples data and how often the app averages those samples and logs the average to a file.



I first used NSTimer but that was wildly inaccurate, especially when the display went to sleep. I am now using a DispatchSourceTimer but it is still losing 1 millisecond about every 21-23 seconds which is about 1 second every 6 hours or so. I'd ideally like that to be less than 1 second per day.



Any ideas how I can tune in the timer to be a little more accurate?



func setupTimer() -> DispatchSourceTimer {
let timer = DispatchSource.makeTimerSource(flags: .strict, queue: nil)
let repeatInterval = DispatchTimeInterval.seconds(samplingInterval)
let deadline : DispatchTime = .now() + repeatInterval
timer.schedule(deadline: deadline, repeating: repeatInterval, leeway: .nanoseconds(0))
timer.setEventHandler(handler: self.collectPlotAndLogDatapoint)
return timer
}

func collectPlotAndLogDatapoint() {
samplingIntervalCount += 1
let dataPoint : Float = softwareLoggingDelegate?.getCurrentCalibratedOutput() ?? 0
accumulatedTotal += dataPoint
if samplingIntervalCount == loggingInterval / samplingInterval{
let average = self.accumulatedTotal/Float(self.samplingIntervalCount)
DispatchQueue.global().async {
self.logDataPoint(data: average)
self.chartControls.addPointsToLineChart([Double(average)], Date().timeIntervalSince1970)
self.samplingIntervalCount = 0
self.accumulatedTotal = 0
}
}
}









share|improve this question
















I have an app that reads environmental data from a USB sensor connected to a Mac. Users are able to configure how often the app samples data and how often the app averages those samples and logs the average to a file.



I first used NSTimer but that was wildly inaccurate, especially when the display went to sleep. I am now using a DispatchSourceTimer but it is still losing 1 millisecond about every 21-23 seconds which is about 1 second every 6 hours or so. I'd ideally like that to be less than 1 second per day.



Any ideas how I can tune in the timer to be a little more accurate?



func setupTimer() -> DispatchSourceTimer {
let timer = DispatchSource.makeTimerSource(flags: .strict, queue: nil)
let repeatInterval = DispatchTimeInterval.seconds(samplingInterval)
let deadline : DispatchTime = .now() + repeatInterval
timer.schedule(deadline: deadline, repeating: repeatInterval, leeway: .nanoseconds(0))
timer.setEventHandler(handler: self.collectPlotAndLogDatapoint)
return timer
}

func collectPlotAndLogDatapoint() {
samplingIntervalCount += 1
let dataPoint : Float = softwareLoggingDelegate?.getCurrentCalibratedOutput() ?? 0
accumulatedTotal += dataPoint
if samplingIntervalCount == loggingInterval / samplingInterval{
let average = self.accumulatedTotal/Float(self.samplingIntervalCount)
DispatchQueue.global().async {
self.logDataPoint(data: average)
self.chartControls.addPointsToLineChart([Double(average)], Date().timeIntervalSince1970)
self.samplingIntervalCount = 0
self.accumulatedTotal = 0
}
}
}






swift macos grand-central-dispatch nstimer






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 20 '18 at 18:07









Damon

523318




523318










asked Nov 20 '18 at 16:35









jgramsejgramse

286




286








  • 1





    What about comparing the time in your event handler to the system time as got from DispatchTime.now() and adjusting the firing interval accordingly when the drift gets unacceptably large?

    – JeremyP
    Nov 20 '18 at 16:41








  • 2





    Just in case, make sure you disable App Nap.

    – Ken Thomases
    Nov 20 '18 at 17:05











  • @KenThomases I'm surprised I haven't seen this yet with all my searching how to fix this. Thanks for commenting. It is now disabled while logging is active.

    – jgramse
    Nov 20 '18 at 17:29











  • @JeremyP I think that is probably going to be the best approach and it should work well. I was hoping the timer would auto-calibrate itself in some way but I guess that's just wishful thinking.

    – jgramse
    Nov 20 '18 at 17:29














  • 1





    What about comparing the time in your event handler to the system time as got from DispatchTime.now() and adjusting the firing interval accordingly when the drift gets unacceptably large?

    – JeremyP
    Nov 20 '18 at 16:41








  • 2





    Just in case, make sure you disable App Nap.

    – Ken Thomases
    Nov 20 '18 at 17:05











  • @KenThomases I'm surprised I haven't seen this yet with all my searching how to fix this. Thanks for commenting. It is now disabled while logging is active.

    – jgramse
    Nov 20 '18 at 17:29











  • @JeremyP I think that is probably going to be the best approach and it should work well. I was hoping the timer would auto-calibrate itself in some way but I guess that's just wishful thinking.

    – jgramse
    Nov 20 '18 at 17:29








1




1





What about comparing the time in your event handler to the system time as got from DispatchTime.now() and adjusting the firing interval accordingly when the drift gets unacceptably large?

– JeremyP
Nov 20 '18 at 16:41







What about comparing the time in your event handler to the system time as got from DispatchTime.now() and adjusting the firing interval accordingly when the drift gets unacceptably large?

– JeremyP
Nov 20 '18 at 16:41






2




2





Just in case, make sure you disable App Nap.

– Ken Thomases
Nov 20 '18 at 17:05





Just in case, make sure you disable App Nap.

– Ken Thomases
Nov 20 '18 at 17:05













@KenThomases I'm surprised I haven't seen this yet with all my searching how to fix this. Thanks for commenting. It is now disabled while logging is active.

– jgramse
Nov 20 '18 at 17:29





@KenThomases I'm surprised I haven't seen this yet with all my searching how to fix this. Thanks for commenting. It is now disabled while logging is active.

– jgramse
Nov 20 '18 at 17:29













@JeremyP I think that is probably going to be the best approach and it should work well. I was hoping the timer would auto-calibrate itself in some way but I guess that's just wishful thinking.

– jgramse
Nov 20 '18 at 17:29





@JeremyP I think that is probably going to be the best approach and it should work well. I was hoping the timer would auto-calibrate itself in some way but I guess that's just wishful thinking.

– jgramse
Nov 20 '18 at 17:29












1 Answer
1






active

oldest

votes


















1














The answers (and comments in response) to this seem to suggest that sub-millisecond precision is hard to obtain in Swift:



How do I achieve very accurate timing in Swift?



Apple apparently have their own dos & don'ts for high precision timers: https://developer.apple.com/library/archive/technotes/tn2169/_index.html



~3-4 seconds a day is pretty accurate for an environmental sensor, I'd imagine this would only prove an issue (or even noticeable) for those users who are wanting to take samples on an interval << 1 second.






share|improve this answer


























  • JeremyP's suggestion is also pretty good, if the offset is consistent (i.e. you are drifting 1s/6hr consistently) then you can apply a correction offset every 6 hours

    – zb1995
    Nov 20 '18 at 16:51











  • @zb1955 Yes 3-4 seconds a day is pretty accurate but we make research grade environmental sensors and our customers expect resolution better than this. In a normal consumer type product this wouldn't be an issue at all. I do think I'm going to try JeremyP's suggestion and implement some sort of auto-calibration. Thanks for posting!

    – jgramse
    Nov 20 '18 at 17:31











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53397513%2fmost-accurate-timer-on-macos%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














The answers (and comments in response) to this seem to suggest that sub-millisecond precision is hard to obtain in Swift:



How do I achieve very accurate timing in Swift?



Apple apparently have their own dos & don'ts for high precision timers: https://developer.apple.com/library/archive/technotes/tn2169/_index.html



~3-4 seconds a day is pretty accurate for an environmental sensor, I'd imagine this would only prove an issue (or even noticeable) for those users who are wanting to take samples on an interval << 1 second.






share|improve this answer


























  • JeremyP's suggestion is also pretty good, if the offset is consistent (i.e. you are drifting 1s/6hr consistently) then you can apply a correction offset every 6 hours

    – zb1995
    Nov 20 '18 at 16:51











  • @zb1955 Yes 3-4 seconds a day is pretty accurate but we make research grade environmental sensors and our customers expect resolution better than this. In a normal consumer type product this wouldn't be an issue at all. I do think I'm going to try JeremyP's suggestion and implement some sort of auto-calibration. Thanks for posting!

    – jgramse
    Nov 20 '18 at 17:31
















1














The answers (and comments in response) to this seem to suggest that sub-millisecond precision is hard to obtain in Swift:



How do I achieve very accurate timing in Swift?



Apple apparently have their own dos & don'ts for high precision timers: https://developer.apple.com/library/archive/technotes/tn2169/_index.html



~3-4 seconds a day is pretty accurate for an environmental sensor, I'd imagine this would only prove an issue (or even noticeable) for those users who are wanting to take samples on an interval << 1 second.






share|improve this answer


























  • JeremyP's suggestion is also pretty good, if the offset is consistent (i.e. you are drifting 1s/6hr consistently) then you can apply a correction offset every 6 hours

    – zb1995
    Nov 20 '18 at 16:51











  • @zb1955 Yes 3-4 seconds a day is pretty accurate but we make research grade environmental sensors and our customers expect resolution better than this. In a normal consumer type product this wouldn't be an issue at all. I do think I'm going to try JeremyP's suggestion and implement some sort of auto-calibration. Thanks for posting!

    – jgramse
    Nov 20 '18 at 17:31














1












1








1







The answers (and comments in response) to this seem to suggest that sub-millisecond precision is hard to obtain in Swift:



How do I achieve very accurate timing in Swift?



Apple apparently have their own dos & don'ts for high precision timers: https://developer.apple.com/library/archive/technotes/tn2169/_index.html



~3-4 seconds a day is pretty accurate for an environmental sensor, I'd imagine this would only prove an issue (or even noticeable) for those users who are wanting to take samples on an interval << 1 second.






share|improve this answer















The answers (and comments in response) to this seem to suggest that sub-millisecond precision is hard to obtain in Swift:



How do I achieve very accurate timing in Swift?



Apple apparently have their own dos & don'ts for high precision timers: https://developer.apple.com/library/archive/technotes/tn2169/_index.html



~3-4 seconds a day is pretty accurate for an environmental sensor, I'd imagine this would only prove an issue (or even noticeable) for those users who are wanting to take samples on an interval << 1 second.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 20 '18 at 16:56

























answered Nov 20 '18 at 16:49









zb1995zb1995

26111




26111













  • JeremyP's suggestion is also pretty good, if the offset is consistent (i.e. you are drifting 1s/6hr consistently) then you can apply a correction offset every 6 hours

    – zb1995
    Nov 20 '18 at 16:51











  • @zb1955 Yes 3-4 seconds a day is pretty accurate but we make research grade environmental sensors and our customers expect resolution better than this. In a normal consumer type product this wouldn't be an issue at all. I do think I'm going to try JeremyP's suggestion and implement some sort of auto-calibration. Thanks for posting!

    – jgramse
    Nov 20 '18 at 17:31



















  • JeremyP's suggestion is also pretty good, if the offset is consistent (i.e. you are drifting 1s/6hr consistently) then you can apply a correction offset every 6 hours

    – zb1995
    Nov 20 '18 at 16:51











  • @zb1955 Yes 3-4 seconds a day is pretty accurate but we make research grade environmental sensors and our customers expect resolution better than this. In a normal consumer type product this wouldn't be an issue at all. I do think I'm going to try JeremyP's suggestion and implement some sort of auto-calibration. Thanks for posting!

    – jgramse
    Nov 20 '18 at 17:31

















JeremyP's suggestion is also pretty good, if the offset is consistent (i.e. you are drifting 1s/6hr consistently) then you can apply a correction offset every 6 hours

– zb1995
Nov 20 '18 at 16:51





JeremyP's suggestion is also pretty good, if the offset is consistent (i.e. you are drifting 1s/6hr consistently) then you can apply a correction offset every 6 hours

– zb1995
Nov 20 '18 at 16:51













@zb1955 Yes 3-4 seconds a day is pretty accurate but we make research grade environmental sensors and our customers expect resolution better than this. In a normal consumer type product this wouldn't be an issue at all. I do think I'm going to try JeremyP's suggestion and implement some sort of auto-calibration. Thanks for posting!

– jgramse
Nov 20 '18 at 17:31





@zb1955 Yes 3-4 seconds a day is pretty accurate but we make research grade environmental sensors and our customers expect resolution better than this. In a normal consumer type product this wouldn't be an issue at all. I do think I'm going to try JeremyP's suggestion and implement some sort of auto-calibration. Thanks for posting!

– jgramse
Nov 20 '18 at 17:31


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53397513%2fmost-accurate-timer-on-macos%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

Does disintegrating a polymorphed enemy still kill it after the 2018 errata?

A Topological Invariant for $pi_3(U(n))$