1. 程式人生 > >android手機高精度定時機制--higher timer tick 筆記版 轉載請註明出處---

android手機高精度定時機制--higher timer tick 筆記版 轉載請註明出處--- 阿新 發佈:2019-02-01


作者  
[email protected]

沒想到這篇隨意記錄的筆記成為老夫部落格裡閱讀量最多的。看來這的確是兄弟們關注較多的地方,待老夫抽時間把這個部分重新整理下,寫一個從核心到應用API的更新吧。

這裡簡單說一下android系統定時的原理。

首先,萬佛歸宗,在ARM SOC硬體體系中,通常會提供幾個硬體計數器,輸入為PLL過來的脈衝,計數到一定數量產生中斷。這就是硬體時鐘,可見其精度可以達到PLL的脈衝週期。

但是這個時鐘只能被核心感知,而且由於核心有時會關閉中斷,所以這個時鐘中斷有時不能被及時收到,產生偏移。但這不要緊,這只是脈衝週期級別的偏移,精度依然可以接受。

再扯遠一點,以前核心的定時機制是以tick為單位,而tick通常是1ms到數十ms產生一次,這依據具體的硬體系統而變。這樣其精度就只能以tick為單位,所以早期的核心裡tick就以為可控制的時間精度。

再往後人們希望更精確的定時,於是希望依據硬體時鐘精度來控制定時,於是就有了一個核心patch,在tick之間插入時候時鐘,再往後隨著linux架構的不斷完善,出現的hrtimer,這是不管三七二十一,以硬體時鐘作為定時的依據,而ticker只是其中的一種情況。

但是,hrtimer並不意味著依據此定時的應用就能真正的或者其精度(拋去中斷不能及時接受而產生的偏移)。這是因為作為一個分時系統(基於linux核心的android系統完全遵循其規律),即使到了觸發時刻如果對應的執行緒不能被及時排程,時鐘到來沒有意義。所以排程是另外一個最大的影響。

上面說的定時是基於硬體時鐘的定時機制,其前提是系統正常工作,其特點是精度高,但是系統休眠時這個機制就沒法工作。這時就是另外一個時鐘RTC的任務了。

所謂RTC即實時時鐘,在 ARM SOC硬體體系中有一塊區域非常特殊,由單獨的電路供電,而且有一個單獨的晶振為其提供脈衝,及時休眠也不例外,這就是RTC時鐘。

RTC不停地對晶振脈衝計數,用來長時間的定時,它有著喚醒處理器的作用,在Andorid系統中使用的定時通常是基於RTC工作的。

/****************************************原筆記*****************************************************/

android手機核心時鐘整體架構分為上下兩層,下層理解為物理時鐘的操控,即按照上層時鐘邏輯的要求產生物理時鐘中斷、程式設計產生下一次時鐘中斷、切換時鐘中斷產生的模式、初始、關閉物理時鐘。而上層時鐘的作用是根據核心執行時的要求對下層下發各種命令,並根據下層送上來的時鐘事件驅動核心的high resolution timer,schedule tick,tickless sleep等機制的執行。

1 初始化

Linux核心用struct clock_event_device;來管理時鐘裝置。
舉例來看:對於PXA系列SOC上,用於核心時鐘的定時器,就用了一個如下的結構來管理:


static struct clock_event_device ckevt_pxa_osmr0 = {
.name= "osmr0",
.features = CLOCK_EVT_FEAT_ONESHOT,
.shift = 32,
.rating = 200,
.cpumask = CPU_MASK_CPU0,
.set_next_event= pxa_osmr0_set_next_event,// 對物理暫存器程式設計以產生下一次時鐘中斷
.set_mode = pxa_osmr0_set_mode,//根據核心抽象邏輯的時鐘產生要求,實現物理晶片的操作
};


PXA 板級支援包在初始化的時候將這個核心時鐘設備註冊到核心。在核心原始碼樹下$SRC_ROOT/kernel/time裡的檔案是在核心邏輯層面管理時鐘的程式碼。PXA 板級支援包註冊的ckevt_pxa_osmr0會在這裡被近一步初始化:
當一個時鐘裝置被註冊到核心後,核心通過notify機制啟用時鐘相關管理程式碼,對於註冊新的時鐘裝置tick_check_new_device函式將初始化這個時鐘


/*
 * Check, if the new registered device should be used.
 */
static int tick_check_new_device(struct clock_event_device *newdev)
{

tick_setup_device(td, newdev, cpu, cpumask);//初始化該裝置
if (newdev->features & CLOCK_EVT_FEAT_ONESHOT)
tick_oneshot_notify();


spin_unlock_irqrestore(&tick_device_lock, flags);
return NOTIFY_STOP;



return ret;
}


static void tick_setup_device(struct tick_device *td,
     struct clock_event_device *newdev, int cpu,
     cpumask_t cpumask)
{





//注意在這裡,核心根據該時鐘的模式,將其設定為固定週期的核心時鐘中斷,還是非固定週期的核心時鐘中斷


if (td->mode == TICKDEV_MODE_PERIODIC)
tick_setup_periodic(newdev, 0);
else
tick_setup_oneshot(newdev, handler, next_event);

}


這裡關鍵的操作是對於固定週期的核心時鐘將其struct clock_event_device 的成員函式event_handler設定為tick_handle_periodic;


void tick_handle_periodic(struct clock_event_device *dev)
{

next = ktime_add(dev->next_event, tick_period);//確定下一次時鐘中斷的時間,注意這裡是tick_period,即為傳統unix作業系統下的tick時間。
for (;;) {
if (!clockevents_program_event(dev, next, ktime_get()))
return;
tick_periodic(cpu);
next = ktime_add(next, tick_period);
}
}


2 執行時分析
首先從核心中斷體系來看,核心時鐘中斷機制是其一個常規的中斷。PXA BSP包將
static struct irqaction pxa_ost0_irq = {
.name= "ost0",
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = pxa_ost0_interrupt,
.dev_id = &ckevt_pxa_osmr0,
};
中斷處理單元,在初始化時通過static void __init pxa_timer_init(void)掛入核心中斷處理連結串列,當硬體時鐘中斷到來時,核心找到pxa_ost0_irq的handler成員函式執行。而該中斷處理函式只做了2件事:關了時鐘中斷;將中斷時間送給struct clock_event_device的event_handler成員函式來執行。
static irqreturn_t
pxa_ost0_interrupt(int irq, void *dev_id)
{
struct clock_event_device *c = dev_id;


/* Disarm the compare/match, signal the event. */
OIER &= ~OIER_E0;
OSSR = OSSR_M0;
c->event_handler(c);


return IRQ_HANDLED;
}
這裡的event_handle即為我們上文看到的tick_handle_periodic函式


3 切換


為什麼要切換,其實如果linux核心沒有加入這一部分,無論timer這部分程式碼改動多大,都只是表面的形式的變化,其核心工作機理和原先的是一樣。


但是核心加入的這個新功能,使得linux向前進化了一大步。我們可以分析一下,既然時鐘中斷的週期是固定的,那麼我們能夠獲得的最小定時粒度,就決定於這個系統時鐘中斷週期,這個值如果太小就會使系統中時鐘中斷過於密集,如果太大系統的最小定時粒度就會過大,嚴重影響實時性。所以對於大部分處理器架構這個值在1~10MS之間。但是對於一些實時應用來說1MS實在是太長的時間的。而現代處理器無論是基於X86-64、IA32、IA64的PC、伺服器系統,還是基於的ARM低功耗嵌入式處理器,其硬體定時間隔的能力都遠遠小於1MS。另一方面,有些嵌入式晶片在sleep狀態下,不希望被時鐘中斷頻繁打斷,因為如果中斷到來這些晶片會切換到normal狀態下,造成不必要的耗電。所以基於以上情況,核心社群大幅度修改了linux核心時鐘架構,使得核心時候以我們需要的時間間隔到來。其具體做法如下:




