dpdk多进程示例解读(examples/multi_process/simple_mp)

程序功能

进程之间的master和slave线程互发字串
dpdk多进程示例(examples/multi_process/simple_mp)

运行

启动primary和secondary进程

先启动primary进程,-l参数指定使用的逻辑核为core0和core1,–proc-type参数可以省略,默认第一个进程是primary进程,也可以指定值auto,表示自动检测进程的类型

simple_mp -l 0,1 --proc-type primary

程序启动会有大量的日志,初始化结束后,将进入程序命令行界面:

EAL: Detected lcore 0 as core 0 on socket 0
EAL: Detected lcore 1 as core 1 on socket 0
EAL: Detected lcore 2 as core 2 on socket 0
...
EAL: Master lcore 0 is ready (tid=c1f1e900;cpuset=[0])
...
Starting core 1
simple_mp >

secondary进程需要在primary进程之后启动,–proc-type参数必须指定(因为不指定该参数,将默认为primary进程,程序将初始化失败,因为已经存在了primary进程),值可以为secondary或auto:

simple_mp -l 0,1 --proc-type secondary

secondary进程启动后,同样进入simple_mp命令行。

simple_mp功能

simple_mp使用dpdk cmd_line完成命令行功能,启动simple_mp程序后,输入?可以查看支持的命令:

simple_mp > 
 send [Fixed STRING]: send a string to another process
 quit [Fixed STRING]: close the application
 help [Fixed STRING]: show help

也可以输入help查看帮助:

simple_mp > help
Simple demo example of multi-process in RTE

This is a readline-like interface that can be used to
send commands to the simple app. Commands supported are:

- send [string]
- help
- quit

primary进程发送字串

在primary进程的命令行中,输入:

simple_mp > send hello1

secondary进程将打印:

simple_mp > core 1: Received 'hello1'

在secondary进程执行send hello2,primary进程也将打印core 1: Received 'hello2'

分析

收发队列

main函数,将在primary进程创建两个ring队列
- 发送队列 PRI_2_SEC
- 接受队列 SEC_2_PRI

if (rte_eal_process_type() == RTE_PROC_PRIMARY){
    send_ring = rte_ring_create(_PRI_2_SEC, ring_size, rte_socket_id(), flags);
    recv_ring = rte_ring_create(_SEC_2_PRI, ring_size, rte_socket_id(), flags);
    message_pool = rte_mempool_create(_MSG_POOL, pool_size,
            string_size, pool_cache, priv_data_sz,
            NULL, NULL, NULL, NULL,
            rte_socket_id(), flags);
} else {
    recv_ring = rte_ring_lookup(_PRI_2_SEC);
    send_ring = rte_ring_lookup(_SEC_2_PRI);
    message_pool = rte_mempool_lookup(_MSG_POOL);
}

对于secondary进程,查找发送和接受队列,顺序跟primary相反:
- 发送队列 SEC_2_PRI
- 接受队列 PRI_2_SEC
当在primary进程执行send hello1时,cmd_send_parsed函数执行入队PRI_2_SEC逻辑:

/* simple_mp/mp_commands.c */
static void cmd_send_parsed(void *parsed_result,
        __attribute__((unused)) struct cmdline *cl,
        __attribute__((unused)) void *data)
{
    void *msg = NULL;
    struct cmd_send_result *res = parsed_result;

    if (rte_mempool_get(message_pool, &msg) < 0)
        rte_panic("Failed to get message buffer\n");
    snprintf((char *)msg, string_size, "%s", res->message);
    if (rte_ring_enqueue(send_ring, msg) < 0) {
        printf("Failed to send message - message discarded\n");
        rte_mempool_put(message_pool, msg);
    }
}

(primary进程)每个slave core上的线程,在SEC_2_PRI执行出队,master线程通过管道消息通知(rte_eal_remote_launch)每个slave线程执行lcore_recv函数:

static int
lcore_recv(__attribute__((unused)) void *arg)
{
    unsigned lcore_id = rte_lcore_id();

    printf("Starting core %u\n", lcore_id);
    while (!quit){
        void *msg;
        if (rte_ring_dequeue(recv_ring, &msg) < 0){
            usleep(5);
            continue;
        }
        printf("core %u: Received '%s'\n", lcore_id, (char *)msg);
        rte_mempool_put(message_pool, msg);
    }

    return 0;
}

内存管理

ring队列存储的是指针,所以内存需要自己申请。
primary进程创建名为MSG_POOL的内存池,可以存放1024个元素,每个元素的大小是64字节,逻辑核缓存32个元素。
secondary进程使用primary创建的内存池:

if (rte_eal_process_type() == RTE_PROC_PRIMARY){
    message_pool = rte_mempool_create(_MSG_POOL, pool_size,
            string_size, pool_cache, priv_data_sz,
            NULL, NULL, NULL, NULL,
            rte_socket_id(), flags);
} else {
    message_pool = rte_mempool_lookup(_MSG_POOL);
}

入队前,先获取内存池的一块内存:

if (rte_mempool_get(message_pool, &msg) < 0)
    rte_panic("Failed to get message buffer\n");
snprintf((char *)msg, string_size, "%s", res->message);
if (rte_ring_enqueue(send_ring, msg) < 0) {
    printf("Failed to send message - message discarded\n");
    rte_mempool_put(message_pool, msg);
}

出队后归还内存池:

if (rte_ring_dequeue(recv_ring, &msg) < 0){
    usleep(5);
    continue;
}
printf("core %u: Received '%s'\n", lcore_id, (char *)msg);
rte_mempool_put(message_pool, msg);

注意:本进程的slave线程收不到master线程的消息,master线程将消息入队到PRI_2_SEC,而slave从SEC_2_PRI队列读取消息

在线源码

http://dpdk.org/browse/dpdk/tree/examples/multi_process/simple_mp

你可能感兴趣的:(DPDK)