DPDK系列之四十硬件加速和功能卸载

一、硬件卸载

硬件加速,听名字就是明白是利用硬件加速。不太准确,硬件加速其实更有效进行硬件的分工,通过分工实现硬件的整体的效率的提升。其实硬件卸载就是硬件加速,而实现硬件加速就需要进行功能卸载,整体上就可以叫做硬件卸载。
硬件卸载是指将某些任务或计算从计算机的主处理器 (CPU) 或一些软件功能转移到专用硬件组件(例如网络接口卡 (NIC) 或图形处理单元 (GPU))的过程,以提高系统性能和效率。而提到硬件卸载就不得提到软件定义网络:
软件定义网络的主流的解决方案是从传统的包含专用硬件与控制平面相结合并提供选定的功能的交换机等单个设备,转移到软件定义网络抽象出的控制平面、数据平面、管理平面三个不同的层。
第一层是管理层或管理平面。它包括像OpenStack这类应用所在的位置,可以将一些配置应用于网络并将其用于虚拟化等领域。下一层是控制平面。最下面是数据平面。它由硬件(例如白盒交换机)和软件(软件数据平面)组成,数据平面就是硬件卸载所在的地方。而软件定义网络一般是指通过某种技术将网络设备的控制面与数据面分离开,形成灵活智能的网络。
软件数据平面是一个常用的术语,用来描述处理网络数据包中用户数据的应用程序。DPDK,数据平面开发套件,这下明白了吧。

二、DPDK中的应用

DPDK主要是应对网络应用开发,所以其主要和网卡打交道。DPDK为了支持网卡的硬件卸载,需要提供相关的软件接口,具体到实际情况,网卡的硬件卸载可能是基于端口设置也可能是基于每个包设置使能。DPDK的mbuf可能是对应着一个包也可能多个mbuf对应着一个包,这在mbuf中都有对应的标识来标定(ol_flags)。在“\dpdk-stable-19.11.14\lib\librte_mbuf\rte_mbuf_core.h”中有这些具体的定义,如“PKT_RX_IP_CKSUM_NONE”等等。在相同文件夹下,还有其它一些具体的宏定义,大家也可以参考。
相关的硬件卸载功能主要是与实际的网卡的实现情况有关,其主要有以下几种情况:
1、硬件与更新功能卸载
它根据实际情况又可以分为:
a.VLAN硬件卸载,通过报文中Tag标识来进行标识控制。通过硬件卸载可以直接使用硬件操作而非软件利用CPU来进行操作,减轻了CPU的负荷。
b.IEEE1588硬件卸载功能,PTP(Precision Timing Protocol,精准时间同步协议),这个用硬件实现更便捷准确
c.IP TCP/UDP/SCTP checksum硬件卸载功能,这个就不用说了,硬件更快捷高效
d.Tunnel硬件卸载功能,这个更好理解,其实就是纯粹的协议的控制,隧道,就是一个安全通道,一个专门的通道,可以将不同的协议连接起来。类似于集装箱,直接把原始包扔进去做负载。这种简单的封装其实更适合用硬件来完成。

2、分片功能卸载
分片说得有点高级,其实也很好理解,一个大城市不好管理,划成一个个小片不就好管理了,这就是分片。在网络通信中,上层应用可能不会顾及底层的硬件和驱动的缓冲大小,向下输出大量数据,可实际的TCP的传输是有大小控制的,这就需要将上层的数据分片成合适的大小。而这个分片的过程软件其实是不如硬件更容易实现。因为这种机械的固定的功能最是硬件的擅长的了。

3、组包功能卸载
组包其实就上面分片的逆操作。毕竟数据最终还是回流到上层应用,必须保持数据的一致性呈现,这就需要把在数据传输过程中的一系列辅助的动作恢复原样。这就和在网上购物一样,可能是一个很小的物件,但在实际传输中可能不断的被打包,验证,然后装箱,运输。等到达目的地时再逆向操作,最终原样送到购买者手中。

三、源码分析

在DPDK提供了对IEEE1588的功能支持:

