女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

CPU優(yōu)化技術(shù)-NEON自動(dòng)向量化

安芯教育科技 ? 來(lái)源:安謀科技學(xué)堂 ? 2023-01-11 14:53 ? 次閱讀

本文選自極術(shù)專(zhuān)欄《嵌入式AI》的文章,授權(quán)轉(zhuǎn)自知乎作者高性能計(jì)算學(xué)院的《移動(dòng)端算法優(yōu)化。前面我們學(xué)習(xí)了如何快速上手開(kāi)始NEON編程ArmNEON優(yōu)化技術(shù)Arm NEON 匯編與Intrinsics編程,CPU優(yōu)化技術(shù)之NEON介紹CPU 優(yōu)化技術(shù)-NEON 指令介紹本篇將會(huì)詳細(xì)介紹NEON 自動(dòng)向量化

一、概述

SIMD 作為一種重要的并行化技術(shù),在提升性能的同時(shí)也會(huì)增加開(kāi)發(fā)的難度。目前大多數(shù)編譯器都具有自動(dòng)向量化的功能,將 C/C++ 代碼自動(dòng)替換為 SIMD 指令。

從編譯技術(shù)上來(lái)說(shuō),自動(dòng)向量化一般包含兩部分:循環(huán)向量化(Loop vectorization)和超字并行向量化(SLP,Superword-Level Parallelism vectorization,又稱(chēng)Basic block vectorization)

演示代碼:

void add(int *a, int *b, int n, int * restrict sum)
{
    // it is assumed that the input n is an integer multiple of 4
    for (int i = 0; i < (n & ~3); ++i)
    {
        sum[i] = a[i] + b[i];
    }
}
  • 循環(huán)向量化將循環(huán)進(jìn)行展開(kāi),增加循環(huán)中的執(zhí)行代碼來(lái)減少循環(huán)次數(shù)。如以下代碼將循環(huán)次數(shù)精簡(jiǎn)到之前的1/4。
for (int i = 0; i < (n & ~3); i += 4)
{
    sum[i]     = a[i    ] + b[i];
    sum[i + 1] = a[i + 1] + b[i + 1];
    sum[i + 2] = a[i + 2] + b[i + 2];
    sum[i + 3] = a[i + 3] + b[i + 3];
}
  • SLP 向量化:編譯器將多個(gè)標(biāo)量運(yùn)算綁定到一起,使其成為向量運(yùn)算。下圖將四次標(biāo)量運(yùn)算替換為一次向量運(yùn)算。

495aabde-9110-11ed-bfe3-dac502259ad0.png

SLP 自動(dòng)向量化

接下來(lái)介紹如何通過(guò)編譯器實(shí)現(xiàn)自動(dòng)向量化。

二、編譯器配置

目前支持自動(dòng)向量化的編譯器有 Arm Compiler 6、Arm C/C++ Compiler、LLVM-clang 以及 GCC,這幾種編譯器間的相互關(guān)系如下表所示。

498f1838-9110-11ed-bfe3-dac502259ad0.png

自動(dòng)向量化默認(rèn)不會(huì)被啟用,編程人員需要向編譯器提供允許自動(dòng)向量化的“許可證”來(lái)對(duì)自動(dòng)向量化功能進(jìn)行使能

A.Arm Compiler 中使能自動(dòng)向量化

下文中 Arm Compiler 6 與 Arm C/C++ Compiler 使用 armclang 統(tǒng)稱(chēng),armclang 使能自動(dòng)向量化配置信息如下表所示:

49985a60-9110-11ed-bfe3-dac502259ad0.png

armclang 實(shí)現(xiàn)自動(dòng)向量化示例:

# AArch32
armclang --target=arm-none-eabi -mcpu=cortex-a53 -O1 -fvectorize main.c

# AArch64
armclang --target=aarch64-arm-none-eabi -O2 main.c

B. LLVM-clang中使能自動(dòng)向量化

Android NDK 從 r13 開(kāi)始以 clang 為默認(rèn)編譯器,本節(jié)通過(guò) cmake 調(diào)用Android NDK r19c 工具鏈展示 clang 的自動(dòng)向量化方法。

  • 使用 Android NDK 工具鏈?zhǔn)鼓茏詣?dòng)向量化配置參數(shù)如下表:

49a5ed38-9110-11ed-bfe3-dac502259ad0.png

  • 在 CMake 中配置自動(dòng)向量化方式如下:
# method 1
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O1 -fvectorize")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O1 -fvectorize")

# method 2
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")

C. GCC 中使能自動(dòng)向量化

