竟是CPU BUG?--记ARM指令SWP导致的QT卡住问题

本文记录了一次在三星Exynos4412 Cortex-A94手机上,QT 4.4版本遭遇卡顿的问题。通过GDB调试和堆栈跟踪,发现问题源自QT框架内嵌的ARM汇编指令SWP。作者通过代码搜索和实验确认,该指令在特定处理器上的模拟版本导致了性能问题,最终修复方法是替换为非模拟版本或调整代码。
摘要由CSDN通过智能技术生成

竟是CPU BUG?--记ARM指令SWP导致的QT卡住问题

现象:QT运行一段时间后会卡住

环境:QT版本为4.4
           CPU为三星EXYNOS 4412,Cortex A9 4核心,1.5G
      
过程及原因分析:
  既然程序会卡住,一定是什么地方出了问题,这个时候,最直接高效的方式是使用GDB查看进程的堆栈。
  但是,如果进程编译时没有使用-g选项,也就是编译的release版本,或者连接的库有release版本,则堆栈有可能出现符合无法解析的问题。
  这个时候,可以尝试使用addr2line工具来分析,或者查看进程proc下的mmap,猜测地址在哪个模块中,看是否能够缩小范围。
  如果缩小范围后的代码属于本工程编译的,也就是非第三方的,则可以重新编译debug版本替代,再次复现问题,打印堆栈。
  
  通过gdb挂载进程,发现问题不在QT应用中,而是在QT框架内,重新编译了debug版本的QT框架。debug版本的体积会大很多,如果可以的话,可以只对特定库编译带符号版本。
  再次gdb挂载,就可以看到出问题时的完整堆栈了:

(gdb) bt
  #0  0x40cd901c in qt_atomic_yield () from /opt/Qtopia4.4.3/lib/libQtCore.so.4
  #1  0x407a0f0c in QRegion::copy () from /opt/Qtopia4.4.3/lib/libQtGui.so.4
  #2  0x407a10c4 in QRegion::detach () from /opt/Qtopia4.4.3/lib/libQtGui.so.4
  #3  0x407a1930 in QRegion::translate () from /opt/Qtopia4.4.3/lib/libQtGui.so.4
  #4  0x407a1a30 in QRegion::translated () from /opt/Qtopia4.4.3/lib/libQtGui.so.4
  #5  0x406e7260 in QWidgetPrivate::getOpaqueSiblings () from /opt/Qtopia4.4.3/lib/libQtGui.so.4
  #6  0x406e7474 in QWidgetPrivate::subtractOpaqueSiblings () from /opt/Qtopia4.4.3/lib/libQtGui.so.4
  #7  0x407fab50 in QWidgetBackingStore::updateWidget () from /opt/Qtopia4.4.3/lib/libQtGui.so.4
  #8  0x407faf74 in QWidget::update () from /opt/Qtopia4.4.3/lib/libQtGui.so.4
  #9  0x40a4b1f4 in QAbstractItemView::viewportEvent () from /opt/Qtopia4.4.3/lib/libQtGui.so.4
  #10 0x409fdce4 in QAbstractScrollAreaFilter::eventFilter () from /opt/Qtopia4.4.3/lib/libQtGui.so.4
  #11 0x40dcbacc in QCoreApplicationPrivate::sendThroughObjectEventFilters () from /opt/Qtopia4.4.3/lib/libQtCore.so.4
  #12 0x406b0514 in QApplicationPrivate::notify_helper () from /opt/Qtopia4.4.3/lib/libQtGui.so.4
  #13 0x406b0940 in QApplication::notify () from /opt/Qtopia4.4.3/lib/libQtGui.so.4
  #14 0x4021481c in QtopiaApplication::notify () from /opt/Qtopia4.4.3/lib/libqtopia.so.4
 (gdb) bt
  #0  0x4050a2bc in nanosleep () from /lib/libpthread.so.0
  #1  0x40d160b0 in qt_atomic_yield () from /opt/Qtopia4.4.3/lib/libQtCore.so.4
  #2  0x40d2322c in QMutex::lock () from /opt/Qtopia4.4.3/lib/libQtCore.so.4
  #3  0x40e3e6e8 in QObjectPrivate::clearGuards () from /opt/Qtopia4.4.3/lib/libQtCore.so.4
  #4  0x40e42758 in QObject::~QObject () from /opt/Qtopia4.4.3/lib/libQtCore.so.4
  #5  0x406e1a78 in QWSTtyKbPrivate::~QWSTtyKbPrivate () from /opt/Qtopia4.4.3/lib/libQtGui.so.4
  #6  0x406e1a9c in QWSTtyKbPrivate::~QWSTtyKbPrivate () from /opt/Qtopia4.4.3/lib/libQtGui.so.4
  #7  0x40e448b0 in QObjectCleanupHandler::clear () from /opt/Qtopia4.4.3/lib/libQtCore.so.4
  #8  0x406d07c4 in QWSSignalHandler::handleSignal () from /opt/Qtopia4.4.3/lib/libQtGui.so.4
  #9  <signal handler called>
  #10 0x411316cc in sched_yield () from /lib/libc.so.6
  #11 0x40d160c0 in qt_atomic_yield () from /opt/Qtopia4.4.3/lib/libQtCore.so.4
  #12 0x400c2a2c in QBasicAtomicInt::ref () from /opt/Qtopia4.4.3/lib/libQtXml.so.4
  #13 0x40df08d4 in QConfFileSettingsPrivate::children () from /opt/Qtopia4.4.3/lib/libQtCore.so.4
