Fork me on GitHub
Showing posts with label linux. Show all posts
Showing posts with label linux. Show all posts

8/11/2012

[Linux] tweak process priority

在 debug vsync 的過程中,發現 CPU scheduling 對於 vsync accuracy 有影響,因此需要針對 vsync 所在的 process 修改其 process priority.
過程中發現利用 pthread 的 pthread_attr_t 並沒有辦法更動 priority,以下整理了網路上關於 process priority 的資料,目前猜測原因應該是:
Setting a priority under the default scheduling policy (SCHED_OTHER) isn't valid. The default Linux scheduling policy is SCHED_OTHER, which have no priority choice but a nice level to tweak inside the policy
由上面節錄的敘述中可以發現兩個陌生的東西:"scheduling policy" 和 "nice value". 來認識他們:
All Linux threads have one of the following scheduling policies:
  1. 'Normal' scheduling policies: ranging from 100 (highest priority) to 139 (lowest priority)
    SCHED_OTHER   the standard round-robin time-sharing policy;
    SCHED_BATCH   for "batch" style execution of processes; and
    SCHED_IDLE    for running very low priority background jobs.
    
  2. Real-time scheduling policies: ranging from 1 (lowest priority) to 99 (higest priority)
    SCHED_FIFO    a first-in, first-out policy
    SCHED_RR      a round-robin policy
    
Real-time scheduling 有什麼特性呢,簡單理解應該就是擁有比 Normal scheduling 更不可被搶佔的特性:
SCHED_FIFO can't be preempted (context switched to another process) unless another process of higher priority shows up in the execution queue.

SCHED_RR can be preempted by a time quantum (delay given to a process to execute).
一般的 process 沒有特別指定 default 應該都是 SCHED_OTHER 所以沒辦法透過 pthread_attr_t 設定其 priority,不過還有另外一個方法就是使用其 nice value.
Conventional process's static priority = (120 + Nice value)
因為 Normal scheduling policies 的 priority range 是從 100 ~ 139,那麼從上面可以推得,nice value 的 range 是 -20(highest priority) ~ 19(lowest priority).
至於設定 nice value 的方式似乎不只一種,經過試驗,setpriority 這個 function 是有效的。

Ref

  1. How to increase thread priority in pthreads?
  2. how to increase the priority of a child pthread relative to the parent thread
  3. Understanding Linux CPU scheduling priority
-- EOF --

6/14/2012

[Linux] Unbalanced irq

中斷算是 kernel 開發過程中經常遇到問題的部份,最近在 log 當中經常看到 Unbalanced irq 的訊息,雖然只是 Warning,還是想研究一下怎麼把它弄掉!

