【96】write combine机制介绍

news2024/11/19 3:41:01


前言

这篇文章主要介绍了write combine的机制


一、write combine的试验

1.系统配置

(1)、CPU:11th Gen Intel(R) Core(TM) i7-11700 @ 2.50GHz

(2)、GPU:XX

(3)、link status:X16 GEN4(受限于CPU能力)

(4)、主板: TUF GAMING B560M-PLUS

(5)、linux  5.15.0-107-generic,ldd (Ubuntu GLIBC 2.31-0ubuntu9.16) 2.31

注意:CPU write combine受到CPU write combine buffer大小、write combine buffer entry数量、CPU的运行频率以及CPU evict write combine buffer的策略影响非常大,因此,绝对速率和CPU有关,这里只需要关注两种情况下,速率提高比例就可以了。

2、数据对比

    可见使用memcpy 把32M数据从system main memory拷贝的到GDDR,开启write combine后,CPU写的性能提供了13.3倍。这是怎么做到的呢?在讲write combine前需要先讲一下处理器的memory system,以及memory system中的cache。

二、背景知识:X86下的memory system

1、X86下的memory system简介

    上图中的白色框就是memory system的组件。其中main memory在处理器芯片外,是离processor execution units最远的。

    Cache是离processor execution units(处理器中负责执行指令和计算操作的部分)最近的。图中只是画了三种cache(L1 instruction cache、L1 data cache、L2 cache),实际上,对于多CPU core还有L3 cache。不同的微架构,L1/L2/L3的功能可能不太相同,但是基本原理差不多。

    L1 cache和L2 cache一般是每个core都有自己独立的,只是L1 cache通常会被分成L1 data cache和L1 instruction cache ,而L2 cache的data 和instruction是合一的。

2、skylake CPU的cache hierarchy

    下图是intel skylake CPU的 cache hierarchy(缓存层次结构),可看到每个CPU core有自己独立的L1和L2 cache,但是L3 cache(LLC)是share给所有的processors的。

    在L2 cache和L3 cahce之间是L2 Snoop Filter, 是skylake架构中的一个缓存一致性机制。L2 Snoop Filter通过减少不必要的snoop请求(记录缓存数据的位置),来减少的缓存之间的通信开销,提高缓存一致性协议的效率。

    所谓缓存一致性就是在多核处理器系统中,各个核的缓存需要保持一致性,以确保不同核访问同一内存地址时,数据是一致的。当一个核需要访问另一个核的缓存数据时,会发出 snoop 请求。这种请求会在总线上广播,以检查其他缓存中是否有该数据。

    关于snoop,Intel64 andlA-32 Architectures Software Developer's Manual的11.2 CACHING TERMINOLOGY讲得比较清楚了。

    在MP(多处理器)系统中,像Intel486和Intel 64这样的处理器具有snoop(侦听、监视)其他处理器访问system memory和访问处理器internal cache的能力,也就是所谓的“snoop”。 Snoop的功能让处理器的internal cache与system memory和总线上其他处理器中的cache保持一致。

     例如,在Pentium和P6系列处理器中,通过侦听功能,如果处理器A检测到另一个处理器打算写一块memory location,而这块memory location已经自己被cache了,侦听处理器A就会invalidate自己的cache line,强制让自己在下一次访问相同的memory location时执行cache line fill的操作(从system memory来获取最新的数据)。

    从P6系列处理器开始,如果一个处理器A检测到另一个处理器正在尝试访问一块memory location,而这块memory location已经在自己的cache中修改,但尚未写回到system memory,那么侦听处理器A将向其他处理器发出HITM#信号(Hold In Transaction Mode),这个信号告诉另一个处理器该cache line处于modify状态。

    在这种情况下,具有有效修改数据的处理器可能会直接将此数据传递给其他处理器,而不立即将其写回system memory中。负责管理系统内存的memroy controller监视此操作,以确保系统内存最终得到最新的数据。因此,即使数据可能在处理器之间共享而不立即写回内存,内存控制器也确保系统内存最终反映出最新的数据。。

    也就说,任何一个处理器别想偷偷干坏事(让自己的internal cache和其他处理的internal cache不一致),其他处理器一直在偷偷看着呢。