在 gcc 中使能自動(dòng)向量化配置參數(shù)如下:

49b39eec-9110-11ed-bfe3-dac502259ad0.png

  • 在不明確配置 -mcpu 的情況下,編譯器將使用默認(rèn)配置(取決于編譯工具鏈時(shí)的選項(xiàng)設(shè)置)進(jìn)行編譯。

  • 通常情況下 -mfpu 和 -mcpu 的配置存在關(guān)聯(lián)性,對(duì)應(yīng)關(guān)系如下。(如當(dāng)選取-mcpu為cortex-a8時(shí),-mfpu一般設(shè)置為vfpv3或neon)

49c1dd7c-9110-11ed-bfe3-dac502259ad0.png

gcc 中實(shí)現(xiàn)自動(dòng)向量化的編譯配置如下

# AArch32
arm-none-linux-gnueabihf-gcc -mcpu=cortex-a53 -mfpu=neon -ftree-vectorize -O2 main.c

# AArch64
aarch64-none-linux-gnu-gcc -mcpu=cortex-a53 -ftree-vectorize -O2 main.c

此外,gcc 中可以通過(guò) -fopt-info-vec 命令查看自動(dòng)向量化的詳細(xì)信息,比如哪些代碼實(shí)現(xiàn)了向量化,哪些代碼沒(méi)有實(shí)現(xiàn)向量化及沒(méi)有進(jìn)行向量化的原因。

D. 自動(dòng)向量化實(shí)例

我們以上節(jié)的求和示例代碼,來(lái)對(duì)編譯器自動(dòng)向量化的功能進(jìn)行演示。編譯器以 32 位 arm-gcc 為例:

# automatic vectorization is not enabled
arm-none-linux-gnueabihf-gcc -O2 main.c -o avtest

# automatic vectorization is enabled
arm-none-linux-gnueabihf-gcc -mfpu=neon -ftree-vectorize -O2 main.c -o avtest
  • 使用 objdump 查看反匯編代碼,反匯編命令如下:
arm-none-linux-gnueabihf-objdump -d avtest > assemble.txt
  • 反匯編結(jié)果對(duì)比如下圖:

49cba10e-9110-11ed-bfe3-dac502259ad0.png

反匯編代碼

啟用自動(dòng)向量化之后,編譯器通過(guò)矢量化加載 (ldr -> vld1)求和 (add -> vadd)以及保存 (str -> vst1)等指令,將每次循環(huán)中處理的數(shù)據(jù)變?yōu)?4 個(gè),循環(huán)次數(shù)精簡(jiǎn)為之前的 1/4。

三、自動(dòng)向量化友好型代碼

基于一定的編程優(yōu)化準(zhǔn)則,可以更好的協(xié)助編譯器完成自動(dòng)向量化的工作,獲得理想的性能狀態(tài)。

A. 避免使用難以向量化的語(yǔ)句

  • 數(shù)據(jù)依賴(lài)

當(dāng)循環(huán)中存在數(shù)據(jù)依賴(lài)時(shí),編譯器無(wú)法進(jìn)行向量化。

下述代碼中計(jì)算 a[i] 時(shí)依賴(lài)上一次循環(huán)的輸出,無(wú)法被向量化。

// the output of a[i] depends on its last result
for (int i = 1; i < n; ++i)
{
    a[i] = a[i - 1] + 1;
}
  • 多級(jí)指針

編譯器無(wú)法對(duì)間接尋址,多級(jí)索引、多級(jí)解引用等行為進(jìn)行向量化,盡量避免使用多級(jí)指針。

下述代碼通過(guò) idx 進(jìn)行了多級(jí)索引,無(wú)法被向量化。

// idx is unpredictable, so this code cannot be vectorized
for (int i = 0; i < n; ++i)
{
    sum[idx[i]] = a[idx[i]] + b[idx[i]];
}
  • 條件及跳轉(zhuǎn)語(yǔ)句

當(dāng)循環(huán)中存在條件語(yǔ)句或跳轉(zhuǎn)語(yǔ)句時(shí),代碼很難被向量化。因此應(yīng)盡量避免在循環(huán)中的使用if、break等語(yǔ)句。當(dāng)循環(huán)中需要調(diào)用函數(shù)時(shí),盡量使用內(nèi)聯(lián)函數(shù)進(jìn)行替換。

下述代碼通過(guò)調(diào)用內(nèi)聯(lián)函數(shù) add_single2 避免發(fā)生函數(shù)跳轉(zhuǎn)。

__attribute__((noinline)) int add_single1(int a, int b);

__inline__ __attribute__((always_inline)) int add_single2(int a, int b);

