DPDK初始化

news2024/7/7 16:50:06
rte_eal_init
│
├──rte_cpu_is_supported:检查cpu是否支持
│
├──rte_atomic32_test_and_set:操作静态局部变量run_once确保函数只执行一次
│
├──pthread_self() 获取主线程的线程ID,只是用于打印
│
├──eal_reset_internal_config:初始化内部全局配置变量struct internal_config
│
├──eal_log_level_parse 解析命令行参数,只处理“--log-level”
│   │
│   └──eal_parse_log_level 填充struct rte_logs rte_logs全局log控制变量
│
├──rte_eal_cpu_init:赋值全局结构struct lcore_config
│   │
│   ├──rte_eal_get_configuration:获取全局配置结构struct rte_config,初始指向全局变量early_mem_config
│   │
│   ├──eal_cpu_detected
│   │   │
│   │   └──如果文件“/sys/devices/system/cpu/cpu%u/topology/core_id”存在,则存在此编号的cpu
│   │
│   ├──eal_cpu_core_id
│   │   │
│   │   └──eal_parse_sysfs_value:读取文件“/sys/devices/system/cpu/cpu%u/topology/core_id”,
│   │         获取core number onsocket for this lcore
│   │
│   ├──eal_cpu_socket_id
│   │   │
│   │   └──如果目录“/sys/devices/system/node/node%u/cpu%u”存在,得到physical socket id for this lcore
│   │
│   └──计数得到number of available logical cores,保存在struct rte_config.lcore_count中
│
├──eal_parse_args:解析处理EAL的命令行参数,赋值struct internal_config 结构的相关字段
│
├──eal_plugins_init (EAL的“-d”选项可以指定需要载入的动态链接库)
│   │
│   ├──如果全局变量 default_solib_dir 所指的Default path of external loadable drivers有效
│   │   │
│   │   └──eal_plugin_add
│   │         │
│   │         ├──malloc一个struct shared_driver结构,拷贝路径名称
│   │         │
│   │         └──将此struct shared_driver结构挂载到List of external loadable drivers中 solib_list
│   │
│   └──遍历solib_list上挂载的所有struct shared_driver结构
│         │
│         ├──如果当前struct shared_driver结构所保存的路径是目录
│         │   │
│         │   └──eal_plugindir_init
│         │         │
│         │         └──对目录中的每个普通文件,执行eal_plugin_add
│         │                (将文件挂载到Listof external loadable drivers的尾部,待接下来的遍历循环进行处理)
│         │
│         └──否则,是共享库的情况
│               │
│               └──调用dlopen打开指定的动态链接库
│
├──eal_option_device_parse (EAL的“-b、-w、--vdev”选项可以指定需要解析支持的设备 eal_option_device_add)
│   │
│   ├──如果全局变量链表有挂载指定支持的设备的话devopt_list
│   │   │
│   │   └──rte_devargs_parse 解析后,存放到全局链表 devargs_list 里面
│   │         │
│   │         ├──calloc一个struct rte_devargs 结构
│   │         │
│   │         ├──rte_devargs_parse读取系统所有设备,如果能找到表示属于合法设备
│   │         │
│   │         └──将此struct rte_devargs结构挂载到devargs_list
│   │
│   └──解析后的struct device_option从devopt_list删除
│
├──rte_config_init
│   │
│   ├──主进程的情况(RTE_PROC_PRIMARY) rte_config.mem_config这块内存,在初始化巨页之前,使用本地全局变量&early_mem_config临时使用
│   │   │      在rte_eal_config_create里面,rte_config.mem_config的内存改为配置文件/var/run/config,用来主从进程共享使用.
│   │   │
│   │   ├──rte_eal_config_create
│   │   │      │
│   │   │      ├──eal_runtime_config_path:获取runtime配置文件路径,如“/var/run/config”
│   │   │      │
│   │   │      ├──如果EAL配置了巨页映射的虚拟地址的话,在这里把它保存到 rte_mem_cfg_addr 变量里面
│   │   │      │
│   │   │      ├──打开文件,上锁,mmap映射文件到内存
│   │   │      │
│   │   │      ├──将early configuration structure(全局变量early_mem_config)拷贝到此内存中,
│   │   │      │   rte_config.mem_config指向这块内存,early_mem_config在巨页没初始化之前,用来当做早期简单配置使用的.
│   │   │      │
│   │   │      └──映射地址保存在rte_config.mem_config->mem_cfg_addr中,用于从应用将来映射到相同的地址
│   │   │
│   │   └──eal_update_mem_config 更新rte_config里面的rte_mem_config legacy_mem和single_file_segments变量,让从进程可以读取这个信息eal_update_internal_config
│   │   
│   └──从进程的情况(RTE_PROC_SECONDARY) 从进程先mmap /var/run/config,然后读取主进程的rte_mem_cfg_addr地址,最后在重新mmap /var/run/config,
│         │   这样做的目的是保证主从进程的rte_mem_cfg_addr虚拟地址和物理地址都是完全一样的.
│         │
│         ├──rte_eal_config_attach
│         │   │
│         │   ├──eal_runtime_config_path
│         │   │
│         │   ├──打开文件,mmap映射文件到内存
│         │   │
│         │   └──rte_config.mem_config指向映射的内存
│         │
│         ├──rte_eal_mcfg_wait_complete
│         │   │
│         │   └──如果struct rte_mem_config结构的magic成员没有被写成RTE_MAGIC,就继续等待
│         │          (主应用ready后会将struct rte_mem_config结构的magic成员写成RTE_MAGIC)
│         │
│         ├──rte_eal_config_reattach
│         │      │
│         │      ├──从前面mmap映射文件中获取主应用mmap的映射地址(即rte_config.mem_config->mem_cfg_addr)
│         │      │
│         │      ├──munmap解除先前的映射
│         │      │
│         │      ├──指定主应用映射地址重新执行mmap映射,如果最终映射地址和指定映射地址不一致,则出错退出
│         │      │
│         │      └──将rte_config.mem_config指向重新映射的内存
│         │
│         └──eal_update_internal_config读取主进程初始化的内存配置,保存到本地的internal_config.legacy_mem和internal_config.single_file_segments 
│
├──rte_eal_intr_init 初始化中断系统,dpdk把中断注册到epoll里面,通过epoll来处理发送的中断事件
│   │
│   ├──初始化global interrupt source head (struct rte_intr_source_list intr_sources)
│   │
│   ├──创建pipe,主要是用来唤醒eal_intr_thread_main重建中断列表,一般在用户注册了中断事件后,会write pipe,epoll read后重建中断列表
│   │
│   └──创建线程来等待处理中断,线程执行函数为eal_intr_thread_main
│      │
│      └──线程运行循环
│            │
│            ├──epoll_create:创建epoll文件描述符
│            │
│            ├──epoll_ctl:把前面创建的the read end of the pipe,添加到epoll wait list中
│            │
│            ├──遍历以global interrupt source head为头部的struct rte_intr_source结构链表
│            │   │
│            │   ├──如果当前struct rte_intr_source结构没有挂载的callback函数,跳过
│            │   │
│            │   └──把所有的uio device file descriptor,添加到epoll wait list中
│            │
│            ├──eal_intr_handle_interrupts
│            │   │
│            │   └──循环
│            │         │
│            │         ├──epoll_wait:wait for an I/O event on an epoll file descriptor
│            │         │
│            │         ├──eal_intr_process_interrupts
│            │         │   │
│            │         │   └──遍历所有发生的I/O event
│            │         │         │
│            │         │         ├──如果the read end of the pipe可用,执行read操作,函数返回
│            │         │         │    (此时会rebuild the wait list)
│            │         │         │
│            │         │         ├──遍历struct rte_intr_source结构链表,查找当前I/O event对应的structrte_intr_source结构
│            │         │         │
│            │         │         ├──根据interrupt handle type(uio/alarm/…),确定需要读取的字节长度
│            │         │         │
│            │         │         ├──执行文件read操作
│            │         │         │
│            │         │         └──如果read数据成功,执行当前struct rte_intr_source结构挂载的所有callback函数
│            │         │
│            │         └──调用eal_intr_process_interrupts返回负数,本次中断处理结束返回
│            │
│            └──关闭epoll文件描述符
│
├──rte_mp_channel_init 创建主从进程通信socket接口,使用AF_UNIX socket 类型,处理任务 mp_handle
│   │
│   ├──初始化socket路径 /var/run/mp_socket
│   │
│   ├──打开目录/var/run 加锁
│   │
│   ├──创建socket,主进程使用/var/run/mp_socket,从进程使用/var/run/mp_socket_getpid_rte_rdtsc, fd使用全局变量保存mp_fd
│   │
│   └──创建mp处理进程 mp_handle
│
├──rte_mp_dev_hotplug_init 注册主从进程通信的消息处理回调钩子,该动作是承接rte_mp_channel_init,
│   │                      rte_mp_channel_init初始化了处理任务mp_handle-->process_msg-->查找hotplug action
│   │
│   ├──主进程流程
│   │   │
│   │   ├── malloc 一个struct action_entry
│   │   │
│   │   ├── 初始化action_entry的action_name(EAL_DEV_MP_ACTION_REQUEST)和action(handle_secondary_request)
│   │   │
│   │   └── 增加action_entry到全局链表中action_entry_list
│   │
│   └──从进程流程
│       │
│       ├── malloc 一个struct action_entry
│       │
│       ├── 初始化action_entry的action_name(EAL_DEV_MP_ACTION_REQUEST)和action(handle_primary_request)
│       │
│       └── 增加action_entry到全局链表中action_entry_list
│
├──rte_bus_scan 扫描所有已注册设备的总线,主要有pci bus,还有其他厂家提供的总线,如DPAA bus,Intel FPGA bus
│       │
│       ├──循环获取设备总线链表 rte_bus_list
│       │
│       └──对每一个注册到的设备总线最新scan
│           │
│           ├──设备总线注册使用RTE_REGISTER_BUS
│           │
│           └──设备bus注册需要提供scan,probe,find_device,plug,unplug,parse,dev_iterate等函数实现,pci总线是 rte_pci_bus
│
├──初始化系统巨页 
│   │
│   ├──主进程 eal_hugepage_info_init:赋值struct hugepage_info数组(internal_config.hugepage_info)
│   │   │
│   │   ├──hugepage_info_init 读取系统巨页的信息,填充到internal_config.hugepage_info数组里面如果没有巨页数量可用,这里返回失败,
│   │   │    否则,hugepage_info数组里面按照巨页大小排序存储hugepage_info[0]>hugepage_info[1]>hugepage_info[2],这里是巨页大小不是巨页数量
│   │   │     │
│   │   │     ├── 打开系统的/sys/kernel/mm/hugepages目录,里面存在系统当前使用的巨页大小对应的信息
│   │   │     │
│   │   │     ├── 遍历/sys/kernel/mm/hugepages子目录信息,如果子目录以hugepages-开头,则继续处理,否则不处理,
│   │   │     │   一般有hugepages-2048kB或者hugepages-1048576kB两种存在
│   │   │     │
│   │   │     ├── /sys/kernel/mm/hugepages子目录数量不能超过dpdk运行的最大数,目前为3个
│   │   │     │
│   │   │     ├── 以数组方式,把系统不同巨页信息按顺序存放在internal_config.hugepage_info[]数组里面
│   │   │     │    │
│   │   │     │    └── get_hugepage_dir 根据系统巨页的大小,获取系统巨页mount路径
│   │   │     │         │
│   │   │     │         ├── 读取系统的/proc/mounts目录,里面存放了用户所有mount信息
│   │   │     │         │
│   │   │     │         ├── 获取默认的巨页大小,说白了就是获取系统默认的巨页大小,一般是2MB, 获取方式,cat /proc/meminfo |grep Hugepagesize
│   │   │     │         │
│   │   │     │         └── 循环判断/proc/mounts所有信息,如果有hugetlbfs的标识,表示是系统的巨页挂载点
│   │   │     │              │ 
│   │   │     │              ├── 一条mount信息包含四个选项,按顺序分别是device、mountpt、fstype、options分别按顺序存放到splitstr指针数组里面
│   │   │     │              │ 
│   │   │     │              ├── 如果用户设置了启动参数--huge-dir选项,就只检查这个目录是否存在
│   │   │     │              │ 
│   │   │     │              └── 查找mount信息里面的options,是否存在"pagesize="选项,如果是,则直接使用该页大小,否则使用默认的页大小
│   │   │     │         
│   │   │     ├── 系统总的可用巨页数量保存到internal_config.num_hugepage_sizes  
│   │   │     │    
│   │   │     └── 到此为止,internal_config里面关于巨页相关的变量基本都初始化了 
│   │   │
│   │   └──如果设置了不共享巨页信息,直接返回,否则下面会创建一个文件,把internal_config.hugepage_info信息存放到eal_hugepage_info_path里面,
│   │      让从进程可以attach,共享同一块内存
│   │       │
│   │       └──create_shared_memory 创建共享文件/var/run/hugepage_info,把internal_config.hugepage_info保存进去,让从进程可以读取
│   │
│   └──从进程 eal_hugepage_info_read
│              │
│              └──读取主进程存放在/var/run/hugepage_info文件里面的信息,读取出来保存到本地的internal_config.hugepage_info
│
├──rte_srand(rte_rdtsc()) 将当前时间作为种子,产生伪随机数序列
│