3、memory type(cache type)

    前面说了那么多,就是为了引出cache type(memory type),Intel 64和IA-32架构定义下面的memory type。

    对WC类型的memory的写操作可能会delay并被combine在write combing buffer中,因此来减少memory access。如果WC buffer只是部分填充,write会被delay直到下一个串行事件发生,比如SFENCE或者MFENCE指令,CPUID或者其他串行指令,read或者write uncached memory,中断产生,或者执行LOCK指令。

    WC 类型的cache-control非常适合video frame buffer,因为写order不重要。只要写入操作更新了内存,显示内容能够正确地显示在屏幕上即可。换句话说,即使写入操作的顺序不同,只要最终的内存状态能够正确反映出视频内容,就可以保证画面的正常显示。

4、Write combining buffer

    往WC memory的写的数据会被保存在internal write combining buffer,这个buffer和L1/L2/L3 cache是不同的(见前面的Figure 7-1. Processor and Memory System)。WC buffer没有snoop功能,因此,不能提供数据一致性。

    WC缓冲区的大小和结构在本架构文档上没有定义(也就说是vendor specific的)。对于Intel Core 2 Duo、Intel Atom、Intel Core Duo、Pentium M、Pentium 4和Intel Xeon处理器,WC缓冲区由若干个64字节的WC缓冲区组成。对于P6系列处理器,WC缓冲区由若干个32字节的WC缓冲区组成

    当软件开始向WC内存写入数据时,处理器就开始逐个填充WC缓冲区当一个或多个WC缓冲区被填满后,处理器可以选择将数据从write combining buffer evict到system memory。WC缓冲区evict协议取决于厂商具体的实现,软件不能依赖此协议来确保系统内存的一致性。使用WC内存类型时,软件必须要注意:数据延迟写入系统内存,并在需要系统内存一致性时,需要软件主动清空WC缓冲区

    一旦处理器开始从WC缓冲区将数据evict到系统内存,它将基于缓冲区中包含的有效数据量做bus-transaction style的决策。如果缓冲区已满(例如,所有字节都是有效的),处理器将在总线上执行一个burst-write transaction。一个burst-write transaction会有32字节(P6系列处理器)64字节(奔腾4及更高版本处理器)的数据会传输到data bus上。如果WC缓冲区的数据有一个或多个字节是无效的(例如,尚未被软件写入),处理器将使用“partial”transaction将数据传输到内存(一次一个chunk,其中一个“chunk”是8字节)。

    “partial”transaction将导致将WC缓冲区中的数据发送到内存时最多进行4个(32/8)“partial”transaction(对于P6系列处理器)或8个(64/8)“partial”transaction(对于奔腾4及更高版本处理器)。

    WC内存类型在定义上是weakly order的。一旦开始evict WC缓冲区中的数据,数据就受到weakly order的影响。在连续分配/释放WC缓冲区时不会保持顺序(例如,对WC缓冲区1的写入后,然后对WC缓冲区2的写入,可能在系统总线上看起来是缓冲区2先于缓冲区1)。使用partial write把数据从WC缓冲区中evict到system memory时,连续部分写之间也没有保证的顺序(例如,chunk 2的partial write可能在总线上先于chunk 1的partial write,反之亦然)。

三、Linux中Write combine相关函数

1、使能PAT的debug打印

    关于pat的介绍可以参考

13. PAT (Page Attribute Table) — The Linux Kernel documentation

    在cmdline增加debugpat就可以让dprintk打印

    下面的打印就是我们cmdline增加debugpat,然后调用对应的API接口时,OS的打印:

[28168.324996] x86/PAT: memtype_reserve added [mem 0x6000000000-0x67ffffffff], track write-combining, req write-combining, ret write-combining

[28168.325001] mtgpu 0000:01:00.0: Enable mtrr success,base:0x6000000000,size:0x800000000, mtrr 0.

[28168.325006] x86/PAT: Overlap at 0xa4a00000-0xa4a48000

[28168.325009] x86/PAT: memtype_reserve added [mem 0xa4000000-0xa5ffffff], track uncached-minus, req uncached-minus, ret uncached-minus

[28168.325021] mtgpu 0000:01:00.0: PCIe BAR0 map start:0xa4000000 size:0x2000000, virtal addr:00000000d90d9aa4 (attribution: UC)

[28168.325028] x86/PAT: Overlap at 0x6000000000-0x6800000000

