linux对于内存分配,linux 内存分配学习

搜集整理了一些概念 :

writethough vs writeback

1. writethough

write-through意思是写操作根本不使用缓存。数据总是直接写入磁盘。关闭写缓存,可释放缓存用于读操作。(缓存被读写操作共用)

Write caching可以提高写操作的性能。数据不是直接被写入磁盘;而是写入缓存。从应用程序的角度看,比等待完成磁盘写入操作要快的多。因此,可以提高写性能。

由控制器将缓存内未写入磁盘的数据写入磁盘。表面上看,Write cache方式比write-through方式的读、写性能都要好,但是也要看磁盘访问方式和磁盘负荷了。

2. writeback

write-back(write cache)方式通常在磁盘负荷较轻时速度更快。负荷重时,每当数据被写入缓存后,就要马上再写入磁盘以释放缓存来保存将要写入的新数据,

这时如果数据直接写入磁盘,控制器会以更快的速度运行。因此,负荷重时,将数据先写入缓存反而会降低吞吐量。

cacheable vs buferfable

1。对于Write-though的写策略,Cacheable是回写数据指是否要放进Cache(当然对于一些I/O操作等自然不能Cacheable了),

Bufferable是指回写数据可以放进WriteBuffer中,慢慢回写仅主存(有些情况对于一些数据是要求立即写回的,不能先buffer一下)

2。对于Write-back的写策略,同样这样解释,但是一个例外就是Cacheable/unbufferable的情况,因为既然都Cache了,

对于Write-back策略来说就意味着要等到Cache line被替换的时候才被写入主存,这也就意味着写回主存时间注定要被delay,

所以一般它会被翻译成Write-though cached/buffered的行为。

Starting && stopping cache flushing levels

这两个设置影响控制器如何处理未写入磁盘的缓存内数据,并且只在write-back cache方式下生效。缓存内数据写入磁盘称为flushing.你可以配置

Starting and stopping cache flushing levels值,这个值表示占用整个缓存大小的百分比。当缓存内未写入磁盘的数据达到starting flushing value时,

控制器开始flushing(由缓存写入磁盘)。当缓存内未写入磁盘数据量低于stop flush value时,flushing过程停止。控制器总是先flush旧的缓存数据。

缓存内未写入数据停留超过20秒钟后被自动flushing.

典型的start flushing level是80%。通常情况下,stop flushing level也设置为80%。也就是说,控制器不允许超过80%的缓存用于write-back cache,

但还是尽可能保持这一比例。如果你使用此设置,可以在缓存内存更多的未写入数据。这有利于提高写操作的性能,但是要牺牲数据保护。如果要得到数据保护,

你可以使用较低的start and stop values。通过对这两个参数的设置,你可以调整缓存的读、写性能。经测试表明,使用接近的start and stop flushing levels时

性能较好。如果stop level value远远低于start value,在flushing时会导致磁盘拥塞。

Cache block size

这个值指缓存分配单元大小,可以是4K或16K。选择合适的值,可以明显的改善缓存使用性能。

如果应用程序更多时候访问小于8K的数据,而将cache block size设置为16K,每次访问仅使用一部分cache block。

在16K的cache block里总是存储8K或更小的数据,意味着只有50%的缓存容量被有效使用,使性能下降。对于随机I/O和小数据块的传送,

4K比较合适。另一方面,如果是连续I/O 并使用大的segment size,最好选择16K。大的cache block size意味着cache block数量少并可缩短缓存消耗延时。

另外,对于同样大小的数据,cache block size大一些,需要的缓存数据传送量更小。

dma_alloc_coherent vs dma_alloc_writecombine

都是分配连续物理内存,返回虚拟地址

1.dma_alloc_coherent

#define pgprot_noncached(prot) __pgprot(pgprot_val(prot) & ~(L_PTE_CACHEABLE | L_PTE_BUFFERABLE))

禁用cahceable 和 bufferable

2.dma_alloc_writecombine

#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~L_PTE_CACHEABLE)

禁用cahceable

cma vs ump

