搜索
bottom↓
回复: 16

Cortex M3 的新指令 LDREX/STREX 是否真的比原来的 SWP 更有优势?

[复制链接]

出0入0汤圆

发表于 2010-4-21 11:28:51 | 显示全部楼层 |阅读模式
从资料上看, 好象是更有优势
可是在我的应用中发现, 有些时候, 这个指令对并不方便, 因为它规定必须成对使用
而很多时候, ldrex 装载后先做条件检测, 如果满足条件才修改
弄了半天, 终于放弃, 还是 开关中断来阻止并发访问吧,
虽然能够解决问题, 但这样肯定不是好办法!

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2010-4-21 13:29:10 | 显示全部楼层
这个问题的解决思路和OS的优先级反转是类似的。

关中断类似于Mutex,把低优先级的任务,在访问互斥资源时,提升到最高优先级来进行,以防止优先级反转。
LDREX就是假设高优先级没修改,最后验证一下是不是真的。

使用关中断的核心问题在于:只防范本内核的互斥操作。LDREX从设计的角度讲,是可以支持全局互斥的。即说,关中断,对多内核是没有防范的。关中断并不能阻止并行的另外一个内核/控制器方位关键数据。

关键代码,核心就是读-修改-写。多核的时候,系统很难去屏蔽别人的读,修改时间无法确定,写是LDREX完成的。。。单核的时候,SWP和关中断都是去限制读,是阻塞的做法。可以看到,LDREX在单核上不一定是好办法,至少不一定高效;多核上应该是一个不错的办法,尽管放在一个内核上看,效率可能降低了,综合下来看,不一定。

可以参考ARM的指令手册。

出0入0汤圆

 楼主| 发表于 2010-4-22 11:08:20 | 显示全部楼层
不错, 楼上把多核系统的特性都考虑进去了,
确实, 对于多核系统, 关中断是无法避免共享的互斥访问的.
但是在 stm32 这个还是单核的系统里, 这个方式对于 SWP 指令来说, 显得还是麻烦和低效了些.
不过因为 Cortex M3 已经不提高 SWP 指令了, 自我感觉开关中断在应用中更有效率些,
只是感觉不是个好办法, 所以不推荐网友们也这么干, 这只是作为一个技术探讨, 跟大家讨论.

出0入0汤圆

发表于 2010-4-22 12:03:30 | 显示全部楼层
简单讨论一下。首先说明,我由于对SWP的效果没有想清楚,实际Coding的时候没用过该指令。

按ARM手册上所说,SWP设想的场景,是把一个临时的令牌交换到MEM,本地判断换回的数据,然后SWP回去。
这里我产生的疑问就是,在前后台环境下,如果SWP之后,发生中断等,可能造成阻塞,或者说造成优先级反转。

在一般意义下的单核MCU系统来说,对于SWP,我没看到其对常见的原子操作有太大的贡献,依然需要中断去进行保护。
在有RTOS下,阻塞的Token可以做为休眠线程的依据,但依然是优先级反转的场景。

总之就是没发现SWP对原子操作有啥用处。-_b
不知道您有啥看法没有。

出0入0汤圆

 楼主| 发表于 2010-4-22 15:52:21 | 显示全部楼层
SWP 其实就是数据对换, 因为单指令完成的缘故, 它就避免了在判断完成后, 又被别的进程占用去了混乱.

出0入0汤圆

发表于 2010-4-22 19:54:45 | 显示全部楼层
就因为只是单纯对换,所以才没有太多价值。无论是换入还是换出的数据,都没有受到保护,只保护了换这个操作。

读-修改-写,这个原子操作而言。SWP是保证第N次写和第N+1次读,这两个操作是原子的。

出0入0汤圆

发表于 2011-4-13 12:02:32 | 显示全部楼层
这个问题是可以用指令解决的。

《CM3权威指南CnR2.pdf》上的P56,指令集中有这样的指令:

  CLREX: 在本地处理器上清除互斥访问状态的标记(先前由LDREX/LDREXH/LDREXB做的标记)

这个应该能满足LZ的要求的。

出0入0汤圆

发表于 2019-1-21 15:01:16 | 显示全部楼层
dr2001 发表于 2010-4-22 19:54
就因为只是单纯对换,所以才没有太多价值。无论是换入还是换出的数据,都没有受到保护,只保护了换这个操作 ...

dr2001大侠,我在armfly论坛上看到使用KEIL5.25移植RL_RTX4系统出现警告信息
里面提到的问题,归结原因后是这句话:The ARM compiler does not guarantee to preserve the state of the exclusive monitor. This is why the __ldrex, __ldrexd, __strex and __strexd intrinsics are deprecated.

如何理解这句话?我认为是不是说在带cache的arm中,因为访存会被cache,因此编译器只按照字面解释这种intrinsic指令无法保证真正的访存,也就是说编译器不会自动生成dsi,dsb这种刷新cache的指令,因此deprecated,但是在不带cache的mcu中还是可用的?