void add(const int *a, const int *b, int n, int * restrict sum)
{
    for (int i = 0; i < (n & ~3); ++i)
    {
        // replace normal functions with inline functions
        // sum[i] = add_single1(a[i], b[i]);
        sum[i] = add_single2(a[i], b[i]);
    }
}
  • 長(zhǎng)數(shù)據(jù)類(lèi)型

neon 對(duì) 64 位長(zhǎng)數(shù)據(jù)類(lèi)型的支持有限,且較小的數(shù)據(jù)位寬有更高的并行度,應(yīng)盡量選用較小的數(shù)據(jù)類(lèi)型。當(dāng)程序中存在浮點(diǎn)數(shù)據(jù)時(shí),指明其數(shù)據(jù)類(lèi)型。

下述代碼指明1.0是浮點(diǎn)數(shù)據(jù),否則編譯器會(huì)優(yōu)先將其理解為double。

// assume that array sum and a are floating-point arrays
for (int i = 0; i < (n & ~3); ++i)
{
    // replace 1.0 with 1.f
    // sum[i] = a[i] + 1.0;
    sum[i] = a[i] + 1.f;
}

B. 增加自動(dòng)向量化信息

  • 地址交疊

指針操縱同一片數(shù)據(jù)區(qū)的情況被稱(chēng)為地址交疊。地址交疊會(huì)阻止自動(dòng)向量化操作。

當(dāng)程序不會(huì)發(fā)生地址交疊時(shí),用 restrict 限定符(C99 引入)在代碼中聲明指針?biāo)竻^(qū)域是獨(dú)立的。

下述代碼通過(guò)restrict限定 sum 與 a、b 間沒(méi)有地址交疊的情況

// add restrict before the output parameter sum
void add(const int *a, const int *b, int n, int * restrict sum)
  • 數(shù)組尺寸

明確數(shù)組尺寸,使其達(dá)到向量化處理長(zhǎng)度的整數(shù)倍。但應(yīng)注意處理不足向量化部分的剩余數(shù)據(jù)。

下述代碼通過(guò)掩碼操作表明處理循環(huán)次數(shù)是 4 的整數(shù)倍。

// make number of cycles is an integer multiple of 4, 
for (int i = 0; i < (n & ~3); ++i)
// don't forget to process the remaining data
  • 循環(huán)展開(kāi)

在一些編譯器中可以通過(guò)在 for 循環(huán)之前增加預(yù)處理語(yǔ)句告知編譯器循環(huán)展開(kāi)級(jí)數(shù)。

下述代碼告知 armclang 編譯器希望將循環(huán)展開(kāi) 4 次。

// #pragma unroll (4) // armcc
#pragma clang loop interleave_count(4) //armclang
for (int i = 0; i < n; ++i)
{
    // ...
}
  • 結(jié)構(gòu)體加載

編譯器僅會(huì)對(duì)每一成員都有操作的結(jié)構(gòu)體加載操作進(jìn)行自動(dòng)向量化,可以結(jié)合實(shí)際需求考慮去除用于結(jié)構(gòu)體對(duì)齊的填充數(shù)據(jù)。

下述代碼中刪除用于填充結(jié)構(gòu)體的變量 padding 以避免無(wú)法向量化。

struct st_align  
{    
    char r;    
    char g;
    char b;
    // delete the data used to populate the structure
    // char padding;
};
  • neon 加載指令要求結(jié)構(gòu)體中的所有項(xiàng)有相同的大小。

下述代碼中結(jié)構(gòu)體由于 short 類(lèi)型與 char 類(lèi)型不一致而不會(huì)被執(zhí)行自動(dòng)向量化。

struct st_align  
{    
    short r; // change short to char to get auto-vectoration
    char g;
    char b;  
};
  • 循環(huán)構(gòu)造

盡量通過(guò)

下述代碼通過(guò)調(diào)整i的范圍實(shí)現(xiàn)

// use '<' to construct a loop instead of '<='
// for(int i = 1; i <= n; ++i)
for (int i = 1; i < n + 1; ++i)
{
    // ...
}
  • 數(shù)組索引

當(dāng)對(duì)數(shù)組進(jìn)行操作時(shí),使用數(shù)組索引替代指針?biāo)饕?/span>

下述代碼通過(guò) sum[i]進(jìn)行索引,而不是*(sum + i)。

// replace arrary with pointer
// *(sum + i) = *(a + i) + *(b + i);
sum[i] = a[i] + b[i];

C. 重排數(shù)據(jù)實(shí)現(xiàn)緩存友好

  • 循環(huán)合并

