high precision timer in Swift - ios

What would be the best solution in Swift for a precise clock to control external hardware? I need to write a loop function that would fire at a set rate per second (hundreds or thousands Hz) reliably and with high precision.

You can define a GCD timer property (because unlike NSTimer/Timer, you have to maintain your own strong reference to the GCD timer):
var timer: DispatchSourceTimer!
And then make a timer (probably a .strict one that is not subject to coalescing, app nap, etc., with awareness of the power/battery/etc. implications that entails) with makeTimerSource(flags:queue:):
let queue = DispatchQueue(label: "com.domain.app.timer", qos: .userInteractive)
timer = DispatchSource.makeTimerSource(flags: .strict, queue: queue)
timer.scheduleRepeating(deadline: .now(), interval: 0.0001, leeway: .nanoseconds(0))
timer.setEventHandler {
// do something
}
timer.resume()
Note, you should gracefully handle situations where the timer cannot handle the precision you are looking for. As the documentation says:
Note that some latency is to be expected for all timers, even when a leeway value of zero is specified.

Related

How to use gcd barrier in iOS?

I want to use gcd barrier implement a safe store object. But it not work correctly. The setter sometime is more early than the getter. What's wrong with it?
https://gist.github.com/Terriermon/02c446d1238ad6ec1edb08b607b1bf05
class MutiReadSingleWriteObject<T> {
let queue = DispatchQueue(label: "com.readwrite.concurrency", attributes: .concurrent)
var _object:T?
var object: T? {
#available(*, unavailable)
get {
fatalError("You cannot read from this object.")
}
set {
queue.async(flags: .barrier) {
self._object = newValue
}
}
}
func getObject(_ closure: #escaping (T?) -> Void) {
queue.async {
closure(self._object)
}
}
}
func testMutiReadSingleWriteObject() {
let store = MutiReadSingleWriteObject<Int>()
let queue = DispatchQueue(label: "com.come.concurrency", attributes: .concurrent)
for i in 0...100 {
queue.async {
store.getObject { obj in
print("\(i) -- \(String(describing: obj))")
}
}
}
print("pre --- ")
store.object = 1
print("after ---")
store.getObject { obj in
print("finish result -- \(String(describing: obj))")
}
}
Whenever you create a DispatchQueue, whether serial or concurrent, it spawns its own thread that it uses to schedule and run work items on. This means that whenever you instantiate a MutiReadSingleWriteObject<T> object, its queue will have a dedicated thread for synchronizing your setter and getObject method.
However: this also means that in your testMutiReadSingleWriteObject method, the queue that you use to execute the 100 getObject calls in a loop has its own thread too. This means that the method has 3 separate threads to coordinate between:
The thread that testMutiReadSingleWriteObject is called on (likely the main thread),
The thread that store.queue maintains, and
The thread that queue maintains
These threads run their work in parallel, and this means that an async dispatch call like
queue.async {
store.getObject { ... }
}
will enqueue a work item to run on queue's thread at some point, and keep executing code on the current thread.
This means that by the time you get to running store.object = 1, you are guaranteed to have scheduled 100 work items on queue, but crucially, how and when those work items actually start executing are up to the queue, the CPU scheduler, and other environmental factors. While somewhat rare, this does mean that there's a chance that none of those tasks have gotten to run before the assignment of store.object = 1, which means that by the time they do happen, they'll see a value of 1 stored in the object.
In terms of ordering, you might see a combination of:
100 getObject calls, then store.object = 1
N getObject calls, then store.object = 1, then (100 - N) getObject calls
store.object = 1, then 100 getObject calls
Case (2) can actually prove the behavior you're looking to confirm: all of the calls before store.object = 1 should return nil, and all of the ones after should return 1. If you have a getObject call after the setter that returns nil, you'd know you have a problem. But, this is pretty much impossible to control the timing of.
In terms of how to address the timing issue here: for this method to be meaningful, you'll need to drop one thread to properly coordinate all of your calls to store, so that all accesses to it are on the same thread.
This can be done by either:
Dropping queue, and just accessing store on the thread that the method was called on. This does mean that you cannot call store.getObject asynchronously
Make all calls through queue, whether sync or async. This gives you the opportunity to better control exactly how the store methods are called
Either way, both of these approaches can have different semantics, so it's up to you to decide what you want this method to be testing. Do you want to be guaranteed that all 100 calls will go through before store.object = 1 is reached? If so, you can get rid of queue entirely, because you don't actually want those getters to be called asynchronously. Or, do you want to try to cause the getters and the setter to overlap in some way? Then stick with queue, but it'll be more difficult to ensure you get meaningful results, because you aren't guaranteed to have stable ordering with the concurrent calls.

