亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 服務器 > Web服務器 > 正文

學習在kernel態下使用NEON對算法進行加速的方法

2024-09-01 13:53:22
字體:
來源:轉載
供稿:網友

本文跟著小編一起來學習在linux kernel態下如何使用NEON對算法進行加速的技巧,內容通過圖文實例給大家做了詳細分析,一起來看下。

ARM處理器從cortex系列開始集成NEON處理單元,該單元可以簡單理解為協處理器,專門為矩陣運算等算法設計,特別適用于圖像、視頻、音頻處理等場景,應用也很廣泛。

本文先對NEON處理單元進行簡要介紹,然后介紹如何在內核態下使用NEON,最后列舉實例說明。

一.NEON簡介

其實最好的資料就是官方文檔,Cortex™-A Series Programmer's Guide ,以下描述摘自該文檔

1.1 SIMD

NEON采用SIMD架構,single instruction multy data,一條指令處理多個數據,NEON中這多個數據可以很多,而且配置靈活(8bit、16bit、32bit為單位,可多個單位數據),這是優勢所在。

如下圖,APU需要至少四條指令完成加操作,而NEON只需要1條,考慮到ld和st,節省的指令更多。

 kernel,NEON,算法,加速

上述特性,使NEON特別適合處理塊數據、圖像、視頻、音頻等。

 1.2 NEON architecture overview

NEON也是load/store架構,寄存器為64bit/128bit,可形成向量化數據,配合若干便于向量操作的指令。

1.2.1 commonality with VFP         1.2.2 data type

kernel,NEON,算法,加速

 指令中的數據類型表示,例如VMLAL.S8:

kernel,NEON,算法,加速

1.2.3 registers 

32個64bit寄存器,D0~D31;同時可組成16個128 bit寄存器,Q0~Q15。與VFP公用。

kernel,NEON,算法,加速

寄存器內部的數據單位為8bit、16bit、32bit,可以根據需要靈活配置。

kernel,NEON,算法,加速

NEON的指令有Normal,Long,Wide,Narrow和Saturating variants等幾種后綴,是根據操作的源src和dst寄存器的類型確定的。

kernel,NEON,算法,加速

   kernel,NEON,算法,加速

1.2.4 instruction set

kernel,NEON,算法,加速

                     kernel,NEON,算法,加速

1.3 NEON 指令分類概述

指令比較多, 詳細可參考Cortex™-A Series Programmer's Guide。可大體分為:

NEON general data processing instructions   NEON shift instructions  NEON logical and compare operations  NEON arithmetic instructions NEON multiply instructions  NEON load and store element and structure instructions B.8 NEON and VFP pseudo-instructions

簡單羅列一下各指令

kernel,NEON,算法,加速

                kernel,NEON,算法,加速

                  kernel,NEON,算法,加速

                kernel,NEON,算法,加速

  kernel,NEON,算法,加速

無循環左移,負數左移按右移處理。

load和store指令不太好理解,說明一下。

  kernel,NEON,算法,加速

1.4 NEON 使用方式      

1.4.1 NEON使用方式

NEON有若干種使用方式:

C語言被編譯器自動向量化,需要增加編譯選項,且C語言編碼時有若干注意事項。這種方式不確定性太大,沒啥實用價值   NEON匯編,可行,匯編稍微復雜一點,但是核心算法還是值得的   intrinsics,gcc和armcc等編譯器提供了若干與NEON對應的inline函數,可直接在C語言里調用,這些函數反匯編時會直接編程響應的NEON指令。這種方式比較實用與C語言環境,且相對簡單。本文后續使用這種方式進行詳細說明。          1.4.2  C語言NEON數據類型

需包含arm_neon.h頭文件,該頭文件在gcc目錄里。都是向量數據。