https://www.cnblogs.com/jiayy/p/dpdk-memory.html

1 dpdk 内存初始化源码解析
入口:
  rte_eal_init(int argc,char ** argv) dpdk 运行环境初始化入口函数
      —— eal_hugepage_info_init 这4个是内存相关的初始化函数
      ——rte_config_init
      ——rte_eal_memory_init
      ——rte_eal_memzone_init
1.1 eal_hugepage_info_init
这个函数比较简单,主要是从 /sys/kernel/mm/hugepages 目录下面读取目录名和文件名,从而获取系统的hugetlbfs文件系统数,
以及每个 hugetlbfs 的大页面数目和每个页面大小,并保存在一个文件里,这个函数,只有主进程会调用。存放在internal_config结构里

2.2 rte_config_init
构造 rte_config 结构
  rte_config_init
    ——rte_eal_config_create 主进程执行
    ——rte_eal_config_attach 从进程执行
rte_eal_config_create 和 rte_eal_config_attach 做的事情比较简单,就是将 /var/run/.config 文件shared 型

mmap 到自己的进程空间的 rte_config.mem_config结构上,这样主进程和从进程都可以访问这块内存

rte_eal_config_attach

1.3 rte_eal_memory_init

 rte_eal_memory_init

    ——rte_eal_hugepage_init   主进程执行,dpdk 内存初始化核心函数

    ——rte_eal_hugepage_attach  从进程执行

