随着科技的飞速发展,计算需求日益复杂和多样化,传统的单核处理器已难以满足所有应用场景的需求。在这样的背景下,异构多核系统应运而生,成为推动计算领域进步的重要力量。异构多核系统不仅提高了计算效率,还优化了能耗,为众多领域带来了革命性的变革。
异构多核系统是指在一个芯片上集成多种不同类型的处理器核心,这些核心可能采用不同的指令集架构(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) 协议的轻量级实现。RPMsg 协议定义了一个标准化的二进制接口,用于在异构多核系统中的多个核之间进行通信。与开放非对称多处理 (OpenAMP) 框架(https://github.com/OpenAMP/open-amp)的 RPMsg 实现相比,RPMsg-Lite 减少了代码大小、简化了 API 并改进了模块化。在较小的基于 Cortex-M0+ 的系统上,建议使用 RPMsg-Lite。RPMsg-Lite 是由 NXP Semiconductors 开发的开源组件,并在 BSD 兼容许可下发布。
.
├── 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 分层模型中的作用:
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 | 断言实施。 |
本文分享自 Rice 嵌入式开发技术分享 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!