當(dāng)數(shù)據(jù)連續(xù)存儲(chǔ)在結(jié)構(gòu)體中時(shí),可以進(jìn)行循環(huán)合并操作,即在一個(gè)循環(huán)內(nèi)處理臨近的數(shù)據(jù),提高緩存命中率。

下述代碼將 r、g、b 三個(gè)通道的處理合并到一個(gè)循環(huán)中。

// combine the rgb operation
/*
for (...)
{
    pixels[i].r = ....;
}  
for (...)
{
    pixels[i].g = ....;
}  
for (...)
{
    pixels[i].b = ....;
}
*/

// cache friendly code
for (...) 
{    
    pixels[i].r = ....;    
    pixels[i].g = ....;    
    pixels[i].b = ....;  
}

四、總結(jié)

本章節(jié)主要介紹了自動(dòng)向量化的相關(guān)內(nèi)容,其優(yōu)缺點(diǎn)對(duì)比如下:

49e3cf68-9110-11ed-bfe3-dac502259ad0.png

總之,雖然通過(guò)自動(dòng)向量化技術(shù)我們可以在一定程度上降低向量化編程難度,增強(qiáng)代碼的可移植性,但是不能完全依賴(lài)于編譯器,而且有時(shí)為了獲得更高性能的代碼,還是需要通過(guò)intrinsic甚至neon匯編進(jìn)行編程。

審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    11033

    瀏覽量

    215995
  • C++
    C++
    +關(guān)注

    關(guān)注

    22

    文章

    2117

    瀏覽量

    74778
  • 編譯器
    +關(guān)注

    關(guān)注

    1

    文章

    1655

    瀏覽量

    49890

原文標(biāo)題:Arm NEON學(xué)習(xí)(七)CPU 優(yōu)化技術(shù)-NEON 自動(dòng)向量化

