A. 我的电脑已启用dhcp,但网络诊断却显示 以太网未启用dhcp.所以连不上网,怎么办
DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)是一个雹余局域网的网源歼滚络协议,使用UDP协议工作改团, 主要有两个用途:给内部网络或网络服务供应商自动分配IP地址;给用户或者内部网络管理员作为对所有计算机作中央管理的手段。
解决方法如下:
1、按win+r,输入Services.msc;
B. 服务器DPDK l3fwd性能测试
由于项目中需要用到dpdk,当时在服务器平台选型上有如下2种不同配置旅氏可供选择,为了理解老的Xeon处理器和Xeon金牌处理器对DPDK转发性能的影响,需要在两台服务器上分别进行DPDK l3fwd性能转发测试。
采用如下拓扑进行测试,测试仪的4个10GE端口连接X710-DA4的4个接口,测试时测试仪的4个端口同时打流,经过服务器DPDK转发后分别从X710-DA4网卡的不同接口送出,在测试仪的4个端口查看是否有丢包。在无丢包的情况下测试仪端口打流的最大速率即为服务器端DPDK能够提供的最大转发能力,以MPPS为单位。
(1) 在服务器上运行dpdk
./examples/l3fwd/x86_64-native-linux-gcc/l3fwd -l 4,6,8,10 -n 4 -w 0000:04:00.0 -w 0000:04:00.1 -w 0000:04:00.2 -w 0000:04:00.3 -- -p 0xf --config="(0,0,2),(1,0,4),(2,0,6),(3,0,8)"
运行l3fwd前有一些准备工作:
上述是DPDK官方的性能测试报告中建议的BIOS配置,在实际测试用我没有修改CPU C-state和P-state,并关闭了超线程州告的功能。
也可以通过 cat /sys/class/net/p6p1/device/numa_node 查看
在上述操作完成后便可以知道dpdk运行时应该设置参数。
(2)测试仪打流
在l3fwd运行起来后,会添加192.18.0.0/24、192.18.1.0/24、192.18.2.0/24、192.18.3.0/24四个网段的路由,因此在测试拆迹散仪端4个端口设置流的时候需要将流的目的IP地址分别设置为上述4个网段的地址,流的目的MAC地址设置为对应接口的MAC地址。
上述的DUT2对应Server01,DUT3对应Server02,DUT1的性能数据和配置是从DPDK的性能测试报告中拿到的。DUT1、DUT2和DUT3的配置对比如下。
从测试结果可以看出,DUT3上运行DPDK就能够实现64字节数据包的线速转发。对比DUT2和DUT3的转发性能可以看出,基于 Xeon Gold 5118处理器的平台相比老的Xeon处理器平台,转发性能是有一定提升的。
当然,从我个人的理解来看,现在的转发测试只是测4条路由表的情况,路由表均能够存放到处理器的一级cache中,没有大规模内存访问的压力。如果有大规模的路由表或者服务器上多个网卡同时收发数据,并且涉及到跨网卡之间的数据包转发,当前的服务器能否实现性能的线性扩展还需要后面进一步测试。
C. 配置了dpdk,怎么查看
需要自己dpdk接口,自己开发
D. Hugepagesize相关配置(Linux | DPDK)
使用 cat /proc/meminfo | grep Huge 查看当前配置的Hugepagesize大小与数目
以下为临肆枣数时配置2M*1024大页内存的方式:
配置完成之后可以使用 cat /proc/meminfo 查看是否成功。
然后将hugepages中的内存给DPDK使用:
修改裂首/etc/default/grub 中的 GRUB_CMDLINE_LINUX,然后运行 grub 更新并重启系统:
在GRUB_CMDLINE_LINUX配置中添加以下内容
更新grub
重启系统
查看
注意:重启之后需要再重新加载UIO驱动以及绑定网卡岩毕
E. 计算机网络之DPDK(四)skeleton程序
姓名:周肇星;学号:22011110028;学院:通信工程学院
【嵌牛导读】DPDK是INTEL公司开发的一款高性能的网络驱动组件,旨在为数据面数行应用程序提供一个简单方便的,完整的,快速的数据包处理解决方案,主要技术有用户态、轮询取代中断、零拷贝、网卡RSS、访存DirectIO等
【嵌牛鼻子】计算机网络,高性能网络,DPDK
【嵌牛提问】读完本文,对DPDK技术的skeleton程序有所认识了吗?
【嵌牛正文】
在rte_mempool_create创建内存池时,还会创建一个ring,这个ring队列用来管理内存池中的每个对象元素的:记录内存池中哪些对象使用了,哪些对象没有被使用
当初始化好一个对象元素后,会将这个对象元素放到这个ring队列中,在所有元素都初始化完成后,此时ring队列存放了内存池上所有的对象元素
需要注意的是ring队列存放的是对薯察哗象元素的指针而已,而不是对象元素本身的拷贝
本地缓存策略:mempool的对象存放在rte_ring中,当mempool所在NUMA节点上的多个lcore都需要通过这个ring来访问内存对象时,CAS(compare-and-set)操作会影响效率。为了解决这个问题,mempool为每个lcore维护了一个本地缓存(local cache),lcore需要取出对象时,优先在这个cache取,如果不够,再从ring上拿
DPDK为多核设计,但skeleton为单核实例,设计初衷是实现一个最简单的报文收发示例,程序可用于平台的单核报文出入性能测试。对收入报文不做任何处理直接发送,是基础的二层转发工具:将偶数个网口进行配对,从0接收到的包转发到1口中,从1接收到的包转发到0口中,以此类推
入口main函数调用rte_eal_init初始化运行环境,检查网络接口数,据此调用rte_pktmbuf_pool_create分配内存池,随后调用没烂port_init初始化网卡并配置,最后调用lcore_main进行主处理流程
对指定端口设置队列数,在本程序示例中,只指定单队列。随后,在收发两个方向上,基于端口与队列进行配置设置,缓冲区进行关联设置
F. DPDK PKTGEN使用
PKTGEN有两种形式,一种是直接由linux系统自带的内核模块进行发包(也就是略过协议栈,直接控制发包),另一种是依赖于dpdk的pktgen也就是本文主要讲的,需要进行稍微复杂的编译
modprobe pktgen
在/proc/net/pktgen看到以下文件:
kpktgend_0 kpktgend_1 kpktgend_2 kpktgend_3 pgctrl
其中kpktgen_*的多少是根据你的CPU的个数决定的,如我的机子的CPU数目为4,则有四个此文件皮宴。
通卜迹过命令cat /proc/net/pktgen/pgctrl可以型握并查看pktgen的版本等信息:
注:也有使用insmod的,和modprobe的区别是:比如需要安装b模块,但是b依赖于a模块,因此使用insmod安装就需要先安装a模块再安装b模块;如果使用modprobe的话,就可以直接安装b模块,默认将安装a模块
基本上设置完成后就可以进行测试,要查看是否有流量,可以使用ifstat,tcpmp工具查看,使用应用层的抓包工具是无法看到的
关键参数介绍
参数中,最复杂的是 -m <string>
-m <string> 配置端口到逻辑核的映射关系,使用类似BNF类语法.映射的逻辑核要与 [EAL options]中的逻辑核要一致。
运行命令 ./app/x86_64-native-linuxapp-gcc/pktgen -l 0-2 -n 3 -- -P -m "[1].0, [2].1"
官方的default.cfg内容如下:
需要修改的地方有三处:
修改完后即可执行。
图中port1和port2已经有明显区别,收包数相差100个包
用pkggen再发1000个包
G. 如何查看pktgen-dpdk发送的包
dpdk就是运行于通用linux+x86系统上的,具有intel核心的网卡即可。dpdk的特点有:Dpdk驱动拿数据,绕过内核,跑在用户态,避免核心态带大到用户态的拷贝巧败,即UIO利用cpu亲和性,线蠢宽竖程绑定核,避免线程核间切换开销使用大页缓存提高内存访问效率
H. DPDK QoS 框架 - 3. 分级调度模块的实现
下图展示了内部数据结构的细节。
在不同的CPU核上处理同一个发送端口的入队/出队操作可能会对调度器的性能造成重大影响,因此不建议这样做。
端口入队/出队操作需要共享对以下数据结构的访问:
以下操作山虚正会造成预期的性能下降:
因此,调度程序的入队和出队操作必须在同一个线程中运行,从而允许队列和Bitmap操作可以是非线程安全的,并保持调度程序的数据结构在同一个CPU核内部。 尽量将数据结构局部化,避免跨线程共享。
增加NIC端口的数量仅仅需要按比例增加用于流量调度的CPU核的数量。
包处理步骤如下:
需要注意的是,这些步骤之间有很强的依赖关系,在步骤1和步骤2的结果可用之前,步骤2和步骤3不能启动,因此没法利用处理器乱序执行引擎提供的任何性能优化。
当有大量的数据包和队列需要处理时,很有可能处理当前包所需要的数据结构不在L1和L2缓存中,因此上述3个步骤对内存的访问结果会造成L1/L2 cache miss。考虑到性能因素,每个数据包都造成3次L1/L2 cache miss是不可接受的。
解决方案是提前预取需要的数据结构。预取操作有执行延迟,在此期间处理器不应该尝试访问当前正在预取的数据结构,因此处理器应该执行其他工作。唯一可做的其他工作是对其他输入包执行入队操作流程的不同步骤,从而以流水线的方式处理入队操作。
图逗悔2演示了入队操作的流水线实现,其中有4个流水线阶段,每个阶段处理2个不同的输入包。在给定的时间内,任何输入包都不能成为多个流水线阶段的一部分。
上面描述了非常基本的入队流水线拥塞管理方案:将数据包塞入队列,当队列被填满时,所有到达同一队列的数据包将被丢弃,直到有数据包通过出队操作被消费掉,才可以在队列中塞入新的数据包。如果用RED/WRED改进入队流水线,就可以通过查看队列占用率和包的优先级,为特定的包做出入队/丢弃决策(而不是不加选择地将所有包入队或者丢弃)。
在当前管道调度处理下一个包的步骤为:
以上操作涉及到的数据结构(pipe, queue, queue array, mbufs)可以在被访问之前预取进缓存,从而避免cache miss。在对当前管道(管道A)的数据发出预取操作后,可以立即切换到另一个管道(管道B)进行处理,等到管道A的预取操作完成,再切换回去,从而利用预取本身的时延同步处理多个管道的数据。
出队状态机利用处理器缓存机制,尽可能同时处理多个活跃管道,从而发送更多的数据包。
输出端口就是一个被调度器不断的用待传输数据填充的队列。对于10 GbE,每秒有12.5亿个字节需要被端口调度器填充。如果调度器的速度不够快,不能填满队列(假设有足够的待传输数据包和credit),那么必然有一些带宽会被闲置,从而产生浪费。
原则上,分层调度器出队操作应该由网卡发送器触发。通常情况下,一旦网卡发送队列的输入流量低于一个预定义的阈值,端口调度程序将被唤醒(基于中断或轮询的方式,通过持续监控队列占用决定是否被唤醒),填充更多的数据包进入队列。
调度器需要跟踪随着时间推移而变化的credit信息,这需要基于时间进行credit的更新(例如,子端口和管道流量整形、流量组上限的强制执行,等等)。
每次调度器决定向网卡发送器传递数据包时,调度器将相应地调整其内部时间信息。因为在物理接口上每发送一个字节所需的时间是固定的,所以可以以字节为单位作为内部时间的参考值,这样处理起来也会比较方便。当一个包准备传输时,时间以(n + h)的形式递增,其中n是以字节为单位的包长度,h是每个包的帧数据字节数(包括帧头、CRC等)。
调度器需要将其内部时间参考值与端口速率对齐,从而确保调度器不会填充超过网卡发送速率的数据,从而防止由于网卡发生队列已满而发誉桥生的丢包。
调度器需要读取每次出队调用的当前时间。CPU时间戳可以通过读取TSC寄存器(Time Stamp Counter)或HPET寄存器(High Precision Event Timer)来获得。当前CPU时间戳需要通过以下公式将CPU时钟转换为字节数:time_bytes = time_cycles / cycles_per_byte, cycles_per_byte是传输一个字节所消耗的CPU周期(例如,10GbE的端口以2GHz的CPU频率传输数据,cycles_per_byte = 2G/(10G/8) = 1.6)。
调度器会维护针对网卡时间的内部时间引用,网卡时间将随着被调度的数据包的长度(包含帧开销)的增加而增加。在每次出队调用时,调度程序会根据当前时间检查其对网卡时间的内部引用:
调度器往返延迟(SRTD,Scheler Round Trip Delay)是调度器连续两次检查同一管道之间的时间(以CPU周期为单位)。
为了跟上发送端口的速率(即避免网卡带宽的浪费),调度器应该能够比网卡发送器实际传输速度更快地调度数据包。
假设没有发生端口带宽超卖,调度器需要根据配置的令牌桶,跟踪每个管道的速率。这意味着管道的令牌桶的大小应该设置得足够高,以防止它因较大的SRTD而溢出,从而导致管道的可用带宽损失。
当以下所有条件都满足时,调度器可以为(子端口S、管道P、流量组TC、队列Q)做出发送下一个包的合理调度决策:
如果以上条件都满足,则可以选择一个数据包进行传输,并从子端口S、子端口S的流量组TC、管道P、管道P的流量组TC中减去必要的credit。
由于所有数据包长度的最大公约数是一个字节,因此以字节作为credit的计量单位。传输n字节的数据包所需的credit数等于(n+h),其中h等于每个数据包的帧开销(以字节为单位)。
子端口和管道的流量整形是通过令牌桶来实现的,每个令牌桶使用一个饱和计数器(saturated counter)来实现,通过这个计数器跟踪credit的数值。
令牌桶泛型参数和操作如下表所示:
为了实现上面描述的令牌桶通用操作,当前设计使用下表中给出的持久数据结构:
可以用以下公式计算桶速率(单位为字节/秒):
式中,r = 端口线速(单位为字节/秒)。
令牌桶操作的实现如下表所示:
同一管道内TC的优先级是严格定义的,其调度是由管道出队状态机实现的,该状态机按照优先级升序排列选择队列。因此,队列0(与TC 0相关,优先级最高的TC)在队列1(优先级低于TC 0的TC 1)之前被处理,队列1在队列2(优先级低于TC 1的TC 2)之前被处理,并继续下去,直到除最低优先级TC以外的所有TC队列都被处理。最后,队列12-15(尽力而为TC, 最低优先级TC)被处理。
管道和子端口级别的TC不支持流量整形(traffic shaping),所以在这两个级别的上下文里没有维护令牌桶。管道和子端口级别的TC上限被强制限定为周期性回填的credit,每次在管道/子端口级别处理包的时候,credit就会被消费掉,如下两表所示。
子端口/管道TC强制上限的持久化数据结构:
最低优先级TC(尽力而为TC,best effort TC)的WRR设计方案从简单到复杂的演变如下表所示。
子端口流量组X的超售是一个配置问题,当子端口的成员管道为流量组X分配的带宽大于在上层子端口级别为同一流量组分配的带宽时发生。
特定子端口和流量组的超售完全是管道和子端口级配置的结果,而不是由于运行时流量负载的动态演化(如拥塞)造成的。
如果当前子端口对流量组X的总体需求较低,超售的存在并不代表问题,因为所有成员管道对流量组X的需求已经完全可以满足。然而,当所有子端口的成员管道的流量组X的需求合在一起超过了在子端口级别配置的限制时,这将不再能够实现。
下表总结了处理这个问题的一些可能的方案,当前实现是基于第三种方案。
通常,子端口TC超售只对最低优先级的流量组启用,这通常用于尽力而为(best effort)的流量,管理平面需要防止其他(更高优先级)的TC发生这种情况。
为了便于实现,还假设子端口的最低优先级TC的上限设置为子端口速率的100%,并且对于所有子端口的成员管道,管道最低优先级TC的上限设置为管道速率的100%。
该算法会先计算一个容量(watermark),容量会根据子端口的成员管道当前的需求定期更新,其目的是限制每个管道允许发送的最低优先级(best effort)TC的流量。在每个TC上限计算周期开始时,在子端口级别上计算该容量,并在当前实施周期内在所有子端口的成员管道上使用相同的容量值。下面说明在每个周期开始时作为子端口级别计算的容量如何传播到所有子端口的成员管道的。
当前计算周期开始(和上一个计算周期结束的时间相同)时,容量值需要基于上一周期开始时分配给尽力而为TC但没有被子端口的成员管道消费掉的带宽值做出调整。
如果子端口有尽力而为TC带宽没用掉,就增加当前时段的容量值,以鼓励子端口的成员管道消耗更多带宽。否则,降低容量值,以强制子端口成员管道的尽力而为TC带宽的消耗相等。
容量值的增加或减少会以很小的增量进行,因此可能需要几个执行周期才能达到平衡状态。由于子端口成员管道对尽力而为TC的需求的变化,这种状态可以在任何时候发生改变,例如,由于需求增加(当需要降低容量值时)或需求减少(当可以增加容量值时)。
在需求较低时,为防止子端口成员管道占用太多带宽,需要设置高容量值。容量的最高值被选为子端口成员管道配置的最高速率。下表说明了容量操作。
每个TC流量限制执行周期开始时,从子端口级别到成员管道的容量传递:
容量值计算:
为了调度一个报文,调度器必须在多个队列里查看报文和credit,当调度器需要查看的队列越多,其性能就越低。
调度器维护了活跃队列的Bitmap,从而可以直接跳过非活跃队列,但是为了检测特定的管道是否有足够的credit,必须使用管道发送状态机进行探测,无论最终调度结果如何(没有报文或者至少产生一个报文),总会消耗CPU时间。
这个场景强调了策略对调度器性能的重要性:如果管道没有足够的credit,其数据包应该尽快丢弃(在触发分层调度器之前),从而可以将管道队列标识为不活跃,发送端就可以跳过这个管道而不用消耗资源去查看管道credit。
端口调度器的性能针对大量队列进行了优化。但如果队列的数量很少,那么对于相同级别的活动流量,端口调度器的性能预期会比一小组消息传递队列的性能更差。
I. 吃鸡是一个吃内存还是cpu的
CPU是怎样访问内存的?简单的答案是,CPU执行一条访存指令,把读写请求发往内存管理单元。内存管理单元进行虚实转换,把命令发往总线。总线把命令传递给内存控制器,内存控制器再次翻译地址,对相应内存颗粒进行存取。之后,读取的数据写入确认按照原路返回。再复杂些,当中插入多级缓存,在每一层缓存都未命中的情况下,访问才会最终达到内存颗粒。
知道了完整的路径,开始研究每一步中的硬件到底是怎么样的,读写指令到底是怎样在其中传输的。要了解硬件,首先要说下处理器。处理器的基本结构并不复杂,一般分为取指令、译码、发射、执行、写回五个步骤。而我们说的访存,指的是访问数据,不是指令抓取。访问数据的指令在前三步没有什么特殊,在第四步,它会被发送到存取单元,等待完成。当指令在存取单元里的时候,产生了一些有趣的问题。
第一个问题,对于读指令,当处理器在等待数据从缓存或者内存返回的时候,它到底是什么状态?是等在那不动呢,还是继续执行别的指令?
一般来说,如果是乱序执行的处理器,那么可以执行后面的指令,如果是顺序执行,那么会进入停顿状态,直到读取的数据返回。当然,这也不是绝对的。在举反例之前,我们先要弄清什么是乱序执行。乱序执行是说,对于一串给定的指令,为了提高效率,处理器会找出非真正数据依赖的指令,让他们并行执行。但是,指令执行结果在写回到寄存器的时候,必须是顺序的。也就是说,哪怕是先被执行的指令,它的运算结果也是按照指令次序写回到最终的寄存器的。这个和很多程序员理解的乱序执行是有区别的。我发现有些人在调试软件问题的时候,会觉得使用了一个乱序的处理器,那么可能会使得后面的代码先被执行,从而让调试无法进行。
他们搞混了两个概念,就是访存次序和指令完成次序。对于普通的运算指令,他们仅仅在处理器内部执行,所以你看到的是写回次序。而对于访存指令,指令会产生读请求,并发送到处理器外部,你看到的次序是访存次序。对于乱序处理器,可能同时存在多个请求,而其次序,是打乱的,不按原指令顺序的。但是此时,这些被发送到外部的读请求,并没有拿到返回结果,指令也没有完成。所以,这并不违反乱序执行顺序完成的原则。如果有前后两条读指令,没有数据相关性,哪怕是后面那条读的数据先被返回,它的结果也不能先写回到最终的寄存器,而是必须等到前一条完成后才可以。
对于顺序执行的处理器,同样是两条读指令,一般必须等到前一条指令完成,才能执行第二条,所以在处理器外部看到的是按次序的访问。不过也有例外,比如读写同时存在的时候,由于读和写指令实际上走的是两条路径,所以可能会看到同时存在。
还有,顺序处理器上,哪怕是两条读指令,也有可能同时存在两个外部请求。比如Cortex-A7,对于连续的读指令,在前一条读未命中一级缓存,到下一级缓存或者内存抓取数据的时候,第二条读指令可以被执行。所以说,乱序和顺序并不直接影响指令执行次序。他们的区别在于,乱序需要额外的缓冲和逻辑块(称为重排序缓冲, re-order buffer)来计算和存储指令间的相关性以及执行状态,而顺序处理器没有重排序缓冲,或者非常简单。这些额外的面积可不小,据我所看到的,可以占到处理器核心的40%。它们所带来的更高的并行度,性能提升却未必有40%。因为我们写的单线程程序,由于存在很多数据相关,造成指令的并行是有限的,再大的重排序缓冲也解决不了真正的数据相关。所以对于功耗敏感的处理器还是使用顺序执行。
还有一点需要注意,顺序执行的处理器,在指令抓取,解码和发射阶段,两条或者多条指令,是可以同时进行的。比如,无依赖关系的读指令和运算指令,可以被同时发射到不同的执行单元,同时开始执行。但是完成还是按顺序的。
但是,在有些ARM处理器上,比如Cortex-A53,向量或者加解密指令是可以乱序完成的,这类运算的结果之间并没有数据依赖性。这点请千万注意。
再来看看写指令。写和读有个很大的不同,就是写指令不必等待数据写到缓存或者内存,就可以完成了。写出去的数据会到一个叫做store buffer的缓冲,它位于一级缓存之前,只要它没满,处理器就可以直接往下走,不必停止并等待。所以,对于连续的写指令,无论顺序还是乱序执行处理器,都可能看到多个写请求同时挂在处理器总线上。同时,由于处理器不必像读指令那样等待结果,就可以在单位时间内送出更多写请求,所以我们可以看到写带宽通常是大于读带宽的。
以上所说的读写访问都是在开启缓存的情况。
对于同时存在的多个请求,有一个名词来定义它,叫做outstanding transaction,简称OT。它和延迟一起,构成了我们对访存性能的描述。延迟这个概念,在不同领域有不同的定义。在网络上,网络延迟表示单个数据包从本地出发,经过交换和路由,到达对端,然后返回,当中所花的总时间。在处理器上,我们也可以说读写的延迟是指令发出,经过缓存,总线,内存控制器,内存颗粒,然后原路返回所花费的时间。但是,更多的时候,我们说的访存延迟是大量读写指令被执行后,统计出来的平均访问时间。这里面的区别是,当OT=1的时候,总延时是简单累加。当OT>1,由于同时存在两个访存并行,总时间通常少于累加时间,并且可以少很多。这时候得到的平均延迟,也被称作访存延迟,并且用得更普遍。再精确一些,由于多级流水线的存在,假设流水线每一个阶段都是一个时钟周期,那访问一级缓存的平均延迟其实就是一个周期.而对于后面的二级,三级缓存和内存,就读指令来说,延迟就是从指令被发射(注意,不是从取指)到最终数据返回的时间,因为处理器在执行阶段等待,流水线起不了作用。如果OT=2,那么时间可能缩短将近一半。OT>1的好处在这里就体现出来了。当然,这也是有代价的,存储未完成的读请求的状态需要额外的缓冲,而处理器可能也需要支持乱序执行,造成面积和功耗进一步上升。对于写指令,只要store buffer没满,还是一个时钟周期。当然,如果流水线上某个节拍大于一个时钟周期,那平均的延时就会取决于这个最慢的时间。在读取二级,三级缓存和内存的时候,我们可以把等待返回看作一个节拍,那么就能很自然的理解此时的延迟了。由此,我们可以得到每一级缓存的延迟和访存延迟。
上图的配置中,DDR4跑在3.2Gbps,总线800Mhz,内存控制器800Mhz,处理器2.25Ghz。关掉缓存,用读指令测试。延迟包括出和进两个方向,69.8纳秒,这是在总是命中一个内存物理页的情况下的最优结果,随机的地址访问需要把17.5纳秒再乘以2到3。关于物理页的解释请参看内存一章。
在内存上花的时间是控制器+物理层+接口,总共38.9纳秒。百分比55%。如果是访问随机地址,那么会超过70纳秒,占70%。在总线和异步桥上花的时间是20纳秒,8个总线时钟周期,28%。处理器11.1纳秒,占16%,20个处理器时钟周期。
所以,即使是在3.2Gbps的DDR4上,大部分时间还都是在内存,显然优化可以从它上面入手。在处理器中的时间只有一小部分。但从另外一个方面,处理器控制着linefill,eviction的次数,地址的连续性,以及预取的效率,虽然它自己所占时间最少,但也是优化的重点。
在ARM的路线图上,还出现了一项并不算新的技术,称作stashing。它来自于网络处理器,原理是外设控制器(PCIe,网卡)向处理器发送请求,把某个数据放到缓存,过程和监听snooping很类似。在某些领域,这项技术能够引起质的变化。举个例子,intel至强处理器,配合它的网络转发库DPDK,可以做到平均80个处理器周期接受从PCIe网卡来的包,解析包头后送还回去。80周期是个什么概念?看过了上面的访存延迟图后你应该有所了解,处理器访问下内存都需要200-300周期。而这个数据从PCIe口DMA到内存,然后处理器抓取它进行处理后,又经过DMA从PCIe口出去,整个过程肯定大于访存时间。80周期的平均时间说明它肯定被提前送到了缓存。但传进来的数据很多,只有PCIe或者网卡控制器才知道哪个是包头,才能精确的推送数据,不然缓存会被无用的数据淹没。这个过程做好了,可以让软件处理以太网或者存储单元的速度超过硬件加速器。事实上,在freescale的网络处理器上,有了硬件加速器的帮助,处理包的平均延迟需要200处理器周期,已经慢于至强了。
还有,在ARM新的面向网络和服务器的核心上,会出现一核两线程的设计。处理包的任务天然适合多线程,而一核两线程可以更有效的利用硬件资源,再加上stashing,如虎添翼。(转自玩转单片机)
1.电子刊,不妨来一份儿!
2.35岁,工程师永远的话题!
3.千万不要得罪程序员,复仇方式非常狠,11行代码让你怀疑人生!
4.软件工程师PK硬件工程师,未来你会服哪一个?
5.嵌入式 IoT 协议概述
6.嵌入式领域的职业发展方向是什么?
免责声明:本文系网络转载,版权归原作者所有。如涉及作品版权问题,请与我们联系,我们将根据您提供的版权证明材料确认版权并支付稿酬或者删除内容。
J. dpdk 技术 可否 应用于linux
DPDK主要使用了UIO、HUGEPAGE和CPU Affinity机制三个薯薯技术点来提高高速网络数据的处理性能。
UIO是实现用户空间下驱动程序的支撑机制,DPDK使用UIO机制使网卡驱动程序(主要是intel自身的千兆igb与万兆ixgbe驱动程序)运行在用户态,并采用轮询和零拷贝方式从网卡收取报文,提高收发报文的数槐者性能。
HUGEPAGE的主要好处是通过利用大内存页提高内存的使用效率,DPDK在HUGEPAGE机制上构建内存管理系统,提高应用程序处理报文的性能。
CPU Affinity机制主要是让各个CPU各自干自己的事情,DPDK使用CPU Affinity机制将控制面线程以及各个数据面线程绑定到不同的CPU核,节省反复调度的性能消耗。其工作模式类似于一明碰个CPU核绑定一个死循环线程,专心处理各自的业务。比如两个网卡eth0和eth1都收包,可以让cpu0专心处理eth0,cpu1专心处理eth1,没必要cpu0一下处理eth0,一下又处理eth1,这样就提高了多核CPU的使用效率。
所以,这样看来,DPDK并不高深,用到的东西也都是Linux本身提供的特性,还有额外的内存池、环形缓存等,虽然封装得很好,但都是比较常用经常接触的技术。