一些改進(jìn)AI引擎應(yīng)用程序的延遲和吞吐量的方法
雖然AI引擎是軟件可編程的,但為了在改善AI引擎的延遲和吞吐量方面獲得最佳結(jié)果,了解實(shí)際硬件上發(fā)生的事情非常重要。如果你是一個(gè)FPGA設(shè)計(jì)者,你會(huì)發(fā)現(xiàn)很多并行的FPGA編碼。
讓我們?cè)囍褕D表的不同部分分開(kāi),一步一步地理解硬件上發(fā)生了什么,以及我們?nèi)绾胃倪M(jìn)它。
在本教程中,我們?nèi)匀皇褂脕?lái)自本教程加速系統(tǒng)的相同ai引擎應(yīng)用程序。
我們?cè)噲D理解本教程中的代碼,在本教程中模擬運(yùn)行它,并試圖估計(jì)本教程中圖形的延遲。
注意:本教程是使用2025.1創(chuàng)建的。工具流程在其他版本的工具中可能會(huì)有所不同。
輸入PLIO輸入存儲(chǔ)器
正如我們?cè)诒窘坛讨锌吹降?,?nèi)核首先處理來(lái)自輸入緩沖區(qū)的數(shù)據(jù)。當(dāng)在AI引擎上使用緩沖區(qū)時(shí),內(nèi)核在開(kāi)始之前等待緩沖區(qū)被圖中的數(shù)據(jù)集填滿(mǎn)。
在啟用了Traces的情況下運(yùn)行AI Engine仿真時(shí),我們可以看到內(nèi)核的第一次迭代是在523ns之后開(kāi)始的。這意味著在大約523 ns后,ping緩沖區(qū)被32個(gè)樣本填滿(mǎn)。
輸入緩沖區(qū)滿(mǎn)之前的延遲取決于兩個(gè)因素:
PL輸入PLIO的速度
輸入緩沖區(qū)的大小。填充緩沖區(qū)所需的數(shù)據(jù)越少,內(nèi)核啟動(dòng)速度就越快。然而,這只是減少了初始延遲,并將增加圖的總體延遲。因?yàn)槿绻谔幚磔^小的數(shù)據(jù)集,則需要更頻繁地切換上下文。因此,您將增加獲取緩沖區(qū)鎖的延遲,如果您的內(nèi)核是管道的,您將獲得更多的實(shí)例,您必須填充管道。所以一般來(lái)說(shuō),為了提高圖的吞吐量,你需要增加緩沖區(qū)的大小。
在前一篇文章中,我們已經(jīng)看到兩個(gè)輸出樣本之間的時(shí)間戳間隔為6.4 ns,對(duì)應(yīng)于156.25 MHz的頻率,這是我們平臺(tái)的默認(rèn)PL頻率。
這意味著AI引擎模擬器假設(shè)我們的PL輸入和接收來(lái)自AI引擎的數(shù)據(jù)運(yùn)行在156.25 MHz。
然而,查看AMD Versal AI Edge設(shè)備(DS958)的數(shù)據(jù)表,我們可以看到AI引擎到PL接口可以在-1L速度級(jí)設(shè)備(如TE0950板上的設(shè)備)上以高達(dá)500 MHz的頻率運(yùn)行。
我們可以通過(guò)在project.h中聲明輸入PLIO時(shí)添加頻率作為參數(shù)來(lái)告訴AI Engine編譯器我們打算以500mhz的頻率運(yùn)行PLIO
在進(jìn)行更改并運(yùn)行AI Engine模擬器并啟用trace后,我們可以看到內(nèi)核的第一次調(diào)用現(xiàn)在發(fā)生在368ns之后
有一種方法可以改善這種延遲。
我們現(xiàn)在的樣本到達(dá)了AIE-ML的邊界,頻率為500MHz。AI引擎的速度等級(jí)為-1L,運(yùn)行頻率為1000ghz。
目前,我們?cè)?00MHz的頻率下以32位的數(shù)據(jù)包發(fā)送PL數(shù)據(jù)。在AIE-ML陣列內(nèi)部,流是32位的,頻率為1000MHz。這意味著通過(guò)時(shí)鐘域交叉,我們只使用了AIE-ML流所能支持的發(fā)送帶寬的一半。
為了優(yōu)化這一點(diǎn),AIE-ML的本機(jī)PL接口實(shí)際上是64位的。這樣,您可以從PL到AI引擎接口(64位,500MHz)和從AI引擎接口到AI - ml陣列獲得相同的帶寬。
PLIO接口的大小也在圖.h中的PLIO聲明中定義。我們可以把它改成plio_64_bits
我們還必須將模擬文件更改為每行有2個(gè)樣本(即4個(gè)數(shù)字,每2個(gè)復(fù)雜整數(shù)16樣本)。我已將文件input_64.txt附加到該頁(yè)。
在進(jìn)行更改并運(yùn)行AI引擎模擬器并啟用trace后,我們可以看到內(nèi)核的第一次調(diào)用現(xiàn)在發(fā)生在337ns之后
這基本上非常接近我們?cè)诓粶p少輸入緩沖區(qū)大小(或使用流)的情況下所能獲得的最佳“初始”延遲。
注意:這并不是填充緩沖區(qū)的真正延遲。這還包括初始化數(shù)組的一些延遲(如跟蹤中灰色的_main_init行所示)。因此,如果ai - ml數(shù)組已經(jīng)初始化并等待數(shù)據(jù),那么從第一個(gè)示例進(jìn)入到內(nèi)核啟動(dòng)的延遲將會(huì)低得多
然后,一旦內(nèi)核開(kāi)始從ping緩沖區(qū)讀取數(shù)據(jù)并將其寫(xiě)入其輸出緩沖區(qū),輸入pong緩沖區(qū)就會(huì)并行填充,為下一次內(nèi)核調(diào)用做好準(zhǔn)備。從圖形層面來(lái)看,我們無(wú)法在輸入端做出更多改進(jìn)
我們可以減少內(nèi)核處理數(shù)據(jù)所花費(fèi)的時(shí)間,但這是我們將在下一個(gè)教程中看到的。
內(nèi)核并行化
在之前的教程中,我們已經(jīng)看到內(nèi)核第一和內(nèi)核第二運(yùn)行在同一個(gè)磁貼上,一個(gè)接一個(gè),并在同一個(gè)緩沖區(qū)上工作,即內(nèi)核第一和內(nèi)核第二之間沒(méi)有雙緩沖區(qū)。
如果您不需要更快地處理數(shù)據(jù),這是一個(gè)很好的資源節(jié)省(和省電)。在這個(gè)場(chǎng)景中,內(nèi)核第二等待內(nèi)核第一完成獲取輸入數(shù)據(jù)的處理。對(duì)于第一次迭代,如果內(nèi)核在相同的tile上工作,這將是相同的情況。但是,當(dāng)內(nèi)核第二運(yùn)行時(shí),即使從pong輸入緩沖區(qū)中有數(shù)據(jù)可用,內(nèi)核第一也不會(huì)運(yùn)行。
在這個(gè)場(chǎng)景中,我們可以看到第一次圖迭代(內(nèi)核第二次調(diào)用的結(jié)束)在大約1,270 ns后結(jié)束。
第四次(我們模擬的最后一次迭代)在4123秒后結(jié)束
如果您希望獲得高吞吐量,您可能希望內(nèi)核在不同的ai - ml上運(yùn)行。我們已經(jīng)看到,運(yùn)行時(shí)屬性決定了內(nèi)核是否合并到同一個(gè)tile中。因此,如果我們想要最大的吞吐量我們可以說(shuō)我們的內(nèi)核將需要所有可用的處理時(shí)間通過(guò)將運(yùn)行時(shí)設(shè)置為1(最大值)
我們可以在數(shù)組報(bào)告中看到,兩個(gè)內(nèi)核現(xiàn)在在兩個(gè)不同的塊上實(shí)現(xiàn)
從圖表報(bào)告中我們可以看到,在兩個(gè)內(nèi)核之間實(shí)現(xiàn)了雙緩沖區(qū),這意味著內(nèi)核將能夠并行運(yùn)行。
在運(yùn)行AI引擎模擬器并啟用trace后,我們現(xiàn)在可以看到兩個(gè)內(nèi)核并行運(yùn)行。我們可以看到,第二次調(diào)用kernel first和第一次調(diào)用kernel second是同時(shí)發(fā)生的。
當(dāng)查看內(nèi)核秒第一次調(diào)用結(jié)束的時(shí)間時(shí),它發(fā)生在1,290ns之后。所以比內(nèi)核共用一個(gè)瓦片時(shí)稍微多一點(diǎn)。這可以用以下事實(shí)來(lái)解釋?zhuān)好總€(gè)內(nèi)核都必須管理用于通信的雙緩沖區(qū)的鎖。
對(duì)于圖的第一次執(zhí)行,預(yù)計(jì)會(huì)看到類(lèi)似的時(shí)間,因?yàn)榧词箖?nèi)核從不同的塊運(yùn)行,因此不共享該塊的處理時(shí)間,內(nèi)核第二仍然需要等待內(nèi)核第一完成其第一次執(zhí)行,然后才能通過(guò)ping緩沖區(qū)獲得可用的輸入數(shù)據(jù)。
但是,如果我們看一下內(nèi)核的第四次迭代,它發(fā)生在2751 ns之后,因此我們可以看到延遲和吞吐量的巨大改進(jìn)。
這個(gè)數(shù)字很容易解釋。第4個(gè)內(nèi)核第2次調(diào)用的結(jié)束速度快了1372ns (4,123 ns - 2,751 ns)。我們可以看到,內(nèi)核的3次迭代是并行進(jìn)行的,每次內(nèi)核迭代大約需要460 ns來(lái)完成。
輸出存儲(chǔ)器到輸出PLIO
輸出PLIO上的延遲與我們?cè)谳敵錾峡吹降那闆r類(lèi)似。當(dāng)檢查輸出文本文件(output.txt)時(shí),我們可以看到以下第一行:
我們可以看到第一個(gè)樣本發(fā)生在1344 ns之后。我們已經(jīng)可以看到系統(tǒng)延遲的改善,如果您還記得在更改之前的教程中,第一個(gè)輸入樣本在1,5104 ns之后到達(dá)。
我們還可以看到,以下連續(xù)的采樣發(fā)生在6.4ns之后,提醒我們輸入的156.25 MHz頻率。
我們可以在project.h中對(duì)輸出PLIO進(jìn)行與輸入PLIO相同的設(shè)置:將頻率更改為500MHz并將數(shù)據(jù)寬度更改為64位。
在構(gòu)建圖形并運(yùn)行AI Engine模擬器后,我們可以看到以下第一行輸出文本文件(output.txt):
我們可以看到,我們稍微改善了第一個(gè)樣本的延遲,但最重要的是,連續(xù)的樣本現(xiàn)在只有2ns的間隔,我們每次接收2個(gè)樣本,大大提高了系統(tǒng)的吞吐量。
總結(jié)
在本教程中,我們已經(jīng)看到了如何修改圖形文件,以實(shí)現(xiàn)更低的延遲和更高的吞吐量在我們的AI引擎應(yīng)用程序。我們?nèi)匀豢梢詫?duì)內(nèi)核代碼進(jìn)行改進(jìn),通過(guò)向量化來(lái)提高系統(tǒng)的吞吐量和延遲。這是我們將在下一個(gè)教程中看到的內(nèi)容。
本文編譯自hackster.io