首先要將固定週期的cpu時鐘中斷,改成非固定週期的cpu時鐘中斷。


$SRC_ROOT/kernel/time/tick-oneshot.c
int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *))
{
struct tick_device *td = &__get_cpu_var(tick_cpu_device);
struct clock_event_device *dev = td->evtdev;


if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT) ||
   !tick_device_is_functional(dev)) {


printk(KERN_INFO "Clockevents: "
      "could not switch to one-shot mode:");
if (!dev) {
printk(" no tick device\n");
} else {
if (!tick_device_is_functional(dev))
printk(" %s is not functional.\n", dev->name);
else
printk(" %s does not support one-shot mode.\n",
      dev->name);
}
return -EINVAL;
}
//這個本來是0
td->mode = TICKDEV_MODE_ONESHOT;
dev->event_handler = handler;
clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT);
tick_broadcast_switch_to_oneshot();
return 0;
}






#ifdef CONFIG_HIGH_RES_TIMERS
/**
 * tick_init_highres - switch to high resolution mode
 *
 * Called with interrupts disabled.
 */
int tick_init_highres(void)
{
return tick_switch_to_oneshot(hrtimer_interrupt);
}
#endif



相關推薦

android手機精度定時機制--higher timer tick 筆記 轉載註明出處--- <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4b2839243838202e39252

作者   [email protected] 沒想到這篇隨意記錄的筆記成為老夫部落格裡閱讀量最多的。看來這的確是兄弟們關注較多的地方,待老夫抽時間把這個部分重新整理下,寫一個從核心到應用API的更新吧。 這裡簡單說一下android系統定時的原理。 首先,萬佛歸

Android Studio 3.0.1 gradle編譯報錯 Error : unable to resolve dependency for <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a0c1