typedef __builtin_neon_qi int8x8_t  __attribute__ ((__vector_size__ (8)));typedef __builtin_neon_hi int16x4_t  __attribute__ ((__vector_size__ (8)));typedef __builtin_neon_si int32x2_t  __attribute__ ((__vector_size__ (8)));typedef __builtin_neon_di int64x1_t;typedef __builtin_neon_sf float32x2_t  __attribute__ ((__vector_size__ (8)));typedef __builtin_neon_poly8 poly8x8_t  __attribute__ ((__vector_size__ (8)));typedef __builtin_neon_poly16 poly16x4_t  __attribute__ ((__vector_size__ (8)));typedef __builtin_neon_uqi uint8x8_t  __attribute__ ((__vector_size__ (8)));typedef __builtin_neon_uhi uint16x4_t  __attribute__ ((__vector_size__ (8)));typedef __builtin_neon_usi uint32x2_t  __attribute__ ((__vector_size__ (8)));typedef __builtin_neon_udi uint64x1_t;typedef __builtin_neon_qi int8x16_t  __attribute__ ((__vector_size__ (16)));typedef __builtin_neon_hi int16x8_t  __attribute__ ((__vector_size__ (16)));typedef __builtin_neon_si int32x4_t  __attribute__ ((__vector_size__ (16)));typedef __builtin_neon_di int64x2_t  __attribute__ ((__vector_size__ (16)));typedef __builtin_neon_sf float32x4_t  __attribute__ ((__vector_size__ (16)));typedef __builtin_neon_poly8 poly8x16_t  __attribute__ ((__vector_size__ (16)));typedef __builtin_neon_poly16 poly16x8_t  __attribute__ ((__vector_size__ (16)));typedef __builtin_neon_uqi uint8x16_t  __attribute__ ((__vector_size__ (16)));typedef __builtin_neon_uhi uint16x8_t  __attribute__ ((__vector_size__ (16)));typedef __builtin_neon_usi uint32x4_t  __attribute__ ((__vector_size__ (16)));typedef __builtin_neon_udi uint64x2_t  __attribute__ ((__vector_size__ (16)));typedef float float32_t;typedef __builtin_neon_poly8 poly8_t;typedef __builtin_neon_poly16 poly16_t;typedef struct int8x8x2_t{ int8x8_t val[2];} int8x8x2_t;typedef struct int8x16x2_t{ int8x16_t val[2];} int8x16x2_t;typedef struct int16x4x2_t{ int16x4_t val[2];} int16x4x2_t;typedef struct int16x8x2_t{ int16x8_t val[2];} int16x8x2_t;typedef struct int32x2x2_t{ int32x2_t val[2];} int32x2x2_t;typedef struct int32x4x2_t{ int32x4_t val[2];} int32x4x2_t;typedef struct int64x1x2_t{ int64x1_t val[2];} int64x1x2_t;typedef struct int64x2x2_t{ int64x2_t val[2];} int64x2x2_t;typedef struct uint8x8x2_t{ uint8x8_t val[2];} uint8x8x2_t;typedef struct uint8x16x2_t{ uint8x16_t val[2];} uint8x16x2_t;typedef struct uint16x4x2_t{ uint16x4_t val[2];} uint16x4x2_t;typedef struct uint16x8x2_t{ uint16x8_t val[2];} uint16x8x2_t;typedef struct uint32x2x2_t{ uint32x2_t val[2];} uint32x2x2_t;typedef struct uint32x4x2_t{ uint32x4_t val[2];} uint32x4x2_t;typedef struct uint64x1x2_t{ uint64x1_t val[2];} uint64x1x2_t;typedef struct uint64x2x2_t{ uint64x2_t val[2];} uint64x2x2_t;typedef struct float32x2x2_t{ float32x2_t val[2];} float32x2x2_t;typedef struct float32x4x2_t{ float32x4_t val[2];} float32x4x2_t;typedef struct poly8x8x2_t{ poly8x8_t val[2];} poly8x8x2_t;typedef struct poly8x16x2_t{ poly8x16_t val[2];} poly8x16x2_t;typedef struct poly16x4x2_t{ poly16x4_t val[2];} poly16x4x2_t;typedef struct poly16x8x2_t{ poly16x8_t val[2];} poly16x8x2_t;typedef struct int8x8x3_t{ int8x8_t val[3];} int8x8x3_t;typedef struct int8x16x3_t{ int8x16_t val[3];} int8x16x3_t;typedef struct int16x4x3_t{ int16x4_t val[3];} int16x4x3_t;typedef struct int16x8x3_t{ int16x8_t val[3];} int16x8x3_t;typedef struct int32x2x3_t{ int32x2_t val[3];} int32x2x3_t;typedef struct int32x4x3_t{ int32x4_t val[3];} int32x4x3_t;typedef struct int64x1x3_t{ int64x1_t val[3];} int64x1x3_t;typedef struct int64x2x3_t{ int64x2_t val[3];} int64x2x3_t;typedef struct uint8x8x3_t{ uint8x8_t val[3];} uint8x8x3_t;typedef struct uint8x16x3_t{ uint8x16_t val[3];} uint8x16x3_t;typedef struct uint16x4x3_t{ uint16x4_t val[3];} uint16x4x3_t;typedef struct uint16x8x3_t{ uint16x8_t val[3];} uint16x8x3_t;typedef struct uint32x2x3_t{ uint32x2_t val[3];} uint32x2x3_t;typedef struct uint32x4x3_t{ uint32x4_t val[3];} uint32x4x3_t;typedef struct uint64x1x3_t{ uint64x1_t val[3];} uint64x1x3_t;typedef struct uint64x2x3_t{ uint64x2_t val[3];} uint64x2x3_t;typedef struct float32x2x3_t{ float32x2_t val[3];} float32x2x3_t;typedef struct float32x4x3_t{ float32x4_t val[3];} float32x4x3_t;typedef struct poly8x8x3_t{ poly8x8_t val[3];} poly8x8x3_t;typedef struct poly8x16x3_t{ poly8x16_t val[3];} poly8x16x3_t;typedef struct poly16x4x3_t{ poly16x4_t val[3];} poly16x4x3_t;typedef struct poly16x8x3_t{ poly16x8_t val[3];} poly16x8x3_t;typedef struct int8x8x4_t{ int8x8_t val[4];} int8x8x4_t;typedef struct int8x16x4_t{ int8x16_t val[4];} int8x16x4_t;typedef struct int16x4x4_t{ int16x4_t val[4];} int16x4x4_t;typedef struct int16x8x4_t{ int16x8_t val[4];} int16x8x4_t;typedef struct int32x2x4_t{ int32x2_t val[4];} int32x2x4_t;typedef struct int32x4x4_t{ int32x4_t val[4];} int32x4x4_t;typedef struct int64x1x4_t{ int64x1_t val[4];} int64x1x4_t;typedef struct int64x2x4_t{ int64x2_t val[4];} int64x2x4_t;typedef struct uint8x8x4_t{ uint8x8_t val[4];} uint8x8x4_t;typedef struct uint8x16x4_t{ uint8x16_t val[4];} uint8x16x4_t;typedef struct uint16x4x4_t{ uint16x4_t val[4];} uint16x4x4_t;typedef struct uint16x8x4_t{ uint16x8_t val[4];} uint16x8x4_t;typedef struct uint32x2x4_t{ uint32x2_t val[4];} uint32x2x4_t;typedef struct uint32x4x4_t{ uint32x4_t val[4];} uint32x4x4_t;typedef struct uint64x1x4_t{ uint64x1_t val[4];} uint64x1x4_t;typedef struct uint64x2x4_t{ uint64x2_t val[4];} uint64x2x4_t;typedef struct float32x2x4_t{ float32x2_t val[4];} float32x2x4_t;typedef struct float32x4x4_t{ float32x4_t val[4];} float32x4x4_t;typedef struct poly8x8x4_t{ poly8x8_t val[4];} poly8x8x4_t;typedef struct poly8x16x4_t{ poly8x16_t val[4];} poly8x16x4_t;typedef struct poly16x4x4_t{ poly16x4_t val[4];} poly16x4x4_t;typedef struct poly16x8x4_t{ poly16x8_t val[4];} poly16x8x4_t;

 1.4.3  gcc的NEON函數

