Xenomai定義
一個real time的系統需要保證其工作在給定的時間限制之內完成。系統不需要以最快的速度完成任務,但是需要在指定的定時時間範圍內完成。
在這個前提條件下,realtime的系統任務完成時間是可確定的,根據運行的底層系統的不同,可以分爲以下兩類實時系統:
- Soft Real Time:
系統不一定每次都需要遵守deadline,但較多的deadline miss會導致服務質量降低。 - Hard Real Time:
系統能每次都能在deadline內完成任務。
Real time on Linux
-
PREEMPT_RT (in-kernel; single kernel)
修改原本的 GNU/Linux 核心 (vanilla kernel),以減少non-preemptible section的方式,使其逐步改善 real-time 能力。 -
dual kernel (eg: RTLinux, RTAI, Xenomai)
運作一個 real-time 核心,然後將修改後的的 GNU/Linux 核心程式視爲 real-time 核心的 idle task。
在xenomai中,dual kernel 就是 Xenomai 的 Nucleus / Cobalt Core 和 Linux kernel。Xenomai 改變整個系統架構,讓 ipipe -> xenomai scheduler 來預先處理 real-time task,而 Linux 則拉到上層成為一個task。這樣可以避免 Linux 因為龐大的架構而影響處理 real-time 的時間。
Xenomai系統架構
Xenomai是一個linux kernel的patch 藉由在底層增加一個架構 負責硬體與接收interrupt 並將interrupt 傳給上層的OS(這邊稱為domain)
這個底層的架構是Adeos 是另一個open source的project
在api呼叫上可以看到不同層級的抽象化
ipipe_XXX -> rthal_XXX -> xnXXX
負責傳送interrupt的程式稱為ipipe 示意圖 :
可以找到ipipe_raise_irq()將interrupt推到pipeline
在ipipe上每個domain都有自己的優先度 高優先度的domain會先接收到interrupt 高優先度的domain的thread 可以preempt低優先度domain的thread
Xenomai 3
xenomai3有兩種configuration:
-
Cobalt: 採用dual kernel架構,是xenomai 2的延伸
-
Mercury: 使用單kernel形式,在linux kernel上提供xenomai api,由於本身依賴linux,一般來說會以PREEMPT_RT提供real-time services
Xenomai 3 dual kernal configuration : Cobalt
多一個 priority 比 linux 還高叫 cobalt 的 core 去處理 real-time 的事情,提供不同的 real-time API 給不同的 applications 使用。並且利用Optimistic interrupt protection 機制減少 changing the interrupt mask,一般的機制在每次進入critical section時都要interrupt mask,而Optimistic interrupt protection可以不用。而real-time 在意的 “deadline”,實際上就是探討 latency (latency 越大,系統越難在時限內完成完成高優先權任務,自然即時能力就越差),而 latency 很大的來源則是 interrupt handling。
具有實時內核cobalt、實時驅動模型RTDM、實時應用POSIX接口庫libcobalt,然後再基於libcobalt實現的其他API skins,如Alchemy API、VxWorks® emulator、pSOS® emulator等(具體查看應用編程接口文檔https://xenomai.org/documentation/xenomai-3/html/xeno3prm),即VxWorks、pSOS應用程序可稍微修改源碼就可以在xenomai上編譯運行。
需要說明的是Alchemy API是xenomai除posix外的官方編程接口,提供了更接近於傳統RTOS編程方式的編程接口,對於不熟悉linux應用開發的MCU開發人員也能很快上手。在xenomai2上Alchemy API是xenomai的原生編程接口,性能最好,posix API是在Alchemy API上實現的skin。在xenomai3相反,Alchemy API、VxWorks、pSOS均基於posix接口實現,也正因爲這樣誕生了mercury方式。
Xenomai 3 single kernel configuration :Mercury
運用本機的 linux core 在 PREEMPT_RT之上達到 real-time 的事情,這裡不是強制的,看 applications 對反應時間和 maximum jitter 的要求,有些甚至會作到某種程度 deadline 的忽略。
基於直接修改linux內核源代碼的PREEMPT RT,應用空間在glibc之上,添加xenomai API庫,如下圖所示。可以在不支持cobalt內核時,可使用該方法運行xenomai應用;也就是說你還可以通過mercury方式在PREEMPT RT上編譯運行VxWorks、pSOS等接口的應用程序。 當然,也可不需要PREEMPT RT,直接使用linux,只是實時性就……
xenomai3-cobalt 結構
在內核空間,在標準linux基礎上添加一個實時內核Cobalt,得益於基於ADEOS(Adaptive Domain Environment for Operating System),使Cobalt在內核空間與linux內核並存,並把標準的Linux內核作爲實時內核中的一個idle進程在實時內核上調度。
2000年,Karim發表了一篇名爲《操作系統的自適應域環境》的論文(即Adeos,Adaptive Domain Environment of Operating System),該論文描述了一種簡單而智能的方案,用於在同一系統上運行的多個內核之間共享公共硬件資源。他通過“pipeline”抽象來說明在x86硬件上共享中斷的基本機制,根據整個系統給定的優先級,依次向每個內核傳入中斷。他倡導一種對硬件中斷進行優先級排序的新方法,以便可以開發基於Linux內核的實時擴展,而無需使用當時已被某些專有RTOS供應商申請授予專利方法(這裏的RTOS供應商和專利指的就是WindRiver和RTlinux使用的RTHAL技術)。 ADEOS (Adaptive Domain Environment for Operating System),提供了一個靈活的環境,可以在多個操作系統之間或單個OS的多個實例之間共享硬件資源,從而使多個優先級域可以同時存在於同一硬件上。早期在xenomai 2上使用。 2005年6月17日,Philippe Gerum發佈用於Linux內核的I-pipe,I-pipe基於ADEOS,但是I-pipe更精簡,並且只處理中斷,xenomai3使用I-pipe。
ADEOS ,其核心思想是Domain,也就是範圍的意思,linux內核有linux內核的範圍,cobalt內核有cobalt內核的範圍。
- 兩個內核管理各自範圍內的應用、驅動、中斷;
- 兩個domain之間有優先級之分,cobalt內核優先級高於linux內核;
- I-pipe優先處理高優先級域的中斷,來保證高優先級域的實時性。
- 高優先級域可以通過I-pipe 向低優先級域發送各類事件等。
在用戶空間,添加針對實時應用優化的庫--libcobalt,libcobalt提供POSIX接口給應用空間實時任務使用,應用通過libcobalt讓實時內核cobalt提供服務。
驅動方面,xenomai提供實時驅動框架模型RTDM(Real-Time Driver Model),專門用於Cobalt內核,基於RTDM進行實時設備驅動開發,爲實時應用提供實時驅動。RTDM將驅動分爲2類:
- 字符設備(open/close, read, write, ioctl),如UART,UDD,SPI……
- 協議設備(socket, bind, send, recv, etc),如UDP/TCP,CAN,IPC,……
中斷方面,I-Pipe(interrupt Pipeline)分發Linux和Xenomai之間的中斷,並以Domain優先級順序傳遞中斷。I-Pipe傳遞中斷如下圖所示,對於實時內核註冊的中斷,中斷產生後能夠直接得到處理,保證實時性。對於linux的中斷,先將中斷記錄在i-log,等實時任務讓出CPU後,linux得到運行,該中斷纔得到處理。
實時內核cobalt與非實時內核linux相結合,既能提供工業級RTOS的硬實時性能,又能利用linux操作系統非常出色的生態、網絡和圖形界面服務,在產品的開發週期和成本控制方面都有巨大優勢 。
系統基本實現深度解析參考
xenomai內核解析--雙核系統調用(一)
xenomai內核解析--任務同步互斥機制(一)--優先級倒置
xenomai內核解析--實時內存管理--xnheap
xenomai內核解析--信號signal(一)---Linux信號機制
xenomai proc文件信息介紹
1.1 實時外設中斷信息
ipipe
ipipe爲了xenomai與linux之間更好地結合,引入了虛擬中斷。虛擬中斷和常規softirq本質上不同,softirq只存在linux中,ipipe虛擬中斷更近似於硬件中斷,但不是硬件觸發,由內核之間需要處理緊急任務時向另一個內核發送,ipipe處理虛擬中斷與處理硬件中斷流程一致,這些中斷信息分爲Llinux和xenomai,分別對應文件/proc/ipipe/Linux和/proc/ipipe/Xenomai。
dovetail
dovetail區別與ipipe,它是在已有linux中斷管理代碼上進行擴展,爲實時核提供與ipipe相同的功能。所以/proc/interrupts就包含了ipipe層和xenomai實時中斷信息。
1.2 查看實時核信息
xenomai內核相關信息均爲位於/proc/xenomai/目錄下:
xenomai調度cpu
ubuntu@work-host:/proc/xenomai$ cat /proc/xenomai/affinity
000000ff
/proc/xenomai/affinity
中是一組掩碼,每一個bit表示系統中的一個CPU,該源碼錶示cobalt內核管理的CPU集,若實時應用程序中沒有設置affinity,那麼該實時會調度在該掩碼下的任意一個CPU上。當我們需要將指定cpu給cobalt調度的時候,可以通過添加內核參數 xenomai.supported_cpus=0x06
來修改,這通常結合linux參數isolcpus來優化實時性能。
硬件timer與延遲信息
/proc/xenomai/clock/coreclk
包含了系統的硬件timer和gravity信息。
root@xxxxx:/proc/xenomai# cat clock/coreclk
gravity: irq=1880 kernel=6880 user=6880
devices: timer=timer2, clock=ipipe_tsc
watchdog: off
setup: 1880
ticks: 230615579053 (0035 b1c279ad)
- gravity在前文autotune工具部分已經解釋,它的值可通過autotune 命令來重新測量調整:
root@xxxxx:/proc/xenomai# autotune == auto-tuning started, period=1000000 ns (may take a while) irq gravity... 2880 ns kernel gravity... 4320 ns user gravity... 7200 ns == auto-tuning completed after 38s root@xxxxx:/proc/xenomai# cat clock/coreclk gravity: irq=2880 kernel=4320 user=7200 devices: timer=timer2, clock=ipipe_tsc watchdog: off setup: 1880 ticks: 25641430824 (0005 f8592f28)
- 如果latency測試後只修
user gravity, echo xxxx > /proc/xenomai/latency
即可:root@xxxxx:/proc/xenomai# echo 6680 > latency root@xxxxx:/proc/xenomai# cat clock/coreclk gravity: irq=2880 kernel=4320 user=6680 devices: timer=timer2, clock=ipipe_tsc watchdog: off setup: 1880 ticks: 28659743127 (0006 ac40f997)
- 若三者都需要修改,可通過
echo irq=xxxx kernel=xxxx user=xxxx> /proc/xenomai/clock/coreclk
修改:root@xxxxx:/proc/xenomai# echo irq=0 kernel=0 user=0 > clock/coreclk root@xxxxx:/proc/xenomai# cat clock/coreclk gravity: irq=0 kernel=0 user=0 devices: timer=timer2, clock=ipipe_tsc watchdog: off setup: 1880 ticks: 32430637968 (0007 8d044390)
faults
文件/proc/xenomai/faults
提供了cobalt內核實時上下文產生的fault統計信息,爲什麼需要關注CPU fault?回到實時性,如果我們的實時任務真正進行關鍵的行爲,此時產生了異常,異常必須解決才能繼續運行,這就導致了結果輸出的不確定性,即影響實時性。這也是爲什麼我們在xenomai應用編程時不能通過glibc庫進行動態內存分配的原因,因爲linux內存的惰性內存分配機制,只有在應用訪問分配的虛擬內存地址時才產生缺頁異常(Page fault)進行物理內存分配,同時linux在內存水位過低時也會進行內存回收,需要考慮。這也是爲什麼VxWorks等RTOS很少使用MMU的原因。
該文件只統計cobalt內核管理的CPU且在實時調度上下產生的異常,因此,若你運行的實時任務抖動比較大,建議查看一下文件,是否是受到異常的影響。
X86下各類異常如下:
ubuntu@work-host:/proc/xenomai$ cat faults
TRAP CPU0 CPU1
0: 0 0 (Divide error)
1: 0 0 (Debug)
3: 0 0 (Int3)
4: 0 0 (Overflow)
5: 0 0 (Bounds)
6: 0 0 (Invalid opcode)
7: 0 0 (FPU not available)
8: 0 0 (Double fault)
9: 0 0 (FPU segment overrun)
10: 0 0 (Invalid TSS)
11: 0 0 (Segment not present)
12: 0 0 (Stack segment)
13: 0 0 (General protection)
14: 0 0 (Page fault)
15: 0 0 (Spurious interrupt)
16: 0 0 (FPU error)
17: 0 0 (Alignment check)
18: 0 0 (Machine check)
19: 0 0 (SIMD error)
heap
ubuntu@work-host:/proc/xenomai$ cat heap
TOTAL FREE NAME
4194304 4192256 system heap
262144 262016 shared heap
該文件顯示了xenomai heap的信息。前面說到,爲避免實時性受到影響,實時應用運行過程中不能使用linux的惰性內存分配接口,在內核裏也是一樣,一是linux內核內存分配算法的不確定性,二是linux內核惰性分配原則。所以xenomai的解決機制是,xenomai內核初始化時預先分配一大片內存,並一一讀寫訪問來建立虛擬內存與物理內存的映射,再通過自己的內存分配算法進行管理,該分配算法時間是確定的,xenomai自己管理的內存稱爲xnheap,xenomai運行過程中的動態內存分配均從xnheap中分配,爲避免多個子系統同時訪問一個xnheap,xenomai內核內有多個heap,這些heap的大小可通過內核參數 xenomai.sysheap_size=<kbytes>
配置,或內核編譯時配置:
[*] Xenomai/cobalt --->
Sizes and static limits --->
(512) Number of registry slots
(4096) Size of system heap (Kb)
(512) Size of private heap (Kb)
(512) Size of shared heap (Kb)
關於 xnheap
內存分配管理算法,有單獨的文章介紹。
registry
什麼是registry?與內存資源類似,在操作系統管理應用程序或爲應用程序提供服務的實時,需要管理很多對象。
舉個例子,有兩個xenoami實時任務, 它們使用semaphore做同步互斥,任務1創建一個名爲/test-sem的semaphore,任務2打開這個semaphore並使用該semaphore,思考下面兩個問題:
- 問題1:任務1創建的這個semaphore是如何管理的?
- 問題2:任務2又是如何通過name找到它的?
這裏例子中的semaphore在操作系統內核中可以一種內核對象,registry提供了一個機制,用於保存xenomai全局內核對象。這些對象分爲兩種,一種有name,常用於兩個及以上進程間,可以通過name來找到同一對象。另一種沒有name,常用於同一進程空間。
registry的大小和heap一樣預先分配,xenomai運行過程中直接獲取,一是全局方便查找降低實現複雜度,二避免內存分配導致系統heap競爭。默認大小爲512個條目。
ubuntu@work-host:/proc/xenomai$ cat registry/usage
10/512
若你運行在xenomai上的軟件比較龐大和複雜,512個不夠使用,可重新配置編譯內核:
-> Xenomai/cobalt (XENOMAI [=y])
-> Sizes and static limits
(512) Number of registry slots
關於registry
內核對象的管理機制,會有單獨的文章介紹。
1.3 調度與任務狀態
下面看最重要的部分,xenomai內核和實時任務運行狀態信息在/proc/xenomai/sched
下:
其中/proc/xenomai/sched/rt/threads
與/proc/xenomai/sched/threads
,前者僅包括優先級大於0的xenomai任務信息,後者包括所有xenomai調度的任務信息,比如我們在運行latency時,只有sampling線程是有優先級的,主線程和display線程優先級均爲0。
線程狀態
root@xxxxx:/proc/xenomai/sched# cat threads
CPU PID CLASS TYPE PRI TIMEOUT STAT NAME
0 0 idle core -1 - R [ROOT]
0 265 rt core 98 - W [rtnet-stack]
0 266 rt core 0 - W [rtnet-rtpc]
0 281 rt core 0 - W [rtnetproxy]
0 380 rt cobalt 0 - X latency
0 382 rt cobalt 0 - W display-380
0 383 rt cobalt 99 - Wt sampling-380
root@xxxxx:/proc/xenomai/sched# cat rt/threads
CPU PID PRI PERIOD NAME
0 265 98 - rtnet-stack
0 383 99 - sampling-380
- CPU 表示該實時任務在哪個CPU的調度隊列上。
- CLASS 表示該任務的調度類
- TYPE 中core表示該任務是內核態任務,cobalt用戶態任務
- PRI 表示任務優先級
- STAT 表示任務所處狀態
系統統計信息
下面看cobalt內核統計信息/proc/xenomai/sched/stat
,這對我們查找實時問題時有幫助,以latency運行爲例,輸出如下:
root@xxxxx:/proc/xenomai/sched# cat stat
CPU PID MSW CSW XSC PF STAT %CPU NAME
0 0 0 40051 0 0 00018000 99.1 [ROOT]
0 265 0 2 0 0 00000042 0.0 [rtnet-stack]
0 266 0 2 0 0 00020042 0.0 [rtnet-rtpc]
0 282 0 2 0 0 00020042 0.0 [rtnetproxy]
0 329 1 1 5 0 000600c0 0.0 latency
0 331 40 80 44 0 00060042 0.0 display-329
0 332 2 40003 40046 0 0004c042 0.6 sampling-329
0 0 0 44791 0 0 00000000 0.3 [IRQ16: [timer]]
0 0 0 0 0 0 00000000 0.0 [IRQ46: 4a100000.ethernet]
0 0 0 0 0 0 00000000 0.0 [IRQ47: 4a100000.ethernet]
它統計了cobalt內核線程、用戶態線程、中斷的信息,這些信息包括:
- CPU 運行的CPU和PID
- MSW 域上下文切換。xenomai是雙內核結構,xenomai應用可以無縫使用linux提供的服務,但這是有風險的,因爲使用linux服務需要切換到linux非實時調度上下文,無法保證任務的實時性。MSW表示的就是實時域與非實時域之間的切換次數。
latency是主線程,它創建完高優先級線程sampling-329和負責結果打印的低優先級線程display-329後,等待SIGTERM等結束信號。間隔執行cat stat發現display-329的MSW會不斷增大,是因爲打印輸出需要使用linux提供的服務進行終端打印;而高優先級sampling-329的MSW沒有變化,因爲該線程創建後,沒有調用任何linux服務全程在實時內核上下文運行。爲什麼sampling-329 MSW爲2? 因爲xenomai實時線程的創建是通過linux來完成 的。
因此,如果你的實時任務會出現大的抖動,那麼請通過該文件觀察,是否因爲不經意調用了linux的服務,切換到linux域引起的。
- CSW xenomai內核上下文切換次數。
- XSW 切換到linux域後,由linux內核調度的上下文切換次數。
- PF 爲Page fault產生次數。
- STAT 運行狀態掩碼
- %CPU CPU使用率,需要額外說明的是,[ROOT]表示的是cobalt內核調度下的linux,雙核下linux已經退化爲cobalt內核調度的一個任務。
Xenomai編程注意事項
Reference
https://www.cnblogs.com/wsg1100/category/1744176.html
SourceCode
http://wiki.csie.ncku.edu.tw/embedded/xenomai
https://blog.csdn.net/pupil_wjj/article/details/119456869
https://zhuanlan.zhihu.com/p/520467236
https://blog.csdn.net/tjcwt2011/article/details/81200111