dpdk-helloworld例程解析

dpdk-helloworld例程解析

  • `helloworld` 功能
  • `helloworld`编译
  • `helloworld`例程参数
  • `main.c`源码解析
  • 重要函数及宏定义
  • Makefile 源码解析(待理解)

helloworld 功能

在指定工作的核心上运行lcore_hello子程序(默认为所有核心),子程序的功能是获取绑定该线程的Core ID,并输出"hello from core #"。
其中主线程需等待子线程全部运行完毕后再结束运行。

helloworld编译

详见上一篇编译安装DPDK及例程的编译

helloworld例程参数

helloworld的参数比较重要的有:

 ./helloworld --help
EAL: Detected 4 lcore(s)
EAL: Detected 1 NUMA nodes

Usage: ./helloworld [options]

EAL common options:
  '-c COREMASK         Hexadecimal bitmask of cores to run on '
  //-c 例如:掩码0x0f 二进制就是1111 即低4位,4个核;
  '-n CHANNELS         Number of memory channels'
  //-n 内存通道数单通道1。双通道2。依次类推
  //对于虚拟机来说,分配的内存应该都是单通道的
  '--master-lcore ID   Core ID that is used as master'
  //--master-lcore 0 第0个核心运行主线程

main.c源码解析

/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright(c) 2010-2014 Intel Corporation
 */

#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 

static int
lcore_hello(__attribute__((unused)) void *arg)
{
     //子函数,由每个核心进行调用
	unsigned lcore_id;
	lcore_id = rte_lcore_id(); //获取当前的Core ID
	printf("hello from core %u\n", lcore_id);
	return 0;
}

int
main(int argc, char **argv)
{
     
	int ret; //错误码
	unsigned lcore_id;

	ret = rte_eal_init(argc, argv); //环境层EAL初始化
	if (ret < 0)
		rte_panic("Cannot init EAL\n");

	/* call lcore_hello() on every slave lcore */
	//遍历每一个核心,并获取其lcore_id
	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
     
		rte_eal_remote_launch(lcore_hello, NULL, lcore_id);
		//后通过rte_eal_remote_launch 在每个lcore上,启动被指定的线程。
	}

	/* call it on master lcore too 
	   在主线程上调用该函数         */
	lcore_hello(NULL);
	//等待所有线程都已经执行完毕
	rte_eal_mp_wait_lcore();
	return 0;
}

重要函数及宏定义

int rte_eal_init(int argc, char **argv);

此函数为启动基础运行环境的函数,入口参数为启动DPDK的命令行,也就是上文提到的参数。该函数本身所完成的工作比较复杂,它读取入口参数,解析并保存作为DPDK运行的系统信息,依赖这些信息,构建一个针对包处理设计的运行环境,其主要动作分解如下:

  • 配置初始化
  • 内存初始化
  • 内存池初始化
  • 队列初始化
  • 告警初始化
  • 中断初始化
  • PCI初始化
  • 定时器初始化
  • 检测内存本地化(NUMA)
  • 插件初始化
  • 主线程初始化
  • 轮询设备初始化
  • 建立主从线程通道
  • 将从线程设置在等待模式
  • PCI设备的探测与初始化

多核运行初始化:

int rte_eal_remote_launch(int (*f)(void *),void *arg,unsigned slave_id);

第一个参数是从线程需要执行的函数入口地址,
第二个参数是传给从线程的函数的参数,
第三个参数是指定的逻辑核,从线程会在该core上执行

RTE_LCORE_FOREACH_SLAVE(lcore_id){
     
}

应该是宏定义,遍历所有EAL指定可以使用的lcore。

Makefile 源码解析(待理解)

# SPDX-License-Identifier: BSD-3-Clause
# Copyright(c) 2010-2014 Intel Corporation

# binary name 本程序的二进制名
APP = helloworld

# all source are stored in SRCS-y 所有需要编译的文件
SRCS-y := main.c

# Build using pkg-config variables if possible 查看是否存在pkg-config
ifeq ($(shell pkg-config --exists libdpdk && echo 0),0)

all: shared
.PHONY: shared static
shared: build/$(APP)-shared
	ln -sf $(APP)-shared build/$(APP)
static: build/$(APP)-static
	ln -sf $(APP)-static build/$(APP)

PKGCONF ?= pkg-config

PC_FILE := $(shell $(PKGCONF) --path libdpdk 2>/dev/null)
CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk)
LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk)
LDFLAGS_STATIC = -Wl,-Bstatic $(shell $(PKGCONF) --static --libs libdpdk)

build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)

build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build
	$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC)

build:
	@mkdir -p $@

.PHONY: clean
clean:
	rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared
	test -d build && rmdir -p build || true

else

#判断RTE_SDK是否存在
#如果不存在则输出error,
#"Please define RTE_SDK environment variable"
ifeq ($(RTE_SDK),)
$(error "Please define RTE_SDK environment variable")
endif

# Default target, detect a build directory, by looking for a path with a .config
RTE_TARGET ?= $(notdir $(abspath $(dir $(firstword $(wildcard $(RTE_SDK)/*/.config)))))

include $(RTE_SDK)/mk/rte.vars.mk

CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS)

include $(RTE_SDK)/mk/rte.extapp.mk

endif

你可能感兴趣的:(dpdk)