写在前面
本系列记录了作者在项目过程中由于好奇心驱使而了解到的部分 DPDK 实现细节。比较适合有同样好奇心的 DPDK 的初学者,通过本系列文章
您可以学习到
DPDK 的整体工作原理以及部分实现细节
您不能学习到
应用 DPDK 进行性能调优
如果对 DPDK 的起源不是很清楚的话,可以先浏览下 绝对干货!初学者也能看懂的 DPDK 解析,重点就是 Linux + x86 网络 IO 瓶颈 这部分,总结一句话就是 Linux 内核协议栈太慢了,为了突破这种性能瓶颈,DPDK 的方案是绕过 (bypass) 内核,直接从网卡把数据抓到用户空间。
一些基本的概念
EAL
首先必须明白的一点就是,DPDK 是以若干个 lib 的形式提供给应用链接使用,其中最终要的一个 lib 就是 EAL 了,EAL 的全称是(Environment Abstraction Layer, 环境抽象层),它负责为应用间接访问底层的资源,比如内存空间、线程、设备、定时器等。如果把我们的应用比作一个豪宅的主人的话,EAL 就是这个豪宅的管家。
lcore & socket
这两个概念在 DPDK 的代码中随处可见,注意这里的 socket 不是网络编程里面的那一套东西,而是 CPU 相关的东西。具体的概念可以参看 Differences between physical CPU vs logical CPU vs Core vs Thread vs Socket 或者其翻译版本 physical CPU vs logical CPU vs Core vs Thread vs Socket(翻译)。
对我们来说,只要知道可以 DPDK 可以运行在多个 lcore 上就足够了.
DPDK 如何知道有多少个 lcore 呢 ? 在启动时解析文件系统中的特定文件就可以了, 参考函数 eal_cpu_detected
DPDK 的运行形式
大部分 DPDK 的代码是以 lib 的形式运行在用户应用的进程上下文. 为了达到更高的性能。应用通常都会多进程或者多线程的形式运行在不同的 lcore 上
多线程的场景:
多进程的场景:
多进程的场景下,多个应用实例如何保证关键信息 (比如内存资源) 的一致性呢?答案是不同进程将公共的数据 mmap 同一个文件,这样任何一个进程对数据的修改都可以影响到其他进程。
Primary & Secondary
多进程场景下,进程有两种角色 Primary 或者 Secondary, 正如其名字,Primary 进程可以 create 资源,而 Secondary 进程只能 attach 已存在的资源。一山不容二虎,一个多进程的应用,有且只有一个 Primary 进程,其余都是 Secondary 进程。应用可以通过命令行参数 –proc-type 来指定应用类型。
DPDK 的入口
如同 main 函数在应用程序中的地位,rte_eal_init 函数便是 DPDK 梦开始的地方(其实前面的图已经画出来了!),我们来看看它做了什么事。
/* Launch threads, called at application init(). */
int
rte_eal_init(int argc, char **argv)
{
thread_id = pthread_self();
rte_eal_cpu_init();
eal_parse_args(argc, argv);
rte_config_init();
rte_eal_intr_init();
rte_mp_channel_init();
rte_eal_memzone_init();
rte_eal_memory_init();
rte_eal_malloc_heap_init()
eal_thread_init_master(rte_config.master_lcore);
RTE_LCORE_FOREACH_SLAVE(i) {
/* create a thread for each lcore */
ret = pthread_create(&lcore_config[i].thread_id, NULL,
eal_thread_loop, NULL);
…..
}
/*
* Launch a dummy function on all slave lcores, so that master lcore
* knows they are all ready when this function returns.
*/
rte_eal_mp_remote_launch(sync_func, NULL, SKIP_MASTER);
rte_eal_mp_wait_lcore();
……
}
总结起来就是
检测 lcore
解析用户的命令行参数
内存资源等子模块初始化
在其他 lcore 上启动线程