搜尋後整理一些網路上關於 irq 使用的資訊摘要如下:

  1. enable_irq unbalanced messages 是無害的

     unbalanced 這個問題只會發生在 enalbe_irq 函數中,這裡要提到一個變量disable_depth,這是一個標志中斷禁止與否的變量,如果調用 disabled,這個變量會 ++,成正數,表示禁止中斷; 如果是 enable,這個變量會 --,表示允許。
    
     而如果這個變量本身就是 0,再去 enable 它的時候,表示你這個中斷本來就是打開的,你現在再去打開沒有必要,這就是 unbalanced 了
    
  2. request_irq 的調用應該放到所有的准備工作都完成後再進行

     我們應該確保只有在有能力處理中斷的時候在去註冊中斷!因為只要 request_irq 正確返回就意味著可以響應中斷了。
    
     想要在該註冊函數返回後立刻調用 disable_irq 來暫時屏蔽中斷,然後在後面的某個時刻在 enable 中斷是不對的。因為在你 disable_irq 之前可能中斷已經發生並且調用了中斷處理函數!
    
     一般對中斷的注冊都放在 probe 的最後一步來做!這樣可以避免一些中斷過早被調用的問題!
    
     一般我們會在中斷處理函數進去的時候 disable 一個 irq,並在中斷處理函數退出的時候 enable 這個 irq。這樣做當然能讓 disable 和enable 匹配的很好。
    
     但有的時候你可能想把 disable 放到中斷當中,而把 enable 放到下半部去完成。這就要慎重了,需要仔細檢查下半部的代碼是否一定會在你需要的時候被執行,稍有不慎你可能就會造成下半部的 enable 未被執行。導致缺少一次匹配的 enable,進而導致中斷失效。
    
  3. 中斷有可能在不那麼容易被注意到的時機被觸發

     引述 Reference 中的例子:
    
     在設計這個電容屏的驅動時,我的設計為在其 suspend 函數中直接切斷電容屏的電源以省電,然後在 resume 函數中再從新上電。中斷觸發方式為下降沿觸發方式。測試發現,當在 suspend 中調用斷電操作後總會導致一個 I2C 讀取動作發生,而這個讀取動作是我在中斷處理函數的底半部中實現的動作。僅僅是電容屏的一個斷電動作怎麼會導致這個動作發生呢?
    
     降沿觸發嘛~~  當電容屏斷電後當然沒有誰去保持那個中斷引腳為高電平了,它當然會恢復為默認的低電平了(該平台的中斷默認為電平)。顯然這個過程會導致一個下降沿發生,這便會引起中斷處理函數被調用,從而引起底半部的工作隊列被執行,然後 I2C 讀取動作便發生了。可是這時候電容屏都斷電了,讀取當然要出錯了!
    
     現在的問題就是如何讓這個下降沿不要發生,那就只能想辦法讓系統不要理會這個下降沿。簡單,斷電前先 disable 中斷,resume 完成後重新 enable 這個中斷就好了
    
  4. request_irq 之後沒有 disable 過的 irq 如果 enable_irq 都會造成 Unbalanced irq 的 warning

References

  1. linux中斷的unbalanced問題
  2. request_irq的執行時機 關鍵字: irq INT 底半部 unbalanced 工作隊列
  3. unbalanced enable irq 問題的解決 以及共享的gpio中斷引起的問題
  4. Linux 中斷學習之小試牛刀篇

4/20/2012

[Linux] Use Debugfs on Android

Android 在 user space 可以在 run-time 的時候透過 adb shell getprop/setprop 來動態讀寫變數。所以,kernel 開發的過程中,我在想有沒有類似的東西讓我可以動態的存取變數,這樣 debug 會方便許多。

於是,發現了 Linux 其實已經有提供一個 light-weight 的 filesystem 叫做 Debugfs, 正好可以滿足我的需求,紀錄一下使用方式。

  1. Enable Debug FileSystem

    Kernel hacking
        [*] Debug filesystem
    
    mount -t debugfs none /sys/kernel/debug // Do this manually
    
  2. Include header

    #include <linux/debugfs.h>
    
  3. Call the API to create dir and file, then put them into the module init func

    struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
    struct dentry *debugfs_create_u8(const char *name, mode_t mode, struct dentry *parent, u8 *value)
    
    static struct dentry *dbg_entry_dir, *dbg_entry_test;                                           
    u8 dbg_print_test = 0;
    
    static int debugfs_init(void) {
        dbg_entry_dir = debugfs_create_dir("test_debugfs", NULL);
        if (!dbg_entry_dir)
            return -1;
    
        dbg_entry_test = debugfs_create_u8("print_test", 0644, dbg_entry_dir, &dbg_print_test);
        if (!dbg_entry_test)
            return -1;
    
        return 0;
    }
    
  4. Remember to remove after module remove

    void debugfs_remove(struct dentry *dentry)
    
    debugfs_remove(dbg_entry_dir); // Put this in module remove func
    
  5. Use the filenode you create to debug

    adb shell cat sys/kernel/debug/test_debugfs/print_test
    
    adb shell;
    echo 1 > sys/kernel/debug/test_debugfs/print_test
    

Reference

Linux Debugfs文件系統介紹及使用

Debugfs

Linux内核里的DebugFS

Debugfs

Kernel debugging

-- EOF --