DPDK源码分析之(1)libmbuf模块

DPDK源码分析之(1)libmbuf模块

Author:OnceDay Date:2024年7月2日

漫漫长路,有人对你笑过嘛…

全系列文档可参考专栏:源码分析_Once-Day的博客-CSDN博客

参考文档:

  • DPDK download
  • Getting Started Guide for Linux — documentation (dpdk.org)
  • Sample Applications User Guides — documentation (dpdk.org)
  • 14. Mbuf Library — Data Plane Development Kit 24.07.0-rc1 documentation (dpdk.org)
  • dpdk/lib/mbuf at main · DPDK/dpdk · GitHub
  • TCP/IP Illustrated, Volume 2: The Implementation (kohala.com)

文章目录

      • DPDK源码分析之(1)libmbuf模块
        • 1. 概述
          • 1.1 mbuf介绍
          • 1.2 mbuf设计概念
          • 1.3 mbuf使用mempool
          • 1.4 mbuf对象池构造过程
        • 2. mbuf对象定义
          • 2.1 mbuf数据结构
          • 2.3 mbuf操作函数定义

1. 概述
1.1 mbuf介绍

mbuf(消息缓冲区)库提供了分配和释放缓冲区(mbufs)的功能,这些缓冲区可以被DPDK应用程序用来存储消息。消息缓冲区存储在一个称为mempool(内存池)的结构中,而这个内存池是通过Mempool库来管理的。

通常情况下,rte_mbuf结构体用于承载网络数据包缓冲区,但实际上它可以存储任何类型的数据(例如控制数据、事件等)。为了提高性能,rte_mbuf头部结构被设计得尽可能小,目前只使用了两个缓存行(cache line),并且最常用的字段被放在第一个缓存行中。

  • 内存池(Mempool)管理:内存池库通过预先分配大量固定大小的内存对象(如mbufs),来提高内存分配和释放的效率。这种方法避免了频繁的动态内存分配,从而减少了内存碎片和分配开销。

  • 缓存行优化:缓存行是CPU缓存中存储数据的最小单位。将频繁访问的数据字段放在同一个缓存行中,可以减少CPU缓存未命中(cache miss)的次数,从而提高数据访问速度。

  • 灵活性rte_mbuf不仅能承载网络数据包,还能用于其他用途,如存储控制信息或事件消息。这使得它在各种DPDK应用程序中都能发挥作用。

1.2 mbuf设计概念

为了存储数据包(包括协议头部),考虑了两种方法:

  • 在单个内存缓冲区中嵌入元数据结构,后面跟一个固定大小的区域用于存储数据包。优点是只需要一次操作即可分配/释放整个数据包的内存表示。
  • 使用独立的内存缓冲区分别存储元数据结构和数据包。更灵活,允许元数据结构的分配与数据包缓冲区的分配完全分离。

DPDK选择了第一种方法,元数据包含控制信息,如消息类型、长度、数据起始位置的偏移量以及指向其他mbuf结构的指针,从而实现mbuf链的功能

用于承载网络数据包的消息缓冲区可以处理mbuf链,即需要多个缓冲区来保存完整数据包的情况。例如,巨型帧(jumbo frames)由多个通过next字段链接在一起的mbufs组成。

对于新分配的mbuf,数据的起始位置位于缓冲区开始后RTE_PKTMBUF_HEADROOM字节处,该位置是缓存对齐的。消息缓冲区可以用于在系统的不同实体之间传递控制信息、数据包、事件等。

消息缓冲区还可以使用其缓冲区指针指向其他消息缓冲区的数据部分或其他结构,称为间接mbuf,类似于上面的第二种方法

总结mbuf的设计

  1. 单一内存缓冲区,DPDK选择了在单一内存缓冲区中嵌入元数据结构的设计,简化了分配和释放的操作。
  2. 元数据包含控制信息,元数据结构中包含消息类型、长度、数据起始位置的偏移量以及用于缓冲区链的指针。
  3. 缓冲区链,支持缓冲区链,允许多个mbufs链接在一起,特别适用于需要多个缓冲区来保存完整数据包的情况(如巨型帧)。
  4. 缓存对齐,新分配的mbuf的数据起始位置经过缓存对齐,位于RTE_PKTMBUF_HEADROOM字节之后,优化了性能。
  5. 多用途,消息缓冲区不仅用于传输数据包,还可以在系统中传递控制信息、事件等,具有很高的灵活性。
  6. 完全标准的mbuf操作函数集合,遵循常见标准和原则的mbuf操作函数实现。

