【96】write combine机制介绍


前言

这篇文章主要介绍了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弱一些,我们抓的数据是符合预期的。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Towards Graph Contrastive Learning: A Survey and Beyond

目录 Towards Graph Contrastive Learning- A Survey and Beyond摘要IntroductionPRELIMINARY符号说明GNN对比学习下游任务 GCL自监督学习增强策略基于规则随机扰动或mask子图采样图扩散 基于学习图结构学习图对抗训练图合理化 对比模式同尺度对比全局上下文局部 跨尺度对比局部…

构建体育直播平台源码:深度解析数据分析模块的核心展示内容

在现代的体育直播平台中,数据分析展示已经成为不可或缺的一部分。如下参考借助“东莞梦幻网络科技”提供的体育直播源码,打造的平台,并通过表格形式为用户列出以下数据分析内容: 1、积分排名:反映了各支队伍在赛季中的…

HIK录像机GB28181对接相机不在线问题随笔

一、问题现象 【设备信息】型号:DS-8664N-I16-V3 V4.63.000 build 230412 【问题现象】HIK录像机使用GB28181对接异常相机无法正常上线,对接HIK相机可以正常上线。 【现场拓扑】现场拓扑如下 NVR侧使用固定公网IP地址。IPC侧使用家用宽带的方式&…

玩转ChatGPT:最全学术论文提示词分享【上】

学境思源,一键生成论文初稿: AcademicIdeas - 学境思源AI论文写作 在当今数字时代,人工智能(AI)技术正迅速改变各行各业的运作方式。特别是,OpenAI的ChatGPT等语言模型以其强大的文本生成能力,…

从零开始实现自己的串口调试助手(8)-循环发送

循环发送 准备 创建槽函数 设置QSpinBox的最大值 注意: // 我们不能在qt的ui线程中延时,否则将导致页面刷新问题 //QThread::msleep(ui->spinBox->text().toInt());//设置下次发送时间间隔 定时器实现 关联信号与槽: //添加自动换行定…

C++学习/复习13--list概述

一、list概念 1.带头双向链表 2.构造函数 3.迭代器(其迭代器需尤其注意) 4、size 5.front/back 6.插入删除 删除时的迭代器失效 由于list的节点特殊,既有数据又有指针,其实现需要节点/迭代器/list各成一类再组合

UI框架与MVC模式详解(1)——逻辑与数据分离

【效率最高的耦合方式】 以实际的例子来说明,更容易理解些。 这里从上到下,从左到右共有8个显示项,如果只需要显示这8个,不会做任何改变,数据固定,那么我们只需要最常规的思路去写就好,这是最…

【小海实习日记】Git使用规范

1.Git使用流程 1.1 从master分支拉一个分支,命名要符合规范且清晰。 1.2 commit到本地,push 到远端。 1.3 在Gitlab创建MR,选择develp分支。 1.4 如果要修改的话,先把Gitlab上的MR修改为Draft(修改态),然后在本地修改代…

SwiftUI获取用户的位置信息(CLLocationManager,CLLocationManagerDelegate)

本篇文章将会介绍一下在SwiftUI中如何通过CorLocation框架获取用户的位置信息,因为获取位置信息属于用户的隐私信息,所以需要在Info.plist文件里面加上访问位置权限的说明。 关于位置信息,可以请求两种级别的许可:always和when i…

图的创建和BFS,DFS遍历

图的创建 图是一种用于表示对象及其关系的抽象数据结构,由节点(也称为顶点)和连接节点的边组成。图可以分为有向图(Directed Graph)和无向图(Undirected Graph),以及加权图&…

Redis的事务与关系型数据库事务有何不同?

引言:关于 Redis 的事务很多人可能都是一知半解,大多数人只了解数据库的事务,并且是单体事务,对于 Redis 事务和常见关系型数据库的事务的区别还没有去了解过,本文就来详细进行介绍。 题目 Redis的事务与关系型数据库…

git【工具软件】分布式版本控制工具软件

一、Git 的介绍 git软件的作用:管理软件开发项目中的源代码文件。 常用功能: 仓库管理、文件管理、分支管理、标签管理、远程操作 功能指令: add,commit,log,branch,tag,remote…

UE5 Mod Support 思路——纯蓝图

原创作者:Chatouille 核心功能 “Get Blueprint Assets”节点,用于加载未来的mod。用基础类BP_Base扩展即可。打包成补丁,放到Content\Paks目录下,即可让游戏访问到内容。 与文中所写不同的地方 5.1或者5.2开始,打…

mysql optimizer_switch : 查询优化器优化策略深入解析

码到三十五 : 个人主页 在 MySQL 数据库中,查询优化器是一个至关重要的组件,它负责确定执行 SQL 查询的最有效方法。为了提供DBA和开发者更多的灵活性和控制权,MySQL 引入了 optimizer_switch 系统变量。这个强大的工具允许用户开…

自动驾驶仿真(高速道路)LaneKeeping

前言 A high-level decision agent trained by deep reinforcement learning (DRL) performs quantitative interpretation of behavioral planning performed in an autonomous driving (AD) highway simulation. The framework relies on the calculation of SHAP values an…

Go微服务: 基于使用场景理解分布式之二阶段提交

概述 二阶段提交(Two-Phase Commit,2PC)是一种分布式事务协议,用于在分布式系统中确保多个参与者的操作具有原子性即所有参与者要么全部提交事务,要么全部回滚事务,以维持数据的一致性它分为两个阶段进行&…

3038. 相同分数的最大操作数目 I

题目 给你一个整数数组 nums,如果 nums 至少包含 2 个元素,你可以执行以下操作: 选择 nums 中的前两个元素并将它们删除。一次操作的分数是被删除元素的和。 在确保所有操作分数相同的前提下,请你求出最多能进行多少次操作。 …

数字IC后端物理验证PV | TSMC 12nm Calibre Base Layer DRC案例解析

基于TSMC 12nm ARM A55 upf flow后端设计实现训练营将于6月中旬正式开班!小班教学!目前还有3个名额,招满为止!有需要可以私信小编 ic-backend2018报名。吾爱IC社区所有训练营课程均为直播课! 这个课程支持升级成双核A…

李廉洋:6.7黄金亚盘洗盘暴跌,美盘最新分析策略。

黄金消息面分析:美联储降息可能是经济出现麻烦的信号。自去年10月以来,美国股市一直在上涨,原因是尽管利率持续走高,但美国经济和企业盈利仍保持强劲。如果市场对2024年下半年降息的信心增强,那么硬着陆的可能性就会增…

python-df的合并与Matplotlib绘图

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