rte_eal_hugepage_init  函数分几个步骤:

/*
* Prepare physical memory mapping: fill configuration structure with
* these infos, return 0 on success.
* 1. map N huge pages in separate files in hugetlbfs
* 2. find associated physical addr
* 3. find associated NUMA socket ID
* 4. sort all huge pages by physical address
* 5. remap these N huge pages in the correct order
* 6. unmap the first mapping
* 7. fill memsegs in configuration with contiguous zones
*/

  

函数一开始,将rte_config_init函数获取的配置结构放到本地变量 mcfg 上,然后检查系统是否开启hugetlbfs,如果

不开启,则直接通过系统的malloc函数申请配置需要的内存,然后跳出这个函数。

接下来主要是构建 hugepage 结构的数组 tmp_hp(上图)

下面就是重点了。。

构建hugepage 结构数组分下面几步

首先,循环遍历系统所有的hugetlbfs 文件系统,一般来说,一个系统只会使用一种hugetlbfs ,所以这一层的循环可以认为

没有作用,一种 hugetlbfs 文件系统对应的基础数据包括:页面大小,比如2M,页面数目,比如2K个页面

其次,将特定的hugetlbfs的全部页面映射到本进程,放到本进程的 hugepage 数组管理,这个过程主要由 map_all_hugepages函数完成,

