主頁 > 企業開發 > 高效計算漢明重量

高效計算漢明重量

2022-04-30 14:44:21 企業開發

我在蘋果 m1 處理器上。

我正在嘗試做的是有效地計算 rust 中的大型 char 陣列中的 1 位。我查看了 arm neon 指令,我想我可以通過一條 cnt 指令(每 8 位塊計算 1)然后添加一個 addv 來添加每個 8 位塊。

首先,我想我會輸入一個 64 位的 uint。

fn aarch64_hamming_weight(inp: u64) -> u64 {
    let mut outp: u64;
    unsafe {
        asm!(
            "dup v0.2d, {input}",
            "cnt v0.16b, v0.16b",
            "addv b1, v0.16b",// this adds all the bytes of the vector, how do i get the result?!
            //"fmov {output2}, b1",
            "fmov {output}, v0.d[1]",
            input = in(reg) inp,
            output = out(reg) outp,
        )
    }

    return outp;
}

這幾乎可以作業,但是如果您的數字大于 8 位,那么結果就不太正確;225的二進制數是4 425的二進制數是260

所以

  1. 我需要一種方法來獲取 addv 的輸出
  2. 我需要一種方法來處理任意字符陣列(這需要一個回圈,一次拉 128 位)

uj5u.com熱心網友回復:

當我開始寫答案時,我認為它會表明行內 asm 完全沒有意義,而 RustC 將在矢量化方面做得很好u8.count_ones()不幸的是,情況并非如此,但是如果您要撰寫一個完整的回圈,而不是一次一個,則應該只使用 asm u64(可能仍然是行內匯編,但撰寫一個完整的函式可能是合理的。)

如果 Rust 具有用于 ARM/AArch64 的 SIMD 內在函式,那將是比行內 asm 更好的選擇,并且絕對值得使用。


為了計算整個陣列,您不希望將每個cnt結果分別減少為標量,尤其是不要一直減少到通用整數暫存器。尤其是u64一次不是一個,而不是一個完整的 128 位。添加到最后只減少的計數向量中。

clang/LLVM 知道如何__builtin_popcount()在 C 中的陣列上對 C 中的 popcount 進行自動矢量化,所以我希望基于 LLVM 的 RustC 可以用于 AArch64。這對 來說還可以u64,但不幸的是卻很糟糕u8如果您可以安全地將跨度指向u64您的資料(或參考,或者 Rust 會做什么?),那么您可以在沒有脆弱的行內匯編的情況下獲得很大一部分好處。并且以某種方式,未來的編譯器版本有望改進。

pub fn hamming_weight_arr(inp: &[u64]) -> u64 {
    let mut sum : u64 = 0;
    for v in inp {
        sum  = v.count_ones() as u64;  // maybe not terrible but a lot of hsumming.
        // doing ldp q2, q3 to load 32 bytes per iteration
    }
    return sum;
}

在https://godbolt.org/z/7qP7cK6bv編譯-O --target aarch64-unknown-linux-gnu(使用默認值-C --opt-level=3)。