是这样理解吗,如果真是这样,那么在带cache的arm中这个互斥访问不是全军覆没了吗

出0入0汤圆

发表于 2019-1-22 08:13:01 | 显示全部楼层
myxiaonia 发表于 2019-1-21 15:01
dr2001大侠,我在armfly论坛上看到使用KEIL5.25移植RL_RTX4系统出现警告信息,
里面提到的问题,归结原因 ...

这事儿我没深入研究过,可以对比一下CMSIS前后之间的差异。
你的理解有所偏差,下面的描述供参考(我是好久不用了。。。忘的差不多了

LDREX/STREX解决读-修改-写的共享冲突用,方法是使用总线Monitor。
执行LDREX的时候让Monitor启动并监视一片内存区;执行STREX的时候硬件看一下Monitor监视的内存地址区域是否存在过总线访问,没有就总线原子执行,有就放弃操作。
大体是这么个意思。
细节有不少,可以看ARM的手册,比如Monitor是每个CPU一个啊,还是总线上有一个啊,etc,效果不尽相同

问题来了,如果LDREX/STREX对和之间的代码没有被正确保护起来,实际执行LDREX-A/(中断)LDREX-B/STREX-B(中断返回)/STREX-A这个序列就会有问题,因为A序列的Monitor状态丢了。
LDREX使用的话,牵扯到处理器设计实现的部分细节,比如Monitor在哪里,etc


DMB,DSB,ISB是Memory Model的同步问题,如果处理器可以对读/写进行乱序,那么对某些特定的操作,需要确保Program Order的操作在总线/存储器中操作的顺序(其它处理器核/总线Master的可见性)是一致/满足特定顺序的。


这两个系列的指令关注的不是一个问题,大体上
LDREX系列解决某段时间内,对某个内存地址访问的唯一性(Exclusive);Sync系列解决其它人观测内存操作结果的顺序的一致性。


cache的维护操作另有指令,一般是CP15,对A系列处理器。

出0入0汤圆

发表于 2019-1-22 09:43:50 | 显示全部楼层
myxiaonia 发表于 2019-1-21 15:01
dr2001大侠,我在armfly论坛上看到使用KEIL5.25移植RL_RTX4系统出现警告信息,
里面提到的问题,归结原因 ...

应该是说ARM编译器在LDREX和STREX之间可能产生普通的LDR/STR指令,这些指令可能导致exclusive monitor的状态被清除。和cache没有关系,cache控制器里也可以带有exclusive monitor。

出0入0汤圆

发表于 2019-1-22 09:53:39 | 显示全部楼层
dr2001 发表于 2019-1-22 08:13
这事儿我没深入研究过,可以对比一下CMSIS前后之间的差异。
你的理解有所偏差,下面的描述供参考(我是好 ...

A序列的Monitor状态丢了会有什么问题? A的STREX会失败,A知道自己exclusive access失败后,A可以选择放弃,或是重试整个LDREX和STREX。
虽然中断B可能访问的是和A完全无关的内容。那也只是A在重试时多了一些额外开销。

出0入0汤圆

发表于 2019-1-22 10:08:48 | 显示全部楼层
本帖最后由 myxiaonia 于 2019-1-22 10:21 编辑
caixiuwen 发表于 2019-1-22 09:43
应该是说ARM编译器在LDREX和STREX之间可能产生普通的LDR/STR指令,这些指令可能导致exclusive monitor的 ...


LDREX和STREX之间可能产生普通的LDR/STR指令,这个是常见的,官方说法是尽量保证区间内的LDR/STR指令尽可能少,防止损失更多的工作,实际上就是说exclusive monitor根本无法monitor普通的LDR/STR。从各种实际资料来看,stm32的exclusive monitor监视粒度应该是4个字节,不过这个粒度也影响不大,设想最简单的exclusive monitor,在全内存区域,LDREXr置位一个flag,多个LDREXr也只有一个flag,效果等同一个LDREXr,然后只需监视strex时flag情况并清flag,这种方法虽然低效但是简单有效,也许stm32就是这么做的

看keil官方的解决方案是忽略这个问题,或者让库强制抑制不产生此警告

再看到stackoverflow上的一篇文章Atomic operations in ARM strex and ldrex - can they work on I/O registers?,那里介绍说LDREX和STREX背后的exclusive monitor机制arm官方是让厂家自主决定的,用c标准解释就是unimplement,在移植时可能存在问题

个人用的话,保守点,虽然没有证据,在stm32上无cache情况下,照常使用LDREX和STREX,有cache的话,把需要LDREX和STREX的内存属性设置为不cache

出0入0汤圆

发表于 2019-1-22 10:26:14 | 显示全部楼层
本帖最后由 myxiaonia 于 2019-1-22 10:47 编辑
dr2001 发表于 2019-1-22 08:13
这事儿我没深入研究过,可以对比一下CMSIS前后之间的差异。
你的理解有所偏差,下面的描述供参考(我是好 ...


The ARM compiler does not guarantee to preserve the state of the exclusive monitor

什么情况下,无法保证the state of the exclusive monitor呢,正常的多处ldrex/strex是合理的也是常规用法,除了这么用还能怎么用呢?所以我认为上面这句话不是针对此类做法,而是指编译器看不到的那些情况,个人猜测就是带cache时候,此时编译器没办法产生操作cache的代码

事实上编译器本来就没法保证用户如何用互斥访问实现某些构件,无论如何都是设计者自己才能保证,背后唯一的差别是设计者抱怨说好互斥访问难以使用,潜台词就是互斥访问设计时候还是考虑不周,某些情况下会产生硬件性的bug,这可能是制造商引入的或者说是厂商自己设计实现的时候引入的,事实上arm指令集errta也不少啊,非指令集逻辑上的bug也有,我所知道的一个是svc中断和systick,pendsv中断就可能在同时发生时候而不能按照自然优先级运行,这也是rtx为何要给svc中断一个高优先级的原因,这是keil设计人员给我邮件上承认的

出0入0汤圆

发表于 2019-1-22 10:31:26 | 显示全部楼层
myxiaonia 发表于 2019-1-22 10:08
LDREX和STREX之间可能产生普通的LDR/STR指令,这个是常见的,官方说法是尽量保证区间内的LDR/STR指令尽可 ...

LDREX和STREX之间的普通STR指令是常见的吗?这时的STR指令可能导致状态清除,也可能不清除,是IMPLEMENTATION DEFINED。
关于那个ARM编译器警告,我理解是它不能保证不产生STR指令,而这个STR指令可能导致状态丢失,所以编译器不能保证monitor的状态。

出0入0汤圆

发表于 2019-1-22 10:37:14 | 显示全部楼层
本帖最后由 myxiaonia 于 2019-1-22 10:41 编辑
caixiuwen 发表于 2019-1-22 10:31
LDREX和STREX之间的普通STR指令是常见的吗?这时的STR指令可能导致状态清除,也可能不清除,是IMPLEMENTA ...


LDREX和STREX之间的普通STR指令是常见的吗,这个确实是常见的,arm官方和st官方都是建议尽量在区间内使用较少的普通STR指令,普通str指令根本无法影响exclusive monitor

以下是rtx中rt_membox.c中的一个函数

  1. /*--------------------------- rt_free_box -----------------------------------*/

  2. int rt_free_box (void *box_mem, void *box) {
  3.   /* Free a memory block, returns 0 if OK, 1 if box does not belong to box_mem */
  4. #ifndef __USE_EXCLUSIVE_ACCESS
  5.   int irq_dis;
  6. #endif

  7.   if (box < box_mem || box >= ((P_BM) box_mem)->end) {
  8.     return (1);
  9.   }

  10. #ifndef __USE_EXCLUSIVE_ACCESS
  11.   irq_dis = __disable_irq ();
  12.   *((void **)box) = ((P_BM) box_mem)->free;
  13.   ((P_BM) box_mem)->free = box;
  14.   if (!irq_dis) __enable_irq ();
  15. #else
  16.   do {
  17.     *((void **)box) = (void *)__ldrex(&((P_BM) box_mem)->free);
  18.   } while (__strex ((U32)box, &((P_BM) box_mem)->free));
  19. #endif
  20.   return (0);
  21. }
复制代码


很明显    *((void **)box) = (void *)__ldrex(&((P_BM) box_mem)->free);会产生一次普通str指令

出0入0汤圆

发表于 2019-1-22 11:07:24 | 显示全部楼层
myxiaonia 发表于 2019-1-22 10:37
LDREX和STREX之间的普通STR指令是常见的吗,这个确实是常见的,arm官方和st官方都是建议尽量在区间内使用 ...

搜ARM® Compiler armcc User Guide 10.139 __strex intrinsic。
Note
The compiler does not guarantee that it will preserve the state of the exclusive monitor. It may generate load and store instructions between the LDREX instruction generated for the __ldrex intrinsic and the STREX instruction generated for the __strex intrinsic. Because memory accesses can clear the exclusive monitor, code using the __ldrex and __strex intrinsics can have unexpected behavior. Where LDREX and STREX instructions are needed, ARM recommends using embedded assembly.
普通的STR是可能改变状态的,也可以不改变,在ARMv7文档里说了。一般实现是不改变状态,所以一般忽略这个警告没问题。

出0入0汤圆

发表于 2019-1-22 12:49:48 | 显示全部楼层
caixiuwen 发表于 2019-1-22 11:07
搜ARM® Compiler armcc User Guide 10.139 __strex intrinsic。
普通的STR是可能改变状态的,也可以不改 ...

看来是这个原因了,ARMv7-M Architecture Application Level Reference Manual 上说STR是不是会更新exclusive monitor是厂商自己定义的
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-19 01:29

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表