mmap映射物理内存之一cache与lock

         

目录

单板内存性能

cache与否

  map_locked参数与mlock

    malloc申请内存

mmap映射保留内存

 开关cache的耗时对比

总结


     

     本文介绍通过mmap映射预留的内存,预留内存通过cmdline中增加mem参数来实现。

    测试环境为飞腾D2000。

单板内存性能

以mbw,单进程测试性能带宽,此测试占用完整一个CPU核,但内存带宽并没有压满,仅仅测试单个CPU读写内存的带宽,以此为基准,对比查看应用在使用内存时的性能。

 ./mbw -q -n 10 5000

Method: MEMCPY 3624.776 MiB/s
 Method: DUMB 1052.553 MiB/s
Method: MCBLOCK3614.032 MiB/s

  即,3.6MB/ms的拷贝速率。

cache与否

通过mmap接口映射一段内存,映射后的地址是带cache,还是不带cache呢

走读代码 : kernel\drivers\char\mem.c

mmap_mem->phys_mem_access_prot->uncached_access

这里可以看到在内核以外的地址,例如通过cmdline中增加mem限制以上的内存,通过mmap映射后,默认是关闭cache的

而对于巨页等内核可见的内存,通过mmap映射则cache为打开。比如DPDK使用的 mmap映射。

/* map the segment, and populate page tables,
		 * the kernel fills this segment with zeros. we don't care where
		 * this gets mapped - we already have contiguous memory areas
		 * ready for us to map into.
		 */
		virtaddr = mmap(NULL, hugepage_sz, PROT_READ | PROT_WRITE,
				MAP_SHARED | MAP_POPULATE, fd, 0);
		if (virtaddr == MAP_FAILED) {
			EAL_LOG(DEBUG, "%s(): mmap failed: %s", __func__,
					strerror(errno));
			close(fd);
			goto out;
		}

  map_locked参数与mlock

    

    通常的内存使用如上图,进程创建时建立页表,以映射虚拟地址和物理地址的关系,例如此时进程1占用了此块内存。

   而当进程1,不活跃时,其部分数据内存被认为不活跃,则会被swap磁盘中,并且对应页表会设置为缺页状态,也就是无实际对应的物理内存。

   而进程2此时创建,建立页表,将自己的虚拟地址映射到了原先进程1的内存。

    mlock 可以使进程1一直占用此内存,减少了swap耗时和缺页处理的耗时。

  

    malloc申请内存

   1)   我们用malloc申请两段内存,进行数据拷贝。      

src=(unsigned int *)malloc(0x2000000);
        dst=(unsigned int *)malloc(0x2000000);

拷贝耗时

malloc Read back: 0x0, copy (32)M 14173.000000 us

 2.28MB/ms

2) mlock dst内存

   if (mlock(dst, copy_size) == 0) {
    printf("Memory locked malloc successfully\n");
	} else {
	    perror("mlock malloc failed");
	} 

此时拷贝耗时

malloc Read back: 0x0, copy (32)M 7110.000000 us

4.56MB/ms

拷贝方法速率耗时(32M数据)
mbw测试3.6MB/ms
memcpy 2.28MB/ms14MS
memcpy+mlock dst地址4.56MB/ms7MS

mlock确认生效

通过查看进程status,可以看到进程的确lock了 32MB的内存。

cat /proc/2877/status
Name:   mmapresv

VmSize:   198540 kB
VmLck:     32772 kB

mmap映射保留内存

if (mlock(mem, reserved_size) == 0) {
    printf("Memory locked successfully\n");
	} else {
	    perror("mlock failed");
	}  

 mem地址是通过mmap映射保留内存的虚拟地址,虽然上述mlock执行成功,但实际查看进程的lock内存,值为0,也就是说实际上lock功能并没有对此时mmap应用场景生效。

cat /proc/2830/status
Name:   mmapresv

VmSize:   198540 kB
VmLck:         0 kB

 开关cache的耗时对比

  mmap将保留的物理地址映射为带cache与不带cache。进行拷贝测试

 关cache

Read back: 0x0, copy (32)M 364115.000000 us

开cache

Read back: 0x0, copy (32)M 17313.000000 us

开cache,并且clean cache

Read back: 0x0, copy (32)M 43951.000000 us

 32M 数据拷贝如下. 关cache即 源和目的都关;开则源和目的都开。

关cache364MS90KB/ms
开cache17MS1.88MB/ms
开cache,且clean cache44MS745KB