int
rte_eth_timesync_enable(uint16_t port_id)
{struct rte_eth_dev *dev;RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);dev = &rte_eth_devices[port_id];RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->timesync_enable, -ENOTSUP);return eth_err(port_id, (*dev->dev_ops->timesync_enable)(dev));
}int
rte_eth_timesync_disable(uint16_t port_id)
{struct rte_eth_dev *dev;RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);dev = &rte_eth_devices[port_id];RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->timesync_disable, -ENOTSUP);return eth_err(port_id, (*dev->dev_ops->timesync_disable)(dev));
}
int
rte_eth_timesync_read_rx_timestamp(uint16_t port_id, struct timespec *timestamp,uint32_t flags)
{struct rte_eth_dev *dev;RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);dev = &rte_eth_devices[port_id];RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->timesync_read_rx_timestamp, -ENOTSUP);return eth_err(port_id, (*dev->dev_ops->timesync_read_rx_timestamp)(dev, timestamp, flags));
}int
rte_eth_timesync_read_tx_timestamp(uint16_t port_id,struct timespec *timestamp)
{struct rte_eth_dev *dev;RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);dev = &rte_eth_devices[port_id];RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->timesync_read_tx_timestamp, -ENOTSUP);return eth_err(port_id, (*dev->dev_ops->timesync_read_tx_timestamp)(dev, timestamp));
}

上面的代码很清晰就是使能和读取双向的时间戳。而在app/test-pmd中有计算checksum的方法:

/* if possible, calculate the checksum of a packet in hw or sw,* depending on the testpmd command line configuration */
static uint64_t
process_inner_cksums(void *l3_hdr, const struct testpmd_offload_info *info,uint64_t tx_offloads)
{struct rte_ipv4_hdr *ipv4_hdr = l3_hdr;struct rte_udp_hdr *udp_hdr;struct rte_tcp_hdr *tcp_hdr;struct rte_sctp_hdr *sctp_hdr;uint64_t ol_flags = 0;uint32_t max_pkt_len, tso_segsz = 0;/* ensure packet is large enough to require tso */if (!info->is_tunnel) {max_pkt_len = info->l2_len + info->l3_len + info->l4_len +info->tso_segsz;if (info->tso_segsz != 0 && info->pkt_len > max_pkt_len)tso_segsz = info->tso_segsz;} else {max_pkt_len = info->outer_l2_len + info->outer_l3_len +info->l2_len + info->l3_len + info->l4_len +info->tunnel_tso_segsz;if (info->tunnel_tso_segsz != 0 && info->pkt_len > max_pkt_len)tso_segsz = info->tunnel_tso_segsz;}if (info->ethertype == _htons(RTE_ETHER_TYPE_IPV4)) {ipv4_hdr = l3_hdr;ol_flags |= PKT_TX_IPV4;if (info->l4_proto == IPPROTO_TCP && tso_segsz) {ol_flags |= PKT_TX_IP_CKSUM;} else {if (tx_offloads & DEV_TX_OFFLOAD_IPV4_CKSUM) {ol_flags |= PKT_TX_IP_CKSUM;} else {ipv4_hdr->hdr_checksum = 0;ipv4_hdr->hdr_checksum =rte_ipv4_cksum(ipv4_hdr);}}} else if (info->ethertype == _htons(RTE_ETHER_TYPE_IPV6))ol_flags |= PKT_TX_IPV6;elsereturn 0; /* packet type not supported, nothing to do */if (info->l4_proto == IPPROTO_UDP) {udp_hdr = (struct rte_udp_hdr *)((char *)l3_hdr + info->l3_len);/* do not recalculate udp cksum if it was 0 */if (udp_hdr->dgram_cksum != 0) {if (tx_offloads & DEV_TX_OFFLOAD_UDP_CKSUM) {ol_flags |= PKT_TX_UDP_CKSUM;} else {udp_hdr->dgram_cksum = 0;udp_hdr->dgram_cksum =get_udptcp_checksum(l3_hdr, udp_hdr,info->ethertype);}}if (info->gso_enable)ol_flags |= PKT_TX_UDP_SEG;} else if (info->l4_proto == IPPROTO_TCP) {tcp_hdr = (struct rte_tcp_hdr *)((char *)l3_hdr + info->l3_len);if (tso_segsz)ol_flags |= PKT_TX_TCP_SEG;else if (tx_offloads & DEV_TX_OFFLOAD_TCP_CKSUM) {ol_flags |= PKT_TX_TCP_CKSUM;} else {tcp_hdr->cksum = 0;tcp_hdr->cksum =get_udptcp_checksum(l3_hdr, tcp_hdr,info->ethertype);}if (info->gso_enable)ol_flags |= PKT_TX_TCP_SEG;} else if (info->l4_proto == IPPROTO_SCTP) {sctp_hdr = (struct rte_sctp_hdr *)((char *)l3_hdr + info->l3_len);/* sctp payload must be a multiple of 4 to be* offloaded */if ((tx_offloads & DEV_TX_OFFLOAD_SCTP_CKSUM) &&((ipv4_hdr->total_length & 0x3) == 0)) {ol_flags |= PKT_TX_SCTP_CKSUM;} else {sctp_hdr->cksum = 0;/* XXX implement CRC32c, example available in* RFC3309 */}}return ol_flags;
}

