1. 程式人生 > >ARM-Linux中斷系統

ARM-Linux中斷系統

1.前言

瞭解Linux中斷子系統,同時也需要了解ARM體系結構中斷處理流程;在熟悉整個軟硬體架構和流程基礎上,才能對流程進行細化,然後找出問題的瓶頸。《2. 梳理中斷處理子系統

但是所有的優化都離不開一個量化的過程,有個可靠、高效、可讀性強的度量必不可少。《3. 一種測量中斷效能手段

最後基於此,進行中斷效能的優化。《4.中斷效能優化

2. 梳理中斷處理子系統

中斷系統涉及到軟硬體兩部分,具體到ARM系統和Linux涉及到很多相關點。

硬體以Cortex-A53為基礎,整個GIC架構包括兩部分:CPU內部的GIC CPU Interface(Cortex-A53 Chapter 9)和CPU外部的GIC external distributor component。

ARM Cortex-A53 MPCore Processor Technical Reference Manual》簡單介紹了A53核內部的GIC CPU Interface。

ARM Generic Interrupt Controller Architecture Specification v3/v4》詳細介紹了整個GIC架構的方方面面,具體實現比如GIC-600在《GIC-600 Generic Interrupt ControllerTechnical Reference Manual》。

軟體方面可以參考蝸窩科技關於中斷子系統的一系列文章《》,一共9篇文章,講述了Linux中斷的方方面面。

綜述》是一個導論性質文件,從更高層次介紹了中斷相關軟硬體架構;

《》重點介紹了中斷描述符相關資料結構以及API;

在一箇中斷出發之後,從CPU架構相模組進行現場保護《》-->machine相關中斷處理handler將HW Interrupt ID翻譯成IRQ number《》-->IRQ number對應中斷例程《》,以及最終現場恢復流程《》;

《》重點介紹了ARM架構下中斷控制器的方方面面。

3. 一種測量中斷效能手段

3.1 明確評估標的

評估一個系統的中斷效能,首先要明確評估那一段處理的效能。這裡評估的是從中斷觸發開始,到執行中斷例程(ISR)這段處理。

這一段從外部裝置觸發中斷,到中斷控制器,再到CPU處理,直到ISR的呼叫執行,涉及到軟硬體的方方面面。

3.2 如何對標的進行量化

從硬體觸發開始到軟體ISR執行時間度量,跨軟硬體。測量起來難免會有誤差,尤其是兩者的時間軸問題不易同步。

好在Linux有周期性Timer,週期性Timer設定一個Load值,從Load開始倒計數,計數到達0的時候觸發中斷。

然後重新計數,並且可以隨時讀取當前計數值。

在ISR中讀取計數,就可以知道從上次0計數觸發中斷到當前消耗的Cycle數目,進而得到標的耗時。

3.3 核心實現

核心中主要註冊中斷、提供修改Load介面、建立proc節點。

中斷相關初始化,註冊中斷處理函式。在ISR中進行Timer Cycle的讀取。

提供修改Load介面,供動態修改Load,以達到在不同頻率下測試標的的目的。

選取不同頻率的load:
echo n > /proc/interrupt_stats

讀取Timer中斷統計資訊:
cat /proc/interrupt_stats > interrupt_xxx.txt

proc檔案提供設定Load和讀取標的結果的介面。

//===================================================
#include <asm/uaccess.h>

extern unsigned int interrupt_statiscs[1024][2];
extern unsigned int interrupt_period_count;

extern void interrupt_set_period(unsigned int cycles);

static int interrupts_proc_show(struct seq_file *m, void *v)
{
    int i;

    for(i = 0; i < sizeof(interrupt_statiscs)/sizeof(interrupt_statiscs[0]); i++)
        seq_printf(m, "%u, %u, %u\n", interrupt_period_count, interrupt_statiscs[i][0], interrupt_statiscs[i][1]);

    return 0;
}

static ssize_t interrupts_proc_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
{
    unsigned int period_cycles;
    char buf[1];


    if (copy_from_user(buf, user_buf, 1))
        return -EFAULT;
    sscanf(buf, "%u", &period_cycles);
    printk("%s period_cycles %u\n", __func__, period_cycles);

    if (period_cycles > 0 && period_cycles < 5)
    {
        switch(period_cycles)
        {
            case 0:
                period_cycles = 2600000;
                break;
            case 1:
                period_cycles = 260000;
                break;
            case 2:
                period_cycles = 26000;
                break;
            case 3:
                period_cycles = 2600;
                break;
            case 4:
                period_cycles = 1300;
                break;
            default:
                period_cycles = 260000;
        }

        interrupt_set_period(period_cycles);
        printk("%s set interrupt period to %u\n", __func__, period_cycles);
    }
    return 1;
}