下面是单个段组成的mbuf,一个mbuf持有整个报文的数据

在这里插入图片描述

下面是多个段组成的mbuf,一个主mbuf+多个子mbuf共同持有整个报文的数据

在这里插入图片描述

mbuf的构成如下:

| rte_mbuf | ==> rte_mbuf priv size<== | rte_pktmbuf_headroom |     data(Packet data)        | 
|     ==>    struct mbuf     <==       ↓     Headroom(128)    |     dataroom(2176)           |
								   buf.addr    ---->  data_offset
									                          |       MBUF_RX_SIZE=2176      |

这是一个带有私有应用数据的mbuf,其默认headroom是128字节,数据空间是2176字节,rte_mbuf是控制元数据,两个cache line共128字节。

1.3 mbuf使用mempool

mbuf缓冲区管理器(Buffer Manager)使用内存池库(Mempool Library)来分配缓冲区。因此,它确保数据包头在不同的通道和内存组(ranks)之间以最佳方式交错排列,以便L3缓存处理。

一个mbuf包含一个字段,用于指示其来源的内存池。当调用rte_pktmbuf_free(m)时,mbuf会返回到其原始的内存池中。

(1) 内存池概述

  • 内存池是一种用于管理固定大小对象集合的高效机制,专门设计用于减少动态内存分配和释放的开销。
  • 在DPDK中,内存池库(Mempool Library)负责管理这些内存池,提供快速的对象分配和释放功能。

(2) 内存池的创建和使用

  • 内存池在初始化时分配一组固定大小的内存块。这些内存块可以被反复使用,以提高性能和减少内存碎片。
  • 应用程序通过调用rte_mempool_create()函数来创建一个新的内存池,并指定每个对象的大小、对象数量以及其他参数。

(3) mbuf和内存池的关系

  • 一个mbuf包含一个字段pool,用于指示该mbuf来源的内存池。
  • 当分配新的mbuf时,实际上是从指定的内存池中取出一个空闲的内存块。
  • 当释放mbuf时,通过调用rte_pktmbuf_free(m)函数,mbuf会被归还到其原始的内存池中,这样可以被再次使用。

(4) 优化性能

  • 内存池的设计考虑了缓存的优化,确保对象分配和释放操作尽可能地缓存友好,从而提高整体性能。
  • 数据包头在不同的内存通道和组之间交错排列,有助于优化L3缓存的处理。

(5) 共享和多用途

  • 内存池可以在多个核心之间共享,支持并行处理。
  • 除了用于网络数据包的存储,内存池还可以用于其他需要高效内存管理的场景,如事件处理和控制信息存储。
1.4 mbuf对象池构造过程

在DPDK中,消息缓冲区(mbuf)的构造过程由API提供的构造函数完成。以下是详细的构造过程:

(1) 内存池的创建,首先,需要创建一个内存池(mempool),用于存储mbuf对象。通过调用rte_mempool_create()函数来创建内存池。在创建内存池时,可以传递一个回调函数,用于初始化每个mbuf对象。

(2) mbuf的初始化,DPDK提供了一个默认的mbuf初始化函数rte_pktmbuf_init()

这个函数在创建内存池时作为回调函数传递给rte_mempool_create(),用于初始化每个mbuf对象。rte_pktmbuf_init()函数会初始化mbuf结构中的一些字段,这些字段一旦设置就不会被用户修改。具体初始化的字段包括:

  • mbuf类型(mbuf type)
  • 来源的内存池(origin pool)
  • 缓冲区的起始地址(buffer start address)
  • 其他一些需要初始化的字段