看一下组包的支持:

* Initializes Receive Unit.
*/
int __attribute__((cold))
ixgbe_dev_rx_init(struct rte_eth_dev *dev)
{struct ixgbe_hw     *hw;struct ixgbe_rx_queue *rxq;uint64_t bus_addr;uint32_t rxctrl;uint32_t fctrl;uint32_t hlreg0;uint32_t maxfrs;uint32_t srrctl;uint32_t rdrxctl;uint32_t rxcsum;uint16_t buf_size;uint16_t i;struct rte_eth_rxmode *rx_conf = &dev->data->dev_conf.rxmode;int rc;PMD_INIT_FUNC_TRACE();hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);/** Make sure receives are disabled while setting* up the RX context (registers, descriptor rings, etc.).*/rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN);/* Enable receipt of broadcasted frames */fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);fctrl |= IXGBE_FCTRL_BAM;fctrl |= IXGBE_FCTRL_DPF;fctrl |= IXGBE_FCTRL_PMCF;IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);/** Configure CRC stripping, if any.*/hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);if (rx_conf->offloads & DEV_RX_OFFLOAD_KEEP_CRC)hlreg0 &= ~IXGBE_HLREG0_RXCRCSTRP;elsehlreg0 |= IXGBE_HLREG0_RXCRCSTRP;/** Configure jumbo frame support, if any.*/if (rx_conf->offloads & DEV_RX_OFFLOAD_JUMBO_FRAME) {hlreg0 |= IXGBE_HLREG0_JUMBOEN;maxfrs = IXGBE_READ_REG(hw, IXGBE_MAXFRS);maxfrs &= 0x0000FFFF;maxfrs |= (rx_conf->max_rx_pkt_len << 16);IXGBE_WRITE_REG(hw, IXGBE_MAXFRS, maxfrs);} elsehlreg0 &= ~IXGBE_HLREG0_JUMBOEN;/** If loopback mode is configured, set LPBK bit.*/if (dev->data->dev_conf.lpbk_mode != 0) {rc = ixgbe_check_supported_loopback_mode(dev);if (rc < 0) {PMD_INIT_LOG(ERR, "Unsupported loopback mode");return rc;}hlreg0 |= IXGBE_HLREG0_LPBK;} else {hlreg0 &= ~IXGBE_HLREG0_LPBK;}IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0);/** Assume no header split and no VLAN strip support* on any Rx queue first .*/rx_conf->offloads &= ~DEV_RX_OFFLOAD_VLAN_STRIP;/* Setup RX queues */for (i = 0; i < dev->data->nb_rx_queues; i++) {rxq = dev->data->rx_queues[i];/** Reset crc_len in case it was changed after queue setup by a* call to configure.*/if (rx_conf->offloads & DEV_RX_OFFLOAD_KEEP_CRC)rxq->crc_len = RTE_ETHER_CRC_LEN;elserxq->crc_len = 0;/* Setup the Base and Length of the Rx Descriptor Rings */bus_addr = rxq->rx_ring_phys_addr;IXGBE_WRITE_REG(hw, IXGBE_RDBAL(rxq->reg_idx),(uint32_t)(bus_addr & 0x00000000ffffffffULL));IXGBE_WRITE_REG(hw, IXGBE_RDBAH(rxq->reg_idx),(uint32_t)(bus_addr >> 32));IXGBE_WRITE_REG(hw, IXGBE_RDLEN(rxq->reg_idx),rxq->nb_rx_desc * sizeof(union ixgbe_adv_rx_desc));IXGBE_WRITE_REG(hw, IXGBE_RDH(rxq->reg_idx), 0);IXGBE_WRITE_REG(hw, IXGBE_RDT(rxq->reg_idx), 0);/* Configure the SRRCTL register */srrctl = IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;/* Set if packets are dropped when no descriptors available */if (rxq->drop_en)srrctl |= IXGBE_SRRCTL_DROP_EN;/** Configure the RX buffer size in the BSIZEPACKET field of* the SRRCTL register of the queue.* The value is in 1 KB resolution. Valid values can be from* 1 KB to 16 KB.*/buf_size = (uint16_t)(rte_pktmbuf_data_room_size(rxq->mb_pool) -RTE_PKTMBUF_HEADROOM);srrctl |= ((buf_size >> IXGBE_SRRCTL_BSIZEPKT_SHIFT) &IXGBE_SRRCTL_BSIZEPKT_MASK);IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxq->reg_idx), srrctl);buf_size = (uint16_t) ((srrctl & IXGBE_SRRCTL_BSIZEPKT_MASK) <<IXGBE_SRRCTL_BSIZEPKT_SHIFT);/* It adds dual VLAN length for supporting dual VLAN */if (dev->data->dev_conf.rxmode.max_rx_pkt_len +2 * IXGBE_VLAN_TAG_SIZE > buf_size)dev->data->scattered_rx = 1;if (rxq->offloads & DEV_RX_OFFLOAD_VLAN_STRIP)rx_conf->offloads |= DEV_RX_OFFLOAD_VLAN_STRIP;}if (rx_conf->offloads & DEV_RX_OFFLOAD_SCATTER)dev->data->scattered_rx = 1;/** Device configured with multiple RX queues.*/ixgbe_dev_mq_rx_configure(dev);/** Setup the Checksum Register.* Disable Full-Packet Checksum which is mutually exclusive with RSS.* Enable IP/L4 checkum computation by hardware if requested to do so.*/rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);rxcsum |= IXGBE_RXCSUM_PCSD;if (rx_conf->offloads & DEV_RX_OFFLOAD_CHECKSUM)rxcsum |= IXGBE_RXCSUM_IPPCSE;elserxcsum &= ~IXGBE_RXCSUM_IPPCSE;IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);if (hw->mac.type == ixgbe_mac_82599EB ||hw->mac.type == ixgbe_mac_X540) {rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);if (rx_conf->offloads & DEV_RX_OFFLOAD_KEEP_CRC)rdrxctl &= ~IXGBE_RDRXCTL_CRCSTRIP;elserdrxctl |= IXGBE_RDRXCTL_CRCSTRIP;rdrxctl &= ~IXGBE_RDRXCTL_RSCFRSTSIZE;IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);}rc = ixgbe_set_rsc(dev);if (rc)return rc;ixgbe_set_rx_function(dev);return 0;
}
/*** ixgbe_set_rsc - configure RSC related port HW registers** Configures the port's RSC related registers according to the 4.6.7.2 chapter* of 82599 Spec (x540 configuration is virtually the same).** @dev port handle** Returns 0 in case of success or a non-zero error code*/
static int
ixgbe_set_rsc(struct rte_eth_dev *dev)
{struct rte_eth_rxmode *rx_conf = &dev->data->dev_conf.rxmode;struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);struct rte_eth_dev_info dev_info = { 0 };bool rsc_capable = false;uint16_t i;uint32_t rdrxctl;uint32_t rfctl;/* Sanity check */dev->dev_ops->dev_infos_get(dev, &dev_info);if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_TCP_LRO)rsc_capable = true;if (!rsc_capable && (rx_conf->offloads & DEV_RX_OFFLOAD_TCP_LRO)) {PMD_INIT_LOG(CRIT, "LRO is requested on HW that doesn't ""support it");return -EINVAL;}/* RSC global configuration (chapter 4.6.7.2.1 of 82599 Spec) */if ((rx_conf->offloads & DEV_RX_OFFLOAD_KEEP_CRC) &&(rx_conf->offloads & DEV_RX_OFFLOAD_TCP_LRO)) {/** According to chapter of 4.6.7.2.1 of the Spec Rev.* 3.0 RSC configuration requires HW CRC stripping being* enabled. If user requested both HW CRC stripping off* and RSC on - return an error.*/PMD_INIT_LOG(CRIT, "LRO can't be enabled when HW CRC ""is disabled");return -EINVAL;}/* RFCTL configuration  */rfctl = IXGBE_READ_REG(hw, IXGBE_RFCTL);if ((rsc_capable) && (rx_conf->offloads & DEV_RX_OFFLOAD_TCP_LRO))rfctl &= ~IXGBE_RFCTL_RSC_DIS;elserfctl |= IXGBE_RFCTL_RSC_DIS;/* disable NFS filtering */rfctl |= IXGBE_RFCTL_NFSW_DIS | IXGBE_RFCTL_NFSR_DIS;IXGBE_WRITE_REG(hw, IXGBE_RFCTL, rfctl);/* If LRO hasn't been requested - we are done here. */if (!(rx_conf->offloads & DEV_RX_OFFLOAD_TCP_LRO))return 0;/* Set RDRXCTL.RSCACKC bit */rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);rdrxctl |= IXGBE_RDRXCTL_RSCACKC;IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);/* Per-queue RSC configuration (chapter 4.6.7.2.2 of 82599 Spec) */for (i = 0; i < dev->data->nb_rx_queues; i++) {struct ixgbe_rx_queue *rxq = dev->data->rx_queues[i];uint32_t srrctl =IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxq->reg_idx));uint32_t rscctl =IXGBE_READ_REG(hw, IXGBE_RSCCTL(rxq->reg_idx));uint32_t psrtype =IXGBE_READ_REG(hw, IXGBE_PSRTYPE(rxq->reg_idx));uint32_t eitr =IXGBE_READ_REG(hw, IXGBE_EITR(rxq->reg_idx));/** ixgbe PMD doesn't support header-split at the moment.** Following the 4.6.7.2.1 chapter of the 82599/x540* Spec if RSC is enabled the SRRCTL[n].BSIZEHEADER* should be configured even if header split is not* enabled. We will configure it 128 bytes following the* recommendation in the spec.*/srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK;srrctl |= (128 << IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) &IXGBE_SRRCTL_BSIZEHDR_MASK;/** TODO: Consider setting the Receive Descriptor Minimum* Threshold Size for an RSC case. This is not an obviously* beneficiary option but the one worth considering...*/rscctl |= IXGBE_RSCCTL_RSCEN;rscctl |= ixgbe_get_rscctl_maxdesc(rxq->mb_pool);psrtype |= IXGBE_PSRTYPE_TCPHDR;/** RSC: Set ITR interval corresponding to 2K ints/s.** Full-sized RSC aggregations for a 10Gb/s link will* arrive at about 20K aggregation/s rate.** 2K inst/s rate will make only 10% of the* aggregations to be closed due to the interrupt timer* expiration for a streaming at wire-speed case.** For a sparse streaming case this setting will yield* at most 500us latency for a single RSC aggregation.*/eitr &= ~IXGBE_EITR_ITR_INT_MASK;eitr |= IXGBE_EITR_INTERVAL_US(IXGBE_QUEUE_ITR_INTERVAL_DEFAULT);eitr |= IXGBE_EITR_CNT_WDIS;IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxq->reg_idx), srrctl);IXGBE_WRITE_REG(hw, IXGBE_RSCCTL(rxq->reg_idx), rscctl);IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(rxq->reg_idx), psrtype);IXGBE_WRITE_REG(hw, IXGBE_EITR(rxq->reg_idx), eitr);/** RSC requires the mapping of the queue to the* interrupt vector.*/ixgbe_set_ivar(dev, rxq->reg_idx, i, 0);}dev->data->lro = 1;PMD_INIT_LOG(DEBUG, "enabling LRO mode");return 0;
}