static int interrupts_proc_open(struct inode *inode, struct file *file)
{
    return single_open(file, interrupts_proc_show, NULL);
}

static const struct file_operations interrupt_stats_proc_fops = {
    .open        = interrupts_proc_open,
    .write        = interrupts_proc_write,
    .read        = seq_read,
    .llseek        = seq_lseek,
    .release    = single_release,
};

//===================================================

static int __init proc_uptime_init(void)
{
    proc_create("uptime", 0, NULL, &uptime_proc_fops);
    
    proc_create("interrupt_stats", 0, NULL, &interrupt_stats_proc_fops);
    return 0;
}
module_init(proc_uptime_init);

3.4 分析結果

當前使用測試Timer是26MHz,輔助衡量Load準確行的是32768時鐘計數。

26MHz的時鐘,一個Cycle=38.46納秒,這個精度已經很高了。用於衡量中斷效能應該夠用。

1. 將測試結果從裝置中匯出。第1列是當前Load數,第2列是標的耗時,第3列是輔助時鐘計數。第1、2列是26MHz時鐘,第3列是32K時鐘。

將這些結果按照Load不同儲存到interrupts_1300.txt/...檔案中。

2600000, 321, 3277
2600000, 334, 3277
2600000, 315, 3277
2600000, 321, 3277
2600000, 324, 3277
2600000, 335, 3276
2600000, 355, 3277
2600000, 341, 3277
2600000, 345, 3277
2600000, 346, 3277
...

2. 編寫分析指令碼

import pandas as pd
import numpy as np
import os
import re
import matplotlib.pyplot as plt
import matplotlib
matplotlib.style.use('ggplot')


cnames = ['index', 'count', 'duration']

output = []
output_cycles = []

timer_freq = 26000000
p = re.compile('^interrupts_([0-9]*).txt$')

filenames = os.listdir('.')
for file in filenames:
    if p.match(file):
        data = []
        interrupt_data = []
        interrupt_stats = []

        duration_data = []

        interrupt_stats = pd.read_csv(file, names = cnames)--------------------讀取資料來源
        
        #Show the plotting of interrupts time consumption
        ts = pd.Series(interrupt_stats['count'], index=range(len(interrupt_stats['count'])))
        ts.plot(title='%s'%file)
        fig = plt.gcf()
        fig.set_size_inches(25, 4)
        plt.ylabel('Cycles from trigger to ISR.')
        plt.show()
        
        #Convert to time consumption
        for i in interrupt_stats['count'].tolist():
            data.append(float(i)*1000000/timer_freq)------------------------轉換成時間單位us

        #Calc the timer duration
        for i in interrupt_stats['duration'].tolist():
            duration_data.append(i)

        #Statistics of interrupts
        interrupt_data = np.array(data)
        output.append([interrupt_data.mean(), interrupt_data.max(), interrupt_data.min(), interrupt_data.std()])----每個case的統計資訊
        output_cycles.append([interrupt_stats['count'].mean(),
                              interrupt_stats['count'].max(),
                              interrupt_stats['count'].min(),
                              interrupt_stats['count'].std()])------------------------------------------------------cycles形式的統計資訊
        
df = pd.DataFrame(output, columns=['mean(us)','max(us)','min(us)', 'std(us)'], index=['1300', '2600', '26000', '260000', '2600000'])
df.to_csv('interrupt.csv')
pd.pivot_table(df, index='mean(us)')----------pivot table形式展示統計資訊

  f2 = pd.DataFrame(output_cycles, columns=['mean(us)','max(us)','min(us)', 'std(us)'], index=['1300', '2600', '26000', '260000', '2600000'])
  pd.pivot_table(df2, index='mean(us)')--------pivot table形式展示統計資訊

3. 結果分析

3.1 耗時圖表分析

從下面5張圖中可以看出標的耗時分佈情況,總體來講資料比較穩定。

  • 26000/260000/2600000會有個別特別長的延時;
  • 所有case的最低值比較接近在90-120左右個Cycles;
  • 隨著Load增加,平均耗時呈遞增趨勢;
  • 對26000/260000/2600000修改了ylim到500,可以看出細節部分。

 3.2 耗時統計資訊 下面是每個case的平均值、最大值、最小值、均方差的統計資訊。

4.中斷效能優化

中斷效能優化可以分為兩個階段:中斷公用部分和每個中斷例程包括下半部。

4.1 中斷共用部分

中斷共用部分包括:架構相關程式碼、中斷控制器驅動等。

  • 提高cache命中率?
  • 將相關處理程式碼放入cache中?
  • 中斷和CPU繫結?
  • 級聯對中斷效能的影響?
  • ......

