OpenEM 簡介和基于 OpenEM 的大矩陣乘實(shí)現(xiàn)
Shannon DSP (6678)的內(nèi)存系統(tǒng)包括片內(nèi)的 LL2(local L2)和 SL2(shared L2)。加上片外的 DDR。LL2 的 size 是 512 Kbytes,每個核有一份 LL2。 SL2 的 size 是 4Mbytes,8 個核共享 SL2。DDR size 和硬件板卡設(shè)計有關(guān),一般在 1G bytes 以上。 C66x 核對 LL2 的訪問效率最高,對 SL2 的訪問效率稍差,對 DDR 的訪問效率最低。基于多種存儲區(qū)間的不同特性,我們對數(shù)據(jù)存儲位置按如下規(guī)劃(參見圖 3):
本文引用地址:http://butianyuan.cn/article/201809/388587.htm– 矩陣 X 的 size 是 800 Kbytes,存儲是 shared L2
– 矩陣 Y 的 size 是 16 Mbytes,存儲是 DDR
– 矩陣 Z 的 size 是 800 Kbytes,存儲是 shared L2
雖然矩陣 Y 存儲在 DDR,但是我們啟用了 OpenEM 的 preload 功能。Preload 就是通過 QMSS 的 packet DMA 把待處理的 event 數(shù)據(jù)(通常位于 DDR)搬到被調(diào)度 core 的 LL2。所以 DSP 核運(yùn)行的時候不直接從 DDR 取數(shù)。這保證了 DSP 核的數(shù)據(jù)訪問效率。
2.1.2 處理流程
OpenEM中要有一個 DSP 核作為主核,其他核就是從核,主核要完成的工作較多。本文的演示用例中,核 0 是主核,核 1~7 是從核。主從核的分工差異如圖 4:
1. 初始化 QMSS 和 free pool。
2. OpenEM 的 global 初始化和 local 初始化。global 初始化是主核執(zhí)行。local 初始化是每個核各自執(zhí)行。Local 初始化要等 global 初始化完成才能開始。所以,中間需要加一個barrier。Barrier 可以理解成一個同步點(diǎn),所有 DSP 核在這個點(diǎn)完成一次同步再繼續(xù)向下執(zhí)行。本演示用例的 Barrier 是通過共享內(nèi)存的軟件信號量實(shí)現(xiàn)的。
3. 主核構(gòu)造生產(chǎn)者/消費(fèi)者場景并產(chǎn)生待處理的 event。生產(chǎn)者在 OpenEM 中不是一個軟件對象。我們可以把產(chǎn)生 event 并發(fā)送到 queue 的函數(shù)認(rèn)為是生產(chǎn)者。消費(fèi)者就是 execution object,溝通生產(chǎn)者和消費(fèi)者的管道就是 queue。構(gòu)造生產(chǎn)者/消費(fèi)者場景就是創(chuàng)建execution object 和 queue 并且把它們關(guān)聯(lián)起來。
4. 主核和從核進(jìn)入 event 處理的過程。
5. 主核檢測到所有 event 都處理完成后為每個 DSP 核(包括它自己)產(chǎn)一個 exit job。
6. 主核和從核處理 exit job。從核直接調(diào)用 exit(0)退出。主核先做結(jié)果驗(yàn)證然后調(diào)用 exit(0)退出。
本文演示用例實(shí)現(xiàn)的幾個特點(diǎn)是:
• OpenEM 的 free pool 是由用戶初始化的。在初始化 free pool 的時候 event 描述符不指向數(shù)據(jù)緩沖區(qū)。等分配了一個 event 的時候再在這個 event 對應(yīng)的描述符上掛數(shù)據(jù)緩沖區(qū)。這樣可以避免不必要的數(shù)據(jù)拷貝(從 global buffer 拷貝到 event buffer)。
• 主核通過查詢 free pool 中的 event 個數(shù)是否恢復(fù)回初始值來判斷是否所有“矩陣乘 event”都處理。因?yàn)椋?/p>
– Free pool 在初始化以后有 N 個 free event,
– 從中分配了若干個 event 后,free event 就減少了相應(yīng)的個數(shù),
– 每個 core 每處理完一個 event 就把這個 event 回收到 free pool,free pool 的 event 個數(shù)就加一。當(dāng) free pool 的 event 個數(shù)恢復(fù)回 N,就說明所有 event 都處理完了。
2.2 基于 OpenEM 的大矩陣乘實(shí)現(xiàn)
在初始化 OpenEM之前首先要做 multicore Navigator 的初始化。包括:PDSP firmware 的download, Link RAM 的初始化, Memory region 的初始化還有 free pool (也就是 free descriptorqueue)的初始化。這不屬于本文介紹的范疇,本文直接介紹 OpenEM的初始化。
2.2.1 OpenEM 的 Global 初始化
OpenEM的 global 初始化通過調(diào)用 API 函數(shù) ti_em_init_global()完成的。這個 API 的入?yún)⑹窍旅嫠镜慕Y(jié)構(gòu)體。其中所列的參數(shù)是本文的演示用例使用的配置參數(shù)。本文針對每個參數(shù)的作用做了注釋。了解了參數(shù)了含義,就能了解 OpenEM 的 global 初始化的大致做了些什么。
注釋:
1. OpenEM要使用 hardware queue 資源。hw_queue_base_idx 用來指定 OpenEM 從哪個hardware queue 開始可用。
2. OpenEM 的少量操作需要多 DSP 核訪問共享的數(shù)據(jù)結(jié)構(gòu)。是通過 hardware semaphore 實(shí)現(xiàn)多核lock/unclock 的。所以通過 hw_sem_idx 告訴 OpenEM該使用哪一個 hardware semaphore。
3. 指定 preload 使用的 QMSS packet DMA 的通道的起始索引。QMSS packet DMA 有 32 個 RX/TX channel。在 OpenEM 中,每個 DSP core 要占用一個 TX/RX channel。
4. 指定 preload 使用的 QMSS Tx queues 的起始索引。要和 dma_idx 對應(yīng)起來。QMSS 有 32 個 TX queue,索引是 800~831。對應(yīng) QMSS packet DMA 的 TX channel 0~31。所以,如果前面配置的 dma_idx 是 0,那么這里配置的 dma_queue_base_idx 應(yīng)該是 800。
5. 指定 OpenEM local free pool 對應(yīng)的 free queue index。Local free pool 是和 preload 相關(guān)的。local free pool 在物理上是一個 free descriptor queue。里面存儲著 2 個 host 描述符。每個描述符對應(yīng)一個 local L2 buffer。如果發(fā)生 preload,packet DMA 就從 free descriptor queue pop 描述符,然后把數(shù)據(jù)傳到描述符指向的 local L2 buffer。每個 DSP 核有一個 local free pool。例如,在我們的演示用例中 core0~7 對應(yīng)的 free descriptor queue 索引是 2050~2057。
6. 指定 OpenEM global free pool 的個數(shù)。每個 global free pool 包括 4 個初始化參數(shù),例如{ globalFreePoolFdqIdx, TI_EM_COH_MODE_ON,TI_EM_BUF_MODE_GLOBAL_TIGHT,0}。參數(shù) 1是這個 global free pool 對應(yīng)的 free queue index。接下來幾項是這個 pool 中的 buffer 的屬性。Global free pool 是用來從中分配 free event 的。調(diào)用 em_alloc()的入?yún)⒅痪褪?free pool index。
評論