寫在前面
本系列記錄了作者在項目過程中由於好奇心驅使而瞭解到的部分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上啓動線程