DPDK源码学习——初始化

DPDK所有的宏定义基本都在rte_config.h(需要编译DPDK之后才会在目录中生成)中,所以第一个头文件应该为#include <rte_config.h>

DPDK首先初始化了Environment Abstraction Layer(EAL),EAL主要提供了以下功能:
• Intel® DPDK loading and launching
• Support for multi-process and multi-thread execution types
• Core affinity/assignment procedures
• System memory allocation/de-allocation
• Atomic/lock operations
• Time reference
• PCI bus access
• Trace and debug functions
• CPU feature identification
• Interrupt handling
• Alarm operations

主要的初始化动作:

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

EAL初始化参数:

  • -c COREMASK:要使用CPU core16进制掩码。注意core编号在不同的平台不一样,需要事先确定好。
  • -n NUM:每个处理器socket的内存通道数
  • -b domain:bus:devid.func:网口黑名单,EAL不能使用的PCI设备(可以同时存在多个-b选项)
  • –socket-mem:在指定socket上分配大页内存
  • -m MB:指定分配大大页内存数,不限处理器的socket。加以使用—socket-mem代替这个参数
  • -r NUM:内存的rank数
  • -v:显示程序版本号
  • –huge-dir:大页内存的挂载点
  • –file-prefix:大页内存文件的前缀
  • –proc-type:进程类型(primary,secondary,auto)
  • –xen-dom0:支持程序在Xen Domain0中非大页内存下运行
  • –vmware-tsc-map:使用VMware TSC代替本地的RDTSC
  • –base-virtaddr :指定虚拟地址的基址
  • –vfio-intr:指定VFIO使用的中断类型(如果不是用VFIO则无效)
    -c是必须的,其它都是可选的。

初始化程序

主要是在eal.c文件的rte_eal_init(int argc, char **argv)

