gRPC在CPU-FPGA异构系统上的应用与展望

本文使用gRPC框架实现了CPU - FPGA异构系统的矩阵乘法运算。先介绍了gRPC协议及使用,接着阐述其在CPU - FPGA上的应用,包括背景、前置知识、核心代码实现,最后对比实验显示FPGA运算速度提升约8倍,认为异构系统未来将更重要。

0 本文主体内容与行文组织

本文使用gRPC框架简单实现了CPU-FPGA的异构系统关于矩阵乘法的运算,通过一个小的benchmark我们可以很直观地看到让具有特性的硬件去完成相关的运算,可以高效提升我们运算速率(本文提供的案例提升了8倍的计算速度)。文章是基于中科大孟老师的授课内容与笔者目前关注的一个小领域的简单结合。本文主要是分为三大部分,第一部分简单介绍了gRPC协议、第二部分介绍了具体的实现、第三部分是关于本文的总结以及鸣谢。

1 背景及介绍

1.1 什么是gRPC

wiki百科如是介绍:

gRPC 一开始由 google 开发,是一款语言中立、平台中立、开源的远程过程调用(RPC)系统。

因此在了解gRPC之前,我们需要先了解一下RPC。
RPC(Remote Procedure Call),直译为中文就是远程过程调用,是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一个地址空间(通常为一个开放网络的一台计算机)的子程序,而程序员就像调用本地程序一样,无需额外地为这个交互作用编程(无需关注细节)。RPC是一种服务器-客户端(Client/Server)模式,经典实现是一个通过发送请求-接受回应进行信息交互的系统。
详细介绍可以点此参考官方文档

**RPC 架构包含4个核心组件:**客户端(Client)、客户端存根(Client Stub)、服务端(Server)及服务端存根(Server Stub)。
(1)客户端:服务的调用者。
(2)客户端存根:存放服务端的服务列表,将客户端请求打包并通过网络发送到服务端。
(3)服务端:服务提供者。
(4)服务端存根:接收客户端消息并解包,然后调用本地的方法。
在这里插入图片描述
整个流程可以概括如下:

(1)客户端以本地调用的方式发起调用,这时调用的其实是客户端存根。

(2)服务端存根在收到调用后,负责将被调用的方法名、参数等打包并编码成特定格式的能进行网络传输的消息体。

(3)客户端存根将消息体通过网络发送给服务端。

(4)服务端存根通过网络接收到消息,按照相应的格式进行拆包、解码,获取方法名和参数。

(5)服务端存根根据方法名和参数进行本地调用,这时调用的是真正的服务提供者。

(6)服务提供者调用本地服务,然后将结果返回给服务端存根。

(7)服务端存根将返回值打包并编码成消息。

(8)服务端存根通过网络将消息发送给客户端。

(9)服务端存根在收到消息后,进行拆包、解码并返回给客户端。

(10)服务端存根得到本次RPC调用的最终结果。
在RPC中一般会用到动态代理、序列化反序列化、NIO网络通信、服务注册和发现等技术。

前文已经简单描述了RPC这种协议,而本文着重探讨的,则是Google基于RPC协议开发出来的框架gRPC,它是基于 ProtoBuf 序列化协议进行开发,支持多种语言(Golang、Python、Java等)。

gRPC 里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,能够更容易地创建分布式应用和服务。与许多 RPC 系统类似,gRPC 也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。
在这里插入图片描述

1.2 gRPC的使用

这部分可以参考中科大孟老师的文档,老师的文档非常详细实用,这里我不再画蛇添足。
孟老师的gRPC_Protobuf 快速编程指南
如果需要获取更为详细的文档信息,可以点此参阅官方文档

2 gRPC在CPU-FPGA上的使用

2.1 背景介绍

作为一个用户,我可能不想去关注具体的功能实现,而只是需要调用某个函数来完成我的需求,所以这个场景就相当合适使用gRPC来完成相关的计算。 比如我想完成一个矩阵的计算(由于个人水平原因,暂时只能实现这个),就可以在FPGA上完成相关的硬件布线资源然后在电脑上机进行相关的函数调用来完成计算。
在这里插入图片描述
经过我对gRPC这个框架的进一步了解,我发现它的使用更多是基于分布式框架的应用,刚好我实验室有块ZYNQ7010的FPGA板卡,因此我想尝试一下它的异构调用功能。FPGA是现场可编程门阵列。

现代的我们所使用的电脑的CPU指令是串行执行的,因为现在的计算机体系结构当中的指令流水线(Pipeline)是按照顺序执行的,当然,多核CPU虽然可以并行执行多个进程或线程,但本质上,仍然是基于串行的流水线。

而本文介绍的FPGA基于它特殊的结构,即可以并行执行一些计算,针对这一特性,我设计了一个16 × 16的脉动阵列块,来用于本文实例当中的两个16 × 16的矩阵块的计算,来探讨gRPC在异构系统当中通信的作用。

2.2 相关前置知识

FPGA(现场可编程门阵列) 拥有大量的“逻辑门”资源与布线资源,最基本的逻辑门如我们熟悉的与门,或门,非门,异或门。用户可以通过编写硬件verilog语言经过vivadoquarts综合生成对应的硬件电路,传统的CPUASIC芯片的硬件逻辑在出厂后就已经固定下来了,而FPGA可以多次擦写以实现不同的硬件逻辑。(个人理解,可能有些偏颇)