Mutex alternatives in swift

I have a shared-memory between multiple threads. I want to prevent these threads access this piece of memory at a same time. (like producer-consumer problem)
Problem:
A thread add elements to a queue and another thread reads these elements and delete them. They shouldn't access the queue simultaneously.
One solution to this problem is to use Mutex.
As I found, there is no Mutex in Swift. Is there any alternatives in Swift?
There are many solutions for this but I use serial queues for this kind of action:
let serialQueue = DispatchQueue(label: "queuename")
serialQueue.sync {
//call some code here, I pass here a closure from a method
}
Edit/Update: Also for semaphores:
let higherPriority = DispatchQueue.global(qos: .userInitiated)
let lowerPriority = DispatchQueue.global(qos: .utility)
let semaphore = DispatchSemaphore(value: 1)
func letUsPrint(queue: DispatchQueue, symbol: String) {
queue.async {
debugPrint("\(symbol) -- waiting")
semaphore.wait() // requesting the resource
for i in 0...10 {
print(symbol, i)
}
debugPrint("\(symbol) -- signal")
semaphore.signal() // releasing the resource
}
}
letUsPrint(queue: lowerPriority, symbol: "Low Priority Queue Work")
letUsPrint(queue: higherPriority, symbol: "High Priority Queue Work")
RunLoop.main.run()
Thanks to beshio's comment, you can use semaphore like this:
let semaphore = DispatchSemaphore(value: 1)
use wait before using the resource:
semaphore.wait()
// use the resource
and after using release it:
semaphore.signal()
Do this in each thread.
As people commented (incl. me), there are several ways to achieve this kind of lock. But I think dispatch semaphore is better than others because it seems to have the least overhead. As found in Apples doc, "Replacing Semaphore Code", it doesn't go down to kernel space unless the semaphore is already locked (= zero), which is the only case when the code goes down into the kernel to switch the thread. I think that semaphore is not zero most of the time (which is of course app specific matter, though). Thus, we can avoid lots of overhead.
One more comment on dispatch semaphore, which is the opposite scenario to above. If your threads have different execution priorities, and the higher priority threads have to lock the semaphore for a long time, dispatch semaphore may not be the solution. This is because there's no "queue" among waiting threads. What happens at this case is that higher priority
threads get and lock the semaphore most of the time, and lower priority threads can lock the semaphore only occasionally, thus, mostly just waiting. If this behavior is not good for your application, you have to consider dispatch queue instead.
You can use NSLock or NSRecursiveLock. If you need to call one locking function from another locking function use recursive version.
class X {
let lock = NSLock()
func doSome() {
lock.lock()
defer { lock.unlock() }
//do something here
}
}

Why is decreasing interval not speeding up iOS timer execution?

