最近我一个项目涉及这个平台的内核开发。内核有两个线程,使用 wait_event 进行通讯,有大约万分之一的概率,事件发送方设置事件后,接收方获取不到状态。
类似这个问题: https://stackoverflow.com/questions/23262893/wait-event-timeout-exits-on-timeout-with-condition-set
如果我把两个线程绑定到同一个 CPU 核心上,问题就消失了。
之前我搞这个平台的 AMP 架构的时候,也出现过裸机核心与 Linux 核心缓存不一致的问题。
![]() |
1
cnnblike 19 天前
https://developer.arm.com/documentation/100941/0101/Memory-attributes
内存一致性看这个,一般说来是不在一个 cluster 的时候容易遇到这个 做 amp 的话,内核态 解决方案 https://developer.arm.com/documentation/ddi0500/e/system-control/aarch32-register-summary/c7-system-operations?lang=en 做进程通信的话,整个 core affinity ,或者弄个 memory-barrier 应该也行 |
![]() |
2
cnnblike 19 天前
memory barrier 的官方文档在这里 https://developer.arm.com/documentation/ddi0406/cb/Application-Level-Architecture/Application-Level-Memory-Model/Memory-access-order/Memory-barriers?lang=en#Chddbigg
内核态的内存栅栏看这个 https://www.kernel.org/doc/Documentation/memory-barriers.txt 用户态开发看 std::memory_order |
![]() |
3
villivateur OP @cnnblike 不在一个 cluster 的情况,按我的理解,应该非常容易出现缓存不一致,而不是极低的概率出现。AMP 的方案我现在也不干了,只是提一嘴。另外 wait_event 相关的内核 API 是自带内存屏障的,理论上不需要手动加。
|
![]() |
4
cnnblike 19 天前
@villivateur 不在一个 cluster 的情况不大可能说实话,你直接说 rk 什么型号吧
https://linaro-dev.linaro.narkive.com/f2kFnMmW/why-is-the-the-smp-mb-in-arm64-s-barrier-h-dmb-ish ”In Arm V8 Architecture Reference Manual£¬there is an example (see beblow) to explain the shareability attribute of clusters. It is easy to know: each cluster is corresponding to a Inner shareable domain; the two cluster comprise a Outer shareable domain.“ |
![]() |
5
cnnblike 19 天前
如果是 rk3568 或者是 rk3566 上的核间通信,因为内存不一致触发问题说实话可能性很低,按 arm 的定义(和推荐实现),单一一个 cluster 的所有核都在同一个 innershareable 上,理论上 cluster 内所有核能看到的,都是一样的。
如果是 rk3588 ,那是有可能的,我猜你把一个小核分出来跑 amp ,或者干脆是在 cortex-m 核上跑 amp 通信,那就触发缓存不一致了 |
![]() |
6
villivateur OP @cnnblike 目前这个问题,出在 RK3588 上,是 SMP 架构,全部 8 个核心都是 Linux 。但你这么一说我开始怀疑是大小核的问题,我要去验证下看看如果两个线程都跑在小核或者都跑大核,看看还有没有问题。
另外,之前我在 RK3568 上面跑 AMP ,是 core 3 裸核,开了一块内存,core3 往里面写数据,Linux 核心(另外三个核)读不到,必须 Linux 先写一下这块内存才能读到 |
7
ivan_wl 19 天前
看下反汇编是不是有内存屏障指令,触发 event 前应该是 dmb ishst ,另外一个 cpu 在被唤醒后应该先做 dmb ishld
|
![]() |
8
cnnblike 19 天前
@villivateur
内存段和 shareable 的设置和 tlb 有关系,在内核的 mm 那块的逻辑里,具体说是 The arch/arm64/mm/cache-*.S 和 arch/arm64/mm/proc-*.S 还有一个可能性,我不知道你是用 mem=xxx MB 设置的内存还是用 reversed_memory 设置的内存,所以可能行为会有不同。 如果你用的 jailhouse 的话,他那个实现对大小 cluster 的支持可能是不对的,看此处注释: https://github.com/siemens/jailhouse/blob/master/hypervisor/arch/arm64/entry.S#L453-L458 |
![]() |
9
cnnblike 19 天前
@villivateur 我最近也在研究这块,有兴趣的话,记得把结论也发我一下
|
![]() |
10
cnnblike 19 天前
我仔细分析了一下你遇到的问题,感觉像是这样:
1. rk3588 这个问题是应该是因为那个页面被设置成了 write-back 而不是 write-through ,由于是闲时写,所以在你系统的内存总线空闲的时候会写入,然后叠加 wb 会在写入的时候刷 L1 ,更新另一个 cluster 的 L2 ,所以显得触发概率低,所以我建议你跑一个高内存总线开销的用户态程序,应该能让任务出问题 2. rk3568 的场合,你的页表上对这个页面可能没设置 SH ,看这里 https://zhuanlan.zhihu.com/p/532838098 |
![]() |
11
villivateur OP @cnnblike 嗯,有道理,对于内存管理我也还没入门,目前正在复现不同核心的现象,复现很耗时,我有进展了 @你
|
![]() |
12
villivateur OP @cnnblike 这两天验证了一下该问题与大小核的关系。复现情况是:两个线程都在大核或者都在小核,暂时没有复现问题。如果一个大核一个小核,就可以复现。
|
![]() |
13
cnnblike 17 天前
|
![]() |
14
cnnblike 17 天前
正确的做法可能是用 memremap ,用 dts+memremap 这样的形式会比较好点:
https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18841683/Linux+Reserved+Memory memremap(r.start, resource_size(&r), MEMREMAP_WT); |