Do I need a high precision timer?

Don't use a high precision timer unless you really need it. They consume compute cycles and battery. There can only be a limited number of high precsion timers active at once. A high precision timer is "first in line", and not every timer can be first. When too many try, all the timers lose accuracy.

Example applications that are candidates for high precision timers are games that need to provide precise frame rates, or daemons that are streaming data to hardware with limited buffering, such as audio or video data.

A suggestion for synchronizing with display updates

If you're writing code that needs to synchronize with frame buffer or display updates, Apple has already done much of the hard work for you. If you are developing for iOS, please see the CADisplayLink class, found in the QuartzCore.framework. If you are targeting OS X, see CVDisplayLink, also found in QuartzCore.framework.

iOS: CADisplayLink Class Reference

OS X: CVDisplayLink Reference

How do timers work?

There are many API's in iOS and OS X that allow waiting for a specified period of time. They may be Objective C or C, and they take different kinds of arguments, but they all end up using the same code inside the kernel. Each timer api tells the kernel it needs to wait until a certain time, for example 10 seconds from now. The kernel keeps track of every thread, and when a timer request comes in, that thread is marked as "I'd like to run in 10 seconds".

The kernel tries to be as frugal as possible with cpu cycles, so if there is no other work to do, it will put the cpu's to sleep for 10 seconds, then wake up and run your thread.

Of course, that is an optimum situation, and in the real world, things never seem to work that easily! In a real situation, there are many threads that want to run, and many threads making timer requests, and the kernel has to manage them all. With thousands of threads and only a few cpu's, its easy to see how timers might be inaccurate.

How do high precision timers work?

The only difference between a regular timer and a high precision timer is the scheduling class of the thread making the timer request. Threads that are in the real time scheduling class get first class treatment. They go to the front of the line whenever they need to run. If there is a conflict with multiple threads wanting to run in 10 seconds, a real time thread always goes first.

How do I get put into the real time scheduling class?

Listing 1  The following code will move a pthread to the real time scheduling class

#include <mach/mach.h>
#include <mach/mach_time.h>
#include <pthread.h>
 
void move_pthread_to_realtime_scheduling_class(pthread_t pthread)
{
    mach_timebase_info_data_t timebase_info;
    mach_timebase_info(&timebase_info);
 
    const uint64_t NANOS_PER_MSEC = 1000000ULL;
    double clock2abs = ((double)timebase_info.denom / (double)timebase_info.numer) * NANOS_PER_MSEC;
 
    thread_time_constraint_policy_data_t policy;
    policy.period      = 0;
    policy.computation = (uint32_t)(5 * clock2abs); // 5 ms of work
    policy.constraint  = (uint32_t)(10 * clock2abs);
    policy.preemptible = FALSE;
 
    int kr = thread_policy_set(pthread_mach_thread_np(pthread_self()),
                   THREAD_TIME_CONSTRAINT_POLICY,
                   (thread_policy_t)&policy,
                   THREAD_TIME_CONSTRAINT_POLICY_COUNT);
    if (kr != KERN_SUCCESS) {
        mach_error("thread_policy_set:", kr);
        exit(1);
    }
}

The period, computation, constraint, and preemptible fields do have an effect, and more can be learned about them at:

Using the Mach Thread API to Influence Scheduling

Which timing API(s) should I use?

As mentioned above, all the timer methods end up in the same place inside the kernel. However, some of them are more efficient than the others. At the time this note was written, mach_wait_until() is the api we would recommend using. It has the lowest overhead of all the timing API that we measured. However, if you have specific needs that aren't met by mach_wait_until(), for example you need to wait on a condvar, then feel free to use the appropriate timer API.

Listing 2  This example code demonstrates using mach_wait_until() to wait exactly 10 seconds.

#include <mach/mach.h>
#include <mach/mach_time.h>
 
static const uint64_t NANOS_PER_USEC = 1000ULL;
static const uint64_t NANOS_PER_MILLISEC = 1000ULL * NANOS_PER_USEC;
static const uint64_t NANOS_PER_SEC = 1000ULL * NANOS_PER_MILLISEC;
 
static mach_timebase_info_data_t timebase_info;
 
static uint64_t abs_to_nanos(uint64_t abs) {
    return abs * timebase_info.numer  / timebase_info.denom;
}
 
static uint64_t nanos_to_abs(uint64_t nanos) {
    return nanos * timebase_info.denom / timebase_info.numer;
}
 
void example_mach_wait_until(int argc, const char * argv[])
{
    mach_timebase_info(&timebase_info);
    uint64_t time_to_wait = nanos_to_abs(10ULL * NANOS_PER_SEC);
    uint64_t now = mach_absolute_time();
    mach_wait_until(now + time_to_wait);
}

How accurate should high precision timers be?

Timer accuracy depends on many factors, including the type of hardware being run on, the load on that hardware, and the power available (battery vs plugged in). However, if an otherwise unloaded machine or device is consistently missing your scheduled time by more than 500 microseconds, that should be considered an error, please file a bug with Apple. Often times we can do much better than that, but its best to measure for yourself.

Timers are not accurate across a sleep and wake cycle of the hardware.

What are the do's and dont's of code running with high precision timers?

Do use as little cpu as possible during your timer loop. Remember that your thread now has special privileges, and when you're running, no one else can. Do try to stretch out your timer requests as much as you safely can. This allows the kernel to use less battery by sleeping more often and longer.

Don't spin loop! This burns cpu and battery at very high rates, and when newer faster hardware is released you'll burn cpu and battery even faster!

