SDSoC 讓編程人員能夠構(gòu)建完整的硬件— 軟件系統(tǒng),且不犧牲性能。
當(dāng)今的醫(yī)療、工業(yè)及越來越多其他應(yīng)用領(lǐng)域的“標(biāo)準(zhǔn)”圖像處理系統(tǒng)變得越來越先進(jìn)。很多情況下,圖像處理復(fù)雜性已經(jīng)超出了帶 GPU 加速功能的 PC的處理能力范圍。設(shè)計(jì)團(tuán)隊(duì)在提高圖像處理質(zhì)量標(biāo)準(zhǔn),增加產(chǎn)品特性的同時(shí),他們還必須滿足客戶對(duì)最終產(chǎn)品的更小型化、移動(dòng)性、電池供電等要求。眾多現(xiàn)有平臺(tái)都在努力滿足如此復(fù)雜的要求。
?
幸運(yùn)的是,設(shè)計(jì)團(tuán)隊(duì)可利用賽靈思 Zynq?-7000 All Programmable SoC 和最新賽靈思 SDSoC ? 開發(fā)環(huán)境創(chuàng)建出小型、低功耗、特性豐富并帶有基于 C/C++ 語言的高級(jí)成像系統(tǒng)的產(chǎn)品。我們來了解一下如何使用 SDSoC環(huán)境對(duì)圖像流水線處理系統(tǒng)進(jìn)行加速,以實(shí)現(xiàn)上述目標(biāo)。我用不到一周時(shí)間就完成了這個(gè)項(xiàng)目,且實(shí)現(xiàn)了大幅度的系統(tǒng)加速。
我們的圖像批量處理系統(tǒng)將讀取存儲(chǔ)在SD 卡中的圖像,并利用不同的噪聲級(jí)參數(shù)和結(jié)構(gòu)元素形狀的參數(shù)來處理這些圖像。
圖像批處理
我們的實(shí)例系統(tǒng)使用專門的相機(jī)獲取圖像,然后以批量模式處理圖像。圖像尺寸達(dá) 3,000 x 2,000像素(600 萬像素)。盡管處理后的圖像不是實(shí)時(shí)視頻,但目的是通過圖像流水線盡可能快地發(fā)送圖像。這里所用的流水線相當(dāng)簡(jiǎn)單:將 RGB 圖像轉(zhuǎn)換為灰度圖像;添加椒鹽噪聲;以及用三個(gè)濾波器(膨脹、中值和腐蝕)對(duì)噪聲圖像進(jìn)行濾波。膨脹、中值和腐蝕濾波器均屬于中值濾波器系列,這類濾波器主要用來(但并非專門用于)消除脈沖噪聲以實(shí)現(xiàn)圖像增強(qiáng)。這些都是非線性濾波器,不涉及任何算術(shù)運(yùn)算,而且功能僅限于數(shù)據(jù)排序和采集。盡管算法不是太復(fù)雜,但是當(dāng)處理大圖像時(shí)會(huì)耗用相當(dāng)多的處理時(shí)間,原因在于處理器的有序性,在給定時(shí)間內(nèi)只處理 1 個(gè)像素。
中值濾波器是非線性濾波器,需要逐像素地計(jì)算輸出圖像。方法是取特定形狀(稱為結(jié)構(gòu)元素)內(nèi)輸入像素的臨近像素,將它們進(jìn)行排序,并選
出位于 pth rank 上的像素。腐蝕濾波器選擇最小值(p=1)。膨脹濾波器選擇最大值(p=N,其中 N 是結(jié)構(gòu)元素的像素?cái)?shù)量)。中值濾波器選擇中間值(p =[N/2])。通常,結(jié)構(gòu)元素是正方形、菱形或十字形(圖 1)。
圖 1 — 7x7 邊界框中的結(jié)構(gòu)元素
我們的圖像批處理系統(tǒng)會(huì)讀取存儲(chǔ)在 SD 卡中的圖像,并利用不同的噪聲級(jí)參數(shù)和結(jié)構(gòu)元素形狀的參數(shù)來處理這些圖像。運(yùn)行頻率為 667MHz 的Zynq-7000 SoC 的雙核 ARM? Cortex ? -A9 處理器負(fù)責(zé)執(zhí)行計(jì)算任務(wù)。
軟件實(shí)現(xiàn)
首先,我們用 C++ 編寫完整的應(yīng)用程序,這樣就可估算 Cortex-A9 的計(jì)算性能。應(yīng)用程序包含一系列函數(shù),用以讀寫 SD 卡上的 BMP 圖像,計(jì)算亮度,添加噪聲,并執(zhí)行各種濾波器功能。采用 SDSoC開發(fā)環(huán)境的 SDDebug 配置,能夠通過賽靈思ZC702 評(píng)估平臺(tái)在 Linux 操作系統(tǒng)下快速進(jìn)行軟件實(shí)現(xiàn)。
為生成真正可使用的可執(zhí)行文件,我們選擇選項(xiàng) O3 啟動(dòng)所有編譯器優(yōu)化。結(jié)構(gòu)元素的形狀是應(yīng)用程序的一個(gè)參數(shù),這樣我們可以采用任何適合放在7 x 7 像素邊界框中的結(jié)構(gòu)元素。對(duì)流水線時(shí)延(圖 2)有影響的參數(shù)是圖像尺寸(#Size),結(jié)構(gòu)元素中有效像素的數(shù)量(#Shape)。最小化時(shí)延能改善系統(tǒng)性能。FPGA 對(duì)涉及很多加法和乘法運(yùn)算的信號(hào)處理算法執(zhí)行得非常好。我們的系統(tǒng)實(shí)例將展示可編程邏輯不僅善于強(qiáng)力計(jì)算,而且還善于執(zhí)行更標(biāo)準(zhǔn)的數(shù)據(jù)處理。
圖 2 - Zynq 處理系統(tǒng)的運(yùn)行時(shí)間
基本特性分析(圖 3)顯示,通過 RGB 值計(jì)算亮度 (0.13%),以及為像素添加噪聲 (0.34%),這些操作在軟件中運(yùn)行得非常快。中值濾波器占用了總時(shí)間中的大部分時(shí)間( 達(dá) 92.33%)。文件讀取和保存也會(huì)占用時(shí)間。
圖 3 — 初始軟件的特征分析結(jié)果
將函數(shù)轉(zhuǎn)移到硬件
加速的首要目的是在每個(gè)時(shí)鐘周期內(nèi)處理一個(gè)新樣本。重寫部分代碼重寫以及重新設(shè)計(jì)接口可實(shí)現(xiàn)大幅加速。即使片上可編程邏輯 (PL) 的時(shí)鐘速率遠(yuǎn)低于處理系統(tǒng) (PS) 的時(shí)鐘速率,但是能夠在每個(gè)時(shí)鐘周期內(nèi)處理一個(gè)輸入像素也可以實(shí)現(xiàn)大幅加速。
中值濾波器是唯一被轉(zhuǎn)移到硬件的函數(shù)。在SDSoC 環(huán)境中將功能轉(zhuǎn)移到 PL 是一件非常容易的事情,只需在 Project Explorer 中右鍵點(diǎn)擊即可,而且不會(huì)添加任何指令(除了在接口位置添加外),也不用修改任何一行代碼來提高性能。這些修改由嵌入式編程人員負(fù)責(zé),這就說明了為何初始加速通常不那么明顯。
以上指定的函數(shù)包含兩個(gè)貫穿整個(gè)圖像的嵌套循環(huán)。它還包含多個(gè)貫穿結(jié)構(gòu)元素的子回路,可對(duì)所有元素進(jìn)行排序。在本例中,我們使用標(biāo)準(zhǔn)氣泡排序算法。其他復(fù)雜度低的算法適合通過微處理器實(shí)現(xiàn),而這種算法的規(guī)則性更適合硬件實(shí)現(xiàn):
?
for ( i=0; ifor ( j=0; j{
Some Code
for ( s=0; sfor ( k=0; kk++)
for ( l=0; ll++)
{
Swap pixels if not correctly ordered
}
}
由于我們想在每個(gè)時(shí)鐘周期內(nèi)處理一個(gè) 1 個(gè)輸出圖像像素,因此必須添加一條指令以便針對(duì)每個(gè)時(shí)鐘周期啟動(dòng)像素矢量排序。我們利用值為 1 的啟動(dòng)間距 (II) 對(duì)經(jīng)過圖像縱列的第二個(gè)循環(huán)進(jìn)行流水線化處理。(II 是指新的循環(huán)迭代啟動(dòng)之前所需經(jīng)過的時(shí)鐘周期數(shù)量。)通過使用這條指令,SDSoC 環(huán)境將自動(dòng)展開剩下的內(nèi)循環(huán),讓硬件能夠并行處理所有迭代。
加速的首要目的是能夠在每個(gè)時(shí)鐘周期中處理一個(gè)新樣本。重寫部分代碼以及重新設(shè)計(jì)接口可實(shí)現(xiàn)大幅加速。
在單核處理器中實(shí)現(xiàn)的圖像處理算法很容易用代碼編寫,因?yàn)楦鞣N處理器功能使數(shù)據(jù)可以在外部存儲(chǔ)器和處理器本身之間平穩(wěn)傳輸。存儲(chǔ)器高速緩存 L1 和 L2 會(huì)暫時(shí)存儲(chǔ)以后可能復(fù)用的數(shù)據(jù),從而縮短數(shù)據(jù)存取時(shí)延。
這種機(jī)制在 FPGA 中不是默認(rèn)存在。盡管這樣我們就無法使用同一 C/C++ 源代碼創(chuàng)建硬件加速器,但我們可以設(shè)計(jì)一個(gè)性能和尺寸完全適合我們應(yīng)用的存儲(chǔ)器高速緩存。這是一個(gè)很好的例子,這種情況下我們修改 C/C++ 源代碼的目的不是保持相同的功能,而是將性能提升到一定程度以便滿足我們的要求。賽靈思的 Vivado? 高層次綜合 (HLS) 是一種 SDSoC 引擎,能夠從 C/C++ 代碼生成寄存器傳輸級(jí) (RTL) IP ;HLS 會(huì)考慮到我們的指令,生成一種適用于我們代碼的硬件架構(gòu)。這就是為什么分析圖像處理代碼時(shí)不會(huì)自動(dòng)生成線緩沖器和分析窗口;Vivado HLS 忠于原來的代碼,這樣能防止工具在未經(jīng)開發(fā)者同意的情況下采取并隱藏優(yōu)化措施。
熟悉硬件圖像處理的設(shè)計(jì)人員對(duì)線緩沖器和分析窗口了如指掌。為避免從外部存儲(chǔ)器中多次讀取同一像素,像素會(huì)臨時(shí)存儲(chǔ)在內(nèi)存 (Block RAM)中,如果剩下的執(zhí)行過程再也用不到這些像素,那么這些像素會(huì)被覆蓋。Block RAM 有兩個(gè)端口,這兩個(gè)端口可用作存儲(chǔ)器讀取、存儲(chǔ)器寫入或二者存儲(chǔ)器讀寫。當(dāng)加速器接受了與 L 行和 C 列對(duì)應(yīng)的像素,就會(huì)從線緩沖器中讀取所有與 C 列和 (L-1 …L-6) 行對(duì)應(yīng)的像素,并重新寫入另一個(gè)位置,如圖4 所示。為了實(shí)現(xiàn)每個(gè)時(shí)鐘周期內(nèi)處理 1 個(gè)像素這一目標(biāo),必須以一個(gè)時(shí)鐘周期的吞吐量執(zhí)行所有數(shù)據(jù)移動(dòng)。
?
此外,像素鄰域中的所有像素以及結(jié)構(gòu)元素也必須在一個(gè)時(shí)鐘周期內(nèi)訪問。為此,我們還需要定義一個(gè)分析窗口,其中包含需要處理的特定像
素(隨像素不同而不同)。在 SDSoC 環(huán)境和 VHLS中,代碼不以任何形式進(jìn)行時(shí)控; 工具會(huì)針對(duì)所用的資源和我們的指令將任何可以并行處理的任務(wù)均并行化。在我們的圖像樣本批處理系統(tǒng)代碼中,我們通過使用正確的分區(qū)指令(圖 5) 聲明兩個(gè)數(shù)組,從而為代碼添加線緩沖器和分析窗口。然后,我們將數(shù)據(jù)運(yùn)動(dòng)描述為對(duì)這些數(shù)組的讀/ 寫訪問(圖 6)。
?
由于依賴數(shù)組中的數(shù)據(jù)訪問,因此像素值排序過程在硬件架構(gòu)中實(shí)現(xiàn)起來會(huì)比較復(fù)雜。軟件實(shí)現(xiàn)方法所使用的 C 代碼需要取得像素(已通過結(jié)構(gòu)元素對(duì)像素進(jìn)行了驗(yàn)證)的向量,并使用標(biāo)準(zhǔn)冒泡排序法對(duì)向量排序。還有一些效率更高的算法,但是這些算法只有對(duì)較大向量才能發(fā)揮顯著優(yōu)勢(shì)。算法的復(fù)雜程度與結(jié)構(gòu)元素的像素?cái)?shù)量平方成正比,我們這個(gè)實(shí)例設(shè)計(jì)是 (7 x 7)2。
在硬件中,架構(gòu)必須針對(duì)最壞情況來進(jìn)行設(shè)計(jì)。如果我們要實(shí)現(xiàn)每個(gè)時(shí)鐘周期內(nèi)處理 1 個(gè)像素這個(gè)目標(biāo),需要實(shí)現(xiàn)非常規(guī)則的結(jié)構(gòu)。為此,我們規(guī)定輸入向量總是具有最大尺寸(7 x 7),而且所有未驗(yàn)證的像素都具有數(shù)值 0,這樣它們會(huì)處于排序向量底部。我們還要針對(duì)最差情況設(shè)計(jì)級(jí)數(shù),即使對(duì)于具有較少有效像素的結(jié)構(gòu)元素來說級(jí)數(shù)可能更低。只有相同向量不在每級(jí)重用時(shí),才會(huì)發(fā)生不同級(jí)的并行化。結(jié)果得到一個(gè)數(shù)組,在這個(gè)數(shù)組中初始向量從列索引 0 入,從列索引 7 x 7 = 49 出(如圖7 和 8 所示)。
?
?
SDSOC 系統(tǒng)編譯器
SDSoC 并非簡(jiǎn)單的全系統(tǒng)編譯器。它進(jìn)行大量代碼分析,以決定要求在硬件中實(shí)現(xiàn)的函數(shù)最適合使用哪種數(shù)據(jù)移動(dòng)器,并決定將數(shù)據(jù)移動(dòng)器連接到哪個(gè)端口。對(duì)于函數(shù)的每個(gè)參數(shù),我們必須確定最適合使用 ARM? AMBA? AXI4-Lite、AXI4-Fullmemory-mapped 還是 AXI4-Stream 數(shù)據(jù)移動(dòng)器。
我們還需要確定使用哪個(gè)連接器:AXI4 高性能 (HP) 端口、通用 (GP) 端口或加速器一致性端口(ACP),甚至是來自其他加速器的端口,可在 SDSoC環(huán)境中構(gòu)建或者包含在板支持包 (BSP) 中。
然后,SDSoC 環(huán)境創(chuàng)建一個(gè)設(shè)計(jì),添加所有必要的 IP 以構(gòu)成功能完整的系統(tǒng),例如 AXI4 Stream 數(shù)據(jù)移動(dòng)器的直接存儲(chǔ)器訪問 (DMA) ; 并修改 C 語言源代碼(而非初始的C++ 代碼),以調(diào)用硬件。本例中,接口非常簡(jiǎn)單:通過 AXI4-Stream 和 DMA 訪問兩個(gè)輸入數(shù)組和三個(gè)輸出數(shù)組,通過 AXI4-Lite 設(shè)置幾個(gè)標(biāo)量。我們不必考慮 DMA 的設(shè)置,也不必檢查標(biāo)量寄存器的訪問地址;SDSoC 環(huán)境可自動(dòng)管理所有事情。
在構(gòu)建樣本系統(tǒng)時(shí),我首先確認(rèn)源代碼是否兼Vivado HLS,然后添加 VHLS 指令。我使用特定的 SDSoC 指令來指定數(shù)據(jù)在物理空間內(nèi)連續(xù)存儲(chǔ)(通過函數(shù) sds_alloc 分配的存儲(chǔ)器) ,并指定通過DMA 來訪問數(shù)據(jù)(圖 9)。
?
然后,我把構(gòu)建配置切換至 SDEstimate,以粗略估算所能實(shí)現(xiàn)的加速(圖 10)。我不必為這個(gè)步驟等候很長(zhǎng)時(shí)間,因?yàn)榇藭r(shí)尚未構(gòu)建硬件。SDSoC環(huán)境可通過處理器運(yùn)行時(shí)間(使用針對(duì)硬件修改的代碼計(jì)算出的(這比使用初始針對(duì)處理器修改的代碼計(jì)算得出的慢)并將編譯器優(yōu)化參數(shù)設(shè)定為–O0)和時(shí)鐘周期數(shù)量(采用 VHLS 計(jì)算得出的,作為硬件加速器的時(shí)延)計(jì)算出加速估算值。 該時(shí)延是硬件加速器的最大時(shí)延,因此這個(gè)估算值應(yīng)該作為粗略估算。
?
就硬件加速器本身而言加速效果幾乎達(dá) 700倍。“main”級(jí)有很多文件訪問需要花費(fèi)不少時(shí)間;這就是為什么總體加速“僅為”5 倍。實(shí)際上,我們可以選擇計(jì)算全局加速所涉及的頂層函數(shù),這樣就可獲得更有意義的加速值。
流程的最后一步是構(gòu)建整個(gè)系統(tǒng)。這個(gè)階段,構(gòu)建所有加速器都并連接到處理器。然后,修改C++ 源代碼以啟動(dòng)和控制這些加速器(而非調(diào)用初始 C 函數(shù))。在這個(gè)階段,我們可以得到使用硬件加速器實(shí)現(xiàn)的準(zhǔn)確加速值,其中考慮了所有進(jìn)出DDR 的數(shù)據(jù)。這個(gè)加速值還考慮了清除緩存的時(shí)間,因?yàn)槲覀兊臄?shù)據(jù)位于存儲(chǔ)器的可緩存部分。
硬件加速器占用的時(shí)間與圖像的大小(而非結(jié)構(gòu)元素的大小)成正比這就是為什么結(jié)構(gòu)元素中的有效像素?cái)?shù)量越多,加速比就會(huì)越高。圖 11 中的時(shí)延是整個(gè)圖像流水線的時(shí)延,包含軟件和硬件元素。開發(fā)這個(gè)項(xiàng)目時(shí),構(gòu)建軟件應(yīng)用是時(shí)間最長(zhǎng)的一個(gè)階段。在此之后,修改代碼的時(shí)間不足 2 小時(shí),這樣就可得到完全兼容的 Vivado HLS 代碼,并具備正確的指令來優(yōu)化吞吐量。考慮到該設(shè)計(jì)的硬件部分較大(芯片的半個(gè)查找表),完成最后階段—— 綜合、布局布線、比特流、SD 卡—— 耗用2 個(gè)多小時(shí)。
?
SDSoC 環(huán)境的系統(tǒng)級(jí)特性分析集成工具、可編程邏輯中的自動(dòng)軟件加速功能以及全系統(tǒng)優(yōu)化編譯—— 自動(dòng)生成正確的連接以最小化存儲(chǔ)器訪問瓶頸—— 使我能夠在不到一周的時(shí)間里完成這個(gè)實(shí)例項(xiàng)目。
如果使用標(biāo)準(zhǔn)的RTL 流程創(chuàng)建加速器,并憑借我自己的編程能力來利用不同驅(qū)動(dòng)程序以修改C 代碼,那么根本無法在這么短的時(shí)間內(nèi)完成。
評(píng)論
查看更多