脉动阵列是一种二维硬件结构,其基本组成单元是一个乘法器和累加寄存器组成的计算单元(MAC),MAC 之间在水平和竖直方向上相互连接形成二维阵列。两个矩阵的输入数据从水平方向和竖直方向上流入,经过 n 个周期后在另一端得到计算结果
在这里插入图片描述
可以构造如下的脉动阵列,矩阵A的每一行从左侧输入,矩阵B的每一列元素向下输入,比如第一个cycle之后,元素
a00与元素·b00装入处理单元c00,第二个周期执行乘法然后存储在处理单元当中,元素a00与元素b00分别向左和向右流动,这样相比于传统的计算,矩阵元素不用重复加载,且计算可以并行进行,如下图3×3的矩阵而言,总体只需要6 cycle就能完成计算。
[图片]

2.3 核心源代码的实现

2.3.1 硬件布线的实现

block.v单元设计,这个单元主要负责乘法和加法

module pe(inp_north, inp_west, clk, rst, outp_south, outp_east, result);
	input [31:0] inp_north, inp_west;
	output reg [31:0] outp_south, outp_east;
	input clk, rst;
	output reg [63:0] result;
	wire [63:0] multi;
	always @(posedge rst or posedge clk) begin
		if(rst) begin
			result <= 0;
			outp_east <= 0;
			outp_south <= 0;
		end
		else begin
			result <= result + multi;
			outp_east <= inp_west;
			outp_south <= inp_north;
		end
	end
	assign multi = inp_north*inp_west;
endmodule

16 × 16的脉动阵列块
避免文章繁琐,这里仅给出核心代码块,部分代码重复较多已经省略。

//16 * 16 个block模块的实例化 
//16 * 16 个block模块的实例化 
`include "block.v"
module systolic_array(
              clk, rst, done);
    //from north and west
    block P0 (inp_north0, inp_west0, clk, rst, outp_south0, outp_east0, result0);
    block P1 (inp_north1, outp_east0, clk, rst, outp_south1, outp_east1, result1);
    block P2 (inp_north2, outp_east1, clk, rst, outp_south2, outp_east2, result2);
    block P3 (inp_north3, outp_east2, clk, rst, outp_south3, outp_east3, result3);
    block P4 (inp_north4, outp_east3, clk, rst, outp_south4, outp_east4, result4);
    block P5 (inp_north5, outp_east4, clk, rst, outp_south5, outp_east5, result5);
    block P6 (inp_north6, outp_east5, clk, rst, outp_south6, outp_east6, result6);
    block P7 (inp_north7, outp_east6, clk, rst, outp_south7, outp_east7, result7);
    block P8 (inp_north8, outp_east7, clk, rst, outp_south8, outp_east8, result8);
    block P9 (inp_north9, outp_east8, clk, rst, outp_south9, outp_east9, result9);
    block P10 (inp_north10, outp_east9, clk, rst, outp_south10, outp_east10, result10);
    block P11 (inp_north11, outp_east10, clk, rst, outp_south11, outp_east11, result11);
    block P12 (inp_north12, outp_east11, clk, rst, outp_south12, outp_east12, result12);
    block P13 (inp_north13, outp_east12, clk, rst, outp_south13, outp_east13, result13);
    block P14 (inp_north14, outp_east13, clk, rst, outp_south14, outp_east14, result14);
    block P15 (inp_north15, outp_east14, clk, rst, outp_south15, outp_east15, result15);
    //from west
    block p16 (outp_south0, inp_west16, clk, rst, outp_south16, outp_east16, result16);
    block p32 (outp_south16,inp_west32, clk, rst, outp_south32, outp_east32, result32);
    block P16 (outp_south0, inp_west16, clk, rst, outp_south16, outp_east16, result16);
    block P32 (outp_south16, inp_west32, clk, rst, outp_south32, outp_east32, result32);
    block P48 (outp_south32, inp_west48, clk, rst, outp_south48, outp_east48, result48);
    block P64 (outp_south48, inp_west64, clk, rst, outp_south64, outp_east64, result64);
    block P80 (outp_south64, inp_west80, clk, rst, outp_south80, outp_east80, result80);
    block P96 (outp_south80, inp_west96, clk, rst, outp_south96, outp_east96, result96);
    block P112 (outp_south96, inp_west112, clk, rst, outp_south112, outp_east112, result112);
    block P128 (outp_south112, inp_west128, clk, rst, outp_south128, outp_east128, result128);
    block P144 (outp_south128, inp_west144, clk, rst, outp_south144, outp_east144, result144);
    block P160 (outp_south144, inp_west160, clk, rst, outp_south160, outp_east160, result160);
    block P176 (outp_south160, inp_west176, clk, rst, outp_south176, outp_east176, result176);
    block P192 (outp_south176, inp_west192, clk, rst, outp_south192, outp_east192, result192);
    block P208 (outp_south192, inp_west208, clk, rst, outp_south208, outp_east208, result208);
    block P224 (outp_south208, inp_west224, clk, rst, outp_south224, outp_east224, result224);
    block P240 (outp_south224, inp_west240, clk, rst, outp_south240, outp_east240, result240);
    // 2 row

    block P17 (outp_south1, outp_east16, clk, rst, outp_south17, outp_east17, result17);
    block P18 (outp_south2, outp_east17, clk, rst, outp_south18, outp_east18, result18);
    block P19 (outp_south3, outp_east18, clk, rst, outp_south19, outp_east19, result19);
    block P20 (outp_south4, outp_east19, clk, rst, outp_south20, outp_east20, result20);
    block P21 (outp_south5, outp_east20, clk, rst, outp_south21, outp_east21, result21);
    block P22 (outp_south6, outp_east21, clk, rst, outp_south22, outp_east22, result22);
    block P23 (outp_south7, outp_east22, clk, rst, outp_south23, outp_east23, result23);
    block P24 (outp_south8, outp_east23, clk, rst, o
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值