int rte_eal_init(int argc, char **argv)
{
    int i, fctret, ret;
    pthread_t thread_id;
    static rte_atomic32_t run_once = RTE_ATOMIC32_INIT(0);
    const char *logid;
    char cpuset[RTE_CPU_AFFINITY_STR_LEN];
    char thread_name[RTE_MAX_THREAD_NAME_LEN];

    /* 只允许运行一次 */
    if (!rte_atomic32_test_and_set(&run_once))
        return -1;

    logid = strrchr(argv[0], '/');
    logid = strdup(logid ? logid + 1: argv[0]);

    thread_id = pthread_self();

    if (rte_eal_log_early_init() < 0)
        rte_panic("Cannot init early logs\n");

    eal_log_level_parse(argc, argv);

    /* set log level as early as possible */
    rte_set_log_level(internal_config.log_level);

    /* 获取系统中的CPU数量 */
    if (rte_eal_cpu_init() < 0)
        rte_panic("Cannot detect lcores\n");

    /* 根据命令行参数初始化internal_config */
    fctret = eal_parse_args(argc, argv);
    if (fctret < 0)
        exit(1);

     /* 获取系统中hugepage种类以及数量信息到internal_config.hugepage_info,用于后续内存初始化 */
    if (internal_config.no_hugetlbfs == 0 &&
            internal_config.process_type != RTE_PROC_SECONDARY &&
            internal_config.xen_dom0_support == 0 &&
            eal_hugepage_info_init() < 0)
        rte_panic("Cannot get hugepage information\n");

    /* 获取系统中所有hugepage内存大小,计算方法hugepage_sz*num_pages */
    if (internal_config.memory == 0 && internal_config.force_sockets == 0) {
        if (internal_config.no_hugetlbfs)
            internal_config.memory = MEMSIZE_IF_NO_HUGE_PAGE;
    }

    if (internal_config.vmware_tsc_map == 1) {
#ifdef RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT
        rte_cycles_vmware_tsc_map = 1;
        RTE_LOG (DEBUG, EAL, "Using VMWARE TSC MAP, "
                "you must have monitor_control.pseudo_perfctr = TRUE\n");
#else
        RTE_LOG (WARNING, EAL, "Ignoring --vmware-tsc-map because "
                "RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT is not set\n");
#endif
    }

    rte_srand(rte_rdtsc());

    /* 在/var/run或者用户的home目录创建.rte_config文件用于存储内存配置信息(rte_mem_config结构)
        如果process type为RTE_PROC_SECONDARY则等待PRIMARY完成内存初始化                */
    rte_config_init();

    /* 扫描系统中所有的PCI设备,并创建对应的device结构链到device_list中 */
    if (rte_eal_pci_init() < 0)
        rte_panic("Cannot init PCI\n");

#ifdef VFIO_PRESENT
    if (rte_eal_vfio_setup() < 0)
        rte_panic("Cannot init VFIO\n");
#endif

#ifdef RTE_LIBRTE_IVSHMEM
    if (rte_eal_ivshmem_init() < 0)
        rte_panic("Cannot init IVSHMEM\n");
#endif

    /* 初始化rte_config->mem_config,并映射hugepage到挂载目录下的文件rte_mapxx */
    if (rte_eal_memory_init() < 0)
        rte_panic("Cannot init memory\n");

    /* the directories are locked during eal_hugepage_info_init */
    eal_hugedirs_unlock();

    /* memzone可用内存初始化 */
    if (rte_eal_memzone_init() < 0)
        rte_panic("Cannot init memzone\n");

    if (rte_eal_tailqs_init() < 0)
        rte_panic("Cannot init tail queues for objects\n");

#ifdef RTE_LIBRTE_IVSHMEM
    if (rte_eal_ivshmem_obj_init() < 0)
        rte_panic("Cannot init IVSHMEM objects\n");
#endif

    if (rte_eal_log_init(logid, internal_config.syslog_facility) < 0)
        rte_panic("Cannot init logs\n");

    if (rte_eal_alarm_init() < 0)
        rte_panic("Cannot init interrupt-handling thread\n");

    /* 定时器 */
    if (rte_eal_timer_init() < 0)
        rte_panic("Cannot init HPET or TSC timers\n");

    /* 检查master core所在socket是否有内存 */
    eal_check_mem_on_local_socket();

    if (eal_plugins_init() < 0)
        rte_panic("Cannot init plugins\n");

    /* master线程绑定CPU */
    eal_thread_init_master(rte_config.master_lcore);

    ret = eal_thread_dump_affinity(cpuset, RTE_CPU_AFFINITY_STR_LEN);

    RTE_LOG(DEBUG, EAL, "Master lcore %u is ready (tid=%x;cpuset=[%s%s])\n",
        rte_config.master_lcore, (int)thread_id, cpuset,
        ret == 0 ? "" : "...");


    if (rte_eal_dev_init() < 0)
        rte_panic("Cannot init pmd devices\n");

    /* 创建与收包驱动通信用管道并初始化中断处理线程 */
    if (rte_eal_intr_init() < 0)
        rte_panic("Cannot init interrupt-handling thread\n");

    /* 创建lcore的主线程 */
    RTE_LCORE_FOREACH_SLAVE(i) {

        /*
         * create communication pipes between master thread
         * and children
         */
        if (pipe(lcore_config[i].pipe_master2slave) < 0)
            rte_panic("Cannot create pipe\n");
        if (pipe(lcore_config[i].pipe_slave2master) < 0)
            rte_panic("Cannot create pipe\n");

        lcore_config[i].state = WAIT;

        /* create a thread for each lcore */
        ret = pthread_create(&lcore_config[i].thread_id, NULL,
                     eal_thread_loop, NULL);
        if (ret != 0)
            rte_panic("Cannot create thread\n");

        /* Set thread_name for aid in debugging. */
        snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN,
            "lcore-slave-%d", i);
        ret = rte_thread_setname(lcore_config[i].thread_id,
                        thread_name);
        if (ret != 0)
            RTE_LOG(DEBUG, EAL,
                "Cannot set name for lcore thread\n");
    }

    /*
     * 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();

    /* Probe & Initialize PCI devices */
    if (rte_eal_pci_probe())
        rte_panic("Cannot probe PCI\n");

    rte_eal_mcfg_complete();
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SPDK(存储性能开发套件)官方文档中文版。 第一章 简介 1 1.1.什么是SPDK? 1 1.2.入门 1 1.3. Vagrant开发环境 3 1.4.更新日志(略) 6 第二章 概念 6 2.1. 用户空间驱动程序** 6 2.2. 来自用户空间的DMA** 7 2.3. 消息传递和并发** 9 2.4. NAND Flash SSD内部 13 2.5. 将I / O提交到NVMe设备** 15 2.5.1 NVMe规范 15 2.5.2 SPDK NVMe驱动程序I / O路径 15 2.6. 使用Vhost-user进行虚拟化I / O. 16 2.6.1 介绍 16 2.6.2 QEMU 17 2.6.3 设备初始化 18 2.6.4 I / O路径 19 2.6.5 SPDK优化 20 2.7. SPDK目录结构概述 20 2.8. SPDK移植指南 22 第三章 用户指南 22 3.1. 系统配置用户指南 22 3.1.1 IOMMU配置 22 3.2. SPDK应用程序概述 23 3.2.1 配置SPDK应用程序 23 3.3. iSCSI Target 26 3.3.1. iSCSI Target入门指南 26 3.3.2. 通过配置文件配置iSCSI Target 27 3.3.3. 通过RPC方法配置iSCSI Target 28 3.3.4. 配置iSCSI启动器 29 3.3.5. rpc配置示例*** 30 3.3.6. iSCSI 热插拔 32 3.4. NVMe over Fabrics Target 32 3.5. Vhost Target(略) 37 3.6 块设备用户指南 38 3.6.1 bdev介绍 38 3.6.2 通用RPC命令 38 3.6.3 Ceph RBD 39 3.6.4 压缩虚拟Bdev模块 40 3.6.5 加密虚拟Bdev模块 41 3.6.6 延迟vbdev模块 41 3.6.7 GPT(GUID分区表) 42 3.6.8 iSCSI bdev 43 3.6.9 Linux AIO bdev 43 3.6.10 OCF虚拟bdev 43 3.6.11 Malloc bdev 44 3.6.12 NULL bdev 44 3.6.13 NVMe bdev 44 3.6.14 逻辑卷Lvol 45 3.6.15 RAID 46 3.6.16 Passthru 46 3.6.17 Pmem 46 3.6.18 Virtio Block 47 3.6.19 Virtio SCSI 47 3.7 BlobFS(Blobstore文件系统) 48 3.7.1 RocksDB集成 48 3.7.2 FUSE插件 49 3.8 JSON-RPC方法(略) 49 第四章 程序员指南 49 4.1. Blobstore程序员指南 49 4.1.1 介绍 50 4.1.2 运作理论 50 4.1.3 设计注意事项 52 4.1.4 例子 54 4.1.5配置 54 4.1.6 组件细节 54 4.2. 块设备层编程指南 56 4.3 编写自定义块设备模块 58 4.3.1 介绍 58 4.3.2 创建一个新模块 59 4.3.3创建虚拟Bdev 60 4.4 NVMe over Fabrics目标编程指南 61 4.4.1 介绍 61 4.4.2 原语结构体 61 4.4.3 基础函数 62 4.4.4访问控制 62 4.4.5发现子系统 62 4.4.6 传输 63 4.4.7选择线程模型 63 4.4.8 跨CPU核心扩展 63 4.4.9 零拷贝支持 63 4.4.10 RDMA 63 4.5 Flash传输层 64 4.5.1 术语 64 4.5.2 使用方法 67 4.6 GDB宏用户指南 69 4.6.1 介绍 69 4.6.2 加载gdb宏 71 4.6.3 使用gdb数据目录 72 4.6.4 使用.gdbinit加载宏 72 4.6.5 为什么我们需要显式调用spdk_load_macros 72 4.6.6 以上可用的宏总结 73 4.6.7 添加新宏 73 4.7 SPDK “Reduce”块压缩算法 73 4.7.1 介绍 73 4.7.2 例子 74 4.8 通知库 78 第五章 基本信息 79 5.1 事件框架 79 5.1.1 事件框架设计注意事项 80 5.1.2 SPDK事件框架组件 80 5.1.3 应用框架 80 5.2 逻辑卷 81 5.2.1 术语 81 5.2.2 配置逻辑卷 84 5.3 矢量数据包处理(略) 86 第六章 杂项 86 6.1 介绍 86 6.2 NVMe的P2P API 86 6.3 确定设备支持 87 6.4 P2P问题 87 第七章 驱动程序 88 7.1 NVMe驱动程序*** 88 7.1.1 介绍 88 7.1.2 例子 88 7.1.3 公共接口 89 7.1.4 NVMe驱动程序设计 89 7.1.5 NVMe over Fabrics主机支持 91 7.1.6 NVMe多进程 91 7.1.7 NVMe Hotplug 92 7.2 I/OAT驱动程序 93 7.2.1 公共接口 93 7.2.2 关键功能 93 7.3 Virtio驱动程序 93 7.3.1 介绍 93 7.3.2 2MB大页面 93 第八章 工具 94 8.1 SPDK CLI 94 8.1.1 安装所需的依赖项 94 8.1.2 运行SPDK应用程序实例 94 8.1.3 运行SPDK CLI 94 8.1.4 可选 - 创建Python虚拟环境 94 8.2 nvme-CLI 95 8.2.1 nvme-cli with SPDK入门指南 95 8.2.2 使用场景 95 第九章 性能测试报告(略) 96 第十章NVMe-oF Target跟踪点*** 96 10.1 介绍 96 10.2 启用跟踪点 97 10.3 捕获事件的快照 97 10.4 捕获足够的跟踪事件 98 10.5 添加新的跟踪点 99

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值