void rte_pktmbuf_init(struct rte_mempool *mp, void *opaque_arg, void *_m, unsigned i) {
    struct rte_mbuf *m = _m;

	memset(m, 0, mbuf_size);
	/* start of buffer is after mbuf structure and priv data */
	m->priv_size = priv_size; //mbuf应用数据空间大小,在私有应用数据之后才是报文数据存储空间
	m->buf_addr = (char *)m + sizeof(struct rte_mbuf) + priv_size; 
	rte_mbuf_iova_set(m, rte_mempool_virt2iova(m) + mbuf_size);
	m->buf_len = (uint16_t)buf_len; //mbuf数据空间大小, 包括headroom和tailroom

	/* keep some headroom between start of buffer and data */
	m->data_off = RTE_MIN(RTE_PKTMBUF_HEADROOM, (uint16_t)m->buf_len);

	/* init some constant fields */
	m->pool = mp;
	m->nb_segs = 1;
	m->port = RTE_MBUF_PORT_INVALID;
	rte_mbuf_refcnt_set(m, 1);
	m->next = NULL;
}
2. mbuf对象定义
2.1 mbuf数据结构

相关字段如下:

字段大小描述
cacheline0
buf_addr8 bytes(void *)报文数据的起始地址(虚拟地址)
buf_iova8 bytes(rte_iova_t)报文数据的起始地址(物理地址),总是对齐8字节
rearm_data在RX描述重装时会自动清除接下来8个字节的数据
data_off2 bytes(uint16_t)报文数据的偏移量(相对于buf_addr)
refcnt2 bytes(uint16_t)mbuf引用计数, 用于广播报文零拷贝
nb_segs2 bytes(uint16_t)mbuf的分段sbuf链节点数目,对于一个mbuf不够的报文有效
port2 bytes(uint16_t)报文的输入/输出端口ID(port)
ol_flags8 bytes(uint64_t)网卡硬件卸载特性
rx_descriptor_fields1
packet_type4 bytes(uint32_t)报文数据类型(L2/L3/L4层和隧道信息)
l2_type(4 bits)外层报文的L2类型信息
l3_type(4 bits)外层报文的L3类型信息
l4_type(4 bits)外层报文的L4类型信息
tun_type(4 bits)隧道类型信息
inner_esp_next_proto(8 bit)inner_esp_next_proto(隧道内层信息)
inner_l2_type(4 bit)内层报文的L2类型信息
inner_l3_type(4 bit)内层报文的L3类型信息
inner_l4_type(4 bit)内层报文的L4类型信息
pkt_lenuint32_t(4 byte)整个报文长度(包括所有关联mbuf的数据长度之和)
data_lenuint16_t(2 byte)当前mbuf的报文数据长度(只计算当前mbuf的数据空间)
vlan_tciuint16_t(2 type)(cpu order)VLAN ID,如果RTE_MBUF_F_RX_VLAN存在
hash8 bytes(联合体)报文hash相关信息
rss(4 byte)网卡RSS哈希的结果
fdir(8 byte)网卡FDIR的标识信息 ,包括lo(hash+id) + hi
sched( 8byte)调度队列信息(queue id/traffic class/color)
txadater(8 bytes)dpdk事件设备(eventdev)的关联发送队列(txq)
vlan_tci_outeruint16_t(2 bytes)(cpu order)外层VLAN ID,如果RTE_MBUF_F_RX_QINQ存在
buf_lenuint16_t(2 bytes)当前mbuf的数据空间大小(初始化时给定值)
poolstruct rte_mempool*(8 bytes)当前mbuf所属的内存池
cacheline10 byte
nextstruct rte_mbuf *(8 bytes)长报文的分段mbuf链表,最后一个节点next需要为零
tx_offloaduint64_t (8 bytes)发送网卡硬件卸载信息
l2_lenL2 (MAC) Header Length for non-tunneling pkt。
Outer_L4_len + … + Inner_L2_len for tunneling pkt
l3_lenL3 (IP) Header Length.
l4_lenL4 (TCP/UDP) Header Length.
tso_segszTCP TSO segment size
outer_l3_lenOuter L3 (IP) Hdr Length
outer_l2_lenOuter L2 (MAC) Hdr Length
shinfo12 bytesstruct rte_mbuf_ext_shared_info,mbuf关联的外部数据信息。
priv_sizeuint16_t(2 bytes)mbuf私有数据大小,作为外层应用的mbuf的实际大小来使用。
timesyncuint16_t(2 bytes)Timesync flags for use with IEEE1588
dynfield19 * 4 bytes动态使用字段
2.3 mbuf操作函数定义