第一次映射的虚拟地址存放在 hugepage结构的 orig_va变量

第三,遍历hugepage数组,找到每个虚拟地址对应的物理地址和所属的物理cpu,将这些信息也记入 hugepage数组,物理地址

记录在hugepage结构的phyaddr变量,物理cpu号记录在 hugepage结构的socket_id变量

第四,跟据物理地址大小对hugepage数组做排序

第五,根据排序结果重新映射,这个也是由函数 map_all_hugepages完成,重新映射后的虚拟地址存放在hugepage结构的final_va变量

第六,将第一次映射关系解除,即将orig_va 变量对应的虚拟地址空间返回给内核

下面看 map_all_hugepages的实现过程

这个函数是复用的,共有两次调用。

对于第一次调用,就是根据hugetlbfs 文件系统的页面数m,构造

m个文件名称并创建文件,每个文件对应一个大页面,然后通过mmap系统调用映射到进程的一块虚拟地址

空间,并将虚拟地址存放在hugepage结构的orig_va地址上。如果该hugetlbfs有1K个页面,最终会在

hugetlbfs 挂载的目录上生成 1K 个文件,这1K 个文件mmap到进程的虚拟地址由进程内部的hugepage数组维护

对于第二次调用,由于hugepage数组已经基于物理地址排序,这些有序的物理地址可能有2种情况,一种是连续的,

