打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
<linux kernel>plz do not use usleep(0)!

 


最近发现很多hpc 领域的MPI程序中在用usleep(0) ,比较差异。 后来问了之前做hpc 的同事 得到的答复是

一般用usleep(0) 的主要目的应该是:

CPU交出当前线程的执行权,让CPU去执行其他线程。也就是放弃当前线程的时间片,转而执行其他线程

 

我感觉很诧异。 Usleep(0) 来做这个事情 是POSIX要求的 还是一个意外的发现呢? 我记得我之前都是用 sched_yield() 的啊。

于是有2个问题 

1 :usleep(0) 能不能让权, 

:如果可以和sched_yield 比到底谁更合适

我先man了一下usleep(0) linux上 , 

Usleep 不应该大于 1s 这个是确定无疑的, 但是usleep(0) 的行为 就比较诡异了。Man 上没有明确提到 看来POSIX是不要求让权的, 这在QNX MAC 等操作系统上 明确看到

Glibc 对于 usleep(0) 


同时linux man 到明确写着


usleep 究竟有没有这个效果呢 

先来看几个奇怪的现象:



 执行shell usleep 0 会明显的看到调用了



 难道 

usleep(0) = sched_yield? 

 



 执行shell usleep x (x!=0 ) 会去调用naonsleep


这就比较合理了,  之前猜测 usleep  就应该是调用了 nanosleep 

 

然后写一个 函数调用来看看 

会发现 无论是0  还是 !0 都是调用的



 

这就比较合理了, 看了glibc源码 也验证了确实是 封装naosleep 


那第一个问题在linux 上就变成 naosleep(0,0) 是不是会去让权了, 他和sheld_yield 的区别。 

 

.18 之后 应该naosleep 都是基于 hrtimer的机制实现了 (

============================================================== 

C代码  
  1. <span style="white-space: normal; background-color: #ffffff;">do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode)</span>  
  2.   
  3. {  
  4. hrtimer_init_sleeper(t, current);  
  5. do {  
  6. set_current_state(TASK_INTERRUPTIBLE);  
  7. hrtimer_start_expires(&t->timer, mode);  
  8. if (!hrtimer_active(&t->timer))  
  9. t->task = NULL;  
  10. if (likely(t->task))  
  11. schedule();  
  12. hrtimer_cancel(&t->timer);  
  13. mode = HRTIMER_MODE_ABS;  
  14. while (t->task && !signal_pending(current));  
  15. __set_current_state(TASK_RUNNING);  
  16. return t->task == NULL;  
  17. }  

 =======

补充一个 在2.6.9内核 或者可能之前的glibc实现中 usleep(0) 如果是基于 select (0) 这样的实现  

在判断入参是之后会离开返回 不会调用 schelduer()的 

 

  

 

=====================================================================

 

)

 

根据nanosleep 的 syscall ,发现


 

很明显的有 schedule(), 于是可以确定 usleep(0) 如果一切顺利确实会让权,那么和sched_yield比呢 

 

于是写了一个 main 

 

 

C代码  
  1. #include <unistd.h>  
  2. #include <sched.h>  
  3. int main(){  
  4. int j ;  
  5. for(j=0; j<100000; j++)  
  6. //usleep(0);  
  7. sched_yield();  
  8. }  
 

 

sched_yield() 的时候 调用10万次 的耗时如下


 

 

usleep(0) 的时候 调用10万次 的耗时如下

 


 

 

延迟简直不是一个数量级。。 太可怕了,如果用于网络 那要丢多少UDP , TCP要做多少次拥塞避免。

 

 

在来看一下MPI中的这个问题



 http://trac.mcs.anl.gov/projects/mpich2/ticket/1597\

 

MPI有个Yield宏,使用了 usleep(0) ,但是比较大的延迟

最后一张表的意思是, 应该尽可能的让CPU 100%,这样才算是yield。。

 

 

 

那为什么会造成usleep 如此延迟呢? 

先看一下  trace的信息

Usleep 


非常可怕  因为是非主动让权 调用了 deactivate_task()有简单操作系统知识的都知道

简直就恶魔。。。


 

然而 sched_yield()


非常干净  简直perfect! 

 

 

 

我们知道 在hpc 领域 MPI 的终极目地 就是耗尽CPU 

usleep(0) 这么高的延迟 肯定是不能用来做让权的。 而且我也不觉得 usleep(0) 可以用在任何地方 ,这是一个没保证,(你知道哪天glibc改了呢和极其不高效的方式 。

如果你是为了耗掉一个机器周期 ,那直接asm ("nop") ,如果是为了让权建议所有使用usleep(0) (注意是0,不是其他)的地方换成 sched_yield() ;

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
softlockup检测(watchdog)原理(用于检测系统调度是否正常)
watchdog(二)
Linux进程上下文切换过程context
Java并发编程:Timer和TimerTask(转载)
Linux中多CPU的runqueue及抢占
linux的0号进程和1号进程
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服