跟NEON指令對應,詳見gcc手冊。

kernel,NEON,算法,加速

 二.內核狀態下使用NEON的規則

在linux里,應用態可以比較方便使用NEON instrinsic,增加頭arm_neon.h頭文件后直接使用。但是內核態下使用NEON有較多限制,在linux內核文檔  /Documentation/arm/kernel_mode_neon.txt對此有詳細說明。要點為:

kernel,NEON,算法,加速

 還有一點特別關鍵:

kernel,NEON,算法,加速

 CC [M] /work/platform-zynq/drivers/zynq_fpga_driver/mmi_neon/lcd_hw_fs8812_neon.oIn file included from /home/liuwanpeng/lin/lib/gcc/arm-xilinx-linux-gnueabi/4.8.3/include/arm_neon.h:39:0,         from /work/platform-zynq/drivers/zynq_fpga_driver/mmi_neon/lcd_hw_fs8812_neon.c:8:/home/liuwanpeng/lin/lib/gcc/arm-xilinx-linux-gnueabi/4.8.3/include/stdint.h:9:26: error: no include path in which to search for stdint.h # include_next <stdint.h> 沒有使用-ffreestanding編譯選項時,在內核態下使用出現此編譯錯誤。             

 三.實例

NEON一般在圖像等領域,最小處理單位就是8bit,而不是1bit,這方便的例子非常多,本文就不說明了。在實際項目中,我需要對液晶的一組數據按位操作,變換,形成新的數據,如果用傳統ARM指令,掩碼、移位、循環,想想效率就非常低。于是決定使用NEON的位相關指令完成上述任務。