Don't create large numbers of real time threads. Real time scheduling isn't magic, it works by making your thread higher priority than other threads on the system. If everyone tries to crowd to the front of the line, all the real time threads will fail

Windows 平台的 GetTickCount 这样的函数,找到一个叫 mach_absolute_time() 的函数,但是Apple的文档非常不

给力,找个半天才比较清楚是怎么回事,原来这个函数返回的值只是启动后系统CPU/Bus的clock一个tick数,跟GetTickCount不同,

因为这个 GetTickCount 是系统启动后的毫秒数,所以要获得系统启动后的时间需要进行一次转换

https://developer.apple.com/library/ios/technotes/tn2169/_index.html

iOS 精确定时器的更多相关文章

  1. IOS 设置定时器

    IOS 设置定时器  自动滚动视图 定时发送坐标信息 即时显示 时钟 NSTimer *timer; - (void)start {//1second 调用一次 timer = [NSTimer sc ...

  2. iOS中定时器的使用

    1. NSTimer 不是很精确 2.CADisplayLink 屏幕 3.通过GCD来实现定时间器 //定时循环执行事件 //dispatch_source_set_timer 方法值得一提的是最后 ...

  3. 【转】IOS NSTimer 定时器用法总结

    原文网址:http://my.oschina.net/u/2340880/blog/398598 NSTimer在IOS开发中会经常用到,尤其是小型游戏,然而对于初学者时常会注意不到其中的内存释放问题 ...

  4. 【转】iOS中定时器NSTimer的使用

    原文网址:http://www.cnblogs.com/zhulin/archive/2012/02/02/2335866.html 1.初始化 + (NSTimer *)timerWithTimeI ...

  5. iOS中定时器NSTimer的使用-备用

    1.初始化 + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelect ...

  6. [置顶] ios 时间定时器 NSTimer应用demo

    原创文章,转载请注明出处:http://blog.csdn.net/donny_zhang/article/details/9251917 demo功能:ios NSTimer应用demo .ipho ...

  7. linux下使用select实现精确定时器

    在编写程序时,我们经常回用到定时器.本文讲述如何使用select实现超级时钟.使用select函数,我们能实现微妙级别精度的定时器.同时,select函数也是我们在编写非阻塞程序时经常用到的一个函数. ...

  8. IOS NSTimer 定时器用法总结

    NSTimer在IOS开发中会经常用到,尤其是小型游戏,然而对于初学者时常会注意不到其中的内存释放问题,将其基本用法总结如下: 一.初始化方法:有五种初始化方法,分别是 + (NSTimer *)ti ...

  9. iOS CADisplayLink 定时器的使用

    CADisplayLink 是一个能让我们以和屏幕刷新频率相同的频率将内容刻画到屏幕上的定时器,在应用中创建一个新的CADisplayLink对象,把他添加到一个runloop中,并且给他提供一个ta ...

随机推荐

  1. vmware虚拟机上网:host-only

    host-only配置 首先主机:vmware1要能共享本地连接这个网络,共享后vmware的ip会自动设置为如图 其次,vmware网络设置如图 最后,虚拟机设置如图 这样,主机与虚拟机之间就能pi ...

  2. SSL handshake failed: SSL 错误:在证书中检测到违规的密钥用法。

    问题:在WINDOWS中创建的SVN Server,在Linux client中无法连接.原因:WINDOWS中的证书无法被Linux正确识别,因此需要修改证书,以使双方都可以正确识别. 修改方法如下 ...

  3. find命令小结

    find命令小结 find命令用于在系统中查找文件,配合 -exec 选项或 xargs命令还能对查找到得文件执行一些列的自动化操作. 基本格式:find [-H] [-L] [-P] [path.. ...

  4. 在线压缩zip

    <?php //验证密码 $password = "test"; ?> <html> <head> <meta http-equiv=&q ...

  5. (菜鸟要飞系列)一,基于Asp.Net MVC5的后台管理系统(前言)

    今天真是个郁闷的日子,因为老师两个星期前给我的一个任务,用递归算法将Oracle数据库中用户信息及权限显示在jquery-treeView上,网上虽然有大神写出了这类算法,但是不贴全部代码,真的很难跟 ...

  6. int main(int argc,char* argv[]) 简单理解

    (1)第一个int代表整个main函数的返回值,若函数正常执行完毕,返回0,异常返回则是-1 (2)int argc代表命令行参数的总个数,既然是个数,那就是整型的,即:int; (3)char* a ...

  7. 分析 "ADO" "ADODB" "ADODC" 之间的区别与联系

    在敲学生信息管理系统的时候,通过查阅了解了一些关于 ADO / ADODB / ADODC / 的简单描述,想想将他们对 比着总结一下更容易理解记忆.尽管都是一些浅显的东西,不过对像我这样的菜鸟们还是 ...

  8. VBS基础篇 - 变量

    VBScript只有一种数据类型 —— Variant,它是根据上下文来判断是数字还是字符串.因为Variant是VBScript中唯一的数据类型,所以它也是VBScript中所有函数的返回值的数据类 ...

  9. LoadRunner 学习笔记(1)性能测试常见术语

    并发用户数据:与服务器进行交互的在线用户数量 请求响应时间:从Client端发出请求到得到响应的整个时间 一般包括网络响应时间 + server的响应时间 事务请求响应时间:完成这个事务所用的时间 这 ...

  10. ubuntu下搭建nfs,tftp,安装qt等一些基本的启动bootloader前的服务

    之前做三星的6410是在红帽下做的,现在公司给了个TI的AM3359的开发板,开发环境是ubuntu10-04.这周经过半天的研究对比,终于算是搭好tftp下载的一些服务了. [防火墙] sudo u ...