另一种是不连续的,这时候的调用会遍历这个hugepage数组,然后统计连续物理地址的最大内存,这个统计有什么好处?

因为第二次的映射需要保证物理内存连续的其虚拟内存也是连续的,在获取了最大连续物理内存大小后,比如是100个页面大小,

会调用 get_virtual_area 函数向内涵申请100个页面大小的虚拟空间,如果成功,说明虚拟地址可以满足,然后循环100次,

每次映射mmap的首个参数就是get_virtual_area函数返回的虚拟地址+i*页面大小,这样,这100个页面的虚拟地址和物理地址

都是连续的,虚拟地址存放到final_va 变量上。

下面看 find_physaddr的实现过程

这个函数的作用就是找到hugepage数组里每个虚拟地址对应的物理地址,并存放到 phyaddr变量上,最终实现由函数

rte_mem_virt2phy(const void * virt)函数实现,其原理相当于页表查找,主要是通过linux的页表文件 /proc/self/pagemap 实现

/proc/self/pagemap 页表文件记录了本进程的页表,即本进程虚拟地址到物理地址的映射关系,主要是通过虚拟地址的前面若干位

定位到物理页框,然后物理页框+虚拟地址偏移构成物理地址,其实现如下

下面看 find_numasocket的实现过程

这个函数的作用是找到hugepage数组里每个虚拟地址对应的物理cpu号,基本原理是通过linux提供的 /proc/self/numa_maps 文件,

/proc/self/numa_maps 文件记录了本 进程的虚拟地址与物理cpu号(多核系统)的对应关系,在遍历的时候将非huge page的虚拟地址

过滤掉,剩下的虚拟地址与hugepage数组里的orig_va 比较,实现如下

sort_by_physaddr 根据hugepage结构的phyaddr 排序,比较简单

unmap_all_hugepages_orig 调用 mumap 系统调用将 hugepage结构的orig_va 虚拟地址返回给内核

上面几步就完成了hugepage数组的构造,现在这个数组对应了某个hugetlbfs系统的大页面,数组的每一个节点是一个

hugepage结构,该结构的phyaddr存放着该页面的物理内存地址,final_va存放着phyaddr映射到进程空间的虚拟地址,

socket_id存放着物理cpu号,如果多个hugepage结构的final_va虚拟地址是连续的,则其 phyaddr物理地址也是连续的。

下面是rte_eal_hugepage_init函数的余下部分,主要分两个方面,一是将hugepage数组里 属于同一个物理cpu,物理内存连续

的多个hugepage 用一层 memseg 结构管理起来。 一个memseg 结构维护的内存必然是同一个物理cpu上的,虚拟地址和物理