... some setup
.LBB1_5:                                 // inner loop
        ldp     q2, q3, [x8, #-16]       // load pair of 16-byte vectors = unroll by 4x u64
        add     x8, x8, #32              // pointer increment by 32 bytes
        subs    x12, x12, #4
        cnt     v2.16b, v2.16b
        cnt     v3.16b, v3.16b
        uaddlp  v2.8h, v2.16b            // hsum byte pairs to u16 halfwords
        uaddlp  v3.8h, v3.16b
        uaddlp  v2.4s, v2.8h             // hsum u16 pairs to u32 words
        uaddlp  v3.4s, v3.8h
        uadalp  v0.2d, v2.4s          // sum u32 pairs into accumulator u64 vectors (doublewords)
        uadalp  v1.2d, v3.4s
        b.ne    .LBB1_5
        add     v0.2d, v1.2d, v0.2d        // combine pair of accumulators
        cmp     x10, x11
        addp    d0, v0.2d                  // and reduce to one 64-bit
        fmov    x8, d0
        b.eq    .LBB1_9
.LBB1_7:
        add     x10, x0, x1, lsl #3
.LBB1_8:
        ldr     d0, [x9], #8               // scalar cleanup loop, one u64 at a time
        cmp     x9, x10
        cnt     v0.8b, v0.8b
        uaddlv  h0, v0.8b                  // slow instruction, as Jake mentioned.  Or at least high latency
        fmov    w11, s0
        add     x8, x11, x8
        b.ne    .LBB1_8
.LBB1_9:
        mov     x0, x8
        ret

你會認為sum: u32會有所幫助,需要在回圈內減少。(如果您有可能溢位的巨大陣列,請使用外回圈)。但實際上,我認為 RustC 仍然擴展到 64 位,但隨后做了更多作業將這些計數截斷為 32 位。幾乎可以肯定是錯過了優化。(也許是一種圍繞 x86 構建的策略psadbw,它可以一步將位元組求和到 u64 塊中;LLVM 使用 pshufb 自動矢量化 popcount 以及 x86 上的 AVX2。)

你會認為對u8陣列做同樣的事情應該向量化到相同的代碼,只需要一些額外的標量清理,對吧? 好吧,它應該,但實際上它仍然只展開 4,就像 LLVM 喜歡做的那樣,但那是 4 個u8元素,內部回圈變成了完全的垃圾

// &[u8] version  inner loop is a disaster

LBB2_5:
        ldurb   w12, [x8, #-2]            // scalar zero-extending byte load
        subs    x11, x11, #4
        ldrb    w13, [x8]                 // scalar sign-extending byte load
        fmov    d2, x12                   // copy it into vector reg
        ldurb   w12, [x8, #-1]
        fmov    d3, x13
        ldrb    w13, [x8, #1]
        add     x8, x8, #4
        mov     v2.d[1], x12              // get two more bytes into the high 64 bits of a vector
        mov     v3.d[1], x13
        cnt     v2.16b, v2.16b           // same cnt / uaddlp sequence as before
        cnt     v3.16b, v3.16b
        uaddlp  v2.8h, v2.16b
        uaddlp  v3.8h, v3.16b
        uaddlp  v2.4s, v2.8h
        uaddlp  v3.4s, v3.8h
        uadalp  v0.2d, v2.4s
        uadalp  v1.2d, v3.4s
        b.ne    .LBB2_5

所以它是矢量化的(v as u64).count(),并使用它不知道如何優化的罐頭食譜。(例如,如果結果為零,除了每個 64 位塊的低位元組之外,uaddlp擴大是沒有意義的,他們可以只使用64 位塊的垂直。)cntadd


與來自https://github.com/WojciechMula/sse-popcount/的手動矢量化 ARM 代碼的 C 編譯器進行比較。如果 ARM Neon 代碼與同一個 repo 中的 x86 代碼一樣經過良好調整,那么就編譯器的最終 asm 輸出而言,這就是您應該瞄準的目標,但是您可以到達那里。

我猜想一個只將每位元組計數擴大到 16 位的內部回圈會很好,運行到可能的迭代次數,而不會因為看到饋送的位元組對中的全一u16而溢位 =16進去。即 65535/16 向下舍入 = 4095 個向量,然后擴展到 64 位塊。

Mula 的版本只進行了 31 次內回圈迭代,累積成 8 位元素vaddq_u8但是uadalp v0.16b, v2.8hu8 位元組到 u16 半字元素的水平對累積不適用于 32 位 NEON,僅適用于 AArch64 ASIMD。

關鍵是在最內層回圈中做最少的作業,理想情況下每個cnt結果向量只使用一條廉價指令。 如果您可以在積累時免費獲得一些擴展(或者足夠便宜而不會成為瓶頸),那么可以讓執行在內部回圈中停留更長時間而不會發生溢位。(并且意味著外回圈中后面的水平縮減步驟更便宜。)

uadalp在某些 CPU 上與純垂直的性能有些不同add,但很可能值得使用。Cortex-A57 優化指南說它有 4 (1) 個周期延遲,1/時鐘吞吐量(1) 部分是目標運算元的累積延遲;它允許在源元素的水平對添加已經發生之后,從相同型別的先前操作進行延遲轉發。所以在使用sum = pairswithuadalp的回圈中,回圈攜帶的依賴鏈只有 1 個回圈長。這是理想的。

整數向量上的規則add是 3 個周期延遲,2 個/時鐘吞吐量,因此它具有更好的吞吐量,但創建了一個 3 周期回圈攜帶的依賴鏈。(并且沒有完成水平累加作業的步驟,并且會更快溢位,因為它只使用 8 位和。)

在 Cortex-A57 上,cnt也只有 1/clock 吞吐量,因此uadalp1/clock 吞吐量不是總體瓶頸。除非他們競爭同一個執行埠。 uadalp在 F1 上運行,SIMD 整數add在 F0/F1 上cnt運行,在 F0/F1 上運行。所以無論哪種方式,加法操作都需要竊取一些cnt吞吐量,問題就變成了cnt,當 F1 有一堆未來的uadalp操作排隊時,是否可以有效地調度到大多數埠 F0。(在尚未準備好的資料上;亂序 exec 向前看。在大多數 CPU 上,操作被調度到埠,因為它們從前端重命名/分配到后端。CPU 不知道什么訂單資料將準備好,但它可以看到埠的佇列長度不同。

有可能做(偽代碼)

// Probably not a good idea
c1 = cnt(load1)
c2 = cnt(load2)
c1  = c2    // plain SIMD vertical add
uadalp accumulator, c1

這意味著只有一個uadalp在回圈中,以防出現吞吐量瓶頸,同時仍然只使用uadalp累加器,這使得通過累加器的回圈攜帶的依賴鏈保持較短。(假設其他 AArch64 CPU 也對累積指令進行早期轉發)。

并且它使一個迭代內的短獨立依賴鏈稍長(從加載到累加的輸入),而不是將其保持為兩個獨立的 dep 鏈。)低端 ARM CPU 通常具有非常有限的亂序執行能力(小型調度程式緩沖區)來查找指令級并行性和跨回圈迭代的重疊作業。保持非回圈攜帶的 dep 鏈較短,這對 CPU 來說更容易。除非你展開很多,否則它對于像 Cortex-A53 這樣的有序 AArch64 來說非常糟糕。

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/468266.html

標籤:部件 arm64 汉明重量

上一篇:如何獲得從Z80裝配中的43h減去時會產生某些標志條件的數字范圍?

下一篇:減去0x1-0x80000000如何導致溢位?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more