目前我正在 linux 上,写一个用户态的一个 c 程序。里面有一个逻辑是,去写了一段 RAM ,但写的动作实际上只发生在了 x86 CPU 的 cache 里面,还没有真正写到 RAM 里,然后这导致了错误发生(可以认为我需要结合 DMA 做一些操作,但 DMA 需要读到的东西还在 CPU 的 cache 里面呢)。
所以我想知道,linux 里有提供这种函数吗?(类似 arm ,都会提供这种函数的)
另外,我在网上搜,搜到的 全是 shell 里执行的命令:sync; echo 1 > /proc/sys/vm/drop_caches
。这个关键词到底该怎么搜索。
1
Yourshell 2023-09-05 22:15:53 +08:00
你用 C 也可以写/proc/sys/vm/drop_caches 啊
|
2
Yourshell 2023-09-05 22:16:43 +08:00
Linux 文件就是接口
|
3
geelaw 2023-09-05 22:17:24 +08:00 via iPhone
关键词是 linux flush cpu cache
|
4
Yourshell 2023-09-05 22:17:53 +08:00
|
5
codehz 2023-09-05 22:21:58 +08:00
我觉得这里有很多概念上的问题啊。。。
/proc/sys/vm/drop_caches 这个显然和 cpu cache 没有关系 你要 bypass cpu cache 的话,直接 volatile 不就好了 |
6
amiwrong123 OP |
7
leonshaw 2023-09-05 22:28:36 +08:00 via Android
XY 问题
|
8
ljn917 2023-09-05 22:31:34 +08:00 via Android
|
9
codehz 2023-09-05 22:31:51 +08:00
@amiwrong123 (小寄巧:用 *(volatile int __attribute__((force)) *)&x = 1 写入
内核也在用,不过把 __attribute__((force)) 加了个宏__force 简化) |
10
geelaw 2023-09-05 22:32:44 +08:00 via iPhone
读了一下文档,看起来 drop_caches 只能清除文件系统里没有写过的缓存,sync 的作用是刷新所有文件,此外楼主的命令的影响范围是整个系统,而不是自己的进程,这样做几乎永远是错误的。
@codehz #5 可能楼主需要写很多内容后一起刷新? |
11
codehz 2023-09-05 22:34:26 +08:00
不过 linux 用内核用是有正当理由的,你这是 x86 带有硬件 dma 或者别的硬件内存映射技术一类的吗,那样用户态也访问不到吧
|
12
codehz 2023-09-05 22:35:54 +08:00
@geelaw 我感觉根本不是一个目的啊,drop_caches drop 的是 page cache 这些,和 cpu 缓存一点关系都没,下文提及的也看出不太像是访问文件的问题)
|
13
amiwrong123 OP @codehz
是的,用到了硬件的 DMA 。 用户态是可以访问的呀,只要最终映射出一个虚拟地址出来给 CPU 用就好了。我的程序逻辑很简单,以 RAM 作为交互,简单来说,CPU 先往 RAM (也就是内存条)里写,然后 DMA 从 RAM 里读。 |
14
sujin190 2023-09-05 22:40:07 +08:00 via Android
没听说过还有手动清 cpu cache line 的,并发不一致也仅限于多核并发写,cpu 都自己管理好了和内存一致,时钟周期级别的一致,否则那么多程序都只是 lock 一下就能从内存读到正确值岂不是都要挂了,如果你硬要说有那应该就是 lock 之类的操作触发总线同步来标记 cache line 无效就是了吧
|
15
shimanooo 2023-09-05 22:43:00 +08:00
volatile?
|
16
polaa 2023-09-05 22:43:32 +08:00
缓存一致性问题 关键词 Cache coherence
函数 : __clear_cache 指令 clflash wbinvd |
17
codehz 2023-09-05 22:45:46 +08:00
@amiwrong123 参考这个 https://github.com/ikwzm/udmabuf mmap 的时候加一个 O_SYNC
|
18
codehz 2023-09-05 22:52:59 +08:00
虽然理论上这种情况还有编译器优化的问题,也就是如果 a b a 这样写,可能会跳过中间的 b
再用前面说的 volatile 转换方式也不迟( |
19
codehz 2023-09-05 22:56:13 +08:00
哦,不对,编译器优化用 asm volatile("" ::: "memory");隔开就够了,O_SYNC 配合合适的用户态 dma 映射实现,应该就足够了
(不过用户态 dma 你还是得考虑调度的问题,没准你循环写入的时候进程被调度走了呢) |
20
polaa 2023-09-05 22:57:09 +08:00
然后你的这种做法的关键词是 self-modifying code ,但是我只接触过 arm 架构的 x86 架构不熟悉
可以参考一下 intel 的 Intel® 64 and IA-32 Architectures Optimization Reference Manual @polaa |
21
codehz 2023-09-05 23:05:50 +08:00
udmabuf 能 O_SYNC 的原因是加了这个参数后,就会在内核里用 dma_sync_single_for_cpu 来同步 cpu 缓存(
其他普通的实现可不一定有这个) |
22
amiwrong123 OP @codehz #19
理解你说的意思,就是说,如果一个进程 malloc 了一片空间,这片空间只是属于这个进程的,但可能进程调度,把 RAM 的东西从内存条上调度走了。 不过我这个应该没有这个担心,因为不是用户态 malloc 的空间,是直接 搞了一块 连续的物理地址出来,再映射到虚拟地址。 |
23
amiwrong123 OP @codehz #21
代码是这样的,是用 devmem 获得的 fd ,获得时是使用了 O_SYNC 的(不知道为啥,还是没起作用)。然后用这个 fd 进行 mmap ,获得了一个虚拟地址。 |
24
nuk 2023-09-05 23:20:24 +08:00
Memory barrier 吧,硬件不同实现不同
|
25
codehz 2023-09-05 23:21:23 +08:00
@amiwrong123 前面说的被调度走指的不是说内存映射也炸了
而是说 dma 硬件处理上可能会有不低概率观察到只进行到一半的修改( 后面补充的 o sync 就是为了应对你说的这个的 dev mem 的问题,正经解决方法就是用 udmabuf 那个模块去映射,效率也高一点 |
26
nuk 2023-09-05 23:52:18 +08:00
原来是 DMA ?如果直接 mmap /dev/mem 的话,DMA 的内存区域本身就是 uncache 的,如果 dynamic DMA ,那不能直接用户态 mmap 创建 dma 内存,需要内核模块先分配 dma 内存。
|
27
liuminghao233 2023-09-06 00:07:48 +08:00 via iPhone
内存屏障做的是 cache 可见性同步,不能保证刷入 ram
你需要 CLFLUSH ,可以把 l1 l2 l3 的 cache 都刷掉 用 _mm_clflush 应该就可以 |
28
ryd994 2023-09-06 00:31:47 +08:00 via Android
memory barrier 只是避免编译器优化,缓存一致性仍然由 CPU 自己维护,也就无法解决 dma 的问题。
dma 是设备修改内存,CPU 无法维护缓存一致性 volatile 就是最简单的办法。 正规做法是 dma_map_single(), dma_sync_single_for_device(), dma_unmap_single(), dma_sync_single_for_cpu() 这几个 API 。合理使用的话,它们会处理 dma 一致性问题 |
29
ryd994 2023-09-06 00:34:24 +08:00 via Android
顺带一提,我用的关键字是
dma sync cpu cache 你不应该搜 Linux cache 。因为,cache 有很多种。CPU cache 也是 cache ,Page cache 也是 cache 。一般用户是不可能需要清 CPU cache 的,只有写驱动的人才需要。所以直接搜 cache ,大部分内容都是 Page cache |
30
feather12315 2023-09-06 00:55:32 +08:00 via Android
|
31
jimages 2023-09-06 01:05:05 +08:00
WBINVD 指令,不过这个执行只能在特权模式下执行,你需要看一下操作系统有没有提供这个指令的函数,比如 windows 好像提供了 https://learn.microsoft.com/en-us/cpp/intrinsics/wbinvd?view=msvc-170
linux 不太清楚 |
32
jimages 2023-09-06 01:08:46 +08:00
这个 repo 写了一个 linux 扩展,你也许可以使用 https://github.com/batmac/wbinvd/blob/master/wbinvd.c
|