前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >多核异构通信框架(RPMsg-Lite)

多核异构通信框架(RPMsg-Lite)

作者头像
Rice加饭
发布2024-03-12 08:32:54
3270
发布2024-03-12 08:32:54
举报
文章被收录于专栏:Rice嵌入式Rice嵌入式

概要

随着科技的飞速发展,计算需求日益复杂和多样化,传统的单核处理器已难以满足所有应用场景的需求。在这样的背景下,异构多核系统应运而生,成为推动计算领域进步的重要力量。异构多核系统不仅提高了计算效率,还优化了能耗,为众多领域带来了革命性的变革。

异构多核系统是指在一个芯片上集成多种不同类型的处理器核心,这些核心可能采用不同的指令集架构(ISA),具备不同的性能特性和功耗要求。这些核心可以是高性能的通用处理器核心,也可以是专为特定任务设计的专用核心,如图形处理单元(GPU)、数字信号处理器(DSP)或神经网络处理器(NPU)等。

异构多核系统的特点主要体现在以下几个方面:

  • 性能提升:通过结合不同类型的处理器核心,异构多核系统能够充分发挥各核心的优势,实现计算性能的大幅提升。例如,高性能核心可以处理复杂的计算任务,而专用核心则可以加速特定类型的数据处理。
  • 能效优化:异构多核系统能够根据任务需求动态调整核心的使用,避免资源浪费和不必要的功耗。对于计算密集型任务,可以使用高性能核心;而对于数据密集型任务,则可以利用专用核心进行高效的数据处理,从而实现能效比的最大化。
  • 灵活性:异构多核系统能够适应多样化的应用场景,通过灵活的任务调度和核心分配,满足不同任务的需求。这使得系统能够同时处理多种类型的任务,提高整体计算效率。
  • 并行处理:不同类型的核心可以并行工作,实现任务级别的并行处理。这种并行性可以进一步提高系统的整体性能,缩短计算时间。

多核通信

市面目前多核异构芯片形态:

形态

型号

核心组成

方案

ARM MCU系列

STM32H747XIH6U

ARM Cortex-M7 + ARM Cortex-M4

RTOS(裸机) + RTOS(裸机)

ARM MPU系列

RK3568

四核 ARM Cortex-A55

1. 核心0:Linux + 核心1~3:RTOS(裸机) 2. 核心0~2(SMP):Linux + 核心3:RTOS(裸机)

ARM MPU系列 + ARM MCU系列

STM32MP157

双核ARM Cortex-A7 + ARM Cortex-M4

双核ARM Cortex-A7:Linux(RTOS) + ARM Cortex-M4:RTOS(裸机)

ARM MPU系列 + RISC-V系列

V853

ARM Cortex-A7 + RISC-V

ARM Cortex-A7:Linux(RTOS) + RISC-V:RTOS(裸机)

RISC-V系列 + DSP系列 + ARM MCU系列

R128

RISC-V + HiFi5 DSP + ARM M33

RISC-V:RTOS + HiFi5 DSP:裸机 + ARM M33:RTOS

由于异构多核系统中集成了多种不同类型的处理器核心,这些核心之间需要进行高效的数据通信和协同工作,以确保整体系统的性能和稳定性。因此,通信机制在异构多核系统中扮演着至关重要的角色。为了确保核心间的顺畅通信,异构多核系统采用了多种通信协议和接口技术,如共享内存、消息传递接口(MPI)、高级可扩展接口(AEI)等。这些通信机制使得不同核心之间能够快速地传输数据、共享资源和协同执行任务,从而实现整体系统的高效运行。

异构多处理系统中往往会形成主-从(Master-Remote)结构。主核上的系统先启动,并负责准备好运行环境,然后根据需要或者一定规则启动从核并对其进行管理。主-从核心上的系统都准备好之后,他们之间就通过 IPC(Inter Processor Communication)方式进行通信,而 RPMsg 就是 IPC 中的一种。RPMsg,全称 Remote Processor Messaging,它定义了异构多核处理系统(AMP,Asymmetric Multiprocessing)中核与核之间进行通信时所使用的标准二进制接口。