总结

    期望通过mmap实现对保留物理内存的映射,并完成数据的拷贝。但是简单映射性能比较差。

    1)关闭cache后,再让CPU读写,速率只有100MB/s左右。这种方式虽然和外设DMA打交道时简单,但是到CPU 读写数据时,速率太慢。

因素影响
失去 Cache 加速每次读写直接访问内存(DRAM),延迟从 ~10ns(L1 Cache)升至 ~100ns
总线带宽利用率低无预取(Prefetch)和突发传输(Burst),总线效率下降
流水线停滞CPU 无法并行执行指令(需等待内存读写完成)
ARM 架构限制AArch64 的普通加载/存储指令(如 LDR/STR)在 Non-Cacheable 模式下性能极低

 理论带宽对比

模式预期带宽(Cortex-A72 示例)实测典型值
With Cache10-20 GB/s2000-5000 MB/s
No Cache1-5% of peak50-200 MB/s

 # 使用 perf 统计缓存命中率

perf stat -e cache-misses,cache-references,L1-dcache-load-misses ./your_program

1,000,000 cache-misses      # 缓存未命中率接近 100%

   2)开cache映射

   主要两个问题:

    1) 不能被mlock 锁定成功。导致拷贝优化不上来。

     2) cache在用户态的clean与invalid操作。

