DPU网络开发SDK—DPDK(八)

13 篇文章 3 订阅
rte_eal_init()函数负责DPDK环境的初始化,包括内存堆初始化,多进程间内存分配处理函数注册,尾队列初始化,计时器设置,主线程CPU亲和性配置,worker线程的启动和服务初始化等关键步骤。此过程确保DPDK环境准备就绪,能进行后续的配置和操作。
摘要由CSDN通过智能技术生成

rte_eal_init()

接上次内容继续对rte_eal_init()所做的工作进行分析。

25. 内存堆初始化

调用rte_eal_malloc_heap_init()进行初始化。

如果进程类型是primary的,需要额外先做如下工作:初始化mem_config.malloc_heaps数组,初始化元素的数量为当前socket的数量,即每个socket对应一个堆结构。

接下来调用register_mp_requests(),该func是注册多进程间内存分配的action处理函数,分进程是否是primary和非primary进行。

  • 进程是primary

            primary进程仅需要注册一个action,即MP_ACTION_REQUEST,相应的处理函数为handle_request。

            handle_request接收rte_mp_msg类型的消息,并从中提取出malloc_mp_req类型的请求。首先检查请求是否是重复请求,不是重复请求,则判断请求类型是alloc还是free。如果是alloc,调用handle_alloc_request()处理;如果是free,则调用malloc_heap_free_pages()处理。alloc和free处理完成之后,如果处理是失败的,调用rte_mp_sendmsg()发送fail结果对请求方;如果是成功的,则构造sync请求类型并多次调用rte_mp_request_async()直到同步完成。

  • 进程是非primary

            非primary进程需要注册多个action,包括MP_ACTION_SYNC,MP_ACTION_ROLLBACK,MP_ACTION_RESPONSE,前两个action处理函数都为handle_sync,最后一个action处理函数为handle_response。

            handle_sync接收类型为sync的请求,并调用eal_memalloc_sync_with_primary()来处理之。

            handle_response接收到response之后,调用find_request_by_id(),查找之前发送过的请求,如果存在,则调用pthread_cond_signal对请求做完结处理。

执行完register_mp_requests()注册了多进程内存分配处理函数之后,对于primary进程,需要额外调用malloc_add_seg()将所有iova连续内存区域加入到堆当中。malloc_add_seg是通过rte_memseg_contig_walk()调用的,contig_walk()实际上是前面提到的rte_memseg_list_walk()的变种,与list_walk()不同的是,contig_walk()在遍历memseg list时会将连续分配的memseg统一交给作为参数传入其中的func处理,这里的func参数即是malloc_add_seg。

26. 初始化尾队列

调用rte_eal_tailqs_init()来初始化,该func中遍历以全局变量rte_tailq_elem_head为头部的列表中的元素,元素类型为rte_tailq_elem,而每个元素又是一个列表头。对每个元素调用rte_eal_tailq_update()来进行初始化,同样primary和secondary进行。

  • 进程是primary

调用rte_eal_tailq_create(),首先去调用rte_eal_tailq_lookup()查找mem_config.tailq_head中是否已经创建好,没有创建则在mem_config.tailq_head中查找一个空闲项,初始化之后并返回。

  • 进程是secondary

调用rte_eal_tailq_lookup(),在mem_config.tailq_head中根据传入的名称进行匹配,查找匹配的项并返回。

27. 初始化计时器

调用rte_eal_timer_init()初始化计时器,该func调用set_tsc_freq()设定计时器的刷新频率,如果是secondary进程,直接用mem_config.tsc_hz作为全局变量eal_tsc_resolution_hz的值;如果是primary,则通过系统调用get_tsc_freq_arch()/get_tsc_freq()/estimate_tsc_freq()等获取到具体的值。

28. 检查main_lcore所在socket上的内存配置

调用eal_check_mem_on_local_socket(),获取main_lcore上所在的socket_id,并在list_walk()的帮助下调用check_socket()检查各memseg list的socket是否与main_lcore的socket相符。

29. 设置主线程的cpu亲和性

rte_eal_init()是由main线程启动的,在启动完成之后,他应该跑在main_lcore上,故调用pthread_setaffinity_np()将当前现场绑定在lcore_config[config->main_lcore].cpuset指定的处理核上。pthread_setaffinity_np()是Linux的系统调用。

接下来调用__rte_thread_init(),将main_lcore的值、当前线程的id、当前的socket id设定在per-lcore的内存空间当中

30. 为每个worker lcore启动线程

使用宏定义RTE_LCORE_FOREACH_WORKER遍历每个worker处理核,为每个处理核建立两条管道,分别是从main线程到该worker线程以及从该worker线程到main线程。接下来调用Linux系统调用pthread_create()启动一个线程,线程入口函数为eal_thread_loop();然后为线程设定名称,名称的格式为“lcore-worker-${worker lcore id}”;最后调用pthread_setaffinity_np()来设定worker线程的亲和性。

eal_thread_loop()这个线程完成以下工作:根据thread id在lcore_config中找到当前线程属于哪个lcore;调用__rte_thread_init(),将main_lcore的值、当前线程的id、当前的socket id设定在per-lcore的内存空间当中;最后进入一个无限循环执行如下工作:从main_to_worker管道接收消息,将线程设为running状态,并向worker_to_main管道写入确认消息;执行lcore_config[lcore_id].f函数指针指向的入口函数,将lcore_config[lcore_id].arg作为函数的参数;待入口函数执行完毕之后,将结果记录在lcore_config[lcore_id].ret当中;最后将线程状态设置为finish。

31.等待所有worker lcore的线程执行完毕

调用rte_eal_mp_wait_lcore()等待所有worker lcore上的线程变为finish状态。

32. 初始化service

调用rte_service_init(),初始化service类型的lcore。

33. 总线探测

调用rte_bus_probe(),遍历所有总线,调用总线的probe方法,其中vdev类型的总线只调用一次。以pci总线的probe为例,pci_probe()中,遍历总线上的每一个设备,去查找是否存在匹配的驱动,如果所有设备都没有找到匹配的驱动,则返回错误。

34. 按默认配置启动service

调用rte_service_start_with_defaults(),运行service处理函数。

35. 清理运行时目录

调用eal_clean_runtime_dir()清理掉runtime目录下的无用文件。

36. 初始化遥测接口

调用rte_telemtry_init(),开启一个线程,监听一个socket,接受外界发来的查询dpdk进程运行状态的请求。

37. 标记memconfig初始化完成

调用eal_mcf_complete(),标记internal_config->init_compelete为true,标识内存配置初始化完成。

到此为止,整个rte_eal_init()过程完全初始化完成,之后即可进行dpdk接下来的配置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值