[28168.325030] x86/PAT: memtype_reserve added [mem 0x6000000000-0x67ffffffff], track write-combining, req write-combining, ret write-combining

[28168.325038] mtgpu 0000:01:00.0: PCIe BAR2 map start:0x6000000000 size:0x800000000, virtal addr:00000000542d4401 (attribution: WC)

2、debugFS中PAT

    cat /sys/kernel/debug/x86/pat_memtype_list,在我们drv中调用对应API后,debugFS会显示对应的page attribute。

    Linux 代码中的实现如下:

 3、API接口

3.1 arch_io_reserve_memtype_wc

4.9.0增加了arch_io_reserve_memtype_wc

[PATCH 1/2] x86/io: add interface to reserve io memtype for a resource range. - Dave Airlie

memtype.c - arch/x86/mm/pat/memtype.c - Linux source code (v5.15) - Bootlin

3.2 memtype_reserve_io

arch_io_reserve_memtype_wc->memtype_reserve_io

memtype.c - arch/x86/mm/pat/memtype.c - Linux source code (v5.15) - Bootlin

3.3 memtype_reserve

arch_io_reserve_memtype_wc->memtype_reserve_io->memtype_reserve

memtype.c - arch/x86/mm/pat/memtype.c - Linux source code (v5.15) - Bootlin

    memtype_reserve是API调用栈的核心代码,主要实现下面功能

(1)memtype_reserve->pat_x_mttr_type来获取actual_type,

(2)然后memtype_reserve->pat_pagerange_is_ram来检查start和end是否不是RAM

./kprobe 'r:myopen pat_pagerange_is_ram $retval'

    使用kprobe查看pat_pagerange_is_ram的返回值,当传入的start和end是MMIO地址的话,pat_pagerange_is_ram返回是的0。

(3)申请一个entry_new,memtype_reserve->memtype_check_insert,把新的entry插入到memtype_rbroot

./kprobe 'r:myopen pat_pagerange_is_ram $retval'

3.4 memtype_check_insert

arch_io_reserve_memtype_wc->memtype_reserve_io->memtype_reserve->memtype_check_insert

memtype_interval.c - arch/x86/mm/pat/memtype_interval.c - Linux source code (v5.15) - Bootlin

3.5、哪些接口会调用memtype_check_insert

./kprobe -s 'p:myprobe memtype_check_insert'

可以看到涉及到使用MMIO的下面接口都会调用memtype_check_insert

3.6、ioremap和ioremap_wc区别

ioremap.c - arch/x86/mm/ioremap.c - Linux source code (v5.15) - Bootlin

    ioremap和ioremap_wc区别就是传入的page attribute不一样。最终还是会调用memtype_check_insert把对应的entry放到memtype_rbroot。

3.7 arch_phys_wc_add

linux kernel 3.11.0增加了arch_phys_wc_add

如果pat_enable已经enable或者mtrr_enable没有enable,arch_phys_wc_add直接返回了。

四、开启write combine后访问MMIO提升的原因

    回到我们最初的问题,使用memcpy 把32M数据从system main memory拷贝的到GDDR,开启write combine后,CPU写的性能提供了13.3倍。这是怎么做到的呢?在回答这个问题前,我们先看看两种场景下PCIe trace的差异。

1、disable write combine时PCIe trace

    我们从PCIe trace上看到第一笔写到最后一笔写,耗时是90753us,和测试代码抓到的耗时(90707us)一致。

    分析trace可以发现,disable write combine时,所有写请求都是32byte的,32M的数据需要32M/32= 1,048,576笔操作。

    这里为啥每一笔写请求都是32byte,而不是4byte的,和glibc对于memcpy的实现有关系,这里不展开说明,有兴趣的看glibc的memcpy作者马凌的回答。

https://www.zhihu.com/question/35172305

    随机找了两笔相邻的请求,时间间隔93ns,看了一下统计基本上在80-100ns之间,个别可能超过100ns。1,048,576笔传输,耗时90753us,每传输32Byte耗时90753us/1,048,576=86.5ns,每传输64Byte需要耗时173ns。