4.2 每中斷例程及下半部

每中斷例程及下半部:首先針對中斷例程,儘量短小快速、不睡眠;對下半部,採取合適的方法softirq/tasklet/workqueue。

中斷例程的優化,可以通過Tracepoint中中斷相關trace進行統計。

/sys/kernel/debug/tracing/events/irq/irq_handler_entry
/sys/kernel/debug/tracing/events/irq/irq_handler_exit
/sys/kernel/debug/tracing/events/irq/softirq_entry
/sys/kernel/debug/tracing/events/irq/softirq_exit
/sys/kernel/debug/tracing/events/irq/softirq_raise

 下面是一箇中斷例程執行耗時統計資訊。

平均值大說明例程需要優化,因為在中斷例程執行期間是遮蔽中斷的,遮蔽時間太長容易丟中斷。

如果均方差大,說明中斷例程內流程差異較大,可能存在隱患。

+------------------------+-------+--------+-------+-------+--------+------------------+
|          name          |  mean |  max   |  min  | count |  sum   |       std        |
+------------------------+-------+--------+-------+-------+--------+------------------+
|      dwc_otg_pcd       | 0.457 | 32.196 |  0.0  |  104  | 47.516 |  3.26191450776   |
|        xxxxxxx         | 0.004 | 0.031  |  0.0  |  675  | 2.903  | 0.0106282606939  |
|  dwc_otg_powerdown_up  | 7.644 |  7.66  | 7.629 |   2   | 15.289 |      0.0155      |
|         icp_ps         | 0.006 | 0.031  |  0.0  |   5   | 0.031  |      0.0124      |
|       xxxx_i2c.0       | 0.010 | 0.031  |  0.0  |   48  | 0.459  | 0.0141861232812  |
|       xxxx_timer       | 0.003 | 0.092  |  0.0  |  1378 | 4.305  | 0.00947335198132 |
| dwc_otg_powerdown down | 5.264 |  6.5   | 4.028 |   2   | 10.528 |      1.236       |
+------------------------+-------+--------+-------+-------+--------+------------------+

 下面是這些中斷在時間軸上的分不情況,長度表示耗時。可以看出他們的頻率,以及相互之間的關係。

 

相關推薦

ARM-Linux中斷系統

1.前言 瞭解Linux中斷子系統,同時也需要了解ARM體系結構中斷處理流程;在熟悉整個軟硬體架構和流程基礎上,才能對流程進行細化,然後找出問題的瓶頸。《2. 梳理中斷處理子系統》 但是所有的優化都離不開一個量化的過程,有個可靠、高效、可讀性強的度量必不可少。《3. 一種測量中斷效能手段》 最後基於此,進行中

(轉)ARM Linux中斷發生時內核堆棧切換

平臺 晶體 處理器 har 接口 步驟 成了 重要 lin 轉載註明出處:http://www.wowotech.net/forum/viewtopic.php?id=54 對ARM Linux中斷非常簡潔、精確的描述。 發生了中斷,最重要的是保存現場,在中斷處理完之後,

alsa移植到arm linux嵌入式系統

1  alsa-lib的移植 1.1  軟體包下載 alsa-lib庫:進入網站http://www.alsa-project.org/選擇下載,在這裡下載的是alsa-lib-1.0.22.tar.bz2假設該軟體包存放在目錄/home/alsa中 1.2 安裝als

ARM+LINUX嵌入式系統的終端顯示中文亂碼解決

前一段時間解決的一個問題,看起來是個小問題,實際解決這個問題卻花了一個星期的晚上休息時間,記錄分享一下。 問題描述: linux核心配置中NLS(native language support)已經選擇了預設語言配置為utf8,幷包含一些其他常用語言的編碼,但是在se

ARM-Linux嵌入式系統啟動流程

        作為一個嵌入式新手,閱讀資料之後做一下筆記還是很有必要的,下面從四個階段來描述嵌入式系統的大致啟動流程。如下圖所示: 圖片引用自OMAPpedia的WIKI 其他相關參考資料: TI官方WIKI的boot sequence        由此可見啟

Linux + arm 中斷系統理解

arm中斷框架: 我把中斷系統的硬體組成分為三個部分,CPU、中斷控制器、外設中斷源。imx6q的Interrupt Controller為GIC,支援多CPU Core。 【1】首先來看CPU 目標架構相關的的中斷處理 中斷向量表 arch/arm/ker

Linux中斷(interrupt)子系統之一:中斷系統基本原理