相关操作函数和宏定义如下:

操作名称描述
rte_pktmbuf_mtod_offset返回在指定偏移量处的指定类型指针,使用需要注意mbuf数据地址的连续性(是否都在一个mbuf里),即mbuf->buf_addr + mbuf->data_off + offset位置。
rte_pktmbuf_mtod返回偏移量0处指定类型指针,即mbuf->buf_addr + mbuf->data_off位置。
rte_pktmbuf_iova_offset与rte_pktmbuf_mtod_offset类似,但返回的是物理地址(而不是虚拟地址)。
rte_pktmbuf_iova与rte_pktmbuf_mtod类似,但返回的是物理地址(而不是虚拟地址)。
rte_get_rx_ol_flag_name获取Rx offload标识的字符串化表示,一次一个。
rte_get_rx_ol_flag_list获取Rx offload标识的字符串化表示,可以多个标识。
rte_get_tx_ol_flag_name获取Tx offload标识的字符串化表示,一次一个。
rte_get_tx_ol_flag_list获取Rx offload标识的字符串化表示,可以多个标识。
rte_mbuf_prefetch_part1L1缓存预取mbuf第一个cache line的数据
rte_mbuf_prefetch_part2L1缓存预取mbuf第二个cache line的数据
rte_mbuf_iova_get获取mbuf数据的IOVA(虚拟IO地址,IOMMU管理和映射)(mbuf->buf_iova)。
如果RTE_IOVA_IN_MBUF未使能,则等于虚拟地址(mbuf->buf_addr)。
rte_mbuf_iova_set设置IOVA地址,如果RTE_IOVA_IN_MBUF使能,改变mbuf->buf_iova,否则无操作。
rte_mbuf_data_iova获取mbuf报文数据的起始IOVA地址,加上mbuf->data_off。
rte_mbuf_data_iova_default返回默认的mbuf报文数据的起始IOVA地址,固定data offset为RTE_PKTMBUF_HEADROOM(128)
rte_mbuf_from_indirect从一个indirect mbuf的bufffer addr获取其direct(源) mbuf的首地址(指针偏移得到)。
rte_mbuf_buf_addr从mbuf的地址和mempool对象获取mbuf buffer addr
rte_mbuf_data_addr_default从mbuf的地址和mempool对象获取mbuf buffer addr + RTE_PKTMBUF_HEADROOM地址
rte_mbuf_to_baddr获取mbuf buffer addr,从mbuf地址+mempool对象里的mbuf私有数据空间大小算出
rte_mbuf_to_priv返回mbuf私有数据空间的起始地址
rte_pktmbuf_priv_flags返回mbuf私有数据的flags,这是mbuf提供的一种标准私有数据定义。
rte_mbuf_sanity_checkmbuf合规检测,通常用于debug模式,有问题直接panic。
rte_mbuf_checkmbuf合规检测,通常用于debug模式,有问题返回错误原因字符串。
__rte_mbuf_raw_sanity_check原始mbuf合规检测(refcnt=1, next=null, nb_segs=1,通常用于debug模式,有问题直接panic。
rte_mbuf_refcnt_read读取mbuf引用计数,relaxed松散内存序。
rte_mbuf_refcnt_set写入mbuf引用计数,relaxed松散内存序。
__rte_mbuf_refcnt_update更新mbuf引用计数,获取-释放内存序(acquire &release )
rte_mbuf_ext_refcnt_read读取mbuf扩展共享数据的引用计数,relaxed松散内存序。
rte_mbuf_ext_refcnt_set设置mbuf扩展共享数据的引用计数,relaxed松散内存序。
rte_mbuf_ext_refcnt_update更新mbuf扩展共享数据的引用计数,获取-释放内存序(acquire &release )
rte_mbuf_raw_alloc原始方式从mempool申请一个mbuf,buf_addr/buf_iova/buf_len/refcnt=1/nb_segs/next/pool/priv_size等信息应该为重置值。
rte_mbuf_raw_free原始方式释放一个mbuf到mempool,不建议使用,除非优化性能。
rte_pktmbuf_initmempool创建时的初始化函数,用于初始化mbuf全局默认值。
priv_size/buf_addr/buf_iova/buf_len/data_off/pool/nb_segs/port/refcnt/next
其中data_off/nb_segs/port/refcnt/next属于会change的值,需要释放时reset。
rte_pktmbuf_pool_init初始化mempool中私有数据,主要是mbuf的数据空间和私有应用数据空间的大小。
rte_pktmbuf_pool_create创建一个mbuf mempool,提供mbuf数目,私有应用数据和报文数据空间大小等参数。
rte_pktmbuf_pool_create_by_ops与rte_pktmbuf_pool_create类似,但是可以指定mempool ops name。
rte_pktmbuf_pool_create_extbuf与rte_pktmbuf_pool_create类似,但是mbuf的数据存放于外部memory空间。
rte_pktmbuf_data_room_size获取mbuf的数据空间大小(包括RTE_PKTMBUF_HEADROOM)
rte_pktmbuf_priv_size获取mbuf的私有应用数据空间大小,在rte_mbuf和报文数据之间。
rte_pktmbuf_reset_headroom重置mbuf的data_off到默认的headroom起始位置。
rte_pktmbuf_reset重置mbuf的数据,next/pkt_len/tx_offload/vlan_tci/vlan_tci_outer/nb_segs/
port/ol_flags/packet_type/data_off/data_len已初始化。
rte_pktmbuf_alloc从内存池中申请一个mbuf,然后使用rte_pktmbuf_reset进行重置
rte_pktmbuf_alloc_bulk一次从内存池申请多个mbuf,然后使用rte_pktmbuf_reset进行重置
rte_pktmbuf_ext_shinfo_init_helper初始化mbuf的外部共享信息数据结构体,数据需要满足对齐关系。
rte_pktmbuf_attach_extbuf初始化mbuf的外部共享数据,改变buf_addr/buf_iova/buf_len/data_len/data_off=0/ol_flags/shinfo。
修改完成之后,可以调用rte_pktmbuf_reset_headroom/rte_pktmbuf_adj来修复data_len和data_off的值。
rte_pktmbuf_detach_extbufrte_pktmbuf_detach一致。
rte_mbuf_dynfield_copy拷贝rte_mbuf的动态字段dynfield的值。
__rte_pktmbuf_copy_hdr拷贝rte_mbuf的头部数据,port/vlan_tci/vlan_tci_outer/tx_offload/hash/packet_type。
调用rte_mbuf_dynfield_copy拷贝动态空间数据。
rte_pktmbuf_attach将一个mbuf attach到另外一个mbuf上,这种mbuf成为indirect mbuf。
indirect mbuf在attach之前,必须是direct mbuf,其refcnt计数必须为1。
目标mbuf是extbuf,则增加shared info的引用计数,且拷贝ol_flags和shinfo。
目标mbuf是indirect mbuf,增加其源mbuf的引用计数,和普通mbuf一样,拷贝priv_size和ol_flags。
调用**__rte_pktmbuf_copy_hdr**拷贝头部数据。
拷贝data_off/data_len/buf_iova/buf_addr/buf_len/next/pkt_len/nb_segs=1。
__rte_pktmbuf_free_extbuf释放mbuf的extbuf,通过shinfo信息,如果shinfo引用计数为0,则释放extbuf。
__rte_pktmbuf_free_direct减少direct mbuf的引用数目,如果引用计数为0,则直接释放掉direct mbuf。
next/nb_segs=1/refcnt=1, 然后放回mempool
rte_pktmbuf_detach解除一个indirect mbuf的attach状态。
如果mbuf存在extbuf,对于Pinned类型直接Pass。对于其他类型,则调用__rte_pktmbuf_free_extbuf
如果不存在extbuf,直接调用__rte_pktmbuf_free_direct,释放对应的direct mbuf。
重置priv_size,buf_addr,buf_iova,buf_len,data_off,data_len,ol_flags。
__rte_pktmbuf_pinned_extbuf_decrefmbuf释放过程的pinned extbuf处理,重置ol_flags = RTE_MBUF_F_EXTERNAL
如果引用计数为1,则直接结束。如果不为1,则先减去1,最后操作返回值为0的线程再重置为1。
rte_pktmbuf_prefree_seg减少mbuf引用计数,并且判断是否可以free mbuf segment。
mbuf引用计数为1,如果mbuf是indirect mbuf,调用rte_pktmbuf_detach
对于indirect mbuf且存在pinned extbuf,如果extbuf refcnt为1,则需要释放mbuf segment。
mbuf释放操作:next=null,nb_segs=1,返回mbuf(可以回收和释放)。
mbuf引用计数不为1,则减一后为0的线程继续上述释放操作,并且重置mbuf引用计数为1。
rte_pktmbuf_free_seg通过rte_pktmbuf_prefree_seg判读mbuf segment是否可以释放,通过rte_mbuf_raw_free来释放。
rte_pktmbuf_free释放mbuf到mempool池中,支持chain mbuf释放操作。
rte_pktmbuf_free_bulk批量释放mbuf到mempool池中,相当于可以临时缓存mbuf。
rte_pktmbuf_clone基于已有mbuf创建一个clone mbuf,每个mbuf segment都会attach,原mbuf会变成只读mbuf。
rte_pktmbuf_copy基于已有mbuf创建一个全量复制的mbuf,但是private data不会拷贝,两个mbuf将是独立存在的。
可以指定拷贝的报文数据长度,调用**__rte_pktmbuf_copy_hdr**来copy头部。
拷贝会去掉RTE_MBUF_F_INDIRECT和RTE_MBUF_F_EXTERNAL,拷贝后mbuf具有完整的数据。
拷贝mbuf不是逐个mbuf segment拷贝,而是会重新整合数据,尽量填充每个mbuf segment。
rte_pktmbuf_refcnt_update更新mbuf的每个mbuf segment的引用计数。
rte_pktmbuf_headroom获取mbuf的headroom长度,来自data_off。
rte_pktmbuf_tailroom获取mbuf的tailroom长度,来自buf_len - data_off - data_len。
rte_pktmbuf_lastseg获取mbuf的最后一个lastseg。
rte_pktmbuf_pkt_len获取mbuf的报文长度。
rte_pktmbuf_data_len获取mbuf的数据长度。
rte_pktmbuf_prependmbuf报文数据向前扩展指定字节,即尝试减少headroom空间,所以最大上限是headroom大小(data_off=0)。
rte_pktmbuf_append在mbuf后面添加指定字节的数据,尝试减少tailroom,如果空间不足,返回NULL。
rte_pktmbuf_adj移动mbuf的报文数据指针,即data_off,只在第一个mbuf segment移动,不能超过data_len。
rte_pktmbuf_trim裁剪mbuf的尾部数据,裁剪数据长度不能超过最后一个mbuf segment的数据长度(data_len)。
rte_pktmbuf_is_contiguous检查mbuf的数据空间是否连续,即mbuf->nb_segs==1。
__rte_pktmbuf_read在mbuf指定偏移处读取指定长度的数据。
rte_pktmbuf_read如果目标数据是连续的,那么直接返回对应地址的指针,如果非连续,则拷贝到用户buffer中。
rte_pktmbuf_chain将两个mbuf连接起来。
rte_mbuf_tx_offload基于给定的offload参数生成tx_offload值。
rte_validate_tx_offload检查tx_offload的正确性和完整性(ol_flags)。
rte_pktmbuf_linearize将mbuf的数据连续化,要求单个mbuf能放下数据,并且原来的多个mbuf segment被free掉了。
rte_pktmbuf_dump可以dump mbuf的数据。
rte_mbuf_sched_queue_get获取mbuf调度队列的ID。
rte_mbuf_sched_traffic_class_get获取mbuf的traffic class id。
rte_mbuf_sched_color_get获取mbuf的color字段ID。
rte_mbuf_sched_get获取mbuf的queue_id/traffic_class/color的值。
rte_mbuf_sched_queue_set设置mbuf的队列ID。
rte_mbuf_sched_traffic_class_set设置mbuf的class ID。
rte_mbuf_sched_color_set设置mbuf的color ID。
rte_mbuf_sched_set设置mbuf的queue_id, traffic_class and color。

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

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

相关文章

业界数据架构的演变

目录 一、概述 二、业务处理-单体架构 三、业务处理-微服务架构 四、数据分析-大数据Lambda架构 五、数据分析-Kappa架构 六、数据分析-LambdaKappa混合架构 七、湖仓一体架构 一、概述 近年来随着越来越多的大数据技术被开源&#xff0c;例如&#xff1a;HDFS、Spark等…

最小表示法

#define _CRT_SECURE_NO_WARNINGS #include<bits/stdc.h> using namespace std;const int N (int)3e5 5; int n; int a[N * 2];int main() {cin >> n;for (int i 0; i < n; i) {cin >> a[i];a[i n] a[i]; // 构造成链}int l 0, r 1; // 一开始 r …

进入防火墙Web管理页面(eNSP USG6000V)和管理员模块

1、进入防火墙Web管理页面 USG系列是华为提供的一款高端防火墙产品&#xff0c;其特点在于提供强大的安全防护能力和灵活的扩展性。 以eNSP中的USG6000为例&#xff1a; MGMT口&#xff08;web管理口&#xff09;&#xff1a;对应设备上的G0/0/0口&#xff0c;上面初始配有一…

算法-常见数据结构设计

文章目录 1. 带有setAll功能的哈希表2. LRU缓存结构3. O(1)时间插入删除随机(去重)4. O(1)时间插入删除随机(不去重)5. 快速获取数据流中的中位数6. 最大频率栈7. 全O(1)结构8. LFU缓存结构 本节的内容比较难, 大多是leetcodeHard难度级别的题目 1. 带有setAll功能的哈希表 哈希…

QCustomPlot+ vs2022+ qt

零、printSupport 步骤一&#xff1a;下载QCustomPlot 访问QCustomPlot的官网 QCustomPlot 下载最新版本的源代码。 步骤二&#xff1a;配置项目 创建新的Qt项目&#xff1a; 打开VS2022&#xff0c;创建一个新的Qt Widgets Application项目。 将QCustomPlot源代码添加到项目…

集合复习(java)

文章目录 Collection 接口Collection结构图Collection接口中的方法Iterator 与 Iterable 接口Collection集合遍历方式迭代器遍历增强 for 遍历 List&#xff08;线性表&#xff09;List特有方法ArrayList&#xff08;可变数组&#xff09;ArrayList 底层原理ArrayList 底层原理…

【UML用户指南】-30-对体系结构建模-模式和框架

目录 1、机制 2、框架 3、常用建模技术 3.1、对设计模式建模 3.2、对体系结构模式建模 用模式来详述形成系统体系结构的机制和框架。通过清晰地标识模式的槽、标签、按钮和刻度盘 在UML中&#xff0c; 对设计模式&#xff08;也叫做机制&#xff09;建模&#xff0c;将它…

前端技术(三)—— javasctipt 介绍:jQuery方法和点击事件介绍(补充)

6. 常用方法 ● addClass() 为jQuery对象添加一个或多个class <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0">&…

Efficient Contrastive Learning for Fast and Accurate Inference on Graphs

发表于:ICML24 推荐指数: #paper/⭐⭐⭐ 创新点一颗星,证明三颗星(证明的不错,值得借鉴,但是思路只能说还行吧) 如图, 本文采取的创新点就是MLP用原始节点,GCN用邻居节点的对比学习.这样,可以加快运算速度 L E C L − 1 ∣ V ∣ ∑ v ∈ V 1 ∣ N ( v ) ∣ ∑ u ∈ N ( v )…

汇聚荣拼多多电商的技巧有哪些?

在电商平台上&#xff0c;汇聚荣拼多多以其独特的商业模式和创新的营销策略吸引了大量消费者。那么&#xff0c;如何在这样一个竞争激烈的平台上脱颖而出&#xff0c;成为销售佼佼者呢?本文将深入探讨汇聚荣拼多多电商的成功技巧。 一、精准定位目标客户群体 首先&#xff0c;…

Android增量更新----java版

一、背景 开发过程中&#xff0c;随着apk包越来越大&#xff0c;全量更新会使得耗时&#xff0c;同时浪费流量&#xff0c;为了节省时间&#xff0c;使用增量更新解决。网上很多文章都不是很清楚&#xff0c;没有手把手教学&#xff0c;使得很多初学者&#xff0c;摸不着头脑&a…

【Threejs进阶教程-优化篇】4.Vue/React与threejs如何解决冲突和卡顿(续)

Vue/React与threejs如何解决冲突和卡顿-续 使用说明核心思路环境搭建(vuethree)vue运行机制分析业务分离使用threejs做背景 3D模块封装使用ES6的Class来让逻辑性更强Threejs尽量按需引入创建一个类扩展写法本次代码执行顺序 扩展内容添加orbitControls和辅助线解决事件覆盖 与V…

MUX VLAN实现二层流量的弹性管控

一、模拟场景&#xff0c;企业有一台服务器&#xff0c;部门A&#xff0c;部门B&#xff0c;访客 二、要求&#xff1a;三者都可以访问服务器&#xff0c;部门A和B可以进行部门内部通信&#xff0c;A和B不可以通信&#xff0c;访客只能访问服务器 三、拓扑如下图 四、配置流程…

UE5 05-利用 timeline 插值运动

理解成 unity Dotween DoMove 插值运动即可 AddTimeLine 节点 物体插值运动 物体插值缩放 一个timeline 可以K多个动画帧

【js基础巩固】深入理解作用域与作用域链

作用域链 先看一段代码&#xff0c;下面代码输出的结果是什么&#xff1f; function bar() {console.log(myName) } function foo() {var myName "极客邦"bar() } var myName "极客时间" foo()当执行到 console.log(myName) 这句代码的时候&#xff0c…

25_嵌入式系统总线接口

目录 串行接口基本原理 串行通信 串行数据传送模式 串行通信方式 RS-232串行接口 RS-422串行接口 RS-485串行接口 RS串行总线总结 RapidIO高速串行总线 ARINC429总线 并行接口基本原理 并行通信 IEEE488总线 SCSI总线 MXI总线 PCI接口基本原理 PCI总线原理 PC…

Qt | QPen 类(画笔)

01、画笔基础 1、需要使用到的 QPainter 类中的函数原型如下: void setPen(const QPen &pen); //设置画笔,void setPen(const QColor &color); //设置画笔,该笔样式为 Qt::SolidLine、宽度为 1,颜色由 color 指定void setPen(Qt::PenStyle style); //设置画笔,该…

【问题解决】 pyocd 报错 No USB backend found 的解决方法

pyocd 报错 No USB backend found 的解决方法 本文记录了我在Windows 10系统上遇到的pyocd命令执行报错——No USB backend found 的分析过程和解决方法。遇到类似问题的朋友可以直接参考最后的解决方法&#xff0c;向了解问题发送原因的可以查看原因分析部分。 文章目录 pyoc…

90元搭建渗透/攻防利器盒子!【硬件篇】

前言 以下内容请自行思考后进行实践。 使用场景 在某些情况下开软件进行IP代理很麻烦&#xff0c;并不能实现真正全局&#xff0c;而且还老容易忘记&#xff0c;那么为了在实景工作中&#xff0c;防止蓝队猴子封IP&#xff0c;此文正现。 正文 先说一下实验效果&#xff1…

Java 应用启动时出现编译错误进程会退出吗?

背景 开发的尽头是啥呢&#xff1f;超超级熟练工&#xff01; 总结最近遇到的一些简单问题&#xff1a; Java 应用的某个线程&#xff0c;如果运行时依赖的 jar 不满足&#xff0c;线程是否会退出&#xff1f;进程是否会退出&#xff1f;Netty 实现 TCP 功能时&#xff0c;换…