<think>我们正在讨论POSIX共享内存的使用问题。诊断和分析这类问题通常涉及多个方面:性能瓶颈、同步问题、配置错误、内存泄露等。根据提供的引用和一般知识,我们可以构建一个系统的分析框架。引用[1]提到了共享内存的创建接口`shmget`,这是SystemV共享内存的API。但用户询问的是POSIX共享内存,因此我们需要区分这两者。POSIX共享内存使用同的API,如`shm_open`、`mmap`等。然而,引用[3]强调了POSIX线程API的一致性,同样,POSIX也提供了一套共享内存的API,以保证跨平台一致性。因此,我们的分析将围绕POSIX共享内存API展开。诊断步骤:1.**确认共享内存的创建和映射是否正确**:-使用`shm_open`创建或打开共享内存对象,使用`ftruncate`设置大小,然后使用`mmap`映射到进程地址空间。-检查这些调用的返回值,确保没有错误。如果调用失败,检查errno以确定原因(例如权限问题、资源足等)。2.**同步问题诊断**:-共享内存需要配合同步机制(如互斥锁、信号量)来避免竞争条件。引用[3]提到POSIX线程API的一致性,同样适用于同步原语(如POSIX信号量)。-确保同步原语正确初始化(例如,进程间共享的互斥锁需要初始化为PTHREAD_PROCESS_SHARED属性)。-使用工具如`strace`跟踪系统调用,或者使用调试器(如gdb)检查锁的状态。3.**性能问题分析**:-如果遇到性能瓶颈,可能的原因包括:-同步原语竞争激烈(例如,多个进程频繁争夺一个锁)。-共享内存区域过大导致TLB失效频繁。-合理的访问模式(如falsesharing)。-使用性能分析工具,如`perf`,来观察缓存命中率和TLB失效情况。-考虑使用大页(HugePages)来减少TLB压力(引用[4]提到从Buddy分配大页内存的方法,同样适用于用户空间的大页映射)。4.**资源泄漏和配置问题**:-共享内存对象在再需要时应使用`munmap`和`shm_unlink`进行清理。否则可能导致资源泄漏。-检查系统共享内存限制:`/proc/sys/kernel/shmmax`(最大共享内存段大小)、`/proc/sys/kernel/shmall`(系统范围内共享内存页总数)等。注意,这些参数通常针对SystemV共享内存,POSIX共享内存可能受其他参数限制(如`/proc/sys/fs/mqueue/`下的参数用于POSIX消息队列,而共享内存则可能受文件系统限制,因为POSIX共享内存对象通常位于`/dev/shm`)。-使用`ipcs-m`查看SystemV共享内存,使用`lsof`查看打开的共享内存文件(通常在`/dev/shm`下)来确认是否有泄漏。5.**内存一致性分析**:-确保进程对共享内存的访问遵守内存一致性模型。使用内存屏障(如果需要)来保证访问顺序。6.**使用工具辅助诊断**:-`valgrind`(特别是drd工具)可以检测多进程同步错误。-`ipcs`和`ipcrm`用于管理SystemV共享内存,但POSIX共享内存可以通过文件系统命令(如`ls`、`rm`)管理`/dev/shm`下的文件。7.**内核相关问题**:-如果怀疑内核问题(如内存泄露),可参考引用[4]中提到的内核内存分配分析。但用户级共享内存问题通常需要深入到内核分配器,除非有证据表明是内核问题(如系统内存逐渐减少且无用户级泄漏)。示例:使用POSIX共享内存的代码框架```c#include<sys/mman.h>#include<sys/stat.h>#include<fcntl.h>#include<unistd.h>#include<stdio.h>intmain(){constchar*name="/my_shm";constintSIZE=4096;//创建共享内存对象intshm_fd=shm_open(name,O_CREAT|O_RDWR,0666);if(shm_fd==-1){perror("shm_open");return1;}//设置共享内存大小if(ftruncate(shm_fd,SIZE)==-1){perror("ftruncate");return1;}//映射共享内存void*ptr=mmap(0,SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,shm_fd,0);if(ptr==MAP_FAILED){perror("mmap");return1;}//现在可以使用ptr访问共享内存//清理munmap(ptr,SIZE);close(shm_fd);shm_unlink(name);//当所有进程都完成后,应该调用shm_unlinkreturn0;}```如果遇到问题,可以逐步检查上述代码中的每个步骤,并查看错误返回。综上所述,诊断POSIX共享内存问题需要从正确性、同步、性能、资源管理等多个维度进行。使用系统工具和仔细的代码审查是解决问题的关键。§§相关问题§§1.POSIX共享内存和SystemV共享内存有什么区别?2.如何确保多个进程通过共享内存通信时的数据一致性?3.在Linux中,如何监控共享内存的使用情况?4.使用共享内存时,如何避免资源泄漏?</think>### 诊断和分析POSIX共享内存问题的方法 诊断POSIX共享内存问题需要从**同步机制、资源配置、内存管理和跨进程协调**四个维度展开。以下是系统化的分析框架: #### 1. **同步问题诊断**(最常见) - **竞争条件检测** 使用`pthread_mutexattr_setpshared()`确保互斥锁支持进程间共享: ```c pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); // 关键配置 pthread_mutex_init(&shm->lock, &attr); ``` 未设置此属性会导致锁仅在创建进程内有效[^3]。 - **信号量同步验证** 检查POSIX信号量(`sem_open()`)的初始值和操作顺序: ```shell $ ipcs -s # 查看系统信号量状态 ``` 信号量泄漏表现为`semget: No space left on device`错误。 #### 2. **资源配置分析** - **内核参数检查** POSIX共享内存受限于: ```shell /proc/sys/fs/mqueue/msg_max # 最大消息数 /proc/sys/fs/mqueue/msgsize_max # 单消息最大尺寸 ``` 超出限制会导致`shm_open()`返回`EFBIG`错误。 - **挂载点验证** 确认`/dev/shm`挂载且空间充足: ```shell $ df -h /dev/shm && mount | grep shm # 典型问题:未挂载或空间足 ``` #### 3. **内存管理诊断** - **泄漏检测** 使用`lsof`追踪未释放的共享内存对象: ```shell $ lsof /dev/shm # 查看打开共享内存的进程 $ ls -l /dev/shm | wc -l # 统计对象数量 ``` 未调用`shm_unlink()`会导致对象持续占用内存[^4]。 - **映射一致性检查** 验证各进程`mmap()`的地址对齐和大小一致性: ```c void* ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (ptr == MAP_FAILED) { /* 处理错误 */ } ``` 地址对齐会引发`SIGBUS`信号。 #### 4. **跨进程协调验证** - **生命周期管理** 确保遵守创建/销毁协议: ``` 进程A: shm_open(O_CREAT) → ftruncate() → mmap() 进程B: shm_open() → mmap() 所有进程: munmap() → close() 最后进程: shm_unlink() ``` 提前`shm_unlink()`会导致其他进程访问失效。 - **字节序处理** 混合架构环境需验证数据序列化: ```c uint32_t net_val = htonl(local_val); // 主机序转网络序 ``` #### 5. **高级诊断工具** - **内核追踪** 使用`ftrace`跟踪共享内存系统调用: ```shell $ echo 1 > /sys/kernel/debug/tracing/events/syscalls/sys_enter_shm_open/enable ``` - **性能分析** 通过`perf`检测缓存争用: ```shell $ perf record -e cache-misses -p <pid> ``` > **关键原则**:共享内存问题90%源于同步或生命周期管理错误。优先检查互斥锁的`PTHREAD_PROCESS_SHARED`属性和`shm_unlink()`调用时序[^3][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

proware

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值