3.1 任務說明

如下圖,需要對各個bit進行轉換,組成新的數據。

 kernel,NEON,算法,加速

3.2 算法說明

使用vmsk、vshl、vadd等位操作完成。

3.3 kernel配置

必須配置內核支持NEON,否則kernel_neon_begin()和kernel_neon_end()等函數不會編輯進去。

make menuconfig:Floating point emulation,如下圖。

kernel,NEON,算法,加速

未使能“Support for NEON in kernel mode”時會報錯:mmi_module_amp: Unknown symbol kernel_neon_begin (err 0)mmi_module_amp: Unknown symbol kernel_neon_end (err 0)

3.4 模塊代碼

由于NEON代碼需要單獨設置編譯選項,所以單獨建立了一個內核模塊,makefile如下:

CFLAGS_MODULE += -O3 -mfpu=neon -mfloat-abi=softfp -ffreestanding 

核心代碼:

#include <linux/module.h> #include <linux/printk.h>#include <arm_neon.h>  // 來自GCC的頭文件,必須用-ffreestanding編譯選徐昂

#define LCD_8812_ROW_BYTES 16
#define LCD_8812_PAGE_ROWS 8
#define LCD_PAGE_BYTES (LCD_8812_ROW_BYTES*LCD_8812_PAGE_ROWS)

