提升自旋锁spinlock的性能-pause指令

看源码的时候get的一个新的知识点,可以提升自旋锁spinlock的性能-pause指令,看到的源码如下:

     #define cpu_pause()         __asm__ (".byte 0xf3, 0x90")
     #define NOP_CPU3(n)     {int i = 0; while(i++ < (n)) cpu_pause();} 
     // 调用代码
     NOP_CPU3(20);

经过上网查找资料 _asm_ (“.byte 0xf3, 0x90”) intel的pause指令。当spinlock执行lock()获得锁失败后会进行busy loop,不断检测锁状态,尝试获得锁。这么做有一个缺陷:频繁的检测会让流水线上充满了读操作。另外一个线程往流水线上丢入一个锁变量写操作的时候,必须对流水线进行重排,因为CPU必须保证所有读操作读到正确的值。流水线重排十分耗时,影响lock()的性能。

参考这位同学的文章:
自旋锁spinlock剖析与改进

Pause指令解释(from intel):

Description
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.

提升spin-wait-loop的性能,当执行spin-wait循环的时候,笨死和小强处理器会因为在退出循环的时候检测到memory order violation而导致严重的性能损失,pause指令就相当于提示处理器哥目前处于spin-wait中。在绝大多数情况下,处理器根据这个提示来避免violation,藉此大幅提高性能,由于这个原因,我们建议在spin-wait中加上一个pause指令。

名词解释(以下为本人猜想):memory order violation,直译为-内存访问顺序冲突,当处理器在(out of order)乱序执行的流水线上去内存load某个内存地址的值(此处是lock)的时候,发现这个值正在被store,而且store本身就在load之前,对于处理器来说,这就是一个hazard,流水流不起来。

在本文中,具体是指当一个获得锁的工作线程W从临界区退出,在调用unlock释放锁的时候,有若干个等待线程S都在自旋检测锁是否可用,此时W线程会产生一个store指令,若干个S线程会产生很多load指令,在store之后的load指令要等待store在流水线上执行完毕才能执行,由于处理器是乱序执行,在没有store指令之前,处理器对多个没有依赖的load是可以随机乱序执行的,当有了store指令之后,需要reorder重新排序执行,此时会严重影响处理器性能,按照intel的说法,会带来25倍的性能损失。Pause指令的作用就是减少并行load的数量,从而减少reorder时所耗时间。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32F4系列的自旋锁是通过设置特定的寄存器来实现的。在STM32F4中,可以使用内置的DWT(Data Watchpoint and Trace)模块来实现自旋锁。DWT模块可以用来监控程序执行时间,从而实现自旋锁。 在使用自旋锁之前,需要先初始化DWT模块。具体的初始化代码如下: ``` void spin_lock_init(void) { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; } ``` 在上述代码中,首先将Core Debug模块使能,然后启用DWT模块的计数器。 接下来,可以使用以下代码来实现自旋锁的加锁和解锁操作: ``` void spin_lock(volatile uint32_t* lock) { while (__ldrex(lock) == 1); __strex(1, lock); } void spin_unlock(volatile uint32_t* lock) { __strex(0, lock); } ``` 在上述代码中,spin_lock函数会一直循环检查lock指向的变量是否为1,如果是1,则说明锁已经被其他线程占用,当前线程需要一直等待。如果lock指向的变量是0,则将其设置为1,表示当前线程占用了锁。 spin_unlock函数则是将lock指向的变量设置为0,表示当前线程释放了锁。 需要注意的是,自旋锁是一种非阻塞锁,如果其他线程一直占用锁,当前线程会一直循环等待,这会导致CPU占用率过高。因此,在使用自旋锁时,应该根据具体应用场景来选择合适的锁类型。同时,在STM32F4中,还可以使用信号量和互斥锁等更加高级的锁机制来解决多线程同步问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值