www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當前位置:首頁 > 公眾號精選 > 嵌入式IoT

D1 riscv芯片上運行rt-thread進行RVV性能評估


  • 概述

  • rt-thread在D1芯片上的移植

  • 如何開啟D1&&D1s的rvv擴展

  • RVV性能對比評估

  • RVV在RTOS如何使用的更好


概述

D1 && D1s(f133)采用的是平頭哥C906的core,上面已經(jīng)支持了RVV 0.7.1版本,雖然目前RVV1.0已經(jīng)frozen,這就意味著上游編譯器或者一些相關(guān)的生態(tài)軟件將支持RVV1.0,但是作為性能評估RVV0.7.1與RVV1.0影響并不大。下面的文章主要描述如何在D1 && D1s芯片上運行rt-thread,并且描述如何開啟RVV,同時對RVV性能進行一個簡單的評估,最后討論RVV如何與RTOS使用的問題。

rt-thread在D1芯片上的移植

目前D1s有64MB的內(nèi)置DDR2,這非常適合運行RTOS,所以將rtos移植到D1s上是非常不錯的選擇。

其移植的細節(jié)不詳細介紹,可以查看源代碼

https://github.com/bigmagic123/d1-nezha-rtthread

移植的難點在于:

1.啟動,從芯片上電啟動入口處跳轉(zhuǎn)到rt-thread入口處的匯編代碼

2.硬件串口的初始化,這里會涉及到時鐘配置

3.tick時鐘中斷,目前采用的是riscv的通用timer,需要配置clic

4.任務(wù)切換和上下文的保存與恢復,這部分需要對入棧出棧的順序十分的清晰

5.串口中斷,這里需要弄清楚plic中斷處理機制

解決上述問題,移植rt-thread將非常的簡單,當前的rt-thread運行在M-mode,具有比較高的權(quán)限,可以隨意操作寄存器進行配置。

編譯與運行在windows和Linux上均可操作,主要參考如下的文檔:

https://github.com/bigmagic123/d1-nezha-rtthread/blob/main/README.md

目前已經(jīng)實現(xiàn)的功能有:

1.timer
2.uart
3.gpio
4.vector
5.FPU

如何開啟D1&&D1s的rvv擴展

想要使用RVV功能,需要開啟VS標志位,該位位于


VS位于MSTATUS寄存器的23到24位。但是需要注意的是,當使用RVV時,需要開啟浮點寄存器(FS),不然會報錯。

這部分在rt-thread的體現(xiàn)是在上下文切換的時候,需要將使用RVV的線程的MSTATUS設(shè)置成開啟VS的模式。


可以VS設(shè)置b01。

只有當使能該位,才能正常使用RVV指令,不然運行會直接報錯。

接著,編譯選項中還需要添加成如下選項

-march=rv64gcvxtheadc -mabi=lp64d -mtune=c906

這樣才能告訴編譯器支持RVV指令。

RVV性能對比評估

riscv 的RVV其編程模型主要有兩種方式,第一種采用rvv-intrinsic。這就是在編譯器中進行intrinsic函數(shù)的構(gòu)建,可以將相關(guān)的rvv操作變成編輯器的內(nèi)置函數(shù)。采用類似下面的函數(shù)方式進行編程。

vint8mf8_t vcopy_v_i8mf8 (vint8mf8_t src);
vint8mf4_t vcopy_v_i8mf4 (vint8mf4_t src);
...

其操作詳情可以參考:

https://github.com/riscv-non-isa/rvv-intrinsic-doc/

本質(zhì)上就是將復雜的匯編代碼操作換成C語言函數(shù)的形式,這種方式可讀性更強。rvv1.0后面也會提供這一種方式進行。

第二種就是采用匯編進行操作,裸寫匯編代碼的難度很大,但是可以實現(xiàn)比較好的優(yōu)化,這特別是在關(guān)鍵耗時的操作上進行匯編級別的優(yōu)化,可以很大程度上提升程序運行的性能。

在平頭哥開源出來的GCC工具鏈中,并沒有rvv-intrinsic功能,所以只能通過匯編函數(shù)的方式進行操作。

