linux内核中的睡眠函数*delay、*sleep

目录

一、睡眠函数种类

1、原子上下文

2、非原子上下文

    二、使用环境

1、使用环境的不同,选择不同的延时

2、驱动机制不同

3、内核中的计算函数执行的函数

三、实测两类函数的延时以及原因

1、测试系统中的睡眠函数

2、输出结果

3、输出结果现象与解释


内核中的睡眠、延时函数

一、睡眠函数种类


1、原子上下文


使用delay系列函数

ndelay(unsigned long nsecs)//首选使用
udelay(unsigned long usecs)
mdelay(unsigned long msecs)


   这些函数使用对时钟速度的jiffie估计,并将忙于等待足够的循环周期以实现所需的延迟。
    mdelay是udelay的宏包装器,以免udelay传递大参数时可能发生溢出.
    

2、非原子上下文


使用sleep系列的函数

usleep_range(umin,umax);  //推荐使用
msleep(ms);
msleep_interruptible(ms);
ssleep(s);


    
二、使用环境

1、使用环境的不同,选择不同的延时

    -- Backed by busy-wait loop:
        udelay(unsigned long usecs)

    -- Backed by hrtimers:
        usleep_range(unsigned long min, unsigned long max)

    -- Backed by jiffies / legacy_timers
        msleep(unsigned long msecs)
        msleep_interruptible(unsigned long msecs)


2、驱动机制不同

1)睡眠时间 ( < ~10us? ):

        使用 udelay

为什么不使用 usleep?因为在较慢的系统上(如嵌入式)为usleep设置hrtimer的开销可能不值得。

2)睡眠时间 (10us - 20ms):
        使用usleep_range 
        为什么不使用msleep 定时 (1ms - 20ms), 

                睡眠时间经常比设定的长  http://lkml.org/lkml/2007/8/3/250
        为什么没有 "usleep",什么是好的范围?
               usleep建立在hrtimers计时器之上,唤醒将非常精确。因此,一个简单的usleep函数可能会引入大量不需要的中断。  随着范围的引入,调度器可以自由地将您的唤醒与可能由于其他原因发生的任何其他唤醒合并,或者在最坏的情况下,为您的上限触发一个中断。    
    
3)睡眠时间>10ms

        使用 msleep or msleep_interruptible

msleep 设置当前的进程状态为TASK_UNINTERRUPTIBLE
msleep_interruptible 设置当前的进程状态为TASK_INTERRUPTIBLE

4)睡眠时间>1s

        使用ssleep

3、内核中的计算函数执行的函数

u64 ktime_get_real_ns(void);

实例计算foo() bar()函数的延时

#include <linux/ktime.h>
t1 = ktime_get_real_ns();
foo();
bar();
t2 = ktime_get_real_ns();
time_taken_ns = (t2 -> t1);

三、实测两类函数的延时以及原因

计算时间的函数

#define DILLY_DALLY(code_str, run_this) do { \
 u64 t1, t2; \
 t1 = ktime_get_real_ns(); \
 run_this; \
 t2 = ktime_get_real_ns(); \
 pr_info(code_str "-> actual: %11llu ns = %7llu us = %4llu ms\n", \
 (t2-t1), (t2-t1)/1000, (t2-t1)/1000000);\
} while(0)

1、测试系统中的睡眠函数

static int __init delays_and_sleeps_init(void)
{

        //delay        
        DILLY_DALLY("ndelay() for         10 ns", ndelay(10));
        DILLY_DALLY("udelay() for     10,000 ns", udelay(10));
        DILLY_DALLY("mdelay() for 10,000,000 ns", mdelay(10));

        
        //sleep
        DILLY_DALLY("usleep_range(10,20) for 10,000 ns", usleep_range(10, 20));
        DILLY_DALLY("msleep(10) for      10,000,000 ns", msleep(10));
        DILLY_DALLY("msleep_interruptible(10)         ", msleep_interruptible(10));
        DILLY_DALLY("ssleep(1)                        ", ssleep(1));

}

2、输出结果

               1. *delay() functions (atomic, in a delay loop):
[ 4176.946228] ndelay() for         10 ns-> actual:         219 ns =       0 us =    0 ms
[ 4176.946239] udelay() for     10,000 ns-> actual:        9956 ns =       9 us =    0 ms
[ 4176.956217] mdelay() for 10,000,000 ns-> actual:     9976582 ns =    9976 us =    9 ms
[ 4176.956219] 
               2. *sleep() functions (process ctx, sleeps/schedule()'s out):
[ 6372.868032] usleep_range(10,20) for 10,000 ns-> actual:       57183 ns =      57 us =    0 ms
[ 6372.886923] msleep(10) for      10,000,000 ns-> actual:    18880096 ns =   18880 us =   18 ms
[ 6372.906874] msleep_interruptible(10)         -> actual:    19943338 ns =   19943 us =   19 ms
[ 6373.915691] ssleep(1)                        -> actual:  1008605369 ns = 1008605 us = 1008 ms

3、输出结果现象与解释

1、udelay() 与mdelay() 函数实际用的时间比参数要少?这是为什么呢?

 * Please note that ndelay(), udelay() and mdelay() may return early for
 * several reasons:
 *  1. computed loops_per_jiffy too low (due to the time taken to
 *     execute the timer interrupt.)
 *  2. cache behaviour affecting the time it takes to execute the
 *     loop function.
 *  3. CPU clock rate changes.
 *

2、sleep()系列的函数用了更多的时间,在标准的linux上

原因有下

  • 标准的linux系统,高分辨率的定时器,它支持需要小于一个jiffy分辨率的计时器;
  • 将Linux操作系统配置为RTOS,将减少这个问题


参考内核

内核说明文档


 

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为了维护世界和平_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值