int fs8812_cvt_buf( uint8 * dst, uint8 * src ){  uint8x16_t V_src[8];  uint8x16_t V_tmp[8];  uint8x16_t V_dst[8];  uint8x16_t V_msk;  int8x16_t V_shift;  int8 RSHL_bits[8] = {0,1,2,3,4,5,6,7};  int8 row,bit;  uint8 page;  uint8 * fb_page_x = NULL;    // convert the frame_buf for fs8812  for( page=0;page<4;page++ ){    fb_page_x = src + page*LCD_PAGE_BYTES;    for( row=0;row<LCD_8812_PAGE_ROWS;row++ )      V_src[row] = vld1q_u8( fb_page_x + row*LCD_8812_ROW_BYTES );       for( bit=0;bit<8;bit++){        V_msk = vdupq_n_u8(1<<bit);        for( row=0;row<LCD_8812_PAGE_ROWS;row++){          V_tmp[row] = vandq_u8(V_src[row],V_msk);  // only process the desire bit          V_shift = vdupq_n_s8( RSHL_bits[row]-bit );          V_tmp[row] = vshlq_u8( V_tmp[row],V_shift );        }          V_dst[bit] = vorrq_u8(V_tmp[0],V_tmp[1]);   // all bit_x convert to one row        V_dst[bit] |= vorrq_u8(V_tmp[2],V_tmp[3]);        V_dst[bit] |= vorrq_u8(V_tmp[4],V_tmp[5]);        V_dst[bit] |= vorrq_u8(V_tmp[6],V_tmp[7]);              }      // store to ram      fb_page_x = dst + page*LCD_PAGE_BYTES;      for( row=0;row<LCD_8812_PAGE_ROWS;row++ ){         vst1q_u8(fb_page_x,V_dst[row]);        fb_page_x += LCD_8812_ROW_BYTES;      }  }  return 0;}EXPORT_SYMBOL_GPL(fs8812_cvt_buf);

調用模塊,務必沒有“-mfpu=neon -mfloat-abi=softfp ”選項

  // convert the frame_buf for fs8812  kernel_neon_begin();  fs8812_cvt_buf( g_tmp_buf, frame_buf );  kernel_neon_end();

 以上就是本篇文章的全部內容,大家有不懂的可以在下面留言區討論。

 

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91九色国产视频| 2020国产精品视频| 欧美激情精品久久久久| 97在线视频观看| 美女av一区二区| 国产日韩欧美日韩大片| 亚洲毛片在线看| 日韩av电影免费观看高清| 日韩在线免费av| 亚洲美女免费精品视频在线观看| 国产精品视频自拍| 亚洲午夜色婷婷在线| 亚洲国产福利在线| 欧美激情在线视频二区| 91精品久久久久久久久久另类| 国产69精品99久久久久久宅男| 国产成人精品免高潮费视频| 国产精品欧美日韩| 欧美大片免费观看在线观看网站推荐| 日韩黄色在线免费观看| 日韩综合视频在线观看| 日本精品视频在线播放| 久久精品91久久久久久再现| 国内精品久久久久影院 日本资源| 欧美在线xxx| 777777777亚洲妇女| 国产精品一二三在线| 久久精品久久久久久| 97视频在线播放| 亚洲综合色激情五月| 亚洲一区二区在线| 在线电影欧美日韩一区二区私密| 57pao成人永久免费视频| 亚洲欧美在线免费观看| 亚洲第一综合天堂另类专| 青青草国产精品一区二区| 亚洲第一天堂无码专区| 中文字幕无线精品亚洲乱码一区| 91日韩在线视频| 亚洲激情成人网| 久久久久久久网站| 久久久久久国产三级电影| 欧美日韩国产影院| 国产大片精品免费永久看nba| 国产中文字幕91| 日韩电影中文字幕在线观看| 亚洲国产精品免费| 成人黄色午夜影院| 91精品国产91久久久| 国产午夜精品麻豆| 亚洲综合中文字幕在线| 在线观看日韩专区| 亚洲欧美在线免费| 国产一区二区三区直播精品电影| 亚洲精品免费在线视频| 欧美专区国产专区| 亚洲最大福利视频网| 日本精品久久久久久久| 国产视频一区在线| 亚洲欧美中文日韩在线| 国内精品久久久久久久久| 国产在线精品播放| 北条麻妃99精品青青久久| 国产免费一区二区三区香蕉精| 色999日韩欧美国产| 欧美乱大交做爰xxxⅹ性3| 欧美日韩加勒比精品一区| 神马久久久久久| 欧美激情第1页| 欧美性色视频在线| 亚洲国产精彩中文乱码av| 国产精品电影一区| 国产日韩欧美视频| 国产伦精品免费视频| 日本a级片电影一区二区| 国产精品欧美风情| 欧美一性一乱一交一视频| 国产精品久久中文| 日韩在线小视频| 欧美日韩国产精品专区| 久久国产精品首页| 亚洲视频欧美视频| 国产精品久久久久免费a∨大胸| 91理论片午午论夜理片久久| 日本一本a高清免费不卡| 日韩在线中文字幕| 国产精品久久久久77777| 韩日欧美一区二区| 国产一区二区日韩| 91精品国产成人www| 欧美国产精品人人做人人爱| 国内成人精品视频| 久久视频在线播放| 欧美精品videossex88| 国产精品99导航| 亚洲毛茸茸少妇高潮呻吟| 欧美性猛交xxxx乱大交| 2023亚洲男人天堂| 国产精品久久久久久av| 青青草原成人在线视频| 26uuu久久噜噜噜噜| 亚洲成人在线网| 久久久亚洲天堂| 亚洲精品suv精品一区二区| 成人免费黄色网| 日韩国产精品亚洲а∨天堂免| 国产成人精品免高潮在线观看| 91香蕉嫩草神马影院在线观看| 亚洲视频在线免费观看| 77777亚洲午夜久久多人| 欧美色欧美亚洲高清在线视频| 欧美精品第一页在线播放| 九九热精品视频| 欧美成人精品xxx| 青青久久aⅴ北条麻妃| 91精品国产91久久久久久久久| 日韩国产精品亚洲а∨天堂免| 久久综合88中文色鬼| 欧美性生交xxxxx久久久| 国产欧美日韩中文| 久久久伊人欧美| 国产精品亚洲自拍| 亚洲综合日韩中文字幕v在线| 91禁国产网站| 国产视频综合在线| 欧美日韩国产精品专区| 亚洲va欧美va国产综合久久| 精品国内自产拍在线观看| 色婷婷av一区二区三区在线观看| 欧美日韩一区二区三区| 91系列在线观看| 亚洲美女av在线播放| 俺去啦;欧美日韩| 日韩精品视频免费在线观看| 亚洲成人精品av| 久久影院中文字幕| 欧美另类极品videosbest最新版本| 日韩小视频在线| 尤物99国产成人精品视频| 国产女人18毛片水18精品| 国产午夜精品免费一区二区三区| 欧美久久精品午夜青青大伊人| 国产视频久久久久久久| 欧美性在线观看| 91色精品视频在线| 2019中文字幕全在线观看| 91欧美精品午夜性色福利在线| 日韩免费在线视频| 亚洲一区二区少妇| 精品美女永久免费视频| 久久中文字幕在线视频| 国产成人在线一区二区| 91极品女神在线| 国产精品成熟老女人| 亚洲免费视频一区二区| 日韩av理论片| 欧美日韩亚洲一区二| 欧美日韩国产二区| 亚洲欧美一区二区三区四区| 亚洲色图综合网| 中文字幕欧美日韩va免费视频| 久久久久久国产精品三级玉女聊斋| 97精品欧美一区二区三区| 精品国产91久久久久久老师|