蓝天

转载:x86的cpu_relax解析

原文:http://blog.liuw.name/1024

内核执行的任务在很多情况下是不加锁的,只是poll某个公有变量去保证同步。再深一步,即使是使用锁,本质上也是一个poll某个公有变量的过程。这个poll的过程需要CPU一直循环等待。

要是让我这个菜鸟来写的话,循环体内大概是什么都不会做的了,XD。而x86的内核中一般是调用cpu_relax()。这个函数又是何方神圣呢?

实际上,这个函数很简单。

1
2
3
4
5
#define cpu_relax() rep_nop()
static always_inline void rep_nop(void)
{
        asm volatile ( "rep;nop" : : : "memory" );
}

自旋锁里面也有rep;nop这个语句。而我很蛋痛地在想,为什么是rep;nop而不是nop;nop而不是nop;nop;nop…;nop,反正都是什么都不做嘛,为什么偏偏要选这个?众所周知,在内核这个层次,基本上每一行代码都是最优的,做出这样的选择必定事出有因。

rep;nop的机器码是f3 90,其实就是pause指令的机器码,相当于pause的一个“别名”,这是巧合吗?pause指令又是干什么的呢?

从Intel的手册里面翻出来一段话:

Improves the performance of spin-wait loops. When executing a “spin-wait loop,” a Pentium 4 or Intel Xeon processor suffers a severe performance penalty when exiting the loop because it detects a possible memory order violation. The PAUSE instruction provides a hint to the processor that the code sequence is a spin-wait loop. The processor uses this hint to avoid the memory order violation in most situations, which greatly improves processor performance. For this reason, it is recommended that a PAUSE instruction be placed in all spin-wait loops.

An additional fucntion of the PAUSE instruction is to reduce the power consumed by a Pentium 4 processor while executing a spin loop.

简单点说,用pause可以提示CPU接下来的指令序列是用来自旋等待,就不用做memory reorder了,cache什么的也不用废掉了——要知道,cache是很宝贵的资源啊。这指令还有附送的功能——减少能耗。其实内核代码最根本的要求就是:快,快,更加快,这条指令还有附送功能,所以何乐而不为呢?

那么为什么不直接写pause而要写rep;nop呢?理论上是等价的,但是实际上为什么不这样做,不好意思,不清楚。但是可以确定是的pause是Pentium 4才引入的,也许大家比较怀旧所以还用rep;nop也说不定

So,以后写应用程序而又蛋痛写了循环等待的话,不妨也用用pause吧。不过我想会在应用程序中写循环等待这么傻的代码的程序员,应该也想不到用pause去节能减排兼提速了吧,伤脑筋。

posted on 2012-07-24 16:19  #蓝天  阅读(197)  评论(0编辑  收藏  举报

导航