ixgbe_set_rsc会对DEV_RX_OFFLOAD_TCP_LRO进行判断来决定是否组包,这个LRO(Large Receive Offload)其实是RSC(Receive Side Coalescing)的另外一种描述方式。

四、总结

将整个转发的流程相关内容搞清楚后,再去和代码匹配学习,就会发现学习起来相对容易了很多。其实还是推荐大家多看一下DPDK的官方文档,这样会更准确更清晰。但看官方文档有时对小白确实不是一个很友好的入门的方法。这就需要看一看别人学习和实践的心得了。
仁者见仁吧,目的只有一个,学会并能熟练使用DPDK。

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

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

相关文章

饥荒Mod 开发(二一):超大便携背包,超大物品栏,永久保鲜

饥荒Mod 开发(二十)&#xff1a;显示打怪伤害值 源码 游戏中的物品栏容量实在太小了&#xff0c;虽然可以放在箱子里面但是真的很不方便&#xff0c;外出一趟不容易看到东西都不能捡。实在是虐心。 游戏中的食物还有变质机制&#xff0c;时间长了就不能吃了&#xff0c;玩这个游…

【高数定积分求解旋转体体积】 —— (上)高等数学|定积分|柱壳法|学习技巧

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 Shell method Setting up the Integral 例题 Example 1: Example 2: Example 3: Computing…