文章出處:【微信號(hào):Ithingedu,微信公眾號(hào):安芯教育科技】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    CPU優(yōu)化技術(shù)自動(dòng)向量化實(shí)例

    SIMD 作為一種重要的并行化技術(shù),在提升性能的同時(shí)也會(huì)增加開(kāi)發(fā)的難度。目前大多數(shù)編譯器都具有自動(dòng)向量化的功能,將 C/C++ 代碼自動(dòng)替換為 SIMD 指令。
    發(fā)表于 10-08 09:31 ?2263次閱讀

    小白快速上手Arm NEON編程手冊(cè)指南

    開(kāi)始加速我們的應(yīng)用了。使用NEON 技術(shù)通常有下列四種方式:調(diào)用NEON優(yōu)化過(guò)的庫(kù)函數(shù)使用編譯器自動(dòng)
    發(fā)表于 07-15 15:38

    簡(jiǎn)述ARM SVE的發(fā)展以及和NEON的區(qū)別來(lái)探討Vector在AI中的應(yīng)用

    vector length是在每次循環(huán)中通過(guò)指令獲得的,這樣同一份代碼是可以不經(jīng)改動(dòng)跑在不同長(zhǎng)度的sve機(jī)器上,很好的解決了代碼移植的問(wèn)題。第三,隨著編譯技術(shù)的發(fā)展,對(duì)于自動(dòng)向量化的推進(jìn)也獲得了很大
    發(fā)表于 09-19 15:27

    使用SVE對(duì)HACCmk進(jìn)行矢量化的案例研究

    介紹隨著 Arm 引入 Scalable Vector Extensions (SVE) 作為 ARMv8-2 中的可選擴(kuò)展,編譯器自動(dòng)量化器可以在優(yōu)化 SVE 或 Neon 之間進(jìn)
    發(fā)表于 11-08 11:50

    如何使用Arm Compiler 6自動(dòng)量化功能為Neon編譯

    作為一名程序員,你可以通過(guò)多種方式使用Neon技術(shù): ?霓虹燈支持的開(kāi)源庫(kù),如Arm計(jì)算庫(kù)提供了一個(gè)最簡(jiǎn)單的利用Neon的方法。 ?編譯器中的自動(dòng)向量化功能可以
    發(fā)表于 08-02 19:31

    RealView編譯工具NEON量化編譯器指南

    RVCT提供了armcc--Vectorize,這是ARM編譯器的一個(gè)矢量化版本,它以帶有neon單元的ARM處理器為目標(biāo),比如Cortex-A8。 向量化意味著編譯器直接從C或C++代碼生成霓虹燈
    發(fā)表于 08-12 06:22

    NEON音頻編解碼器優(yōu)化技術(shù)

    本文旨在探討在采用NEON技術(shù)的ARM Cortex-A8處理器解決方案中部署音頻編解碼器時(shí)使用的各種優(yōu)化技術(shù)
    發(fā)表于 09-02 22:59 ?26次下載

    發(fā)掘函數(shù)級(jí)單指令多數(shù)據(jù)向量化的方法

    首先分析程序的變量屬性,然后利用一組包括向量函數(shù)予句、一致子句、線性子句等編譯指示予句指導(dǎo)編譯器實(shí)現(xiàn)函數(shù)級(jí)向量化,最后利用變量屬性結(jié)果對(duì)向量化代碼進(jìn)行了優(yōu)化。從多媒體和圖像處理領(lǐng)域選擇
    發(fā)表于 11-29 16:08 ?0次下載
    發(fā)掘函數(shù)級(jí)單指令多數(shù)據(jù)<b class='flag-5'>向量化</b>的方法

    基于Matrix的Givens旋轉(zhuǎn)的QR分解向量化方法

    提出一種基于Matrix的Givens旋轉(zhuǎn)的QR分解向量化方法。針對(duì)Matrix的體系結(jié)構(gòu)特點(diǎn),對(duì)向量數(shù)據(jù)訪存和計(jì)算進(jìn)行優(yōu)化,使計(jì)算均衡分布到各個(gè)向量處理單元;設(shè)計(jì)雙緩沖DMA的數(shù)據(jù)傳
    發(fā)表于 12-05 14:54 ?1次下載
    基于Matrix的Givens旋轉(zhuǎn)的QR分解<b class='flag-5'>向量化</b>方法

    控制流SIMD向量化方法

    SIMD擴(kuò)展部件是近年來(lái)集成到通用處理器中的加速部件,旨在發(fā)掘多媒體和科學(xué)計(jì)算等程序的數(shù)據(jù)級(jí)并行.控制依賴(lài)給發(fā)掘程序中的數(shù)據(jù)級(jí)并行帶來(lái)了阻礙,當(dāng)前,無(wú)論基于loop-based還是SLP的控制流向量化
    發(fā)表于 12-26 14:55 ?0次下載
    控制流SIMD<b class='flag-5'>向量化</b>方法

    DSP的并行指令分析和冗余優(yōu)化算法

    如今單指令多數(shù)據(jù)流( SIMD)技術(shù)在數(shù)字信號(hào)處理器(DSP)上得到了廣泛的應(yīng)用,現(xiàn)有的向量化編譯器大多都實(shí)現(xiàn)了自動(dòng)向量化的功能,但是編譯器并不適合支持DSP為特征的SIMD自動(dòng)向量化
    發(fā)表于 02-24 15:17 ?0次下載
    DSP的并行指令分析和冗余<b class='flag-5'>優(yōu)化</b>算法

    MATLAB的循環(huán)向量化編程方法的詳細(xì)資料研究

    在簡(jiǎn)要介紹MATLAB軟件基礎(chǔ)上,探討了MABLAB傳統(tǒng)循環(huán)結(jié)構(gòu)編程思想及循環(huán)向量化編程思想。通過(guò)實(shí)例對(duì)循環(huán)結(jié)構(gòu)編程與循環(huán)向量化編程進(jìn)行比較。說(shuō)明了循環(huán)向量化編程的優(yōu)點(diǎn)。循環(huán)向量化方法
    發(fā)表于 08-28 17:46 ?4次下載

    NEON編程中的一些常見(jiàn)優(yōu)化技巧

      讀過(guò)上一篇文章“ARM NEON快速上手指南”之后,相信你已經(jīng)對(duì)ARM NEON編程有了基本的認(rèn)識(shí)。但在真正利用ARM NEON優(yōu)化程序性能時(shí),還有很多編程技巧和注意事項(xiàng)。本文將結(jié)
    的頭像 發(fā)表于 12-12 09:11 ?2344次閱讀

    CPU優(yōu)化技術(shù)NEON 的基本原理、指令

    Arm NEON 是適用于 Arm Cortex-A 和 Cortex-R 系列處理器的一種 SIMD(Single Instruction Multiple Data)擴(kuò)展架構(gòu)。
    發(fā)表于 12-19 09:54 ?5213次閱讀

    CPU優(yōu)化技術(shù)層面講解Arm NEON

    NEON intrinsic 函數(shù)提供了一種編寫(xiě) NEON 代碼的方法,該方法比匯編代碼更易于維護(hù),同時(shí)仍然可以控制生成的 NEON 指令。
    發(fā)表于 12-26 10:18 ?2541次閱讀