When I run this timer code for 60 seconds duration/1 sec interval or 6 seconds/.1 sec interval it works as expected (completing 10X faster). However, decreasing the values to 0.6 seconds/.01 seconds doesn't speed up the overall operation as expected (having it complete another 10X faster).
When I set this value to less than 0.1 it doesn't work as expected:
// The interval to use
let interval: NSTimeInterval = 0.01 // 1.0 and 0.1 work fine, 0.01 does not
The rest of the relevant code (full playground here: donut builder gist):
// Extend NSTimeInterval to provide the conversion functions.
extension NSTimeInterval {
var nSecMultiplier: Double {
return Double(NSEC_PER_SEC)
}
public func nSecs() -> Int64 {
return Int64(self * nSecMultiplier)
}
public func nSecs() -> UInt64 {
return UInt64(self * nSecMultiplier)
}
public func dispatchTime() -> dispatch_time_t {
// Since the last parameter takes an Int64, the version that returns an Int64 is used.
return dispatch_time(DISPATCH_TIME_NOW, self.nSecs())
}
}
// Define a simple function for getting a timer dispatch source.
func repeatingTimerWithInterval(interval: NSTimeInterval, leeway: NSTimeInterval, action: dispatch_block_t) -> dispatch_source_t {
let timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue())
guard timer != nil else { fatalError() }
dispatch_source_set_event_handler(timer, action)
// This function takes the UInt64 for the last two parameters
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, interval.nSecs(), leeway.nSecs())
dispatch_resume(timer)
return timer
}
// Create the timer
let timer = repeatingTimerWithInterval(interval, leeway: 0.0) { () -> Void in
drawDonut()
}
// Turn off the timer after a few seconds
dispatch_after((interval * 60).dispatchTime(), dispatch_get_main_queue()) { () -> Void in
dispatch_source_cancel(timer)
XCPlaygroundPage.currentPage.finishExecution()
}
The interval you set for a timer is not guaranteed. It is simply a target. The system periodically checks active timers and compares their target fire time to the current time and if the fire time has passed, it fires the timer. But there is no guarantee as to how rapidly the system is checking the timer. So the shorter the target interval and the more other work a thread is doing, the less accuracy a timer will have. From Apple's documentation:
A timer is not a real-time mechanism; it fires only when one of the
run loop modes to which the timer has been added is running and able
to check if the timer’s firing time has passed. Because of the various
input sources a typical run loop manages, the effective resolution of
the time interval for a timer is limited to on the order of 50-100
milliseconds. If a timer’s firing time occurs during a long callout or
while the run loop is in a mode that is not monitoring the timer, the
timer does not fire until the next time the run loop checks the timer.
Therefore, the actual time at which the timer fires potentially can be
a significant period of time after the scheduled firing time.
This does indeed appear to be a playground limitation. I'm able to achieve an interval of 0.01 seconds when testing on an actual iOS device.
Although I was wrong in my initial answer about the limitation of the run loop speed – GCD is apparently able to work some magic behind the scenes in order to allow multiple dispatch sources to be fired per run loop iteration.
However, that being said, you should still consider that the fastest an iOS device's screen can refresh is 60 times a second, or once every 0.0167 seconds.
Therefore it simply makes no sense to be doing drawing updates any faster than that. You should consider using a CADisplayLink in order to synchronise drawing with the screen refresh rate – and adjusting your drawing progress instead of timer frequency in order to control the speed of progress.
A fairly rudimentary setup could look like this:
var displayLink:CADisplayLink?
var deltaTime:CFTimeInterval = 0
let timerDuration:CFTimeInterval = 5
func startDrawing() {
displayLink?.invalidate()
deltaTime = 0
displayLink = CADisplayLink(target: self, selector: #selector(doDrawingUpdate))
displayLink?.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
}
func doDrawingUpdate() {
if deltaTime >= timerDuration {
deltaTime = timerDuration
displayLink?.invalidate()
displayLink = nil
}
draw(CGFloat(deltaTime/timerDuration))
deltaTime += displayLink?.duration ?? 0
}
func draw(progress:CGFloat) {
// do drawing
}
That way you can ensure that you're drawing at the maximum frame-rate available, and your drawing progress won't be affected if the device is under strain and the run loop is therefore running slower.

How to update variable based on an external event in Swift?

I am using a Particle Core to get the temperature from my room. The temperature is accessed through the cloud, which is being constantly updated in a variable. This is how I access the variable and display it:
func updateTemp(){
let seconds = 3.0
let delay = seconds * Double(NSEC_PER_SEC) // nanoseconds per seconds
let dispatchTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(dispatchTime, dispatch_get_main_queue(), {
self.myPhoton?.getVariable("tempF", completion: { (result:AnyObject!, error:NSError!) -> Void in
if let _ = error {
print("Failed reading temperature from device")
}
else {
if let larry = result as? Int {
self.temp.text="\(larry)˚"
self.truth++ //Once a value has been found, update the count.
}
}
})
})
}
override func viewDidLoad() {
sparkStart()
}
override func viewDidLayoutSubviews() {
updateTemp()
NSTimer.scheduledTimerWithTimeInterval(100.0, target: self, selector: "updateTemp", userInfo: nil, repeats: true) //Gaurantees that the app is updated every 100 seconds. That way we have a fresh temperature often.
//Stop the spinning once a value has been found
if truth == 1{
activity.stopAnimating()
activity.removeFromSuperview()
}
}
Since this is my Particle Core detecting the temperature from environment, the temperature variable is constantly changing. However, when I use NSTimer, the code does not get updated in the time specified. Instead, it begins by updating based on the specified time, but then the time starts decreases exponentially and the variable is updated every 0.001 seconds or so. Any thoughts?
Im assuming what we see is not the full code. In your viewDidLayoutSubviews function, you call updateTemp twice. Once explicitly and once via timer callback.
Your updateTemp function schedules the network call in the main run loop, that's where the timer is also running. The dispatch_after function queues the execution of the readout updates one after the other. I am now assuming, that something in your display code causes repeated triggers of viewDidLayoutSubviews, each of which schedules two new updates etc. Even if the assumption is false (there are a couple of other possibilities due to network code being slow and the timer also running in the main run loop), I am guessing if you drop the explicit call to updateTemp you'll lose the "exponential" and should be fine.
In general, as the web call is largely asynchronous, you could just use the timer and call your sensor directly or if you feel GCD has an important performance advantage switch to dispatch_async and apply for the next available queue with each call via calling dispatch_get_global_queue

iOS - dispatcherTimer blocking touches events?

I am using the dispatcher source timer update a view at different frame rates. (8, 12 or 24 FPS)
Here is the code that initializes the dispatcherTimer and the function used to create the timer.
(this function is directly taken from apple doc in the subsection "creating a timer": http://developer.apple.com/library/mac/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/GCDWorkQueues/GCDWorkQueues.html)
call:
self.dispatchTimer = [self createDispatchTimerWithInterval:self.project.frameDuration * NSEC_PER_SEC
leeway:0.0 * NSEC_PER_SEC
queue:dispatch_get_main_queue()
block:displayFrame];
function:
- (dispatch_source_t)createDispatchTimerWithInterval:(uint64_t)interval leeway:(uint64_t)leeway queue:(dispatch_queue_t)queue block:(dispatch_block_t)block {
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
0, 0, queue);
if (timer) {
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway);
dispatch_source_set_event_handler(timer, block);
dispatch_resume(timer);
}
return timer;
}
My view updates perfectly, but the touch events are not caught. My first bet would be that the block "displayFrame" takes too much processing time because if I reduce the frameDuration to 0.5 second or so, the touch events are caught.
I only tested this on iOS 4 with a iPad 2.
Any help or hint would be greatly appreciated!
Etienne
UPDATE
I have asked a similar question on the apple developper forum, here is the answer I got: https://devforums.apple.com/thread/156633?tstart=0
The main run loop drains the main queue after each pass through the runloop. I think you're right when you say your duration is too short. If the source is adding new blocks to the queue faster than they can be drained, I would certainly expect the runloop to never resume processing events (since it's constantly trying to drain the queue).

Resources