平頭哥開源出來了一個神經(jīng)網(wǎng)絡(luò)的庫,里面有C906的RVV底層操作。

https://github.com/T-head-Semi/csi-nn2

實現(xiàn)了一些基本的操作,抽象了各種常用的網(wǎng)絡(luò)層的接口,并且提供一系列已優(yōu)化的二進制庫。

其主要的使用類似于CMSIS,Tensorflow等等。有了這些抽象接口,在使用RVV進行特定優(yōu)化的時候,難度也會有所降低。

下面主要從csi-nn2抽取出vertor add,vertor mul,memcpy,也就是加法計算,乘法計算和內(nèi)存拷貝,三個方面,對其性能進行評估。

https://github.com/bigmagic123/d1-nezha-rtthread/blob/main/bsp/d1-nezha/applications/vector.c

浮點數(shù)加法

采用向量操作

float a[10] = {1.2,1.3,1.4,1.5,1.6,1.7,1.8,2.0,2.1,2.2}; float b[10] = {1.2,1.3,1.4,1.5,1.6,1.7,1.8,2.0,2.1,2.2}; float c[10];
element_mul_f32(a, b, c, 10);

一次性處理10個元素,采用RVV向量的操作。

普通的加法

for(ii = 0; ii < 10; ii++)
{
 d[ii] = a[ii] + b[ii];
}

單個元素相加。

分別計算30000次。

最后的結(jié)果如下:


采用向量加法只需要7ms,而直接相加,則消耗了36ms,性能相差5倍左右。

浮點數(shù)相乘

與加法操作類似,也是一次性處理10個元素

float a[10] = {1.2,1.3,1.4,1.5,1.6,1.7,1.8,2.0,2.1,2.2}; float b[10] = {1.2,1.3,1.4,1.5,1.6,1.7,1.8,2.0,2.1,2.2}; float c[10];
element_mul_f32(a, b, c, 10);

普通的乘法

for(ii = 0; ii < 10; ii++)
{
 d[ii] = a[ii] * b[ii];
}

兩者性能對比


向量乘法也比普通的乘法性能強大一些,接近5倍的差別。

內(nèi)存拷貝

內(nèi)存拷貝的測試方法是測試rt_memcpy,memcpy,csi_c906_memcpy。分別代表rt-thread內(nèi)置的內(nèi)存拷貝函數(shù),采用C語言進行實現(xiàn),memcpy是newlib庫函數(shù)的實現(xiàn),里面會對riscv架構(gòu)進行優(yōu)化處理,csi_c906_memcpy則是采用向量操作,進行內(nèi)存拷貝。

測試是先申請1MB的目標內(nèi)存,1MB的源內(nèi)存,往源內(nèi)存中寫隨機數(shù)。

拷貝源內(nèi)存中的數(shù)據(jù)到目標內(nèi)存,拷貝100次,也就是100M的內(nèi)存拷貝數(shù)據(jù)量。

結(jié)果如下:


顯然,內(nèi)存拷貝操作newlib中的memcpy性能是最佳的,而向量操作的memcpy反而其次,最差的是rt-thread的rt_memcpy。這里的原因是newlib的memcpy的是經(jīng)過優(yōu)化后的,而vector memcpy也可能是優(yōu)化的不好導致性能與newlib的memcpy相當。rt-thread采用純C語言實現(xiàn),其通用性比較好,但是性能不佳。

RVV在RTOS如何使用的更好

這是一個關(guān)于更好的在RTOS上使用RVV的問題,由于RTOS是為了追求實時性,一般來說,開啟了FPU和RVV后,其寄存器的數(shù)量會非常的多,每次入棧和出棧的操作,如果每次都將全部的寄存器壓入和彈出,將會讓切換任務(wù)的時間變長,影響了系統(tǒng)的實時性。對于這種情況,其實可以利用mstatus中的VS和FS的標志位進行判斷。



在切換任務(wù)時,可以通過這些標識,選擇是否壓棧和出棧,這樣保證了一部分性能實時性的情況下,也可以很好的處理FPU和RVV。


本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
關(guān)閉