地址都连续的内存,最终的memzone 接口是通过操作memseg实现的;2是将 hugepage数组和memseg数组的信息记录到共享文件里,

方便从进程获取;

 

遍历hugepage数组,将物理地址连续的hugepage放到一个memseg结构上,同时将该memseg id 放到 hugepage结构

的 memseg_id 变量上

下面是创建文件 hugepage_info 到共享内存上,然后hugepage数组的信息拷贝到这块共享内存上,并释放hugepage数组,

其他进程通过映射 hugepage_info 文件就可以获取 hugepage数组,从而管理hugepage共享内存

 

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

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

相关文章

Python 利用PIL由多张图片合成gif动画

Python 由多张图片合成gif动画 案例 import os figure_save_path "file_fig_test" import warnings warnings.filterwarnings("error") import numpy as np np.random.seed(0) import matplotlib.pyplot as plt from PIL import Image import timenum 1…

​软考-高级-系统架构设计师教程(清华第2版)【第16章 嵌入式系统架构设计理论与实践(P555~613)-思维导图】​

软考-高级-系统架构设计师教程(清华第2版)【第16章 嵌入式系统架构设计理论与实践(P555~613)-思维导图】 课本里章节里所有蓝色字体的思维导图

将ArduinoIDE库文件移动到其他磁盘的方法

本文主要介绍更改软件包位置Arduino IDE (含2.0以上版本)的方法。 Arduino IDE 默认将软件包安装到 C 盘,如果你使用的开发板较多,产生的库文件很大,会导致 C 盘可用空间不足,博主只用了ESP开发板&#xf…

GCD:异步同步?串行并发?一文轻松拿捏!

GCD 文章目录 GCD进程线程进程与线程的关系进程与线程的区别 任务(执行的代码)队列线程与队列的关系 队列任务**同步执行任务(sync)**辅助方法**异步执行任务(async)**总结栅栏任务迭代任务 队列详细属性QoSAttributes…

CF1899 G. Unusual Entertainment [二维数点/二维偏序]

传送门:CF [前题提要]:没什么好说的,区域赛爆炸之后发愤加训思维题.秒了div3 A~F的脑筋急转弯,然后被G卡了,树剖dfs序的想法已经想到了,题目也已经化简为两个线段是否存在一个合法位置了.但是MD不会二维数点,用一个树剖扫描线搞来搞去最后还是Tle.果然如下图所说:科技还是十分…

掌握未来技术趋势,Python编程引领人工智能时代

掌握未来技术趋势,Python编程引领人工智能时代 摘要:Python作为一种高级编程语言,在人工智能领域中扮演着越来越重要的角色。本文将通过介绍Python编程的特点、应用场景及发展前景,展望Python未来的发展趋势,并结合代…

搭建mysql主从错误集合

1 mysqld --verbose --help --log-bin-index/tmp/tmp.Frnt2oibYI mysqld: Cant read dir of /etc/mysql/conf.d/ my.cnf是在/etc/mysql/conf.d/文件夹下,所以挂载的时候不要写/etc/mysql 2 COLLATION utf8_unicode_ci is not valid for CHARACTER SET latin1 配…

Windows10下Maven3.9.5安装教程

文章目录 1.下载maven2.安装3.配置系统变量3.1.新建系统变量 MAVEN_HOME3.2.编辑系统变量Path 4.CMD命令测试是否安装成功5.配置maven本地仓库6.配置国内镜像仓库 1.下载maven 官网 https://maven.apache.org/download.cgi 点击下载。 2.安装 解压到指定目录 D:\installSoft…

springcloudalibaba-3

一、Nacos Config入门 1. 搭建nacos环境【使用现有的nacos环境即可】 使用之前的即可 2. 在微服务中引入nacos的依赖 <!-- nacos配置依赖 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-…

​软考-高级-系统架构设计师教程(清华第2版)【第18章 安全架构设计理论与实践(P648~690)-思维导图】​