(gdb) bt
  #0  0x40d160b0 in qt_atomic_yield () from /opt/Qtopia4.4.3/lib/libQtCore.so.4
  #1  0x40d2322c in QMutex::lock () from /opt/Qtopia4.4.3/lib/libQtCore.so.4
  #2  0x40e3e6e8 in QObjectPrivate::clearGuards () from /opt/Qtopia4.4.3/lib/libQtCore.so.4
  #3  0x40e42758 in QObject::~QObject () from /opt/Qtopia4.4.3/lib/libQtCore.so.4
  #4  0x406e1a78 in QWSTtyKbPrivate::~QWSTtyKbPrivate () from /opt/Qtopia4.4.3/lib/libQtGui.so.4
  #5  0x406e1a9c in QWSTtyKbPrivate::~QWSTtyKbPrivate () from /opt/Qtopia4.4.3/lib/libQtGui.so.4
  #6  0x40e448b0 in QObjectCleanupHandler::clear () from /opt/Qtopia4.4.3/lib/libQtCore.so.4
  #7  0x406d07c4 in QWSSignalHandler::handleSignal () from /opt/Qtopia4.4.3/lib/libQtGui.so.4
  

  对上面的堆栈进行分析,我们可以发现几个关键的可疑点:qt_atomic_yield 、 QMutex::lock () 、 QBasicAtomicInt::ref。从这几个调用,猜测是跟信号量或者原子操作有关。
  在QT框架中找这些函数,会发现有很多,但是出现了一些 asm volatile 标记的代码。
  上述标记是嵌入汇编的意思,就是为了提高性能,会在一些高频调用上使用汇编指令来提高性能,属于优化的一种;也有通过嵌入汇编指令执行特殊指令,实现特殊功能,比如上面所说的原子操作。
  原子操作和信号量有天然的关系,并且也属于非常高频的调用。
  把这些因素结合起来,高度怀疑上述堆栈最终指向的应该是某段嵌入汇编。
  
  使用grep 在代码中搜索 "asm volatile" 字符串,会看到有很多地方使用了嵌入汇编,这里截取一段

  ./qt-extended-4.4.3/src/3rdparty/libraries/tremor/asm_arm.h:  asm volatile("smull\t%0, %1, %2, %3"
  ./qt-extended-4.4.3/src/3rdparty/libraries/tremor/asm_arm.h:  asm volatile("smull       %0, %1, %2, %3\n\t"
  ./qt-extended-4.4.3/src/3rdparty/libraries/tremor/asm_arm.h:#define MB() asm volatile ("" : : : "memory")
  ./qt-extended-4.4.3/src/3rdparty/libraries/tremor/asm_arm.h:  asm volatile("subs        %1, %0, #32768\n\t"
  ./qt-extended-4.4.3/src/libraries/qtopiagfx/samples/starlist/mmx.c:    asm volatile(
  ./qt-extended-4.4.3/src/libraries/qtopiagfx/samples/starlist/mmx.c:        asm volatile(
  ./qt-extended-4.4.3/src/libraries/qtopiagfx/samples/starlist/mmx.c:            asm volatile (
  ./qt-extended-4.4.3/src/libraries/qtopiagfx/def_blend.cpp:    asm volatile("pld [%0, #32]\n\t" \
  ./qt-extended-4.4.3/src/libraries/qtopiagfx/plugin/mmx/mmx32_blend.c:    asm volatile (
  ./qt-extended-4.4.3/src/libraries/qtopiagfx/plugin/mmx/mmx16_blend.c:    asm volatile(
  ./qt-extended-4.4.3/src/libraries/qtopiagfx/plugin/mmx/mmx16_blend.c:    asm volatile( 
  ./builddir/sdk/qtopiacore/target/include/QtCore/qatomic_arm.h:    asm volatile("swpb %0,%2,[%3]"
  ./builddir/sdk/qtopiacore/target/include/QtCore/qatomic_arm.h:    asm volatile("swp %0,%2,[%3]"
  ./builddir/sdk/qtopiacore/target/include/QtCore/qatomic_arm.h:    asm volatile("swp %0,%2,[%3]"

  其实这里很多与该问题并无直接关系,还有很多是其他平台下的代码,我们这里关注跟arm平台相关的。
  如上面最后部分挑选的,qatomic_arm.h很可能是我们问题所在的代码文件。查看该代码文件,发现使用了SWPB指令。
  搜索该指令,了解到这是ARM中实现的交换内存和寄存器的原子指令。但是该指令好像只在低版本处理器核心中使用,高版本中为了兼容,比如这里用的EXYNOS4412,其实是提供的模拟仿真版本。
  
  难道是该指令出现了问题。很有可能,因为之前使用的一款EXYNOS2410,同样的QT版本框架,就不存在问题。
  我们看看内核中两款CPU的信息。对于EXYNOS4412,如下

  shell@:/proc/cpu $ ls -l
  -rw-r--r-- root     root            0 1970-12-25 11:42 alignment
  -r--r--r-- root     root            0 1970-12-25 11:42 swp_emulation


  对于EXYNOS2410,如下:

  ls /proc/cpu -l
  -rw-r--r--    1 root     root             0 Dec 28 12:58 alignment


  看出4412多了swp_emulation,离问题似乎越来越近了。进一步查看swp_emulation信息

  [root@]# cat /proc/cpu/swp_emulation 
  Emulated SWP:           0
  Emulated SWPB:          1086289
  Aborted SWP{B}:         0
  Last process:           13787 ---该进程是QT进程


  我们看到,短短一小会,QT进程使用该模拟指令集下的SWPB指令的次数高达1086289
  
  莫非是该指令有问题?以我们的常识,CPU应该是不会出问题的的的的...
  本着”尽信书不如无书“的原则,与其猜测,不如做个实验,写一个既简单的程序,反复调用嵌入上述指令的汇编代码,看看可否出问题。
  
  说干就干,很快结果就出来了:程序跑一会就不动了,问题复现并确认了了了!!!
  
  意犹未尽,莫非真让我遇到CPU指令的BUG了?马上修改QT框架中对该指令的调用,重新运行测试,结果UI确实不再卡住了。看来问题就出自该指令调用上。
  
  补充:EXYNOS4412其实也用在三星早期Galaxy 一款旗舰机型上,按说不应该有类似问题。正好手头也有这款手机,就adb连接手机,查看了下cpu信息,结果如下:

  shell@ja3g:/proc/cpu $ ls
  ls
  alignment
  swp_emulation

  shell@ja3g:/proc/cpu $ cat swp_emulation
  cat swp_emulation
  Emulated SWP:           0
  Emulated SWPB:          0
  Aborted SWP{B}:         0


  原来,虽然手机上也有该指令,但是没有使用!!!
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙赤子

你的小小鼓励助我翻山越岭

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值