cma: 管理连续内存,可以预留好,可以用到时分配。4412BSP中为预留。

ump:mali使用内存,使用时动态配分(alloc_page)

NEON

多媒及加速指令集,增强ARM对多媒体处理能力,某些场景可以替代硬件处理单元。

ARM? NEON? 通用 SIMD 引擎可有效处理当前和将来的多媒体格式,从而改善用户体验。

NEON 技术可加速多媒体和信号处理算法(如视频编码/解码、2D/3D 图形、游戏、音频和语音处理、图像处理技术、电话和声音合成),

其性能至少为 ARMv5 性能的 3 倍,为 ARMv6 SIMD 性能的 2 倍。

NEON 技术是通过干净方式构建的,并可无缝用于其本身的独立管道和寄存器文件。

NEON 技术是 ARM Cortex?-A 系列处理器的 128 位 SIMD(单指令多数据)体系结构扩展,旨在为消费性多媒体应用提供灵活强大的加速功能,

从而明显改善用户体验。 它具有 32 个寄存器,64 位宽(是 16 个寄存器,128 位宽的双倍视图。)

request_mem_region && ioremap && phys_to_virt()

Linux在头文件include/linux/ioport.h中定义了三个对I/O内存资源进行操作的宏:

(1)request_mem_region()宏,请求分配指定的I/O内存资源。

(2)check_mem_region()宏,检查指定的I/O内存资源是否已被占用。

(3)release_mem_region()宏,释放指定的I/O内存资源。

这三个宏的定义如下:

#define request_mem_region(start,n,name)   __request_region(&iomem_resource, (start), (n), (name))

#define check_mem_region(start,n)    __check_region(&iomem_resource, (start), (n))

#define release_mem_region(start,n)   __release_region(&iomem_resource, (start), (n))

其中,参数start是I/O内存资源的起始物理地址(是CPU在RAM物理地址空间中的物理地址),参数n指定I/O内存资源的大小。在请求IO内存资源成功后,

开始用ioremap进行映射操作。

void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) 将一个IO地址空间映射到内核的虚拟地址空间上去,便于访问。

入口:phys_addr是要映射的起始的IO地址;size是要映射的空间的大小;flag是要映射的IO空间的和权限有关的标志;

实现:对要映射的IO地址空间进行判断,低PCI/ISA地址不需要重新映射,也不允许用户将IO地址空间映射到正在使用的RAM中,最后申请一个 vm_area_struct结构,

调用remap_area_pages填写页表,若填写过程不成功则释放申请的vm_area_struct空间;根据虚拟地址和欲映射的物理地址修改页表,之后内核就可以用这个虚拟

地址来访问映射的物理地址了。

对于直接映射的I/O地址ioremap不做任何事情(比如不带MMU的Uclinux中就直接返回物理地址) 。有了ioremap(和iounmap),设备就可以访问任何I/O内存空间,

不论它是否直接映射到虚拟地址空间。但是,这些地址永远不能直接使用(像kmalloc返回的地址那样用),而要用readb这种函数。

同样是从物理地址分配得到虚拟地址,还有以下这个函数:phys_to_virt()实际地址转换成虚拟地址,两者是有区别的。用ioremap 和 phys_to_virt 做物理地址

于虚拟地址的转换发现:

addr = (unsigned int volatile *)ioremap(0x56000088,12);

printk(KERN_ALERT"%x\n",addr);

addr = (unsigned int volatile *) phys_to_virt(0x56000088);

printk(KERN_ALERT"%x\n",addr);

两个函数返回的addr值不一样。原因在于:

(1)在内核中phys_to_virt只是给地址减去一个固定的偏移 :

#ifndef __virt_to_phys

#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET)

#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)

#endif

注意:PHYS_OFFSET =0x50000000,在带MMU的内核中,PAGE_OFFSET是0xc0000000;不带MMU的内核中,与PHYS_OFFSET 同。

(2)而ioremap()的原则就是内核会根据指定的物理地址新建映射页表,物理地址和虚拟地址的关系就由这些页表来搭建!:

这个从ioremap的函数体可以看出来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值