2、enable write combine时PCIe trace

    我们从PCIe trace上看到第一笔写到最后一笔写,耗时是6836us,和测试代码抓到的耗时(6837us)一致。

    分析trace可以发现,disable write combine时,所有写请求都是64byte的(和前面intel architecture介绍的WC buffer是64Byte是吻合的),32M的数据需要32M/64= 524,288笔操作。

    随机找了两笔相邻的请求,时间间隔8ns,看了一下统计差异比较大,大部分都在10~20ns之间。524,288笔传输,耗时6837us,每传输64Byte耗时6837us/524,288= 13ns,数据是吻合的。

    猜测每次时间间隔比较大的时候,都是处理器在fill WC buffer的时候(只是猜测,没有datasheet没法证明),只是这种猜测符合WC memory delay and combine的设计。


总结

    使用memcpy 把32M数据从system的main memory拷贝的到GDDR,开启write combine后,CPU写的性能提供了13.3倍,主要原因不是写的transaction的combine(transaction数量只少了一半),而在于数据先处理器被从main memory预取到write combine buffer,然后从write combine buffer使用burst 传输方式推送system bus提供传输效率,这个时间(10多ns)比从main memory的时间短的多(100多ns)。

     上图中architecture中的这两段话值得多读几遍,这是为什么write combine可以提高CPU写的原因所在。

    手上没有11th Gen Intel(R) Core(TM) i7-11700 @ 2.50GHz的资料,只有一个skylake的资料,看到从main memory读大概需要167*0.5(2GHz)需要83ns,考虑到server级别的CPU,而11th Gen Intel(R) Core(TM) i7-11700 @ 2.50GHz是消费级别的CPU,会被skylake弱一些,我们抓的数据是符合预期的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1799266.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何有效提问?

有效提问:正确地向别人提问是一种艺术,可以帮助你获得清晰、有用的答案。 明确表达问题:确保你的问题清晰明了,避免含糊不清或模棱两可的语言。这可以帮助对方更好地理解你的问题,并给出准确的答复。 尊重对方&#x…

[第五空间 2021]WebFTP、[HCTF 2018]Warmup

目录 [第五空间 2021]WebFTP ​[SWPUCTF 2021 新生赛]Do_you_know_http [NCTF 2018]签到题 [HNCTF 2022 Week1]What is Web [HNCTF 2022 Week1]Interesting_http [HCTF 2018]Warmup [第五空间 2021]WebFTP 使用dirsearch扫描,发现有git泄露 使用GitHack克隆目…

HBuilderX编写APP一、获取token

一、新建项目 二、从onenet获取key.js 1、下载之后的压缩包,解压 2、关键就是找到key.js 3、将这个key.js复制到刚才的目录下面去 4、这个key.js文件就是生成token的代码 5、只要调用createCommonToken(params)这个函数,就可以实现生成token了 其中on…

小米开放式耳机怎么样?倍思、西圣、小米开放式耳机测评比较!

作为一名热衷于分享真实体验的博主,我在过去两年开始接触开放式耳机,并因此受到许多朋友的咨询,询问哪款开放式耳机更加出色。为了找出最佳的开放式耳机,我进行了深入的调查和实地测试。我发现高价并不总是代表高质量,…

【全开源】Java共享茶室棋牌室无人系统支持微信小程序+微信公众号

打造智能化休闲新体验 一、引言:智能化休闲时代的来临 随着科技的飞速发展,智能化、无人化服务逐渐渗透到我们生活的各个领域。在休闲娱乐行业,共享茶室棋牌室无人系统源码的出现,不仅革新了传统的休闲方式,更为消费…

嵌入式移植jpeglib--Linux交叉编译ARM平台

一 、交叉编译jpeg库 1.下载源码tar.gz 2. 源码目录下执行 jpeglib配置文件 ./configure CCarm-none-linux-gnueabihf-gcc LDarm-none-linux-gnueabihf-ld --prefix/work/jpeg_arm_lib --exec-prefix/work/jpeg_arm_lib --enable-shared --enable-static --hostarm-none-linu…

高考试卷押运车视频监控解决方案

一、引言 高考作为我国教育领域的重要事件,其公正、公平和安全性一直备受社会关注。试卷押运作为高考的重要环节,其安全性直接关系到高考的顺利进行和考生的切身利益。因此,对高考试卷押运车实施视频监控解决方案,对于确保试卷安…