软考-高级-系统架构设计师教程&#xff08;清华第2版&#xff09;【第18章 安全架构设计理论与实践&#xff08;P648~690&#xff09;-思维导图】 课本里章节里所有蓝色字体的思维导图

【算法每日一练]-图论(保姆级教程 篇5(LCA,最短路,分层图)) #LCA #最短路计数 #社交网络 #飞行路线 # 第二短路

今天讲最短路统计和分层图 目录 题目&#xff1a;LCA 思路&#xff1a; 题目&#xff1a;最短路计数 思路&#xff1a; 题目&#xff1a;社交网络 思路&#xff1a; 题目&#xff1a;飞行路线 思路&#xff1a; 题目&#xff1a;第二短路 思路&#xff1a; 题目&a…

轻量服务器和云服务器的区别,轻量应用服务器和云服务器区别对比

在云计算时代&#xff0c;服务器作为互联网应用的基础设施&#xff0c;扮演着重要的角色。对于个人用户、个人开发者、学生用户和个人站长来说&#xff0c;选择一款适合自己的服务器是一个关键的决策。本文将介绍轻量服务器和标准云服务器的优点和应用场景&#xff0c;帮助读者…

深入理解ResNet网络:实现与应用

Resnet 在深度学习领域&#xff0c;卷积神经网络&#xff08;CNN&#xff09;是一种非常重要的模型&#xff0c;它在图像识别、目标检测等领域取得了显著的成果。然而&#xff0c;随着网络层数的增加&#xff0c;梯度消失和梯度爆炸问题变得越来越严重&#xff0c;导致训练深层…

Prometheus+Grafana环境搭建(window)

PrometheusGrafana环境搭建 1&#xff1a;配置Prometheus 1.1: 下载Prometheus安装包 官方下载地址 找到对应的win版本进行下载并解压 1.2 下载Window数据采集 官方下载地址 下载以管理员运行&#xff0c;安装成功后在服务里会出现一个"windows_exporter"采集…

原型网络Prototypical Network的python代码逐行解释,新手小白也可学会!!由于工作量大,准备整8个系列完事,-----系列5

文章目录 前言一、原始程序---计算原型&#xff0c;开始训练&#xff0c;计算损失二、每一行代码的详细解释2.1 粗略分析2.2 每一行代码详细分析 前言 承接系列4&#xff0c;此部分属于原型类中的计算原型&#xff0c;开始训练&#xff0c;计算损失函数。 一、原始程序—计算原…

IO流-序列化流

一&#xff0c;序列化&#xff08;把java对象写到对象中去&#xff09; 二&#xff0c; Object OutputStream(对象字节输出流) 三&#xff0c;案例 package BigDecimal;import java.io.FileOutputStream; import java.io.ObjectOutputStream;public class Main {public static…

upload-labs(1-17关攻略详解)

upload-labs pass-1 上传一个php文件&#xff0c;发现不行 但是这回显是个前端显示&#xff0c;直接禁用js然后上传 f12禁用 再次上传&#xff0c;成功 右键打开该图像 即为位置&#xff0c;使用蚁剑连接 连接成功 pass-2 源码 $is_upload false; $msg null; if (isse…

Springboot集成JDBC

1&#xff0c;pom.xml配置jar包 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> 2&#xff0c;配置数据源信息 server:port: 8088spring:datasource:dr…

Java-整合OSS

文章目录 前言一、OSS 简介二、OSS 的使用1. Bucket 的创建与文件上传2. 创建 RAM 与用户授权3. 图形化管理工具-ossbrowser 三、Java 整合 OSS1. 基本实现2. 客户端直传 前言 最近公司的技术负责人让我整合下 OSS 到项目中&#xff0c;所以花了一点时间研究了下 OSS&#xff…

Docker入门学习笔记

学习笔记网址推送&#xff1a;wDocker 10分钟快速入门_哔哩哔哩_bilibili docker是用来解决什么问题的&#xff1f; 例如当你在本地主机写了个web应用&#xff0c;而你打算将该应用发送给其他客户端进行案例测试和运行&#xff0c;若是传统做法&#xff0c;就比较复杂&#xf…