免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: ruslin
打印 上一主题 下一主题

内核同步,优化内存屏障问题。 [复制链接]

论坛徽章:
0
21 [报告]
发表于 2011-10-14 13:04 |只看该作者
回复 19# 瀚海书香


    多谢支持。等我把同步方面的知识整理完之后,我会吧最新的文档传上来的

论坛徽章:
0
22 [报告]
发表于 2011-10-14 13:10 |只看该作者
本帖最后由 ruslin 于 2011-10-14 13:14 编辑

回复 17# eexplorer


   
回复  ruslin


write a;
barrier();
read b;

我觉得是这样理解(纯属猜测,不对的地方请高手指出 ...
eexplorer 发表于 2011-10-14 11:06




cpu有这么智能吗?我绝的不太靠谱,从来没有听说过这样的理论。看来得请高人指点了

论坛徽章:
0
23
发表于 2011-10-14 13:26
这是我在kernel log 发现的。。。
  1. Author: Nicolas Pitre <nico@cam.org>
  2. Date:   Wed Dec 21 12:26:25 2005 -0500

  3.     [PATCH] fix race with preempt_enable()
  4.    
  5.     Currently a simple
  6.    
  7.         void foo(void) { preempt_enable(); }
  8.    
  9.     produces the following code on ARM:
  10.    
  11.     foo:
  12.         bic     r3, sp, #8128
  13.         bic     r3, r3, #63
  14.         ldr     r2, [r3, #4]
  15.         ldr     r1, [r3, #0]
  16.         sub     r2, r2, #1
  17.         tst     r1, #4
  18.         str     r2, [r3, #4]
  19.         blne    preempt_schedule
  20.         mov     pc, lr
  21.    
  22.     The problem is that the TIF_NEED_RESCHED flag is loaded _before_ the
  23.     preemption count is stored back, hence any interrupt coming within that
  24.     3 instruction window causing TIF_NEED_RESCHED to be set won't be
  25.     seen and scheduling won't happen as it should.
  26.    
  27.     Nothing currently prevents gcc from performing that reordering.  There
  28.     is already a barrier() before the decrement of the preemption count, but
  29.     another one is needed between this and the TIF_NEED_RESCHED flag test
  30.     for proper code ordering.
  31.    
  32.     Signed-off-by: Nicolas Pitre <nico@cam.org>
  33.     Acked-by: Nick Piggin <nickpiggin@yahoo.com.au>
  34.     Signed-off-by: Linus Torvalds <torvalds@osdl.org>

  35. diff --git a/include/linux/preempt.h b/include/linux/preempt.h
  36. index d9a2f52..5769d14 100644
  37. --- a/include/linux/preempt.h
  38. +++ b/include/linux/preempt.h
  39. @@ -48,6 +48,7 @@ do { \
  40. #define preempt_enable() \
  41. do { \
  42.         preempt_enable_no_resched(); \
  43. +       barrier(); \
  44.         preempt_check_resched(); \
复制代码
回复 23# ruslin

论坛徽章:
0
24 [报告]
发表于 2011-10-14 13:48 |只看该作者
本帖最后由 ruslin 于 2011-10-14 14:01 编辑

回复 18# kouu


1.   》》》》 volatile 是用来修饰变量addr,而不是修饰readl的返回值的吧~ 编译器不可以缓存readl的返回值么?
     对于这个观点,我有点怀疑。
     比如:
     readl(xxx) 展开之后基本就等于 *(const volatile u32 __force *) addr; addr指针变量可以说是volatile的,每次都会从内存读addr指针变量。你是说,*addr的时候被编译器寄存器优化了,直觉编译器应该不对一个volatile指针类型取值进行寄存器优化。如果真的优化了,希望能举个实际代码的例子来,那么我的优化屏障问题就基本解决了。谢谢。

2.   关于指令重排会出问题,就比如preempt_disable的例子:

    inc_preempt_count();
    barrier();
    do_something...

    do_something的代码是需要禁止抢占的,如果没有barrier(),do_something如果被重排到inc_preempt_count()之前,那么就有可能在不该被抢占的地方被抢占。我觉得你这样说是有点道理的。但是为什么这里用了barrier,cpu乱序执行的时候也不会出问题,我的理解是:
    首先可执行代码顺序已经按照次序固定了,然后cpu乱序执行,我绝的cpu乱序执行是有条件的,就是一次发射了连续的多条指令之后,然后在这几条指令内并且cpu自认为没有依赖关系的话才能乱序执行。假设inc_preempt_count,do_something一次被取出来了,然后乱序执行了,就在do_something执行过程中inc还没有执行,来了中断,准备抢占了。但是这时正是这个中断起了内存屏障的作用(中断切换过程也不简单,肯定有这个功能把),中断处理程序执行前cpu已经保证了刚才发射的多条指令全部执行完成了(inc已经执行了)。这个时候中断中再来检查preempt就不会出现错误被抢占的问题了。
    我自己的理解,你说的那篇文章我也没太看懂,还望指正。
   
    不过你说的这个问题是我没有考虑到过的,谢谢。


3. >> 而对于“非普通”的代码,依赖关系可能是存在的,但是又不能从代码的上下文中看出来。这个时候就需要用到屏障了。
    >> 比如:addr=XXX; val=data; 字面上看addr和data毫无关系,但是它们可能正好是某个设备的地址端口和数据端口,addr的值决定了读data时的输出。
   这个我觉的有道理,但是这是内存屏障啊。不是优化屏障。对于我的问题,并没有直接的解释。

论坛徽章:
0
25 [报告]
发表于 2011-10-14 14:10 |只看该作者
回复 24# eexplorer


    你的意思是说防止寄存器优化吗?
   
     跟你之前猜想的cpu工作特点好像每什么关系。

论坛徽章:
0
26 [报告]
发表于 2011-10-14 14:36 |只看该作者
回复 25# ruslin


   
readl(xxx) 展开之后基本就等于 *(const volatile u32 __force *) addr; addr指针变量可以说是volatile的,每次都会从内存读addr指针变量。你是说,*addr的时候被编译器寄存器优化了,直觉编译器应该不对一个volatile指针类型取值进行寄存器优化。如果真的优化了,希望能举个实际代码的例子来,那么我的优化屏障问题就基本解决了。谢谢。

    这个,我之前的猜测可能不太靠谱。
    不过现在我又有另外一个想法。编译器优化不仅可以用寄存器作缓存,还可以指令重排,甚至是跨越基本块的重排。
    比如:
    while (readl(xxx));
    a++;
    b=func(a);
    如果if(readl(xxx))结果为真是小概率事件的话,可能优化成:
    a++;
    if (readl(xxx)) {
        a--;
        while (readl(xxx));
        a++;
    }
    b=func(a);
    这里的barrier()可以防止这样的优化。

   
假设inc_preempt_count,do_something一次被取出来了,然后乱序执行了,就在do_something执行过程中inc还没有执行,来了中断,准备抢占了。但是这时正是这个中断起了内存屏障的作用(中断切换过程也不简单,肯定有这个功能把),中断处理程序执行前cpu已经保证了刚才发射的多条指令全部执行完成了(inc已经执行了)。这个时候中断中再来检查preempt就不会出现错误被抢占的问题了。

    我的理解也差不多,CPU保证了顺序流入就不会有问题。中断来了以后,如果要抢占,就必定要检查preempt_count。就算CPU乱序导致do_something先于inc_preempt_count执行完,但是检查preempt_count的语句则必须在inc_preempt_count之后才能执行,因为它们有依赖。

   
    >> 比如:addr=XXX; val=data; 字面上看addr和data毫无关系,但是它们可能正好是某个设备的地址端口和数据端口,addr的值决定了读data时的输出。
这个我觉的有道理,但是这是内存屏障啊。不是优化屏障。对于我的问题,并没有直接的解释。

    这里的内存屏障不也包含了优化屏障么。因为addr和data在字面上毫无关系,编译器完全可以调整它们的顺序。只是说这个地方只用优化屏障解决不了问题,必须用更强的内存屏障。
    我所知道的,仅仅使用优化屏障就能解决问题的地方,似乎也就是inc_preempt_count这类的情况了。

论坛徽章:
0
27 [报告]
发表于 2011-10-14 15:27 |只看该作者
回复 27# kouu


    thx
    到目前为止,我能理解的优化屏障的地方跟你差不多吧。readl的优化也不能吃透,看来只能等待牛人出现了{:3_186:}

论坛徽章:
0
28 [报告]
发表于 2011-10-14 16:57 |只看该作者
本帖最后由 ruslin 于 2011-10-14 18:47 编辑

小结一下。暂时我就以为优化屏障是这样的原因把:
     readl(xxx) 展开之后基本就等于 *(const volatile u32 __force *) addr; addr指针变量可以说是volatile的,每次都会从内存读addr指针变量。但是*addr的时候可能会被编译器寄存器优化了。所以要加一个barrirer来防止。而且barrier也可以防止潜在的代码重新排序。
    不过我在x86上用gcc尝试写代码让它优化没有成功。或许其他架构,编译器可能会xxx吧。不过,暂时就这样理解把。
   
    如果有牛人看到并能解释一下的话非常感谢了。{:3_189:}

论坛徽章:
7
丑牛
日期:2013-10-18 14:43:21技术图书徽章
日期:2013-11-03 09:58:03辰龙
日期:2014-01-15 22:57:50午马
日期:2014-09-15 07:04:39丑牛
日期:2014-10-16 14:25:222015年亚洲杯之伊朗
日期:2015-03-16 10:24:352015亚冠之城南
日期:2015-05-31 09:52:32
29 [报告]
发表于 2011-10-14 17:25 |只看该作者
编译器的问题还是得请教P姨。

论坛徽章:
7
丑牛
日期:2013-10-18 14:43:21技术图书徽章
日期:2013-11-03 09:58:03辰龙
日期:2014-01-15 22:57:50午马
日期:2014-09-15 07:04:39丑牛
日期:2014-10-16 14:25:222015年亚洲杯之伊朗
日期:2015-03-16 10:24:352015亚冠之城南
日期:2015-05-31 09:52:32
30 [报告]
发表于 2011-10-14 17:46 |只看该作者
本帖最后由 smalloc 于 2011-10-14 17:57 编辑

回复 29# ruslin


    个人觉得
while (clps_readl(SYSFLG(port)) & SYSFLG_UTXFF)
                barrier();
在单流水线的时候没问题,但多发射的时候可能有问题,比如读预取。即预先多读一次,而有些硬件对读可能是有感应的。
而这里barrier到底有没有用也完全决定与具体设计。同时依赖barrier的定义和体系结构-编译器,所以在不确定的时候加barrier是应该的。
我曾经在一个ARM体系下遇到过原子计数出错。多减了一的情形。最后没搞定,但驱动肯定没问题。合乎规范的。我觉得有些特体系结构的有些特细节的地方肯定还有可挖掘之处。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP