SylixOS 零拷贝详解

SylixOS 零拷贝详解

      SylixOS 1.4.5已经开始支持网络接收零拷贝,主要实现代码位于内核源码lwip里的netdev文件中。介绍零拷贝技术主要从两部分入手,一个是lwip内存的管理以及pbuf内存相关的知识,另一个就是当前网络报文接收流程。

1、lwip内存的管理       

(1)内存的类型
      lwip有两种方式的内存,heappool,即动态内存堆动态内存池
      heap:就是可以根据需要来进行分配对应的大小,这中内存利用率高,但容易产生内存碎片,它一般用于缓存应用层生成的数据。
      pool: 就是实现开辟一块内存池,里面有许多块大小已经定好的内存块,用的时候,直接拿这些内存块即可。这个类型的内存,分配快速,而且可以减少内存碎片,但会造成内存浪费。它一般用于缓存链路层生成的数据。

(2)
内存分配的方式

      上面说了内存有两种形式,那么分配无非就是两种:一种是从heap里面拿内存出来,一种是从pool里拿内存出来,说的官方点就是:动态内存堆分配策略动态内存池分配策略。
Ok. lwip里并不只支持上面这两种分配方式,Lwip还提供内存分配的第三种方式,就是使用C库自带的内存分配策略
 在配置内存时,有两个文件opt.h和lwipopts.h需要关注。
      在SylixOS里 lwipopts.h里面只有一句话,包含了一个头文件,这个头文件是lwip_config.h。这也是SylixOS里对网络的配置。在SylixOS里,opt.h和lwipopts.h这两个文件同时作用。

      在opt.h里有这样一段代码:               
  1.    ------------------------------------
  2.    ---------- Memory options ----------
  3.    ------------------------------------
  4. */
  5. /**
  6. * @defgroup lwip_opts_mem Heap and memory pools
  7. * @ingroup lwip_opts_infrastructure
  8. * @{
  9. */
  10. /**
  11. * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library
  12. * instead of the lwip internal allocator. Can save code size if you
  13. * already use it.
  14. */
  15. #if !defined MEM_LIBC_MALLOC || defined __DOXYGEN__
  16. #define MEM_LIBC_MALLOC                 0
  17. #endif

      MEM_LIBC_MALLOC等于0,说明SylixOS使用的是lwip自身的动态内存分配策略,而不是C库的
      另外,这里再说一下动态内存堆分配的方法,主要是两种:               
      (1)通过开辟一块内存对,然后通过模拟C库运行时的内存分配策略来实现。
      (2)(很扯淡)通过动态内存池的方式来实现,也即动态内存堆分配函数通过调用动态内存池分配函数来完成其功能。要想使用这个pool功能,需要同时定义MEM_USE_POOLS和MEMP_USE_CUSTOM_POOLS为1。
      SylixOS里这两个宏为0,即配置为使用第一种方式
      上面说了内存堆,在分析下内存池的分配策略:内存池的分配简单,会根据用户的配置宏,确定要为哪些东西分配内存池,如:初始化会建立TCP类型内存池、UDP类型内存池、PBUF内存池、CUSTOM_POOLS内存池等等。

2、pbuf类型

      这里需要明确一点的就是:我们现在的网卡驱动中创建的pbuf就是属于pbuf_pool类型。 这种类型的pbuf分配快,适合在驱动中使用,另外,这里再介绍一个新的知识,custom_pbuf,
顾名思义,这其实是一种用户可以管理的pbuf,它可以根据用户的需求,自己定义pbuf里面成员的属性。另外,
      最重要的一点就是这个种类型的pbuf,其释放方式不是通过pbuf_freeh函数释放,而是,可以用户自己写释放函数,当协议栈需要释放当前的这个custom_pbuf时,可以协议栈会调用用户自己写的释放函数释放。SylixOS的零拷贝机制就是通过custom_pbuf实现的。

3、报文接收流程        

      当前接收报文内存运行如下:
                         

      在不使用零拷贝的SylixOS机器上,现在的报文接收从底层一直到应用程序,应该只会做一次拷贝操作,这个拷贝操作就是在网卡驱动中,网卡驱动收到报文时,报文是位于DMA可以搬运的物理地中,此时网卡接收处理函数会做一次拷贝,将接收的报文拷贝到lwip协议栈管理的内存区,此时报文存在的形式就是通过pbuf进行管理的。在此之后,协议栈会通过pbuf拿到报文并对其做各种分析,最后,协议栈与应用层之间通过IPC(进程通信方式)来进行交互,因此这里并不会进行拷贝,而是应用程序会通过信号量,消息邮箱等机制去通知协议栈,让协议栈进行对应的处理。
      注意:这里的进行拷贝后的pbuf管理的数据是带cache的。
      下面,再来分析下零拷贝的处理方式:
                
               
      所谓的零拷贝就是将驱动收到报文拷贝到协议栈的这一次拷贝也去掉,要实现这一点思路也不复杂,即用户驱动接收的报文协议栈可以直接拿过来用。 协议栈要用,说明报文格式必须是pbuf管理。所以,要实现零拷贝,方法就显而易见了,即将分配给驱动用于接收的内存,让其变成pbuf的payload指针指向的内容即可。
      下面就来分析一下,SylixOS里的零拷贝实现机制:
      (1)用户网卡驱动里先创建一块大的零拷贝pbuf内存池zc_pool,后续的报文接收的pbuf都从这块池子里分配;
                  注:从池子里分配的pbuf是custom_pbuf
      (2)描述符初始化时,需要给其分配用于DMA搬运的内存,现在,我们分配内存时,并不是单纯的调用DMAmalloc去分配一块物理地址,而是先从第一步中分配的零拷贝的池子里获取一个零拷贝的pbuf,然后将pbuf所指向的内存地址赋值给DMA接收描述符。这样DMA收到报文时,会将报文放在pbuf的payload指向的内存。
      (3)此时,网卡接收处理函数里就并不需要在做拷贝了,而是直接将当前收到报文的描述符对应的pbuf传到协议栈,同时按照第二步的方法,给这个完成接收的描述符分配一块新的零拷贝pbuf。
      经过上面3步,pbuf就已经传送到协议找了,之后的处理就跟普通的pbuf是一样的,只是最后释放的时候,会调用自己的释放函数,其主要工作是将当期的这个零拷贝的pbuf返回到第一步创建的zc_pool中。

注意:
(1)在创建零拷贝pbuf内存池时,分配的地址一定要是DMA类型的,因为DMA搬运时处理的地址就是这个内存池里的地址;
(2)零拷贝适用于X86架构,原因与第一点有关,X86里对内存操作不需要考虑cache;而对于ARM来说,如果使用零拷贝确实可以省略一次拷贝,但是传到协议栈的pbuf也是不带cache的,而协议栈里要对报文不停的做分析操作,因此没有cache,每次都会从内存中取,速度反而会降低。

    • Related Articles

    • SylixOS 功能介绍及版本差异

      SylixOS功能介绍及版本差异 SylixOS 标准版 SylixOS 标准版是 SylixOS 的基础版本,具备如下功能: 兼容 IEEE 1003(ISO/IEC 9945)操作系统接口规范; 兼容 POSIX 1003.1b(ISO/IEC 9945-1)实时编程标准; 支持国军标 GJB7714-2012 操作系统接口规范; 优秀的实时性能(任务调度与切换算法时间复杂度为 O(1)); 支持无限多任务; 抢占式调度支持 256 个优先级; 支持虚拟进程; ...
    • SylixOS lite 版—基于 STM32F767 资源使用情况

      1、基本概念     代码段(text):顾名思义,代码存放的位置,在 STM32 中代码段一般存放于内置 FLASH 中; 已初始化数据段(data):已初始化数据段会分别体现在 FlASH 中和 RAM 中。因为是全局变量,运行过程中需要进行读写操作,因此占用一段 RAM 空间。又因为有初始值,其初始值需要占用 FlASH 空间。   未初始化的数据段(bss):bss 与 data 相同的地方时它也是全局变量,运行过程中需要进行读写操作,因此占用一段 RAM ...
    • error: xxx-sylixos-elf-lzocom.exe

      Q:IDE 在编译工程时出现:xxxx-sylixos-elf-lzocom.exe  应用程序出错。 应用程序无法正常启动(0xc000007b)。请单击“确定”关闭应用程序。信息如下图所示。 安装 vc2010_redist_x86.exe 即可解决此问题, 此文件在 IDE 软件安装包的 Tools 目录下(如 SylixOS IDE 3.9.11_professional\Tools) 。
    • 手动修改 SylixOS 工程类型的方法

       问题描述:        当我们想要通过 IDE 重新选择已有 SylixOS Project 的 base 时,如果 base 的类型需要变化,会遇到如下图所示的问题"SylixOS Base project invalid",导致无法选择想要的base。 问题原因:        当base类型变化了,创建SylixOS Project时,工程设置里设定了base的类型。 解决方法一:       ...
    • SylixOS 动态库更新 version 不一致的问题

      Q:SylixOS 动态库更新 version 不一致的问题 首先 SylixOS 是允许多个进程对共享库文件进行代码段共享的(默认是共享打开的,可以使用 dlconfig share dis 命令进行关闭),代码段共享会出现一个问题:当 A  进程 使用一个 share.so 共享库的时候,B 进程也使用 该 share.so 的共享库,share.so 共享库因为 B 的原因需要修改,修改后,更新share.so文件,然后重启 B 进程,一般来说会出现错误,错误如下: ...