Pytorch学习笔记 | GAN生成对抗网络 | 代码 | 生成mnist手写数字图片

文章目录 GAN网络简介测试判别器和测试生成器测试判别器测试生成器首次生成图片(效果欠佳)生成图片(比较清晰,但还有差距)生成图片(继续优化,输入扩维)生成图片(继续优化,)GAN网络简介 生成对抗网络(GAN,Generative Adversarial Networks)是一种深度学习模型,由…

Linux--shell练习题

1、写一个 bash脚本以输出数字 0 到 100 中 7 的倍数(0 7 14 21...)的命令。 vim /shell/homework1.sh #!/bin/bash for num in {0..100} doif [[ num%7 -eq o ]];thenecho $numfi done执行输出脚本查看输出结果 输出结果&#xff1a; 2、写一个 bash脚本以统计一个文本文件…

LLM之RAG实战(七)| 使用llama_index实现多模态RAG

一、多模态RAG OpenAI开发日上最令人兴奋的发布之一是GPT-4V API&#xff08;https://platform.openai.com/docs/guides/vision&#xff09;的发布。GPT-4V是一个多模态模型&#xff0c;可以接收文本/图像&#xff0c;并可以输出文本响应。最近还有一些其他的多模态模型&#x…

flutter 实战 之 dio小实践