常见的多核通信框架:OpenAMP, RPMsg,rpmsg-lite等,本片文章的主角是:rpmsg-lite

RPMsg-Lite介绍

RPMsg-Lite组件,它是远程处理器消息传递 (RPMsg) 协议的轻量级实现。RPMsg 协议定义了一个标准化的二进制接口,用于在异构多核系统中的多个核之间进行通信。与开放非对称多处理 (OpenAMP) 框架(https://github.com/OpenAMP/open-amp)的 RPMsg 实现相比,RPMsg-Lite 减少了代码大小、简化了 API 并改进了模块化。在较小的基于 Cortex-M0+ 的系统上,建议使用 RPMsg-Lite。RPMsg-Lite 是由 NXP Semiconductors 开发的开源组件,并在 BSD 兼容许可下发布。

  • RPMsg-Lite官方仓库:https://github.com/nxp-mcuxpresso/rpmsg-lite
  • RPMsg-Lite官方文档:https://nxp-mcuxpresso.github.io/rpmsg-lite
  • RPMsg-Lite源码目录:
代码语言:javascript
复制
.
├── common
│   └── llist.c
├── include
│   ├── environment
│   │   └── rt-thread
│   │       └── rpmsg_env_specific.h
│   ├── llist.h
│   ├── platform
│   │   └── RK3568
│   │       ├── rpmsg_config.h
│   │       └── rpmsg_platform.h
│   ├── rpmsg_compiler.h
│   ├── rpmsg_default_config.h
│   ├── rpmsg_env.h
│   ├── rpmsg_lite.h
│   ├── rpmsg_ns.h
│   ├── rpmsg_queue.h
│   ├── virtio_ring.h
│   └── virtqueue.h
├── rpmsg_lite
│   ├── porting
│   │   ├── environment
│   │   │   └── rpmsg_env_threadx.c
│   │   └── platform
│   │       └── RK3568
│   │           └── rpmsg_platform.c
│   ├── rpmsg_lite.c
│   ├── rpmsg_ns.c
│   └── rpmsg_queue.c
└── virtio
    └── virtqueue.c

创建目的

开发RPMsg-Lite的原因有多种:①是需要与RPMsg协议兼容的通信组件占用空间小;②是OpenAMP RPMsg实现的广泛API的简化。RPMsg协议没有记录,其唯一定义是由Linux内核和旧版OpenAMP实现给出的。这已经随着基于无锁共享内存的多核通信协议的出现而改变,它是一个标准化协议,允许多种不同的实现共存并且仍然相互兼容。

基于小型MC 的系统通常不实现动态内存分配。RPMsg-Lite中静态API的创建进一步减少了资源使用。动态分配不仅会额外增加5KB的代码大小,而且通信速度会变慢且确定性较差,这是动态内存引入的一个特性。下表显示了OpenAMP RPMsg实现和新RPMsg-Lite实现之间的一些粗略比较数据:

组件/配置

Flash[B]

RAM[B]

OpenAMP RPMsg / Release (reference)

5547

456 + dynamic

RPMsg-Lite / Dynamic API, Release

3462

56 + dynamic

Relative Difference [%]

~62.4%

~12.3%

RPMsg-Lite / Static API (no malloc), Release

2926

352

Relative Difference [%]

~52.7%

~77.2%

框架说明

RPMsg-Lite的实现可以分为三个子组件。核心组件位于rpmsg_lite.c中。其中rpmsg_ns.c和rpmsg_queue.c是可选的,两个可选组件用于实现阻塞接收API(在rpmsg_queue.c中和动态“命名”端点创建和删除公告服务(在rpmsg_ns.c中)。

实际的“媒体访问”层在virtqueue.c中实现,它是与 OpenAMP 实现共享的少数文件之一。该层主要定义了共享内存模型,内部定义了vring或者virtqueue等用到的组件。

移植层分为两个子层:环境层和平台层。第一个子层将针对每个环境单独实现。(裸机环境已经存在并在rpmsg_env_bm.c中实现,FreeRTOS 环境在rpmsg_env_freertos.c等中实现)只有与所使用的环境匹配的源文件才会包含在目标应用程序项目中。第二个子层在rpmsg_platform.c中实现,主要定义中断启用、禁用和触发的低级函数。情况如下图描述:

核心子组件

该子组件实现了阻塞发送 API 和基于回调的接收 API。RPMsg 协议是传输层的一部分。这是通过使用所谓的端点来实现的。每个端点可以分配不同的接收回调函数。然而,需要注意的是,在当前的设计中,回调是在中断环境中执行的。因此,不鼓励在回调中执行某些操作(例如内存分配)。下图显示了 RPMsg 在类 ISO/OSI 分层模型中的作用:

  • 队列子组件(可选):该子组件是可选的,需要在环境移植层中实现env_*_queue()函数。它使用阻塞接收API,这在RTOS环境中很常见。它支持复制和非复制阻塞接收功能。
  • 名称服务子组件(可选):该子组件是RPMsg的Linux内核实现中存在的名称服务的最小实现。它允许通信节点发送有关“命名”端点(即通道)创建或删除的公告,并在应用程序回调中采取任何用户定义的操作来接收这些公告。用于接收名称服务公告的端点地址被任意固定为53(0x35)。

应用

  1. 应用程序应将 /rpmsg_lite/lib/include 目录放入包含路径,并在应用程序中包含rpmsg_lite.h头文件,或者选择包含rpmsg_queue.h和/或rpmsg_ns.h文件。RPMsg-Lite提供两个移植子层,但如果计划使用其他的RTOS,您需要实现其他RTOS的环境层(例如,rpmsg_env_xxxrtos.c)并将其包含在项目构建中。
  2. 堆栈的初始化是通过调用主端的rpmsg_lite_master_init()和远程端的rpmsg_lite_remote_init()来完成的。该初始化函数必须在任何RPMsg-Lite API调用之前调用。在init之后,需要创建一个通信端点,否则通信是不可能的。通过调用rpmsg_lite_create_ept()函数来完成。可以选择接受最后一个参数,在该参数中创建端点的内部上下文,以防RL_USE_STATIC_API选项设置为1。如果不是,堆栈将在内部调用env_alloc()为其分配动态内存。如果要使用基于回调的接收,则使用用户定义的回调数据指针将ISR回调注册到每个新端点。如果需要阻塞接收(在 RTOS 环境的情况下),则必须在调用rpmsg_lite_create_ept()之前调用rpmsg_queue_create()函数。队列句柄作为回调数据参数传递给端点创建函数,并且回调函数设置为rpmsg_queue_rx_cb()。然后可以使用 rpmsg_queue_receive() 函数在队列对象上侦听传入消息。rpmsg_lite_send()函数用于向对方发送消息。
  3. RPMsg-Lite 还为发送和接收操作实现无复制机制。这些方法需要在应用程序中使用时必须考虑的细节。
  4. 无复制发送机制:该机制允许发送消息,而无需将数据从应用程序缓冲区复制到共享内存中的 RPMsg/virtio 缓冲区。要执行的无复制发送步骤的顺序如下:
    • 调用rpmsg_lite_alloc_tx_buffer()函数获取virtio缓冲区并将缓冲区指针提供给应用程序。
    • 将要发送的数据填充到预先分配的virtio缓冲区中。确保填充的数据不超过缓冲区大小(作为rpmsg_lite_alloc_tx_buffer()大小输出参数提供)。
    • 调用rpmsg_lite_send_nocopy()函数将消息发送到目标端点。考虑缓存功能和virtio缓冲区对齐。
  5. no-copy-receive机制:该机制允许读取消息,而无需将数据从共享内存中的virtio缓冲区复制到应用程序缓冲区。要执行的无复制接收步骤的顺序如下:
    • 调用rpmsg_queue_recv_nocopy()函数获取指向接收数据的virtio缓冲区指针。
    • 直接从共享内存中读取接收到的数据。
    • 调用rpmsg_queue_nocopy_free()函数释放virtio缓冲区并使其可用于下一次数据传输。
  6. 用户有责任在取消初始化时销毁他创建的任何RPMsg-Lite对象。为此,函数rpmsg_queue_destroy()用于销毁队列,rpmsg_lite_destroy_ept()用于销毁端点,最后,rpmsg_lite_deinit()用于取消初始化RPMsg-Lite核间通信堆栈。在取消初始化队列之前,使用队列取消初始化所有端点。否则,您将主动使已使用的队列句柄失效,这是不允许的。RPMsg-Lite不会在内部检查这一点,因为它的主要目标是轻量级。

配置选项

RPMsg-Lite可以在编译时进行配置。默认配置在rpmsg_default_config.h头文件中定义。用户可以通过包含具有自定义设置的rpmsg_config.h文件来自定义此配置。下表总结了所有可能的 RPMsg-Lite 配置选项。

配置选项

默认值

用法

RL_MS_PER_INTERVAL

(1)

用于轮询的非阻塞 API 函数中使用的延迟(以毫秒为单位)。

RL_BUFFER_PAYLOAD_SIZE

(496)

缓冲区有效负载的大小,它必须等于 (240, 496, 1008, ...) [2^n - 16]

RL_BUFFER_COUNT

(2)

缓冲区的数量,必须是 2 的幂 (2, 4, ...)

RL_API_HAS_ZEROCOPY

(1)

启用/禁用零复制 API 函数。

RL_USE_STATIC_API

(0)

启用/禁用静态 API 函数(无动态分配)。

RL_CLEAR_USED_BUFFERS

(0)

在返回到启用/禁用的空闲缓冲区池之前清除已使用的缓冲区。

RL_USE_MCMGR_IPC_ISR_HANDLER

(0)

当启用时,IPC 中断由多核管理器(IPC 中断路由器)管理;当禁用时,RPMsg-Lite 自行管理 IPC 中断。

RL_USE_ENVIRONMENT_CONTEXT

(0)

启用后,环境层使用自己的上下文。某些环境需要 (QNX)。默认值为 0(无上下文,节省一些 RAM)。

RL_DEBUG_CHECK_BUFFERS

(0)

启用后,将检查传递给rpmsg_lite_send_nocopy()和rpmsg_lite_release_rx_buffer()函数(由 RL_API_HAS_ZEROCOPY 配置启用)的缓冲区指针,以避免传递无效的缓冲区指针。默认值为 0(禁用)。请勿在 RPMsg-Lite 到 Linux 配置中使用。

RL_ALLOW_CONSUMED_BUFFERS_NOTIFICATION

(0)

启用后,每次接收到的缓冲区被消耗并放入可用缓冲区队列时,都会通知对方。在 RPMsg-Lite 到 Linux 配置中启用此选项,以允许解除 Linux 阻塞发送的阻塞。默认值为 0(RPMsg-Lite 到 RPMsg-Lite 通信)。

RL_ALLOW_CUSTOM_SHMEM_CONFIG

(0)

它允许定义自定义共享内存配置并替换 rpmsg_config.h 中与共享内存相关的全局设置。当多个实例并行运行但需要不同的共享内存排列(vring 大小和对齐、缓冲区大小和计数)时,这非常有用。默认值为 0(所有 RPMsg_Lite 实例使用由公共配置宏定义的相同共享内存排列)。

RL_ASSERT

请参阅rpmsg_default_config.h

断言实施。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-03-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Rice 嵌入式开发技术分享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概要
  • 多核通信
  • RPMsg-Lite介绍
    • 创建目的
      • 框架说明
        • 应用
          • 配置选项
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档