兩個 ons ... req [0 共享 代碼 not spl 這個中斷系列文章主要針對移動設備中的Linux進行討論,文中的例子基本都是基於ARM這一體系架構,其他架構的原理其實也差不多,區別只是其中的硬件抽象層。內核版本基於3.3。雖然內核的版本不斷地提升,不過自從上一

Linux中斷系統調用

例子 off ipc perror depend 重新開始 stat 適用於 data 早期UNIX系統的一個特性是:如果在進程執行一個低速系統調用而阻塞期間捕捉到一個信號,則該系統調用就被中斷不再繼續執行。該系統調用返回出錯,其errno設置為EINTR。這樣處理的理由是

Linux中斷 - ARM中斷處理過程

thum nio cti abort 兩個 alloc pos 不同 eve 一、前言 本文主要以ARM體系結構下的中斷處理為例,講述整個中斷處理過程中的硬件行為和軟件動作。具體整個處理過程分成三個步驟來描述: 1、第二章描述了中斷處理的準備過程 2、第三章描述了當發生中的

arm linux 系統呼叫過程

在Linux下系統呼叫是用軟中斷實現的,下面以一個簡單的open例子簡要分析一下應用層的open是如何呼叫到核心中的sys_open的。 t8.c 1: #include <stdio.h> 2: #include <sys/types.h> 3:

[問答] 在arm-linux上如何修改系統記憶體的大小?

http://bbs.elecfans.com/jishu_1603506_1_1.html demo板上預設的系統記憶體是512M,我修改了一下boot啟動引數為256M後,發現記憶體啟動過程中掛掉了 而且發現dts檔案中的 memory [ device_type

arm-linux-gcc編譯時出現的一些小插曲-----64位系統需要32位的庫

最近由於工作的需要,重新弄起arm-linux-gcc編譯。離上一次弄這些有整整10年了。 我是在一臺64位的機器上實機安裝的 centos7 發行版,系統和交叉編譯器的安裝過程自是沒話說,問題出在使用arm-linux-gcc編譯 arm程式時, $ arm-linu

ARM Linux系統修改動態IP為靜態IP地址

# Wired or wireless interfaces auto eth0

三十三、Linux 程序與訊號——中斷系統呼叫和函式可重入性

33.1 中斷系統呼叫 程序呼叫 “慢” 系統呼叫時,如果發生了訊號,核心會重啟系統呼叫。 慢系統呼叫 可能會永久阻塞的系統呼叫 從終端裝置、管道或網路裝置上的檔案讀取 向上述檔案寫入 某些裝置上的檔案開啟 pause 和 wait 系統呼叫

Ubuntu系統arm-linux-gcc交叉編譯環境搭建過程

搭建所需環境 Linux版本:Ubuntu 14.10    交叉編譯器版本:arm-linux-gcc-4.4.3資源連結 何為交叉編譯環境 搭建交叉編譯環境,即安裝、配置交叉編譯工具鏈。在Ubun

主機windows系統,虛擬機器linux系統與工控屏arm-linux之間使用tftp進行資料傳輸

1.保證三個系統之前能互相ping 通 2.開啟windows系統,linux系統的tftp-server windows使用tftp32工具。 linux 使用參考以下文章: 重啟xinetd服務: [email protected]:~$ sudo /etc/i

2011-02-20 19:17 Arm Linux下如何儲存設定的系統時間

問:Linux下如何儲存設定的系統時間? 答:分以下步驟進行: (1)通過開發板控制檯設定開發板的當前系統時間: date [MMDDhhmm[[CC]YY][.ss]] 例如: date 010410462008 (2)將系統時間寫入RTC: hwclock -w 讀出檢

第六十一篇:移植不帶系統應用程式到有ARM-LINUX系統的S32V234上

上一篇講了一下有統的應用程式移植,相對來說比較簡單 從今天開始要移植一個沒有系統的應用程式到S32V234上,處理預處理需要用到ISP外,還要使用APEX,還要使用linux系統管理載入檔案,原來的應用程式中的檔案載入管理是自定義的檔案開啟和讀取函式 先分析一下需要做的工作

arm linux 系統呼叫過程

在Linux下系統呼叫是用軟中斷實現的,下面以一個簡單的open例子簡要分析一下應用層的open是如何呼叫到核心中的sys_open的。 t8.c 1: #include <stdio.h> 2: #include <sys/types.

ARM Linux核心中增加一個新的系統呼叫

實驗平臺核心版本為4.0-rc1,增加的系統呼叫僅僅是簡單列印一個Hello World,最後我們在使用者空間用swi指令驗證。涉及到的改動如下:1. 在核心中增加檔案arch/arm/kernel/mysyscall.c,這個檔案實現新的列印Hello World的系統呼叫