我们要对dio进行封装 class HttpRequest {static Future request(String url,{String method "get",Map<String,dynamic>? params})async{// 创建dio实例BaseOptions baseOptions BaseOptions(baseUrl: base_url,connectTimeout: Duration(seconds: 1));fi…

50 个具有挑战性的概率问题 [04/50]:尝试直至首次成功

一、说明 你好&#xff0c;我最近对与概率相关的问题产生了兴趣。我偶然发现了 Frederick Mosteller 所著的《五十个具有挑战性的概率问题及其解决方案》这本书。我认为创建一个系列来讨论这些可能作为面试问题出现的迷人问题会很有趣。每篇文章仅包含 1 个问题&#xff0c;使其…

【四】【C语言\动态规划】地下城游戏、按摩师、打家劫舍 II,三道题目深度解析

动态规划 动态规划就像是解决问题的一种策略&#xff0c;它可以帮助我们更高效地找到问题的解决方案。这个策略的核心思想就是将问题分解为一系列的小问题&#xff0c;并将每个小问题的解保存起来。这样&#xff0c;当我们需要解决原始问题的时候&#xff0c;我们就可以直接利…

一款超好看流行的HTML随机视频播放背景引导页面源码

前言 今天宋佳乐博客给大家带来一款2024新版视频背景网址导航引导页面源码带背景动态HTML源码 源码介绍 2024新版视频背景网址导航引导页面源码带背景动态HTML源码&#xff0c;非常的炫酷&#xff0c;有需要的自行去体验吧&#xff0c;还是非常不错的 演示地址&#xff1a;点…

《xHCI 1.2》3体系结构概览

3.2 xHCI数据结构 3.2.1 Device Context Base Address Array 3.2.2 Device Context 3.2.3 Slot Context

keystone和beaengine的编译

编译Keystone 根据github的文档编译不出来&#xff0c;所以还是用CMake项目转成Visual Studio的项目来编译 1、下载源码 https://github.com/keystone-engine/keystone clone或者直接下载zip都行 2、CMake创建Visual Studio项目 下载和安装CMake就不细说了&#xff0c;在…

《妙趣横生的算法》(C语言实现)-第2章 常用的查找与排序方法

【实例2-1】一个结构体数组中存放的是学生记录&#xff0c;每条记录包括&#xff1a;学号、姓名、成绩。编写一个程序&#xff0c;要求输出1001编号同学的具体信息。 // 2-1 2023年12月23日18点05分-18点14分 typedef struct student{ // 定义学生结构体类型 int id; // 学生…

网络7层架构

网络 7 层架构 什么是OSI七层模型&#xff1f; OSI模型用于定义并理解数据从一台计算机转移到另一台计算机&#xff0c;在最基本的形式中&#xff0c;两台计算机通过网线和连接器相互连接&#xff0c;在网卡的帮助下共享数据&#xff0c;形成一个网络&#xff0c;但是一台计算…

正餐---二叉树的OJ题

目录​​​​​​​ 前言&#x1f36f; 1. 检查两颗树是否相同&#x1f947; 1.1 思路分析&#x1fa99; 1.2 代码实现&#x1f9f0; 2. 单值二叉树&#x1f332; 2.1 思路分析&#x1f52e; 2.2 代码实现&#x1f488; 3. 二叉树的前序遍历&#x1f39f;️ 3.1 思路分…

【数据结构】线性表

一.线性表 1.定义&#xff1a; n个同类型数据元素的有限序列&#xff0c;记为 L为表名&#xff0c;i为数据元素在线性表中的位序&#xff0c;n为线性表的表长&#xff0c;n0时称为空表。 2.数据元素之间的关系&#xff1a; 直接前驱和直接后继 3.抽象数据类型线性表的定义…

SQL进阶:多表查询

在SQL基础部分,我们在讲解的过程中只用到了单表查询。但实际上,常见的业务场景单表查询不能满足,或者拆分查询性能过慢。这个时候我们就需要用到连接查询。即查询多表按一定规则合并后的数据。 注意,合并后的数据也是表,也有列的概念,只不过一般存储在内存中。 由于集合…

jQuery 实现带手柄自由调整页面大小的功能

在https://blog.csdn.net/qq_44327851/article/details/135006421文章中提到了用纯JavaScript实现自由调整页面大小的功能&#xff0c;其中有基础版和优化版&#xff0c;优化版通过添加手柄解决了基础版在调整页面大小的时候不够灵活的问题&#xff0c;其实解决不够灵活的问题还…

git首次使用--去公司第一次拉取

文章目录 一&#xff0c; 在企业中首次拉取项目二&#xff0c;提交项目1. 提交----新添加的文件2. 将分支上的代码同步到master3. 提交----更改后的文件 三&#xff0c;常见问题1. Git Pull Failed 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一&am…

固定效应模型-以stata为工具

固定效应模型-以stata为工具 文章目录 1.固定效应模型2. 模型原理3. `stata`代码实现1.固定效应模型 固定效应模型(Fixed Effects Model)是一种面板数据分析方法,通过引入个体固定效应来控制个体间的异质性,并更准确地估计解释变量对因变量的影响。它在许多经济、社会科学…

(五)Python 垃圾回收机制

一、垃圾回收的工作原理 Python的垃圾回收机制是自动的&#xff0c;负责管理程序中的内存。它基于两种主要技术&#xff1a;引用计数和循环引用检测器。 引用计数 每当一个对象被引用时&#xff0c;Python会增加该对象的引用计数&#xff1b;每当一个对象不再被引用时&#…