在app目錄下build.gradle中引用了第三方類庫,gradle編譯時不斷報錯,無法resolve第三方類庫,或者無法download第三方類庫dependencies { implementation fileTree(include: ['*.jar'],

Spring級話題<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b29ff2f7dcd3d0ded7">[email protected]a>***註解的工作原理

sso metadata bool logs tcl task ota -c ann 出自:http://blog.csdn.net/qq_26525215 @EnableAspectJAutoProxy @EnableAspectJAutoProxy註解 激活Aspe

android Studio 出現:Unable to resolve dependency for ':<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4b2a3b3b0b2f2e293e2c

li經千辛萬苦,我的新工程gradle搞定了 但是卻在變異的時候告訴我 Unable to resolve dependency for ':[email protected]/compileClasspath'xxx 等等,導致我的所有的依賴都拿不下來 我去,這不是要我的命嗎 然後又是一

android.view.WindowManager$BadTokenException: Unable to add window -- token <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2

android.view.WindowManager$BadTokenException: Unable to add window – token [email protected] is

Android探究之<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="9cdbeff3f2dccff9eef5fdf0f5e6f9f8d2fdf1f9">[email protected]a

@SerializedName註解的意義 當我們使用Gson解析Json資料時都會建立一個對應實體類,有時候Json資料裡面的欄位是Java關鍵詞或者Json資料裡面的欄位太簡單,我們想在實體類中自定義欄位名,這時就可以用@SerializedName註解。 @SerializedName註解,不管是物件

Android studio 下載依賴時出現Unable to resolve dependency for ':<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8feeffffcfebeaed

Android studio下載依賴時出現無法解析':app @ debug / compileClasspath'的依賴關係錯誤。 原因安裝Android studio時設定了代理或映象伺服器。  解決方法,在C盤中找到.gradle資料夾(一般都是C盤)如我的位置在用記事本開啟.g

升級 android studio 報錯Unable to resolve dependency for ':<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="026372724266676077

根據日誌裡顯示 http 127.0.0.1 。。。 總是無法build,確定是studio引入了本地的ip所以無法下載更新,於是在我們的studio中開啟System Settings 中的 Http Proxy看是否選擇的是 No proxy, 1 選擇了No proxy 如果是,就

【Spring】定時任務詳解例項<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="92bfd2c1f1faf7f6e7fef7f6">[email protected]a>

最近在做專案,時間比較緊張,也有比較久沒寫部落格了。 現在專案的Redis快取需要用到定時任務,就學習了一下Spring 的@Scheduled註解。使用起來很簡單。 這個例子是建立在之前我的一篇部落格的例項上面的。 也就是架好了SSM框架。 SSM

使用<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="027172706b6c654251616a6766776e67">[email protected]a>註解定時任務時將時間表達式寫入

第一種可以把Scheduled寫到xml檔案中進行配置。第二種在你的類前面新增@PropertySource("classpath:root/test.props")然後修改你的@Scheduled(cron="0/5 * * * * ? ") 為 @Scheduled(

Android 圖片適配使用<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="91f8fee2a3d1">[email protected]a>圖原理解析

在很多公司開發,可能公司只提供一套ios [email protected],[email protected],[email protected]圖片。本文以蘋果6為設計標準 1.首先解釋下android系統下dpi dpi是“dot pe

android 新增依賴出現Failed to resolve:"你新增的依賴名" 或者出現 <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="30545552455770735f5d40595c55

首先出現的問題是 [email protected]的問題,經過一波百度之後都說是AS build.gradle版本3.0以上的問題,但是經過一波修改之後並沒有什麼卵用,並沒有解決這個問題,並且出現了新的問題,就是Failed to resolve:.......

Android在<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6d2a04192d223e2e">[email protected]a>新建專案並上傳原生代碼

1.試了網上幾種方式,但都效果不佳 2.工具:[email protected] + android Studio 3.步驟:1⃣️先在git上新建Android專案 4.在本地A

Android Studio報錯Unable to resolve dependency for ':<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="721302023200171e">[email&#

Android Studio報錯Unable to resolve dependency for’:[email protected]/compileClasspath’:無法引用任何外部依賴的解決辦法 Android Studio 在引用外部依賴時

Android studio提交程式碼到<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b8ffd1ccf8f7ebfb">[email protected]a>

2,有Android studio開發環境 3,在OSC上建立專案 4,android studio建立本地專案,create git repository,選擇當前專案的根目錄: 5,以下為命令列操作:開啟本地的git bash命令列工具,cd進入專案資料夾位置,

android studio更新3.2遇到的坑,unable to resolve dependency for <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5a3b2a2a1a7474747474

距離第一次寫部落格轉眼一週多了,為什麼一直沒寫,真的這個過程中遇到了一些棘手的小麻煩 android studio更新3.2遇到的坑 4天前手賤更新了studio,然後新建工程就一堆報錯,照著網上的很多類似的部落格進行了處理,總結了一下無非以下幾種 1、降低依

android.view.WindowLeaked:Activity has leaked window <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="87c3e2e4e8f5d1eee2f0c7be

E/WindowManager: android.view.WindowLeaked: Activity com.activity.LoginActivity has leaked window [email protected][] that was origi

<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0a597a7863646d4a5969626f6e7f666f">[email protected]a>定時任務原始碼解析

本文以springboot中cron表示式配置的定時任務為例子。 在springboot中的啟動類中新增@EnableScheduling註解,在beanFactory中新增ScheduledAnnotationBeanPostProcessor作為bean初始化完畢後的

Linux時間子系統之六:精度定時器(HRTIMER)的原理和實現

3.4 size 屬於 running return repr 而是 復雜度 ctu 上一篇文章,我介紹了傳統的低分辨率定時器的實現原理。而隨著內核的不斷演進,大牛們已經對這種低分辨率定時器的精度不再滿足,而且,硬件也在不斷地發展,系統中的定時器硬件的精度也越來越高,這也給