如何追踪 DMA?
我正在開發通過直接記憶體訪問 (DMA) 事務與 PCI 卡通信的軟體。我的程序使用一套驅動程序和一個處理 DMA 的庫。一切都在 Red Hat Linux 上執行。
為了測試和測量我的程序的性能,我想跟踪 DMA 事務的開始和結束。現在我通過查看庫中的幾個函式來做到這一點:
dma_from_host
並dma_to_host
通過配置卡寄存器中的值並寫入1
名為的寄存器來啟動交易DMA_DESC_ENABLE
dma_wait``DMA_DESC_ENABLE
通過不斷檢查寄存器的值來等待事務完成。但我希望有一個交易已經開始的更強大的確認,以及交易結束時的更精確的信號。Linux 或硬體本身的東西是最好的。
我知道原則上這是一個麻煩的情況。DMA 的想法是硬體(PCI 卡或主機板上的 DMA 控制器)將內容直接複製到程序的記憶體中,繞過 CPU 和作業系統。但我希望它不會只是將內容複製到 RAM 中而不以某種方式通知 CPU。是否有一些標準方法來跟踪這些交易,或者它是非常特定於平台的?
是否有一些特殊的中斷通知 CPU DMA 的開始和結束?我在我使用的驅動程序中找不到類似的東西。但是我對司機沒有經驗,所以我很容易看錯地方。
另一個想法,是否有任何類似 PMU 的硬體監視器可以提供此資訊?只計算 PCI 通道上的事務的東西?
還有一個想法,我是否理解可以將自定義 DMA 跟踪器編寫為 Linux 模組或 BPF 程序來持續檢查該
DMA_DESC_ENABLE
寄存器的值?這是一種可行的方法嗎?有這樣的已知示踪劑嗎?
受到@dirkt 評論的鼓舞,我更好地查看了驅動程序,並發現了與這些 DMA 事務相對應的 PCI MSI 中斷。
驅動程序通過呼叫啟用這些中斷
pci_enable_msix(.., msixTable,..)
這設置了
struct msix_entry msixTable[MAXMSIX]
. 然後它static irqreturn_t irqHandler()
通過循環呼叫將它們分配給處理程序request_irq()
:request_irq(msixTable[interrupt].vector, irqHandler, 0, devName,...)
處理程序只計算本地
int
數組中的中斷。這些計數器在/proc/<devName>
此驅動程序為診斷等創建的文件中導出。事實上,proc 文件是我開始搜尋中斷的地方。但是有一個更好的方法:
/proc/interrupts
文件。啟用的 MSI-X 中斷以如下行顯示:$ cat /proc/interrupts CPU0 CPU1 ... CPU5 CPU6 CPU7 66: 0 0 ... 0 0 0 IR-PCI-MSI-edge <devName> 67: 0 0 ... 0 0 0 IR-PCI-MSI-edge <devName> 68: 33 0 ... 0 0 0 IR-PCI-MSI-edge <devName> 69: 0 0 ... 0 0 0 IR-PCI-MSI-edge <devName> 70: 0 0 ... 0 0 0 IR-PCI-MSI-edge <devName> 71: 0 0 ... 0 0 0 IR-PCI-MSI-edge <devName> 72: 0 0 ... 0 0 0 IR-PCI-MSI-edge <devName> 73: 0 0 ... 0 0 0 IR-PCI-MSI-edge <devName>
另一種方法是在輸出中找到卡的 PCI 地址,
lspci
並在目錄中檢查分配給卡的中斷/sys
:$ ls /sys/bus/pci/devices/0000:17:00.0/msi_irqs 66 67 68 69 70 71 72 73 # but these are empty $ cat /sys/bus/pci/devices/0000:17:00.0/irq 0
68 號中斷在事務結束時觸發。
irq:irq_handler_entry
中斷處理程序在 Linux 中有一個靜態跟踪點。跟踪點參數在欄位中/sys/kernel/debug/tracing/events/irq/irq_handler_entry/format
有中斷號int irq
。因此,這個中斷可以通過這個帶有過濾條件的跟踪點使用標準的 Linux 工具來跟踪:# setup the ftrace trace-cmd start -e irq:irq_handler_entry -f "irq == 68" # for live stream cat /sys/kernel/debug/tracing/trace_pipe # or just trace-cmd stop trace-cmd show trace-cmd reset # with perf perf record -e "irq:irq_handler_entry" --filter "irq == 68"
好在你得到了中斷的時間戳。例如:
$ sudo trace-cmd start -e irq:irq_handler_entry -f "irq == 99" $ sudo trace-cmd stop $ sudo trace-cmd show | head -n 20 # tracer: nop # # entries-in-buffer/entries-written: 860/860 #P:12 # # _-----=> irqs-off # / _----=> need-resched # | / _---=> hardirq/softirq # || / _--=> preempt-depth # ||| / delay # TASK-PID CPU# |||| TIMESTAMP FUNCTION # | | | |||| | | <idle>-0 [009] d.H. 6090.224339: irq_handler_entry: irq=99 name=xhci_hcd ...
有了這個,仍然值得確認的一件事是這些中斷對於 DMA 是必不可少的,以確保我監視與系統相關的內容,而不僅僅是
proc
在另一種情況下可能無法實現的文件的方便計數器。但我無法通過觀察它們在/proc/interrupts
. 設備的中斷dmar[0123]
似乎與 DMA 有關,但它們從未增加過。這是意料之中的,因為在這種情況下,DMA 引擎必須作為 PCI 卡本身的 FPGA 核心來實現。此外,當然中斷不會讓您訪問有關事務本身的資訊,例如傳輸的記憶體大小。並且您需要確保卡中沒有可以防止中斷的錯誤,並且在交易後立即觸發它們。