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





