版本 f84412aaae3d880fc27a7c69e1273046afdc507b
Changes from f84412aaae3d880fc27a7c69e1273046afdc507b to current
---
title: Xenomai
categories: embedded, arm, raspberrypi
categories: embedded, arm, raspberrypi, rpi, realtime, linux, rtos, xenomai, preempt_rt
...
協作者
=====================================================================
建立環境
==============================
* 下載 Raspbian http://www.raspberrypi.org/downloads/
* Install Cross complier
* 2016 年春季
- [黃鏡清](http://wiki.csie.ncku.edu.tw/User/Workfunction), [王紹華](http://wiki.csie.ncku.edu.tw/User/Hua), [陳博聖](http://wiki.csie.ncku.edu.tw/User/ponsheng)
.. code-block:: c
* 2015 年春季
- 吳哲綱, 曾柏翔, 林展翔, 詹志鴻, 林建慶, 呂鴻, 楊于進
cd <working dir>
wget https://github.com/raspberrypi/tools/archive/master.tar.gz
tar xzf master.tar.gz
* 2014 年春季
- 向澐, 林家宏, 呂科進, 趙愷文, 阮志偉, 陳建霖
* Download source files and patches
- Download kernel
.. code-block:: c
Real Time 的定義
=====================================================================
git clone -b rpi-3.8.y --depth 1 git://github.com/raspberrypi/linux.git linux-rpi-3.8.y
- Download Xenomai
.. code-block:: c
一個real time的系統需要保證其工作在給定的時間限制內完成(稱為deadline)。
系統不需要以最快的速度(real fast)完成任務,但需要時常或每次皆在deadline之內完成。
git clone git://git.xenomai.org/xenomai-head.git xenomai-head
- Download minimal config
在這個前提下,real time系統的任務完成時間是可確定的(deterministic)。
而根據系統的限制不同,real time可分為:
.. code-block:: c
* Soft Real Time
系統不一定每次皆需要遵守deadline,但較多的deadline miss會導致服務品質降低。
wget https://www.dropbox.com/s/dcju74md5sz45at/rpi_xenomai_config
* Hard Real Time
系統能每次皆能在deadline內完成任務。
* Apply patches
Real time on Linux
=====================================================================
- Apply ipipe core pre-patch
.. code-block:: c
cd linux-rpi-3.8.y
patch -Np1 < ../xenomai-head/ksrc/arch/arm/patches/raspberry/ipipe-core-3.8.13-raspberry-pre-2.patch
- Apply Xenomai ipipe core patch
.. code-block:: c
xenomai-head/scripts/prepare-kernel.sh --arch=arm --linux=linux-rpi-3.8.y --adeos=xenomai-head/ksrc/arch/arm/patches/ipipe-core-3.8.13-arm-3.patch
- Apply ipipe core post-patch
.. code-block:: c
cd linux-rpi-3.8.y
patch -Np1 < ../xenomai-head/ksrc/arch/arm/patches/raspberry/ipipe-core-3.8.13-raspberry-post-2.patch
* Compile kernel
- Create build directory
.. code-block:: c
mkdir linux-rpi-3.8.y/build
- Configure kernel
.. code-block:: c
cp rpi_xenomai_config linux-rpi-3.8.y/build/.config
cd linux-rpi-3.8.y
make mrproper
make ARCH=arm O=build oldconfig
- Compile
.. code-block:: c
make ARCH=arm O=build CROSS_COMPILE=/home/$USER/workspace/tools-master/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-
- Install modules
.. code-block:: c
make ARCH=arm O=build INSTALL_MOD_PATH=dist modules_install
- Install headers
.. code-block:: c
make ARCH=arm O=build INSTALL_HDR_PATH=dist headers_install
find build/dist/include \( -name .install -o -name ..install.cmd \) -delete
* 編譯好的kernelImage,移到SD卡的 ``/boot/`` 路徑下並更改名稱為kernel.img
* 將``linux-rpi-3.8.y/build/dist``中的Module,移到SD卡中的``/lib/modules``
* Cyclictest
- Linux
.. code-block:: c
- Xenomai
.. code-block:: c
cd xenomai-head
export PATH=../tools-master/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin/:$PATH
./configure --host=arm-bcm2708hardfp-linux-gnueabi
cd src
mkdir dist
make install DIST_DIR=dist
dist中會出現``usr/xenomai``
將這個資料夾移到sd卡中 ``/usr/``
* PREEMPT_RT (in-kernel; single kernel)
在raspberry pi中
修改原本的 GNU/Linux 核心 (vanilla kernel),以減少non-preemptible section的方式,使其逐步改善 real-time 能力。
.. code-block:: c
* dual kernel (如 RTLinux, RTAI, Xenomai)
export PATH=/usr/xenomai/bin:$PATH
export LD_LIBRARY_PATH=/usr/xenomai/lib
sudo modprobe xeno_posix
運作一個 real-time 核心,然後將修改過的 GNU/Linux 核心程式碼視為該 real-time 核心的 idle task。
接著就能跑使用xenomai機制的cyclictest
在xenomai中,dual kernel 就是 Xenomai 的 Nucleus / Cobalt Core 和 Linux kernel。Xenomai 改變整個系統架構,讓 ipipe -> xenomai scheduler 來預先處理 real-time task,而 Linux 則拉到上層成為一個task。這樣可以避免 Linux 因為龐大的架構而影響處理 real-time 的時間。
- RT_preempt
Xenomai系統架構
=====================================================================
Real Time 的定義
==============================
* Hard Real Time
系統一定可以在 Response Time 內完成指定的task
* Soft Real Time
在特定的機率下,系統可以在 Response Time 內完成指定的task
作業系統架構
===========
.. image:: /xenoarch2.jpg
![](/embedded/xenomai/xenomai_arch.jpg)
Xenomai是一個linux kernel的patch
藉由在底層增加一個架構
負責硬體與接收interrupt 並將interrupt 傳給上層的OS(這邊稱為domain)
這個底層的架構是Adeos 是另一個open source的project
在api呼叫上可以看到不同層級的抽象化
ipipe_XXX -> rthal_XXX -> xnXXX
負責傳送interrupt的程式稱為ipipe
示意圖
http://www.xenomai.org/documentation/xenomai-2.6/html/pictures/life-with-adeos-img4.jpg
示意圖 :
![](/embedded/xenomai/adeos.jpg)
可以找到ipipe_raise_irq()將interrupt推到pipeline
在ipipe上每個domain都有自己的優先度
高優先度的domain會先接收到interrupt
高優先度的domain的thread 可以preempt低優先度domain的thread
## Xenomai 3
iPipe
++++++++++++++
xenomai3有兩種configuration:
主要負責處理irq 與 timer(HRT), ipipe的工作很簡單 就是設定timer並將interrupt往上丟
* Cobalt: 採用dual kernel架構,是xenomai 2的延伸
* 相關檔案︰
* Mercury: 使用單kernel形式,在linux kernel上提供xenomai api,由於本身依賴linux,一般來說會以PREEMPT_RT提供real-time services
- gic.c :
Generic Interrupt Controller, Interrupt prioritization and distribution to each CPU interface. This is known as the Distributor. Priority masking and preemption handling for each CPU. This is known as the CPU Interface.
**Xenomai 3 dual kernal configuration : Cobalt**
- it8152.c:IRQ相關
![](/embedded/xenomai/cobalt.png)
- timer-sp.c:dual timer module(sp804)
多一個 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。
- vic.c:
**Xenomai 3 single kernel configuration :Mercury**
The VIC provides a software interface to the interrupt system. In a system with an interrupt controller, software must determine the source that is requesting service and where its service routine is loaded. A VIC does both of these in hardware.
![](/embedded/xenomai/mercury.png)
功能為提供一個programable的介面讓使用者設定
運用本機的 linux core 在 PREEMPT_RT之上達到 real-time 的事情,這裡不是強制的,看 applications 對反應時間和 maximum jitter 的要求,有些甚至會作到某種程度 deadline 的忽略。
- ipipe-tsc.c:設定精準度(刻度)
## Adeos / iPipe
- ipipe/compat.c:interrupt
- sched/clock.c:取得cpu_clock 解析度為nanosecond,開機後從0開始上數
主要負責處理irq 與 high resolution timer, ipipe的工作很簡單 就是設定timer並將interrupt往上丟
.. image:: /GIC_overview.svg
* Adeos feature
GIC大約是上圖的distributor的位置
- event pipeline :
VIC則是CPU interface的位置
利用pipeline的方式將不同domain的interrupt或system call往上丟
但raspberry pi只有一顆CPU所以不會有SMP與 CPU affinity設定的問題
- Optimistic interrupt protection :
當同一個domain在處理interrupt時,有跟她相同domain的interrupt要進來時,會將它進pending狀態,等到所有pending interrupt完成時,才會處理下個domain的interrupt。但更高優先權domain的interrupt會preempt較低優先權domain的interrupt。
HAL
++++++++++++
- Optimistic v.s Original :
Hardware Abstract Layer:prcess 透過HAL呼叫ipipe的服務。這一層主要是包裝ipipe 與底層資訊 讓nucleus可以不用看到硬體資訊。
Original case:
![](/embedded/xenomai/originalcase1.png)
Nucleus
++++++++++++
![](/embedded/xenomai/originalcase2.png)
Xenomai的kernel, 包含一個scheduler,優先執行real-time tasks.
Optimistic case:
Scheduler
++++++++++++
![](/embedded/xenomai/optiminsticcase1.png)
優先處理realtime task ,linux也被視為其中一個thread,本身也有scheduler,但須等到沒有real-time task時(idle state),才會執行linux thread
![](/embedded/xenomai/optiminsticcase2.png)
從前兩張圖可看出一般的機制在每次進入critical section時都要interrupt mask,而Optimistic interrupt protection可以不用,所以在interrupt management的時間差很多。而real-time 在意的 “deadline”,實際上就是探討 latency (latency 越大,系統越難在時限內完成完成高優先權任務,自然即時能力就越差),而 latency 很大的來源則是 interrupt handling。
Skins
++++++++++++
- System event propagation :
呼叫xenomai的界面, 有native rtdm posix等。
system event(ex : page fault handle) 傳遞方式不同於interrupt,基本上是不可被stall的。
問題
++++++++++++
* realtime support to threads running in the secondary domain
與 RT-PREEMPT 途徑的差異?
- Common priority scheme :
當xenomai task migrates to linux domain時,linux domain會繼承xenomai task的priority。
![](/embedded/xenomai/pirority_scheme.png)
實作
==================
- Predictability of program execution times :
當xenomai threads 進入linux(secondary) domain時,不可被linux domain interrupt preempt掉,也不能被其他low priority activity at linux kernel preempt掉。通常最簡單實作方式就是加一個interrupt shield domain。
Context switch
++++++++++++++
![](/embedded/xenomai/interrupt_shield.png)
.. code-block:: prettyprint
- Fine-grained Linux kernel :
include/arch/arm-asm/bits/pod.h
static inline void xnarch_switch_to(xnarchtcb_t *out_tcb, xnarchtcb_t *in_tcb)
In order to get the best from secondary domain,we need the Linux kernel to exhibit the shortest possible nonpreemptible section, so that rescheduling opportunities are taken as soon as possible after a Xenomai thread running in the secondary domain becomes ready to run.
{
- Priority inversion management :
struct task_struct *prev = out_tcb->active_task;
Both the real-time nucleus and the Linux kernel should handle the case where a high priority thread is kept from running because a low priority one holds a contented resourse for a possibly unbounded amount of time.
struct mm_struct *prev_mm = out_tcb->active_mm;
* 相關檔案︰
struct task_struct *next = in_tcb->user_task;
- gic.c(舊版) -> irq-gic.c(新版) :
Generic Interrupt Controller(GIC)為ARM架構中負責分配interrupt至cpu的裝置。此檔案實作gic功能的界面,包含init、mask、產生軟體interrupt、end of interrupt、取得資訊等。內容除了gic register操作外,也包含了spin locks。
if (likely(next != NULL)) {
- it8152.c:提供ITE8152 (PCI Bridge)的支援。目前該硬體已經停止生產 。
in_tcb->active_task = next;
- timer-sp.c:ARM Dual-Timer Module (SP804)的界面。SP804提供兩個32/64bit count down counter,並提供timer interrupt。
in_tcb->active_mm = in_tcb->mm;
- vic.c -> irq-vic.c:
rthal_clear_foreign_stack(&rthal_domain);
提供Vectored Interrupt Controller(VIC)的界面。VIC主要存在於armv6或以前的架構中,提供priority、IRQ vector等功能,但並不支援SMP。在armv7之後的架構中,其漸漸被NVIC(Cortex-M)與GIC(Cortex-R/A)取代。
} else {
- ipipe-tsc.c -> ipipe_tsc.c:Time Stamp Counter的界面,提供自reset起cycle數的計算。
in_tcb->active_task = prev;
- ipipe/compat.c:與I-pipe legacy interface相關。
in_tcb->active_mm = prev_mm;
- sched/clock.c:取得cpu_clock 解析度為nanosecond,開機後從0開始上數。在新版(3.18)ipipe中,此檔案並無修改。
rthal_set_foreign_stack(&rthal_domain);
![](/embedded/xenomai/cpu_distribute.jpg)
}
GIC大約是上圖的distributor的位置
if (prev_mm != in_tcb->active_mm) {
但raspberry pi只有一顆CPU所以不會有SMP與 CPU affinity設定的問題
/* Switch to new user-space thread? */
## HAL
if (in_tcb->active_mm)
檔案位置在 : xenomai-head/ksrc/arch/arm/hal.c (xenomai 2.6)
wrap_switch_mm(prev_mm, in_tcb->active_mm, next);
Hardware Abstract Layer:process 透過HAL呼叫ipipe的服務。這一層主要是包裝ipipe 與底層資訊 讓nucleus可以不用看到硬體資訊。
if (!next->mm)
## Nucleus / Cobalt
enter_lazy_tlb(prev_mm, next);
檔案位置在 : xenomai-head/ksrc/nucleus (xenomai 2.6) ; xenomai-head/kernel/cobalt (xenomai 3)
}
Xenomai的kernel, 包含schedule、timer、synch、thread、lock等等一般該有的RTOS功能,負責real-time tasks的執行。
/* Kernel-to-kernel context switch. */
## Scheduler
rthal_thread_switch(prev, out_tcb->tip, in_tcb->tip);
優先處理realtime task ,linux也被視為其中一個thread,本身也有scheduler,但須等到沒有real-time task時(idle state),才會執行linux thread
}
![](/embedded/xenomai/xenomai_sched.jpg)
.. code-block:: prettyprint
就檔案有五個關於sched.c應該有四種不同的schedule方式
ksrc/arch/arm/switch.S
/*
/*
* Switch context routine.
*
* Registers according to the ARM procedure call standard:
* Reg Description
* r0-r3 argument/scratch registers
* r4-r9 variable register
* r10=sl stack limit/variable register
* r11=fp frame pointer/variable register
* r12=ip intra-procedure-call scratch register
* r13=sp stack pointer (auto preserved)
* r14=lr link register
* r15=pc program counter (auto preserved)
*
* Copied from __switch_to, arch/arm/kernel/entry-armv.S.
* Right now it is identical, but who knows what the
* future reserves us...
*
* XXX: All the following config options are NOT tested:
* CONFIG_IWMMXT
*
* Calling args:
* r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
*/
ENTRY(rthal_thread_switch)
add ip, r1, #TI_CPU_SAVE
ARM( stmia ip!, {r4 - sl, fp, sp, lr} ) @ Store most regs on stack
THUMB( stmia ip!, {r4 - sl, fp} ) @ Store most regs on stack
THUMB( str sp, [ip], #4 )
THUMB( str lr, [ip], #4 )
load_tls r2, r4, r5
#ifdef USE_DOMAINS
ldr r6, [r2, #TI_CPU_DOMAIN]
#endif
clear_exclusive_monitor
switch_tls r1, r4, r5, r3, r7
#ifdef USE_DOMAINS
mcr p15, 0, r6, c3, c0, 0 @ Set domain register
#endif
fpu_switch r4
ARM( add r4, r2, #TI_CPU_SAVE )
ARM( ldmia r4, {r4 - sl, fp, sp, pc} ) @ Load all regs saved previously
THUMB( add ip, r2, #TI_CPU_SAVE )
THUMB( ldmia ip!, {r4 - sl, fp} ) @ Load all regs saved previously
THUMB( ldr sp, [ip], #4 )
THUMB( ldr pc, [ip] )
ENDPROC(rthal_thread_switch)
sched-idle.c :是專門處理idle狀態給linux schedule使用
sched-rt.c : 給real-time scheduler使用(FIFO+RR)
Cyclictest
+++++++++++
sched-sporadic.c : POSIX SCHED_SPORADIC scheduling class.
* 概念:設定一個時間間隔->取得現在時間->讓process 睡一個間隔->process醒來後再取一次時間->比對兩次取得的時間差與設定的間隔差距
* pseudocode:
sched-tp.c : Temporal partitioning (typical of IMA systems)
.. code-block:: prettyprint
sched.c : 應該是負責四個schedule方式的檔案
clock_gettime((&now))
next = now + par->interval
while (!shutdown) {
clock_nanosleep((&next))
clock_gettime((&now))
diff = calcdiff(now, next)
# update stat-> min, max, total latency, cycles
# update the histogram data
next += interval
}
* 造成時間差的原因
- timer精準度
- IRQ latency
- IRQ handler duration
- scheduler latency
- scheduler duration
## Skins
* 實作流程
- 在main中會使用skin(posix)的systime call
檔案位置在xenomai-head/ksrc/skins (xenomai 2.6)
.. code-block:: prettyprint
呼叫xenomai的界面, 有native rtdm posix psos+ uitron vrtx vxworks等。
pthread_create(&stat[i].thread, &thattr, timerthread, &par[i]); //pthread_create()定義在ksrc/skins/posix/thread.c
.. code-block:: prettyprint
Xenomai與PREEMPT_RT的差異
=====================================================================
int pthread_create(pthread_t *tid,
const pthread_attr_t * attr,
* Linux kernel preemption model 組態 (realtime程度 ↑ => latency↓ but throughput↓)
- PREEMPT_NONE
void *(*start) (void *), void *arg){
著重fairness和throughput,process在執行system call時無法被preempt。
union xnsched_policy_param param; /**使用schedule的參數 可能是sched_rt_param 或 sched_idle_param(這兩個的參數都只有一個int prio)/
- PREEMPT_VOLUNTARY(DESKTOP)
struct xnthread_start_attr sattr;
允許一個低優先權的 process把自己 preempt掉(即便該 process正在 kernel mode 執行著一個系統呼叫)
struct xnthread_init_attr iattr;
- PREEMPT(Low-Latency Desktop)
- PREEMPT_RT
pthread_t thread, cur; /* *pthread_t = pse51thread , pse51thread由xnthread_t與其他成員組成*/
著重determinism,對即時系統而言,作業系統的「可決定性」比 throughput 更為重要,使用固定優先權的 preemptive 排程策略 (POSIX SCHED_FIFO 與 SCHED_RR)。
xnflags_t flags = 0;
size_t stacksize;
* PREEMPT_RT 機制
- Preemptible critical sections
- Preemptible interrupt handlers
- Preemptible "interrupt disable" code sequences
- Priority inheritance for in-kernel spinlocks and semaphores
- Deferred operations
- Latency-reduction measures
- Execute all activities (including IRQ) in “schedulable/thread” context
const char *name;
原本無法preempt的地方讓他可以preemt,讓spinlock 區塊在區分成可以preempt的地方跟不能preempt的地方,將IRQ handler移到thread中執行。
int prio, ret;
Priority inheritance 是讓握有spinlock 或 semaphore的process可以暫時的提高優先權 讓他可以盡快做完critical section釋放spinlock或semaphore
spl_t s;
高Priority的 process才有辦法繼續執行。
if (attr && attr->magic != PSE51_THREAD_ATTR_MAGIC)
* PREEMPT_RT 與 xenomai的差異
return EINVAL;
RT_PREEMPT是基於linux架構去改進 讓更多地方能preempt 達到real-time的能力
/*下面開始分配thread空間 初始化thread */
Xenomai則是改變整個系統架構 新增一個scheduler與IRQ管理的機制
thread = (pthread_t)xnmalloc(sizeof(*thread));
讓處理real-time task流程簡化到只剩ipipe->scheduler 就能執行
if (!thread)
不會因linux龐大的架構影響到real-time task的處理時間
return EAGAIN;
thread->attr = attr ? *attr : default_attr;
使用的硬體規格
=====================================================================
cur = pse51_current_thread();
if (thread->attr.inheritsched == PTHREAD_INHERIT_SCHED) {
/* cur may be NULL if pthread_create is not called by a pse51
## Raspberry pi
thread, in which case trying to inherit scheduling
![](/embedded/xenomai/respberrypi.png)
parameters is treated as an error. */
## Beaglebone
/*這邊應該是說 如果不是用xnthread做出來的pse51 thread而是linux本身的posix pthread 則當作error*/
![](/embedded/xenomai/beaglebone.png)
if (!cur) {
* 詳細規格,腳位圖,及GPIO
xnfree(thread);
- https://hackpad.com/Raspberry-pi-beaglebone-xvENpXJvKIF#:h=GPIO
return EINVAL;
## Raspberry Pi 3
}
![](/raspberry_pi_3.jpg)
* A 1.2GHz 64-bit quad-core ARMv8 CPU
* With embedded bluetooth chip and wifi chip
* 802.11n Wireless LAN
* Bluetooth 4.1
* Bluetooth Low Energy (BLE)
pthread_getschedparam_ex(cur, &thread->attr.policy,
建立 Xenomai 環境
========================================================================
&thread->attr.schedparam_ex);
}
## Xenomai 2.6 on raspberry pi
prio = thread->attr.schedparam_ex.sched_priority;
* 下載 Raspbian: http://www.raspberrypi.org/downloads/
- 將raspbian的img檔燒進sd card上
```
sudo dd if=<raspbian image file> of=/dev/mmcblk0 bs=4M
```
stacksize = thread->attr.stacksize;
- ``if`` 為 input file, ``of`` 為 output file, ``bs``為 block size
- 燒錄詳細介紹: http://life-of-raspberrypi.blogspot.tw/
name = thread->attr.name;
* Install Cross complier
```
cd <working dir>
wget https://github.com/raspberrypi/tools/archive/master.tar.gz
tar xzfv master.tar.gz
```
if (thread->attr.fp)
* Download kernel
```
git clone -b rpi-3.8.y --depth 1 git://github.com/raspberrypi/linux.git linux-rpi-3.8.y
```
flags |= XNFPU;
* Download Xenomai
```
git clone git://git.xenomai.org/xenomai-head.git xenomai-head
```
if (!start)
* Download minimal config
```
wget https://www.dropbox.com/s/dcju74md5sz45at/rpi_xenomai_config
```
flags |= XNSHADOW; /* Note: no interrupt shield. */
* Apply ipipe core pre-patch
```
cd linux-rpi-3.8.y
patch -Np1 < ../xenomai-head/ksrc/arch/arm/patches/raspberry/ipipe-core-3.8.13-raspberry-pre-2.patch
```
iattr.tbase = pse51_tbase;
* Apply Xenomai ipipe core patch
```
cd <working dir>
./xenomai-head/scripts/prepare-kernel.sh --arch=arm --linux=linux-rpi-3.8.y --adeos=xenomai-head/ksrc/arch/arm/patches/ipipe-core-3.8.13-arm-4.patch
```
iattr.name = name;
* Apply ipipe core post-patch
```
cd linux-rpi-3.8.y
patch -Np1 < ../xenomai-head/ksrc/arch/arm/patches/raspberry/ipipe-core-3.8.13-raspberry-post-2.patch
```
iattr.flags = flags;
* Create build directory
```
cd <working dir>
mkdir linux-rpi-3.8.y/build
```
iattr.ops = &pse51_thread_ops;
* Configure kernel
```
cp rpi_xenomai_config linux-rpi-3.8.y/build/.config
cd linux-rpi-3.8.y
make mrproper
make ARCH=arm O=build oldconfig
```
iattr.stacksize = stacksize;
* Compile Linux Kernel (此步驟耗時長,建議用make -j平行加速)
param.rt.prio = prio;
在作此步驟之前須export library
```
export PATH=<working dir(full path)>/tools-master/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin/:$PATH
make ARCH=arm O=build CROSS_COMPILE=<working dir(full path)>/tools-master/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-
```
hread->arg = arg;
* Install modules
```
make ARCH=arm O=build INSTALL_MOD_PATH=dist modules_install
```
xnsynch_init(&thread->join_synch, XNSYNCH_PRIO, NULL);
* Install headers
```
make ARCH=arm O=build INSTALL_HDR_PATH=dist headers_install
find build/dist/include \( -name .install -o -name ..install.cmd \) -delete
```
thread->nrt_joiners = 0;
* 編譯好的kernelImage(<working dir>/linux-rpi-3.8.y/build/arch/arm/boot/Image),移到SD卡的 ``/boot/`` 路徑下並更改名稱為kernel.img
pse51_cancel_init_thread(thread);
* 將``linux-rpi-3.8.y/build/dist``中的Module,移到SD卡中的``/lib/modules``
pse51_signal_init_thread(thread, cur);
* Compile Xenomai
```
cd xenomai-head
export PATH=<working dir(full path)>/tools-master/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin/:$PATH
./configure --host=arm-bcm2708hardfp-linux-gnueabi
cd src
mkdir dist
make install DESTDIR=`pwd`/dist
```
pse51_tsd_init_thread(thread);
* dist中會出現``usr/xenomai``, 將這個資料夾移到sd卡中 ``/usr/``
pse51_timer_init_thread(thread);
* 用 minicom 連進 raspberry pi 中執行以下動作
```
export PATH=/usr/xenomai/bin:$PATH
export LD_LIBRARY_PATH=/usr/xenomai/lib
sudo modprobe xeno_posix
```
if (thread->attr.policy == SCHED_RR)
## Xenomai 3 on raspberry pi
xnpod_set_thread_tslice(&thread->threadbase, pse51_time_slice);
* 取得 xenomai 3.0-rc、rpi-linux 3.18.y、ipipe 3.18.12 arm patch、toolchain
```
git clone -b rpi-3.18.y git://github.com/raspberrypi/linux.git rpi-linux
git clone -b v3.0-rc4 git://git.xenomai.org/xenomai-3.git xenomai-3
wget http://download.gna.org/adeos/patches/v3.x/arm/ipipe-core-3.18.12-arm-1.patch
git clone https://github.com/raspberrypi/tools.git --depth=1
```
xnlock_get_irqsave(&nklock, s);
* checkout rpi-linux至3.18.12
```
git checkout c963de6d8caec6278c0dde76831f9fdab5bace52
git checkout -b 3.18.12
```
thread->container = &pse51_kqueues(0)->threadq;
* 由此處取得rpi post patch
appendq(thread->container, &thread->link);
[post patch](https://drive.google.com/file/d/0B6GwSked9fL9RnU3b3pSajFZbUk/view)
xnlock_put_irqrestore(&nklock, s);
* 上 ipipe patch
```
cd rpi-linux
../xenomai-3/scripts/prepare-kernel.sh --arch=arm --ipipe=<你的patch位置>/ipipe-core-3.18.12-arm-1.patch --linux=.
```
#ifdef CONFIG_XENO_OPT_PERVASIVE
* ipipe post patch (註:pre patch為解決ipipe patch衝突之用,此處無衝突故不需要)
```
patch -Np1 < <你的patch位置>/3.18.12-xenomai3-temp.patch
```
thread->hkey.u_tid = 0;
* configure kernel(使用rpi提供的default)
```
export CCPI=($working_dir)/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-
mkdir build
make mrproper
make ARCH=arm O=build CROSS_COMPILE=$CCPI bcmrpi_defconfig
make ARCH=arm O=build CROSS_COMPILE=$CCPI menuconfig
```
thread->hkey.mm = NULL;
若patch正確,會在設定表裡看到xenomai相關選項。
#endif /* CONFIG_XENO_OPT_PERVASIVE */
使用manuconfig或編輯build/.config,找到CONFIG_CPU_FREQ , CONFIG_CPU_IDLE , CONFIG_KGDB , CONFIG_CONTEXT_TRACKING_FORCE(若有的話)設為n。
/* We need an anonymous registry entry to obtain a handle for fast
* compile kernel
```
make -j 5 ARCH=arm O=build CROSS_COMPILE=$CCPI
```
mutex locking. */
* 安裝kernel modules
```
make ARCH=arm O=build INSTALL_MOD_PATH=dist modules_install
```
ret = xnthread_register(&thread->threadbase, "");
* 安裝headers
```
make ARCH=arm O=build INSTALL_HDR_PATH=dist headers_install
```
if (ret) {
* xenomai
```
cd ../xenomai-3
mkdir dist
export PATH=/home/erickitten/workspace/xenomai/pi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/:$PATH
```
thread_destroy(thread);
* 設定bootstrap
```
./scripts/bootstrap --with-core=cobalt –enable-debug=partial
```
return ret;
* configure
```
./configure CFLAGS="-mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard" LDFLAGS="-mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard" --host=arm-linux-gnueabihf --with-core=cobalt
```
}
* install
```
make DESTDIR=`pwd`/dist install
```
*tid = thread; /* Must be done before the thread is started. */
* 複製kernel
/* Do not start shadow threads (i.e. start == NULL). */
將linux-rpi/build/arch/arm/boot/Image複製到SD卡的/boot (partition),並改名成kernel.img。或使用config.txt,以kernel=<filename>指定名稱。
if (start) {
* 移動module / patches (權限問題,需使用sudo)
```
cd ..
sudo cp -r rpi-linux/build/dist/lib/modules $(sdcard)/lib
sudo cp -r xenomai-3/dist/usr/xenomai $(sdcard)/usr
```
sattr.mode = 0;
## Beaglebone Black 環境設置
sattr.imask = 0;
使用舊版linux(Angstrom)來做測試,核心編譯步驟參考上面步驟 或 http://elinux.org/EBC_Installing_Kernel_Source
sattr.affinity = thread->attr.affinity;
* 下載Kernel Source & 編譯
```
host$ git clone git://github.com/RobertCNelson/bb-kernel.git
host$ cd bb-kernel
host$ git tag (This shows what versions can be checked out.)
host$ git checkout 3.8.13-bone67 -b 3.8.13-bone67
```
sattr.entry = thread_trampoline;
* 預設username/password
```
host$ ./build_kernel.sh
username:root
```
sattr.cookie = thread;
* 設定cross compile
xnpod_start_thread(&thread->threadbase, &sattr);
在Kernel Configuration中選擇General setup,輸入
```
CROSS_COMPILE=arm-linux-gnueabi-
```
}
* 安裝必要套件
```
sudo apt-get update
sudo apt-get install build-essential device-tree-compiler fakeroot lzma lzop u-boot-tools libncurses5-dev:amd64 libc6:i386 libncurses5:i386 libstdc++6:i386 zlib1g:i386
```
return 0;
}
* 完成上述步驟後即可上電,按 boot select button 讓它從 sd card 開機,開機後進入登入畫面,帳號/密碼寫在上面
- 建立一個thread叫timerthread,timerthread主要做的事情是呼叫clock_nanosleep這個function
* 登入後查詢版本
```
sudo su
uname -a
```
.. code-block:: prettyprint
## Xenomai 2.6 on Beaglebone
int clock_nanosleep(clockid_t clock_id,
Kernel裝好後,測試可以成功從 SD 卡開機,接著更換換 Kernel
int flags,
參考資料 http://elinux.org/EBC_Xenomai 與 http://emplearn.blogspot.tw/search?q=xenomai
const struct timespec *rqtp, struct timespec *rmtp){
* 設定路徑
```
mkdir bbb
cd bbb
export BBB=$(pwd)
```
xnthread_t *cur;
* 取得xenomai-2.6.4 (與 beaglebone-kernel 同一層目錄)
```
wget http://download.gna.org/xenomai/stable/latest/xenomai-2.6.4.tar.bz2
```
spl_t s;
* 檢查版本
```
cd bb-kernel/KERNEL
uname -a
git tags | sort | less
```
int err = 0;
* 選擇跟所編譯 Kernel 最接近版本,在此為 3.8.13
```
git checkout 3.8.13-bone67 -b xenomai
```
if (xnpod_unblockable_p())
* Patch the kernel
```
cd bb-kernel/KERNEL
patch -p1 < ../../xenomai-2.6.4/ksrc/arch/arm/patches/beaglebone/ipipe-core-3.8.13-beaglebone-pre.patch
patch -p1 < ../../xenomai-2.6.4/ksrc/arch/arm/patches/ipipe-core-3.8.13-arm-4.patch
patch -p1 < ../../xenomai-2.6.4/ksrc/arch/arm/patches/beaglebone/ipipe-core-3.8.13-beaglebone-post.patch
```
return EPERM;
* Prepare the kernel
```
cd ../../xenomai-2.6.4/scripts
./prepare-kernel.sh --arch=arm --linux=../../bb-kernel/KERNEL/
```
if (clock_id != CLOCK_MONOTONIC && clock_id != CLOCK_REALTIME)
* Prepare the kernel
```
cd ../../bb-kernel
```
return ENOTSUP;
* 確認已經關掉AUTO_BUILD
```
vi system.sh
```
if ((unsigned long)rqtp->tv_nsec >= ONE_BILLION)
* 確認最後一行為
```
#AUTO_BUILD=1
```
return EINVAL;
* 關掉 CPU Power Management ---> CPU Frequency scaling中的 [ ] CPU Frequency scaling.
if (flags & ~TIMER_ABSTIME)
* 將Real-time sub-system ---> Drivers ---> Testing drivers中的選項全部打開
```
cd ../../bb-kernel/KERNEL
make ARCH=arm menuconfig
```
return EINVAL;
* 再重新編譯
```
make -j8 ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- LOADADDR=0x80008000 uImage dtbs modules
```
cur = xnpod_current_thread();
* 編譯完後將 SD 卡內的 Kernel 換掉
```
mkdir sd
```
xnlock_get_irqsave(&nklock, s);
* 掛載 sd 卡
thread_cancellation_point(cur);
* 確認掛載的目錄內一定要有這些路徑
```
sudo mount /dev/mmcblk0p1 sd
sudo cp beagle-kernel/kernel/arch/arm/boot/uImage sd/boot/uImage-3.8.13
cd beagle-kernel/kernel
sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- INSTALL_MOD_PATH=$BBB/sd modules_install
cd -
mkdir sd/home/root/xeno_drivers
cp beagle-kernel/kernel/drivers/xenomai/testing/*.ko sd/home/root/xeno_drivers/
cp -r xenomai-2.6.3 sd/home/root
./configure --target=arm-linux-gnueabi
mkdir -p dist; make DESTDIR=`pwd`/dist install
```
xnpod_suspend_thread(cur, XNDELAY, ts2ticks_ceil(rqtp) + 1,
* 將編譯後dist內的內容複製放到beaglebone上
```
sudo umount sd
```
clock_flag(flags, clock_id), NULL);
* 測試,掛載driver
```
cd ~/xeno_drivers
insmod xeno_klat.ko
/usr/xenomai/bin/cyclictest -p 90
```
thread_cancellation_point(cur);
## Xenomai 3 on Beaglebone Black
if (xnthread_test_info(cur, XNBREAK)) {
* 先下載 linux kernel:
- 參考資料 : http://elinux.org/EBC_Installing_Kernel_Source
```
git clone git://github.com/RobertCNelson/bb-kernel.git
cd bb-kernel
git tag (This shows what versions can be checked out.)
git checkout 3.18-rc7 -b 3.18-rc7
./build_kernel.sh
```
if (flags == 0 && rmtp) {
* Prepare the kernel
```
cd ../../xenomai-2.6.4/scripts
./prepare-kernel.sh --arch=arm --linux=../../bb-kernel/KERNEL/
```
xnsticks_t rem;
* Compile Kernel
```
cd ../../bb-kernel
```
rem = xntimer_get_timeout_stopped(&cur->rtimer);
* 確認狀態,關掉休眠
- 關掉 CPU Power Management ---> CPU Frequency scaling中的 [ ] CPU Frequency scaling.
- 將Real-time sub-system ---> Drivers ---> Testing drivers中的選項全部打開
xnlock_put_irqrestore(&nklock, s);
![](/shutdownhibernation.png)
ticks2ts(rmtp, rem > 1 ? rem : 0);
```
make ARCH=arm menuconfig
```
} else
* 再重新編譯
```
make -j 8 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- LOADADDR=0x80008000 uImage dtbs modules
```
xnlock_put_irqrestore(&nklock, s);
* 把 SD card format 並 燒錄 debian (要進入 root 模式)
```
sudo mkfs -t ext4 /dev/mmcblk0
sudo xz -dkc bone-debian-7.5-2014-05-14-2gb.img.xz > /dev/mmcblk0
```
return EINTR;
* 把dtb file (or dts) and zImage 換掉,把 zImage 放入到 SD card 內
就可以成功開機了!
}
* 然後去下載 Xenomai3.git
- 參考資料 :http://git.xenomai.org/xenomai-3.git
```
wget http://git.xenomai.org/xenomai-3.git/snapshot/xenomai-3-3.0-rc4.tar.bz2
tar jxvf xenomai-3-3.0-rc4.tar.bz2
wget http://download.gna.org/adeos/patches/v3.x/arm/ipipe-core-3.18.12-arm-1.patch //載 ipipe patch
cd bb-kernel/KERNEL
patch -p1 < ../../ipipe-core-3.18.12-arm-1.patch
```
xnlock_put_irqrestore(&nklock, s);
* Compile Xenomai 3
return err;
```
cd xenomai-3-3.0-rc4
mkdir dist
export PATH=/home/neal/Xenomai/tool-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/:$PATH
./scripts/bootstrap --with-core=cobalt –enable-debug=partial
./configure CFLAGS="-march=armv7-a -mtune=cortex-a8 -mfloat-abi=hard -mfpu=neon -ffast-math" --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf
mkdir -p dist; make DESTDIR=`pwd`/dist install
```
}
* dist中會出現usr/xenomai, 將這個資料夾移到sd卡中 /usr/
clock_nanosleep主要用的api有下面幾個
* Install module :
```
cd bb-kernel/KERNEL
mkdir dist
sudo make ARCH=arm INSTALL_MOD_PATH=dist modules_install
```
- xnpod_current_thread
* 把 modules 移到 SD card /lib/modules 內
```
sudo cp -rp dist/lib/modules/3.18.0-rc7+/ /media/neal/rootfs/lib/modules/
```
.. code-block:: prettyprint
* 即可成功 run xenomai 3 的 內建執行檔.
- ex : sudo /usr/xenomai/bin/arm-linux-gnueabihf-latency
#define xnpod_current_thread() \
## **Xenomai 3 on Raspberry Pi 3**
(xnpod_current_sched()->curr)
### linux 核心部份
#define xnpod_current_sched() \
1. 下載 raspberrypi linux kernel source
```
$ git clone https://github.com/raspberrypi/linux.git
$ git checkout rpi-4.1.y
```
為了配合xenomai最新版本只支援linux kernel 4.1
xnpod_sched_slot(xnarch_current_cpu())
2. 下載 xenomai3 source
```
$ git clone http://git.xenomai.org/xenomai-3.git/
$ git checkout v3.0.2
```
4.1.18的patch檔只有3.0.2之後才有
#define xnpod_sched_slot(cpu) \
3. 下載 xenomai3 on bcm2709 patch
```
$ wget http://wiki.csie.ncku.edu.tw/_showraw/patch-xenomai-3-on-bcm-2709.patch
```
(&nkpod->sched[cpu]) //可以發現最後取得的東西是&nkpod->sched[current_cpu]->curr
- xnarch_current_cpu
.. code-block:: prettyprint
4. Patch Xenomai 到 Linux kernel 中
```
$ cd xenomai-3
$ scripts/prepare-kernel.sh --linux=../linux/ --ipipe=kernel/cobalt/arch/arm/patches/ipipe-core-4.1.18-arm-4.patch --arch=arm
```
static inline unsigned xnarch_current_cpu(void)
{
return rthal_processor_id(); //xnarch東西跟平台有關 因此會接到rthal這個abstraction layout
}
5. 打入xenomai3 on bcm2709 patch
```
$ cd linux
$ cat ../patch-xenomai-3-on-bcm-2709.patch | patch -p1
```
- rthal_processor_id()
6. 修改linux組態
```
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2709_defconfig
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
```
修改下列組態([ ]為不選,[X]為選取):
```
CPU Power Management --->
CPU Frequency scaling --->
[ ] CPU Frequency scaling
CPU idle --->
[ ] CPU idle PM support
Kernel Features --->
[ ] Contiguous Memory Allocator
[ ] Allow for memory compaction
Kernel Hacking --->
[ ] KGDB: kernel debugger
Boot options --->
Kernel command line type --->
[X] Extend bootloader kernel arguments
```
.. code-block:: prettyprint
7. 開始編譯核心
```
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs
```
使用 -jx 來建立x個thread平行編譯
#difine rthal_processor_id() ipipe_processor_id()
#define ipipe_processor_id() (0) //因為rapsberry pi只有一顆cpu 沒有SMP 所以會是使用這個macro
8. 輸出編譯完的模組
```
$ mkdir dist
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=dist modules_install
```
在這邊就能看到關於硬體的會從xnarch -> rthal -> ipipe
9. 複製 zImage 及 device tree 至 SD 卡上
```
$ cp arch/arm/boot/zImage /media/${USER}/boot
$ cp arch/arm/boot/dts/bcm2710-rpi-3-b.dtb /media/${USER}/boot
$ rm -rf /media/${USER}/boot/overlays/*
$ cp arch/arm/boot/dts/overlays/*.dtb* /media/${USER}/boot/overlays/
```
- xnlock_get_irqsave
10. 複製模組至 SD 卡上
```
# sudo cp -r linux/dist/lib/modules/* /media/${USER}/${ROOTFS}/lib/modules
```
.. code-block:: prettyprint
11. 修改 /boot/config.txt
內文最後加上
```
kernel=${zImage name}
device_tree=bcm2710-rpi-3-b.dtb
```
#define xnlock_get_irqsave(lock,x) \
((x) = __xnlock_get_irqsave(lock XNLOCK_DBG_CONTEXT))
static inline spl_t
__xnlock_get_irqsave(xnlock_t *lock /*, */ XNLOCK_DBG_CONTEXT_ARGS)
### Xenomai cobalt 核心部份
1. cobalt kernel 參數設定
```
$ cd xenomai-3
$ ./scripts/bootstrap --with-core=cobalt –enable-debug=partial
$ ./configure CFLAGS="-march=armv7-a -mtune=cortex-a8 -mfloat-abi=hard -mfpu=neon -ffast-math" --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf --enable-smp
```
{
unsigned long flags;
2. 編譯
```
$ make DESTDIR=${PWD}/target install
```
rthal_local_irq_save(flags);
3. 放入 SD 卡中
```
$ sudo cp -a target/* /media/${USER}/${ROOTFS}/
```
if (__xnlock_get(lock /*, */ XNLOCK_DBG_PASS_CONTEXT))
All Done!!
flags |= 2; /* Recursive acquisition */
觀察與分析
=====================================================================
return flags;
}
```
pi@raspberrypi:~$ cat /proc/xenomai/stat
CPU PID MSW CSW PF STAT %CPU NAME
0 0 0 206 0 00500080 100.0 ROOT
0 0 0 2688553 0 00000000 0.0 IRQ3: [timer]
```
* CPU : 目前這個tread是使用哪個CPU在運行,而rpi是單核心CPU,故顯示皆為0
* MSW : Mode SWitches, This value should only increase over time for threads that are expected to interact with Linux services.
- 當process從primary mode轉成secondary mode或是secondary mode轉成primary mode時,將會紀錄一次的轉換。
- rthal_local_irq_save
- cyclictest的RT task因為會執行到memset,所以會從xenomai schedule跳到linux schedule,MSW+1,而執行完memset後將在跳回xenomai schedule,故再+1
.. code-block:: prettyprint
* CSW : Number of Context SWitches (or IRQ hits for the particular CPU)
* PF : Number of Page Faults (should stop increasing as soon as mlockall is in effect)
* STAT : A bitfield describing the internal state of the thread. Bit values are defined in include/nucleus/thread.h (See status and mode bits). The STAT field from /proc/xenomai/sched gives a 1-letter-per-bit symbolic translation of a the most significant subset of those bits.
* %CPU : CPU share of the thread (or IRQ handler) since the last retrieval of the statistics.
* NAME : Name of the thread (or IRQ number and registered driver). Can be set, e.g., with the (non portable) POSIX-API-function pthread_set_name_np. See API documentation of the RTOS skin in question.
#define rthal_local_irq_save(x) ((x) = ipipe_test_and_stall_pipeline_head() & 1)
```
pi@raspberrypi:~$ sudo /usr/xenomai/bin/cyclictest >/dev/null 2>/dev/null &
[1] 2253
```
static inline unsigned long ipipe_test_and_stall_pipeline_head(void)
{
return ipipe_test_and_stall_head();
}
static inline unsigned long ipipe_test_and_stall_head(void)
{
hard_local_irq_disable();
return __test_and_set_bit(IPIPE_STALL_FLAG, &__ipipe_head_status);
}
```
pi@raspberrypi:~$ ps aux | grep -i "cy"
root 2253 0.5 0.3 4580 1464 ? S 03:34 0:00 sudo /usr/xenomai/bin/cyclictest
root 2254 2.7 0.4 2340 2132 ? SLl 03:34 0:00 /usr/xenomai/bin/cyclictest
pi 2259 0.0 0.1 3540 820 ttyAMA0 S+ 03:34 0:00 grep --color=auto -i cy
```
- hard_local_irq_disable
```
pi@raspberrypi:~$ cat /proc/xenomai/stat
CPU PID MSW CSW PF STAT %CPU NAME
0 0 0 255 0 00500080 100.0 ROOT
0 2254 1 1 0 00b00380 0.0 cyclictest
0 2256 2 48 0 00300184 0.0 cyclictest
0 0 0 2913946 0 00000000 0.0 IRQ3: [timer]
```
.. code-block:: prettyprint
```
pi@raspberrypi:~$ watch -n 1 cat /proc/xenomai/stat
Every 1.0s: cat /proc/xenomai/stat Wed Jan 8 03:38:43 2014
static inline void hard_local_irq_disable_notrace(void)
{
CPU PID MSW CSW PF STAT %CPU NAME
0 0 0 442 0 00500080 99.9 ROOT
0 2254 1 1 0 00b00380 0.0 cyclictest
0 2256 2 235 0 00300184 0.0 cyclictest
0 0 0 2953543 0 00000000 0.1 IRQ3: [timer]
```
#if __LINUX_ARM_ARCH__ >= 6
在這邊可以看到cyclictest有兩個pid,因為/usr/xenomai/bin/cyclictest它會先創一個thread,並讓這個thread跑nanosleep,所以會有兩個process。接著看向CSW,pid 2254的cyclictest, 他的CSW只有1。pid 2256的卻有235,這是因為2256是一個xenomai realtime task,而 2254是一個 linux的process,所以2256會優先執行,直到realtime task都做完才會換low priority的linux domain process取得CPU,因此2254的CSW值才會是1而沒有增加。
__asm__("cpsid i @ __cli" : : : "memory", "cc");
```
pi@raspberrypi:~$ sudo kill 2254
#else /* linux arch <= 5 */
pi@raspberrypi:~$ ps aux | grep -i "cy"
pi 2324 0.0 0.1 3540 820 ttyAMA0 R+ 03:46 0:00 grep --color=auto -i cy
[1]+ Done sudo /usr/xenomai/bin/cyclictest > /dev/null 2> /dev/null
unsigned long temp;
__asm__ __volatile__(
"mrs %0, cpsr @ hard_local_irq_disable\n"
"orr %0, %0, #128\n"
"msr cpsr_c, %0"
: "=r" (temp)
:
: "memory", "cc");
#endif /* linux arch <= 5 */
}
pi@raspberrypi:~$ sudo /usr/xenomai/bin/cyclictest -p FIFO >/dev/null 2>/dev/null &
```
- __xnlock_get
* 在我們了解MSW時,嘗試了在-p後面加上了文字(如:FIFO、RR……)
.. code-block:: prettyprint
* 發現MSV的值開始往上增加,也發現一開始對於MSW的定義理解錯誤
```
CPU PID MSW CSW PF STAT %CPU NAME
0 0 0 75266 0 00500080 99.9 ROOT
0 2978 1 1 0 00b00380 0.0 cyclictest
0 2980 2 26846 0 00300184 0.0 cyclictest
0 7559 1 1 0 00b00380 0.0 cyclictest
0 7561 66 130 0 00b00184 0.0 cyclictest
0 0 0 11266931 0 00000000 0.1 IRQ3: [timer]
```
#define xnlock_get(lock) __xnlock_get(lock XNLOCK_DBG_CONTEXT)
static inline int __xnlock_get(xnlock_t *lock /*, */ XNLOCK_DBG_CONTEXT_ARGS)
{
unsigned long long start;
int cpu = xnarch_current_cpu();
if (atomic_read(&lock->owner) == cpu)
return 1;
xnlock_dbg_prepare_acquire(&start);
if (unlikely(atomic_cmpxchg(&lock->owner, ~0, cpu) != ~0))
__xnlock_spin(lock /*, */ XNLOCK_DBG_PASS_CONTEXT);
xnlock_dbg_acquired(lock, cpu, &start /*, */ XNLOCK_DBG_PASS_CONTEXT);
return 0;
}
* trace後才了解,這是xenomai在-p的指令上是使用atoi,將輸入的數字轉為int,但並沒有進行偵錯,才導致segment fault,而需跳轉到linux domain進行除錯。
- thread_cancellation_point
.. code-block:: prettyprint
## 效能表現
static inline void thread_cancellation_point (xnthread_t *thread)
{
pthread_t cur = thread2pthread(thread);
if(cur && cur->cancel_request
&& thread_getcancelstate(cur) == PTHREAD_CANCEL_ENABLE )
pse51_thread_abort(cur, PTHREAD_CANCELED);
}
void pse51_thread_abort(pthread_t thread, void *status)
{
thread_exit_status(thread) = status;
thread_setcancelstate(thread, PTHREAD_CANCEL_DISABLE);
* Stock Linux
```
cyclictest -p 90 - m -c 0 -i 200 -n -h 100 -q -l 1000 >log
```
thread_setcanceltype(thread, PTHREAD_CANCEL_DEFERRED);
![](/embedded/xenomai/001.png)
xnpod_delete_thread(&thread->threadbase);
}
* PREEMPT_RT-patched Linux
```
cyclictest -p 90 - m -c 0 -i 200 -n -h 100 -q -l 1000 >log
```
- xnpod_delete_thread
- xnpod_suspend_thread
- xnthread_test_info
- xnlock_put_irqstore
.. code-block:: prettyprint
![](/embedded/xenomai/preemptRt.png)
static inline void xnlock_put_irqrestore (xnlock_t *lock, spl_t flags)
{
/* Only release the lock if we didn't take it recursively. */
if (!(flags & 2))
xnlock_put (lock);
rthal_local_irq_restore (flags & 1);
}
* Xenomai-patched Linux
```
/usr/xenomai/bin/cyclictest -p 90 - m -c 0 -i 200 -n -v 100 -q -l 100" >log
```
static inline void xnlock_put (xnlock_t *lock)
{
if (xnlock_dbg_release(lock))
return;
/*
* Make sure all data written inside the lock is visible to
* other CPUs before we release the lock.
*/
![](/embedded/xenomai/002.png)
xnarch_memory_barrier();
atomic_set(&lock->owner, ~0);
* User,kernal,timer IRQ 在R-pi上使用Xenomai 2.6與Xenomai 3.0之比較圖
}
- Xenomai 3.0
static inline int xnlock_dbg_release(xnlock_t *lock)
{
extern xnlockinfo_t xnlock_stats[];
unsigned long long lock_time = rthal_rdtsc() - lock->lock_date;
int cpu = xnarch_current_cpu();
xnlockinfo_t *stats = &xnlock_stats[cpu];
if (unlikely(atomic_read(&lock->owner) != cpu)) {
rthal_emergency_console();
printk(KERN_ERR "Xenomai: unlocking unlocked nucleus lock %p"
" on CPU #%d\n"
" owner = %s:%u (%s(), CPU #%d)\n",
lock, cpu, lock->file, lock->line, lock->function,
lock->cpu);
show_stack(NULL,NULL);
return 1;
}
lock->cpu = -lock->cpu; /* File that we released it. */
if (lock_time > stats->lock_time) {
stats->lock_time = lock_time;
stats->spin_time = lock->spin_time;
stats->file = lock->file;
stats->function = lock->function;
stats->line = lock->line;
}
return 0;
}
![](/embedded/xenomai/Rpi_xenomai3.png)
#define xnarch_memory_barrier() __sync_synchronize()
- Xenomai 2.6
#define rthal_local_irq_restore(x) ipipe_restore_pipeline_head(x)
![](/Rpi_xenomai2.png)
static inline xnticks_t xntimer_get_timeout_stopped (xntimer_t *timer)
{
return timer->base->ops->get_timer_timeout (timer);
}
* User,kernal,timer IRQ 在Beaglebone上使用Xenomai 2.6與Xenomai 3.0之比較圖
Scheduler
++++++++++
- Xenomai 3.0
.. code-block:: prettyprint
![](/Beaglebonxenomai3.png)
void __xnpod_schedule(struct xnsched *sched)
{
- Xenomai 2.6
int zombie, switched, need_resched, shadow;
![](/Beaglebonexenomai2.png)
struct xnthread *prev, *next, *curr;
## Cyclictest 原理
spl_t s;
if (xnarch_escalate()) /*這function會看現在是不是在root (linux) domain 如果是的話代表沒有realtime task 就將interrupt丟上去*/
* 概念:設定一個時間間隔->取得現在時間->讓process 睡一個間隔->process醒來後再取一次時間->比對兩次取得的時間差與設定的間隔差距
return;
* pseudocode:
```c
clock_gettime((&now))
next = now + par->interval
while (!shutdown) {
clock_nanosleep((&next))
clock_gettime((&now))
diff = calcdiff(now, next)
# update stat-> min, max, total latency, cycles
# update the histogram data
next += interval
}
```
trace_mark(xn_nucleus, sched, MARK_NOARGS);
* 造成時間差的原因
xnlock_get_irqsave(&nklock, s); /*在schudule時如果有interrupt會導致排程亂掉 因此要取得lock
*這邊這個是spinlock 會利用test and set的指令方式確保取得lock的操作是atomic
*後面的irqsave代表他會將interrupt disable*/
curr = sched->curr;
- timer精準度
- IRQ latency
- IRQ handler duration
- scheduler latency
- scheduler duration
xnarch_trace_pid(xnthread_user_task(curr) ?
xnarch_user_pid(xnthread_archtcb(curr)) : -1,
* Cyclictest 實作流程
xnthread_current_priority(curr));
1.cyclictest建立一個timerthread, 它一個 realtime 的 thread
reschedule:
2.timerthread會重複的執行取第一次時間 nanosleep(interval) 取第二次時間 比對兩次時間差與interval的差異
switched = 0;
3.最後將結果輸出在terminal
need_resched = __xnpod_test_resched(sched);
#if !XENO_DEBUG(NUCLEUS)
* Clock_nanosleep 的 timer
if (!need_resched)
clock_nanosleep 使用的timer 是 high resolution timer(HRT) ,讓睡眠時間可以更精確,達到nanosecond的精準度(但還是要看硬體能提供的精準度)
goto signal_unlock_and_exit;
因為能在更準確得時間讓process醒來並取的nanoscecond單位的時間 所以可以計算到由systick無法計算到的duration + latency
#endif /* !XENO_DEBUG(NUCLEUS) */
zombie = xnthread_test_state(curr, XNZOMBIE);
* Clock_nanosleep 實作流程
next = xnsched_pick_next(sched);
1.使用 spinlock (xnlock_get_irqsave) 令 CPU 不接受 Interrupt
/*先檢測thread是否為zombie thread 接著看current thread有沒有取得schedule lock如果有就無法preempt然後回傳current
*接著看current thread有沒有在ready 沒有的話就把他接到run queue 最後從sched_rt中的priority queue回傳queue的head
*也就是priority最高的thread*/
2.使用 xnpod_suspend_thread 改變目前 thread 的狀態
if (next == curr && !xnthread_test_state(curr, XNRESTART)) {
3.使用 xntimer_get_timeout_stopped 取得 tick
/* Note: the root thread never restarts. */
4.使用 ticks2ts 轉換時間單位
```c
int clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *rqtp, struct timespec *rmtp)
{
xnthread_t *cur;
spl_t s;
int err = 0;
if (unlikely(xnthread_test_state(next, XNROOT))) {
if (xnpod_unblockable_p())
return EPERM;
if (testbits(sched->lflags, XNHTICK))
if (clock_id != CLOCK_MONOTONIC && clock_id != CLOCK_REALTIME)
return ENOTSUP;
xnintr_host_tick(sched);
if ((unsigned long)rqtp->tv_nsec >= ONE_BILLION)
return EINVAL;
/*如果next不是root 則把interrupt在傳給root*/
if (flags & ~TIMER_ABSTIME)
return EINVAL;
if (testbits(sched->lflags, XNHDEFER))
cur = xnpod_current_thread();
xntimer_next_local_shot(sched);
xnlock_get_irqsave(&nklock, s);
}
thread_cancellation_point(cur);
goto signal_unlock_and_exit;
xnpod_suspend_thread(cur, XNDELAY, ts2ticks_ceil(rqtp) + 1,clock_flag(flags, clock_id), NULL);
}
thread_cancellation_point(cur);
XENO_BUGON(NUCLEUS, need_resched == 0);
if (xnthread_test_info(cur, XNBREAK)) {
prev = curr;
if (flags == 0 && rmtp) {
xnsticks_t rem;
trace_mark(xn_nucleus, sched_switch,
rem = xntimer_get_timeout_stopped(&cur->rtimer);
xnlock_put_irqrestore(&nklock, s);
"prev %p prev_name %s "
ticks2ts(rmtp, rem > 1 ? rem : 0);
} else
xnlock_put_irqrestore(&nklock, s);
"next %p next_name %s",
return EINTR;
}
xnlock_put_irqrestore(&nklock, s);
prev, xnthread_name(prev),
return err;
}
```
next, xnthread_name(next));
* [Cyclictest](https://rt.wiki.kernel.org/index.php/Cyclictest)
* Test case: POSIX interval timer, Interval 500 micro seconds,. 100000 loops, 100% load.
- Commandline:
```
cyclictest -t1 -p 80 -i 500 -l 100000
```
#ifdef CONFIG_XENO_OPT_PERVASIVE
* 使用 PREEMPT LINUX
```
root@raspberrypi:/home/pi# sudo ./cyclictest -t1 -p 80 -i 500 -l 100000
# /dev/cpu_dma_latency set to 0us
policy: fifo: loadavg: 0.00 0.01 0.05 1/61 2064
T: 0 ( 2063) P:80 I:500 C: 100000 Min: 27 Act: 49 Avg: 42 Max: 1060
```
shadow = xnthread_test_state(prev, XNSHADOW);
* 使用 RT-PREEMPT
```
Linux raspberrypi 3.6.11+ #474 PREEMPT Thu Jun 13 17:14:42 BST 2013 armv6l GNU/Linux
Min: 22 Act: 31 Avg: 32 Max: 169
```
#else
* 使用 Xenomai
```
Linux raspberrypi 3.8.13-core+ #1 Thu Feb 27 03:02:16 CST 2014 armv6l GNU/Linux
Min: 1 Act: 5 Avg: 6 Max: 41
```
(void)shadow;
```
root@raspberrypi:/home/pi# /usr/xenomai/bin/cyclictest -t1 -p 80 -i 500 -l 10000
0.08 0.06 0.05 1/61 2060
T: 0 ( 2060) P:80 I: 500 C: 100000 Min: -4 Act: -2 Avg: 0 Max: 30
```
#endif /* CONFIG_XENO_OPT_PERVASIVE */
if (xnthread_test_state(next, XNROOT)) {
T:thread
xnsched_reset_watchdog(sched);
P:priority
xnfreesync();
I:interval
}
if (zombie) /*如果接下來的thread是root就要重設watchdog timer*/
C:執行cycle數
xnsched_zombie_hooks(prev);
Min:最小延遲
sched->curr = next;
Act:此次延遲時間
if (xnthread_test_state(prev, XNROOT)) /*判斷prev跟next是否為root 對進出root有特出的xnarch_enter(leave)_root*/
Avg:平均延遲
xnarch_leave_root(xnthread_archtcb(prev));
Max:最大延遲
else if (xnthread_test_state(next, XNROOT)) {
最重要的是Max值 為了確保realtime 要能知道worst case,讓開發者可以評估最差的情況可以在多少時間內可以做出回應
if (testbits(sched->lflags, XNHTICK))
* 比較Cyclictest 於使用 PREEMPT LINUX,RT-PREEMPT以及Xenomai
xnintr_host_tick(sched);
- 使用R-pi model B+ , Xenoami 2.6.4
if (testbits(sched->lflags, XNHDEFER))
![](/embedded/xenomai/comparingto3mechanism.png)
xntimer_next_local_shot(sched);
- 實驗數據
| Kernel Type | Max latency(µs) |
|:----------------|:----------------|
| Linux preempt | 271 |
| Full preempt_rt | 96 |
| Xenomai 2.6.4 | 38 |
xnarch_enter_root(xnthread_archtcb(next));
## 示波器 實驗
}
xnstat_exectime_switch(sched, &next->stat.account); /*將thread的csw加到xnstat 讓/porc/xenomai/stat可以看到xenomai thread的情況*/
xnstat_counter_inc(&next->stat.csw);
xnpod_switch_to(sched, prev, next);
試著撰寫driver驅動板子,進而使用示波器測試latency,驗證在不同因素之下造成不同的 max latency
context switch
* Source code
#ifdef CONFIG_XENO_OPT_PERVASIVE
https://github.com/jacky6016/GPIO-test
/*
https://github.com/erickitten/GPIO_test_xenomai3_2
* Test whether we transitioned from primary mode to secondary
* 實驗數據
* over a shadow thread. This may happen in two cases:
+----------------------------------+---------------+
| Driver model |max latency(µs)|
+==================================+===============+
| rpi xenomai-2 RTDM | 4.71 |
+----------------------------------+---------------+
| beaglebone xenomai-2 RTDM | 7.46 |
+----------------------------------+---------------+
| rpi xenomai-3 RTDM | 7.022 |
+----------------------------------+---------------+
| rpi xenomai-2 linux native | 10.92 |
+----------------------------------+---------------+
| rpi xenomai-2 user-level(python) | 244 |
+----------------------------------+---------------+
*
* [詳細實驗紀錄](https://embedded2015.hackpad.com/Xenomai-lab-data-FlbetsD4sEe/)
* 1) the shadow thread just relaxed.
展示
=====================================================================
* 2) the shadow TCB has just been deleted, in which case
* we have to reap the mated Linux side as well.
在 RPi B+ 上結合 Xenomai 3 的成果:[CNC 繪圖機](https://www.youtube.com/watch?v=w77D1Mrx1yo)
*
Q&A
=====================================================================
* In both cases, we are running over the epilogue of Linux's
* schedule, and should skip our epilogue code.
*/
if (shadow && xnarch_root_domain_p())
goto shadow_epilogue;
#endif /* CONFIG_XENO_OPT_PERVASIVE */
switched = 1;
sched = xnsched_finish_unlocked_switch(sched);
/*
* Re-read the currently running thread, this is needed
* because of relaxed/hardened transitions.
*/
curr = sched->curr;
xnarch_trace_pid(xnthread_user_task(curr) ?
xnarch_user_pid(xnthread_archtcb(curr)) : -1,
xnthread_current_priority(curr));
if (zombie)
xnpod_fatal("zombie thread %s (%p) would not die...",
prev->name, prev);
xnsched_finalize_zombie(sched); /*處理掉zombie*/
__xnpod_switch_fpu(sched);
#ifdef __XENO_SIM__
if (nkpod->schedhook)
nkpod->schedhook(curr, XNRUNNING);
#endif /* __XENO_SIM__ */
xnpod_run_hooks(&nkpod->tswitchq, curr, "SWITCH");
signal_unlock_and_exit:
if (xnthread_signaled_p(curr))
xnpod_dispatch_signals();
if (switched &&
xnsched_maybe_resched_after_unlocked_switch(sched))
goto reschedule;
if (xnthread_lock_count(curr))
__setbits(sched->lflags, XNINLOCK);
xnlock_put_irqrestore(&nklock, s); /*解鎖*/
return;
#ifdef CONFIG_XENO_OPT_PERVASIVE
shadow_epilogue:
/* Shadow on entry and root without shadow extension on exit?
Mmmm... This must be the user-space mate of a deleted real-time
shadow we've just rescheduled in the Linux domain to have it
exit properly. Reap it now. */
if (xnshadow_thrptd(current) == NULL) {
splnone();
xnshadow_exit();
}
/* Interrupts must be disabled here (has to be done on entry of the
Linux [__]switch_to function), but it is what callers expect,
specifically the reschedule of an IRQ handler that hit before we
call xnpod_schedule in xnpod_suspend_thread when relaxing a
thread. */
XENO_BUGON(NUCLEUS, !irqs_disabled_hw());
return;
#endif /* CONFIG_XENO_OPT_PERVASIVE */
}
EXPORT_SYMBOL_GPL(__xnpod_schedule);
觀察與分析
=========
.. code-block:: prettyprint
pi@raspberrypi:~$ cat /proc/xenomai/stat
CPU PID MSW CSW PF STAT %CPU NAME
0 0 0 206 0 00500080 100.0 ROOT
0 0 0 2688553 0 00000000 0.0 IRQ3: [timer]
* CPU : 目前這個tread是使用哪個CPU在運行,而rpi是單核心CPU,故顯示皆為0
* MSW : Mode SWitches, This value should only increase over time for threads that are expected to interact with Linux services.
- 當process從primary mode轉成secondary mode或是secondary mode轉成primary mode時,將會紀錄一次的轉換。
- cyclictest的RT task因為會執行到memset,所以會從xenomai schedule跳到linux schedule,MSW+1,而執行完memset後將在跳回xenomai schedule,故再+1
* CSW : Number of Context SWitches (or IRQ hits for the particular CPU)
* PF : Number of Page Faults (should stop increasing as soon as mlockall is in effect)
* STAT : A bitfield describing the internal state of the thread. Bit values are defined in include/nucleus/thread.h (See status and mode bits). The STAT field from /proc/xenomai/sched gives a 1-letter-per-bit symbolic translation of a the most significant subset of those bits.
* %CPU : CPU share of the thread (or IRQ handler) since the last retrieval of the statistics.
* NAME : Name of the thread (or IRQ number and registered driver). Can be set, e.g., with the (non portable) POSIX-API-function pthread_set_name_np. See API documentation of the RTOS skin in question.
.. code-block:: prettyprint
pi@raspberrypi:~$ sudo /usr/xenomai/bin/cyclictest >/dev/null 2>/dev/null &
[1] 2253
* Q1:handler duration 與 schedule latency 之間的延遲原因為何?
- A:
.. code-block:: prettyprint
![](/embedded/xenomai/tasklatency.jpg)
pi@raspberrypi:~$ ps aux | grep -i "cy"
root 2253 0.5 0.3 4580 1464 ? S 03:34 0:00 sudo /usr/xenomai/bin/cyclictest
root 2254 2.7 0.4 2340 2132 ? SLl 03:34 0:00 /usr/xenomai/bin/cyclictest
pi 2259 0.0 0.1 3540 820 ttyAMA0 S+ 03:34 0:00 grep --color=auto -i cy
* Q2:ipipe的效益為何?為什麼要切割damain?切割完要如何確保real-time的穩定速度?
- A:
.. code-block:: prettyprint
ipipe的主要效益是用來切割domain,讓real-time和linux interrupt可以在不同domain下進行運作。
pi@raspberrypi:~$ cat /proc/xenomai/stat
CPU PID MSW CSW PF STAT %CPU NAME
0 0 0 255 0 00500080 100.0 ROOT
0 2254 1 1 0 00b00380 0.0 cyclictest
0 2256 2 48 0 00300184 0.0 cyclictest
0 0 0 2913946 0 00000000 0.0 IRQ3: [timer]
切割domain原因是因為real-time domain的優先序是最高的,當有real-time interrupt進來,就會直接進入real-time domain去執 行,不會在經過整個linux的複雜架構下進行preempt的動作,可確保real-time 能在短時間內進行處理。
.. code-block:: prettyprint
* Q3:ipipe/Adeos理論基礎中的Fine-grained是什麼?
- A:
pi@raspberrypi:~$ watch -n 1 cat /proc/xenomai/stat
Every 1.0s: cat /proc/xenomai/stat Wed Jan 8 03:38:43 2014
![](/criticalsection.png)
CPU PID MSW CSW PF STAT %CPU NAME
0 0 0 442 0 00500080 99.9 ROOT
0 2254 1 1 0 00b00380 0.0 cyclictest
0 2256 2 235 0 00300184 0.0 cyclictest
0 0 0 2953543 0 00000000 0.1 IRQ3: [timer]
在[life with andeos ](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.45.5628&rep=rep1&type=pdf)這篇指的fine-grained linux kernel,是指在編寫linux kernel code時,盡量讓critical section能愈短愈好,確保當real-time thread running in the secondary domain能在一定時間內遇到schedule point,也就可以在schedule point處理real-time thread。
在這邊可以看到cyclictest有兩個pid,因為/usr/xenomai/bin/cyclictest它會先創一個thread,並讓這個thread跑nanosleep,所以會有兩個process。接著看向CSW,pid 2254的cyclictest, 他的CSW只有1。pid 2256的卻有235,這是因為2256是一個xenomai realtime task,而 2254是一個 linux的process,所以2256會優先執行,直到realtime task都做完才會換low priority的linux domain process取得CPU,因此2254的CSW值才會是1而沒有增加。
* Q4:ipipe的相關檔案,gic.c、it8152.c ... 之類的有什麼關係?
.. code-block:: prettyprint
- A:
pi@raspberrypi:~$ sudo kill 2254
* Q5:請解釋下圖
pi@raspberrypi:~$ ps aux | grep -i "cy"
pi 2324 0.0 0.1 3540 820 ttyAMA0 R+ 03:46 0:00 grep --color=auto -i cy
[1]+ Done sudo /usr/xenomai/bin/cyclictest > /dev/null 2> /dev/null
![](/interuptdistributor.png)
pi@raspberrypi:~$ sudo /usr/xenomai/bin/cyclictest -p FIFO >/dev/null 2>/dev/null &
- A:
GIC:Generic Interrupt Controller(GIC)是arm用來集中分配interrupt至cpu的裝置。它主要分為distributor與cpu interfaces.
* 在我們了解MSW時,嘗試了在-p後面加上了文字(如:FIFO、RR……)
![](/embedded/xenomai/gic.png)
* 發現MSV的值開始往上增加,也發現一開始對於MSW的定義理解錯誤
distributor:負責分配interrupts,紀錄執行狀態,並提供registers以決定每個interrupt的enable、priority level、target processor。每個interrupt會有固定的interrupt ID,以供接收的cpu辨認。
.. code-block:: prettyprint
cpu interface:向cpu傳送interrupt request,並提供distributor接收(acknowledge)interrupt、完成interrupt等訊息;它也提供決定priority mask、preemption policy的registers。
CPU PID MSW CSW PF STAT %CPU NAME
0 0 0 75266 0 00500080 99.9 ROOT
0 2978 1 1 0 00b00380 0.0 cyclictest
0 2980 2 26846 0 00300184 0.0 cyclictest
0 7559 1 1 0 00b00380 0.0 cyclictest
0 7561 66 130 0 00b00184 0.0 cyclictest
0 0 0 11266931 0 00000000 0.1 IRQ3: [timer]
當啟動時,cpu interface會收到priority最高的pending interrupt,並決定它是否有足夠的priority被此cpu執行(參考mask、running interrupt、preemption),若是則signal cpu。cpu讀取interface的register(GICC_HPPIR)以接收interrupt,此讀取會得到interrupt ID,當接收後 distributor會改變狀態(由pending->active(and pending));完成之後,cpu寫入register以示意interrupt已經完成。
* trace後才了解,這是xenomai在-p的指令上是使用atoi,將輸入的數字轉為int,但並沒有進行偵錯,才導致segment fault,而需跳轉到linux domain進行除錯。
Interrupt types:
* Private Peripheral Interrupt (PPI) ID:16-31
效能表現
=======
* `Cyclictest<https://rt.wiki.kernel.org/index.php/Cyclictest>`_
* Test case: POSIX interval timer, Interval 500 micro seconds,. 100000 loops, 100% load.
- Commandline: cyclictest -t1 -p 80 -i 500 -l 100000
每個cpu各自獨立的硬體interrupt。
* 使用 PREEMPT LINUX
* Shared Peripheral Interrupt (SPI) ID:32~1019
.. code-block:: prettyprint
外部硬體interrupt。
root@raspberrypi:/home/pi# sudo ./cyclictest -t1 -p 80 -i 500 -l 100000
# /dev/cpu_dma_latency set to 0us
policy: fifo: loadavg: 0.00 0.01 0.05 1/61 2064
T: 0 ( 2063) P:80 I:500 C: 100000 Min: 27 Act: 49 Avg: 42 Max: 1060
* Software-generated interrupt (SGI) ID:0~15
軟體interrupt,由一個cpu發出,可指定至一個或多個cpu,cpu以寫入GICD_SGIR的方式產生SGI,其中PPI與SGI是N-N model,每個cpu的interrupt狀態各自獨立;SPI是1-N model,一旦其中一個目標cpu接受,interrupt即視為已處理。
* 使用 RT-PREEMPT
* Q6:Xenimai2與Xenomai3架構圖
.. code-block:: prettyprint
- A:
Linux raspberrypi 3.6.11+ #474 PREEMPT Thu Jun 13 17:14:42 BST 2013 armv6l GNU/Linux
Min: 22 Act: 31 Avg: 32 Max: 169
* Q7:要如何知道每個CPU上跑哪一個task? SMP是如何排程?
* 使用 Xenomai
- A:
.. code-block:: prettyprint
對CPU來講 thread, process都是程式(program),一如作業系統,CPU只是在其間跳來跳去;有一個 load balancer 會定期得去處理 Processor 間的 Balance 會將 loading 較重的 Processor 內的工作移到 Loading 較輕的 Processor 上去執行,其中會用到 Processor 間的 interrupt 這種 interrupt 叫 IPI (inter-processor interrupt)
* inter-processor interrupt (IPI):
IPI is a special type of interrupt by which one processor may interrupt another processor in a multiprocessor system if the interrupting processor requires action from the other processor.
Linux raspberrypi 3.8.13-core+ #1 Thu Feb 27 03:02:16 CST 2014 armv6l GNU/Linux
Min: 1 Act: 5 Avg: 6 Max: 41
* PPI :
.. code-block:: prettyprint
An interrupt generated by a peripheral.
root@raspberrypi:/home/pi# /usr/xenomai/bin/cyclictest -t1 -p 80 -i 500 -l 10000
0.08 0.06 0.05 1/61 2060
T: 0 ( 2060) P:80 I: 500 C: 100000 Min: -4 Act: -2 Avg: 0 Max: 30
共筆編輯紀錄
=====================================================================
Hackpad
=======
* 討論&紀錄 https://embedded2014.hackpad.com/Xenomai-raspberry-note-XwJtuQn9nkD
## 2016 紀錄
* 開發紀錄:[https://embedded2016.hackpad.com/-in-Xenomai-5zH4JsNDgO5](https://embedded2016.hackpad.com/-in-Xenomai-5zH4JsNDgO5)
* 整理 https://embedded2014.hackpad.com/Xenomai-z2CJPjPLTer
## 2015 紀錄
* 開發紀錄:[https://embedded2015.hackpad.com/Xenomai-LydARMEzEWP](https://embedded2015.hackpad.com/Xenomai-LydARMEzEWP)
組員
====
* 向澐
* 林家宏
* 呂科進
* 趙愷文
* 阮志偉
* 陳建霖
## 2014 紀錄
* 討論&紀錄:[https://embedded2014.hackpad.com/Xenomai-raspberry-note-XwJtuQn9nkD](https://embedded2014.hackpad.com/Xenomai-raspberry-note-XwJtuQn9nkD)
* 整理:[https://embedded2014.hackpad.com/Xenomai-z2CJPjPLTer](https://embedded2014.hackpad.com/Xenomai-z2CJPjPLTer)
參考資料
=======
* https://code.google.com/p/picnc/wiki/RPiXenomaiKernel
* https://code.google.com/p/picnc/wiki/CreateRaspbianLinuxCNC
* http://www.camelsoftware.com/firetail/blog/raspberry-pi/real-time-operating-systems/
* `Quadruped Linux robot feels its way over obstacles<http://linuxgizmos.com/hyq-quadruped-robot-runs-real-time-linux/>`_
* ` Choosing between Xenomai and Linux for real-time applications<https://www.osadl.org/fileadmin/dam/rtlws/12/Brown.pdf>`_
* `Real Time Systems<http://www.slideshare.net/anil_pugalia/real-time-systems>`_
* http://www.cs.ru.nl/lab/xenomai/exercises/
=====================================================================
* [Life with Adeos](https://xenomai.org/2014/06/life-with-adeos/)
* [Fast Interrupt Priority Management in Operating System Kernel](http://www.dtic.mil/dtic/tr/fulltext/u2/a266638.pdf)
* [https://code.google.com/p/picnc/wiki/RPiXenomaiKernel](https://code.google.com/p/picnc/wiki/RPiXenomaiKernel)
* [https://code.google.com/p/picnc/wiki/CreateRaspbianLinuxCNC](https://code.google.com/p/picnc/wiki/CreateRaspbianLinuxCNC)
* [http://www.camelsoftware.com/firetail/blog/raspberry-pi/real-time-operating-systems/](http://www.camelsoftware.com/firetail/blog/raspberry-pi/real-time-operating-systems/)
* [Quadruped Linux robot feels its way over obstacles](http://linuxgizmos.com/hyq-quadruped-robot-runs-real-time-linux/)
* [ Choosing between Xenomai and Linux for real-time applications](https://www.osadl.org/fileadmin/dam/rtlws/12/Brown.pdf)
* [Real Time Systems](http://www.slideshare.net/anil_pugalia/real-time-systems)
* [http://www.cs.ru.nl/lab/xenomai/exercises/](http://www.cs.ru.nl/lab/xenomai/exercises/)
* [背景知識 ](https://www.osadl.org/fileadmin/dam/rtlws/12/Brown.pdf)
* [應用案例 ](http://veter-project.blogspot.tw/search/label/xenomai)
* [應用案例II ](https://www.youtube.com/watch?v=cNZPRsrwumQ)
* [real-time Linux 介紹 ](http://class.svuca.edu/~sau/class/CE460/IntroEmbeddedLinuxDesign_Spring2014_Sec_13.ppt)
* [Xenomai 專案維護人的介紹 ](http://elinux.org/images/7/70/Gerum-elce-09.odp)
* [RTOS 定義 ](http://open-robotics.com/report/rtos/)