Asp .Net Core 系列:详解鉴权(身份验证)以及实现 Cookie、JWT、自定义三种鉴权 (含源码解析)

什么是鉴权(身份验证)? https://learn.microsoft.com/zh-cn/aspnet/core/security/authentication/?viewaspnetcore-8.0 定义 鉴权,又称身份验证,是确定用户身份的过程。它验证用户提供的凭据(如用户名和…

短视频直播教学课程小程序的作用是什么

只要短视频/直播做的好,营收通常都不在话下,近些年,线上自媒体行业热度非常高,每条细分赛道都有着博主/账号,其各种优势条件下也吸引着其他普通人冲入。 然无论老玩家还是新玩家,面对平台不断变化的规则和…

【第四节】C/C++数据结构之树与二叉树

目录 一、基本概念与术语 二、树的ADT 三、二叉树的定义和术语 四、平衡二叉树 4.1 解释 4.2 相关经典操作 4.3 代码展示 一、基本概念与术语 树(Tree)是由一个或多个结点组成的有限集合T。其中: 1 有一个特定的结点,称为该树的根(root)结点; 2 …

python-df的合并与Matplotlib绘图

1 数据连接 concat merge join (append 作为了解) append 竖直方向追加, 在最新的pandas版本中已经被删除掉了, 这里推荐使用concat 1.1 pd.concat 两张表, 通过行名、列名对齐进行连接 import pandas as pd df1 …

Linux网络编程——概念及实现双方聊天

网络编程的场景: 假设你面前有五座房子(服务器),你要走到其中一座房子的某一间,此时你站在五座房子面前很迷茫,突然,第二座房子上面有人在叫,并且用汉语(TCP/UDP&#xf…

从零开始:疾控中心实验室装修攻略,让你的实验室一步到位!

在当今充满挑战和变化的世界中,疾病的控制和预防成为了人类生存与发展的重要课题。而疾控中心作为防控疾病的核心机构,其疾控中心实验室设计建设显得尤为重要。下面广州实验室装修公司小编将分享疾控中心实验室设计建设方案,为疾病防控工作提…

SpringMVC日期格式处理 分页条件查询

实现日期格式处理: springmvc能实现String类型和基本数据类型及包装类的自动格式转换,但是不能识别String和 日期类格式的自动转换。 实现方式: 1是在实体类上加上注解DateTimeFormat,识别String格式为“yyyy-MM-dd” 2使用自定义…

计网期末复习指南(六):应用层(DNS、FTP、URL、HTTP、SMTP、POP3)

前言:本系列文章旨在通过TCP/IP协议簇自下而上的梳理大致的知识点,从计算机网络体系结构出发到应用层,每一个协议层通过一篇文章进行总结,本系列正在持续更新中... 计网期末复习指南(一):计算…

【玩转C语言】第二讲--->数据类型和变量

🔥博客主页🔥:【 坊钰_CSDN博客 】 欢迎各位点赞👍评论✍收藏⭐ 引言: 大家好,我是坊钰,为了让大家深入了解C语言,我开创了【玩转C语言系列】,将为大家介绍C语言相关知识…

centos7环境下安装wine,运行.exe可执行程序

centos7环境下安装wine,运行.exe可执行程序 步骤一:先安装两个扩展 (1) yum groupinstall ‘Development Tools‘ (2) yum install libX11-devel freetype-devel zlib-devel libxcb-devel 步骤二: 命令行…

ADASIS V2 协议-1

ADAS V2协议-1 1 简介2 版本控制3 ADASIS v23.1 ADASIS v2 Horizon (地平线)3.2 ADASIS v2的构建3.3 ADASIS v2 Horizon Provider (ADAS V2地平线提供者)3.4 paths and offsets (路径和偏移量)3.5 Path Pro…

【设计模式深度剖析】【1】【行为型】【模板方法模式】| 以烹饪过程为例加深理解

👈️上一篇:结构型设计模式对比 | 下一篇:命令模式👉️ 设计模式-专栏👈️ 文章目录 模板方法模式定义英文原话直译如何理解呢? 2个角色类图代码示例 应用优点缺点使用场景 示例解析:以烹饪过程为例类图代码示例…

国自然基金的检索

(1)网址 跳转国自然基金网址:https://www.nsfc.gov.cn/ (2)查询入口 (3)进行查询