zoukankan      html  css  js  c++  java
  • dpdk初始化

    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()) 将当前时间作为种子,产生伪随机数序列
    │
  • 相关阅读:
    三步搭建精准召回体系,挽回流失用户
    HMS Core Insights第二期直播预告——华为定位技术让你重拾方向感
    如何区分router.push跳转快应用的来源渠道
    华为预测服务的构建原理是什么?该如何训练模型?
    HarmonyOS开发者日干货资料,奉上!
    技术硬核、体验新颖……HarmonyOS开发者日最值得关注的点都在这里
    Js中Proxy对象
    迭代器模式
    ed命令
    百度实习生前端面试面经
  • 原文地址:https://www.cnblogs.com/ggzhangxiaochao/p/12098653.html
Copyright © 2011-2022 走看看