ARM-Linux中断系统【转】
转自:https://www.cnblogs.com/arnoldlu/p/7406441.html
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》。
相关阅读记录在《阅读GIC-500 Technical Reference Manual笔记》。
软件方面可以参考蜗窝科技关于中断子系统的一系列文章《Linux中断子系统》,一共9篇文章,讲述了Linux中断的方方面面。
《综述》是一个导论性质文档,从更高层次介绍了中断相关软硬件架构;
《IRQ number和中断描述符》重点介绍了中断描述符相关数据结构以及API;
在一个中断出发之后,从CPU架构相模块进行现场保护《ARM中断处理过程》-->machine相关中断处理handler将HW Interrupt ID翻译成IRQ number《IRQ Domain介绍》-->IRQ number对应中断例程《High level irq event handler》,以及最终现场恢复流程《ARM中断处理过程》;
《驱动申请中断API》是从中断使用者角度介绍如何使用中断;中断处理的下半部包括《softirq》和《tasklet》,以及workqueue 1 2 3 4。
《GIC代码分析》重点介绍了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,可以看出细节部分。








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中断系统【转】的更多相关文章
- linux中断系统那些事之----中断处理过程【转】
转自:http://blog.csdn.net/xiaojsj111/article/details/14129661 以外部中断irq为例来说明,当外部硬件产生中断时,linux的处理过程.首先先说 ...
- ARM Linux中断发生时内核堆栈切换
转载注明出处:http://www.wowotech.net/forum/viewtopic.php?id=54 对ARM Linux中断非常简洁.精确的描述. 发生了中断,最重要的是保存现场,在中断 ...
- [Fw]初探linux中断系统(2)
初探linux中断系统(2) 中断系统初始化的过程 用来初始化中断系统的函数位于arch/x86/kernel/irqinit.c,定义如下 void __init init_IRQ(void){ i ...
- ARM linux中断总结
Linux异常处理体系结构 Linux异常体系之vector_stub宏解析 Linux异常体系之stubs_offset Linux中断体系结构 ARM系统调用
- [Fw]初探linux中断系统(1)
1. 重要接口 LDD上说,“内核维护了一个中断信号线的注册表,该注册表类似于I/O端口的注册表.模块在使用中断前要先请求一个中断通道(或者中断请求IRQ),然后在使用后释放该通道.” 撇开系统如何遍 ...
- ARM+LINUX嵌入式系统的终端显示中文乱码解决
前一段时间解决的一个问题,看起来是个小问题,实际解决这个问题却花了一个星期的晚上休息时间,记录分享一下. 问题描述: linux内核配置中NLS(native language support)已经选 ...
- linux中断子系统:中断号的映射与维护初始化mmap过程
本文均属自己阅读源代码的点滴总结.转账请注明出处谢谢. 欢迎和大家交流.qq:1037701636 email:gzzaigcn2009@163.com 写在前沿: 好久好久没有静下心来整理一些东西了 ...
- Linux中断(interrupt)子系统之一:中断系统基本原理【转】
转自:http://blog.csdn.net/droidphone/article/details/7445825 这个中断系列文章主要针对移动设备中的Linux进行讨论,文中的例子基本都是基于AR ...
- Linux中断 - ARM中断处理过程
一.前言 本文主要以ARM体系结构下的中断处理为例,讲述整个中断处理过程中的硬件行为和软件动作.具体整个处理过程分成三个步骤来描述: 1.第二章描述了中断处理的准备过程 2.第三章描述了当发生中的时候 ...
- Linux中断(interrupt)子系统之一:中断系统基本原理
这个中断系列文章主要针对移动设备中的Linux进行讨论,文中的例子基本都是基于ARM这一体系架构,其他架构的原理其实也差不多,区别只是其中的硬件抽象层.内核版本基于3.3.虽然内核的版本不断地提升,不 ...
随机推荐
- Zuul 详解,带视频
疯狂创客圈 Java 高并发[ 亿级流量聊天室实战]实战系列 [博客园总入口 ] 架构师成长+面试必备之 高并发基础书籍 [Netty Zookeeper Redis 高并发实战 ] 前言 Crazy ...
- GitHub Actions 工作流
今天打开github上面的 项目 突然 一个github actions 的提示, 进去后显示: 由于项目是Maven 创建的 选择Maven 进入: 初步看到代码: 大概意思就是 我们push ...
- python中time.strftime不支持中文,报错UnicodeEncodeError: 'locale' codec can't encode character '\u5e74' in position 2: encoding error
使用time.strftime将 "2020-10-10 10:10:10" 转化为 2020年10月10日10时10分10 报错: import time timestr=&q ...
- 剑指offer笔记面试题6----从未到头打印链表
题目:输入一个链表的头结点,从尾到头反过来打印出每个结点的值.链表节点定义如下: struct ListNode{ int m_nKey; ListNode* m_pNext; } 测试用例: 功能测 ...
- 案例——UDP聊天
UDP聊天案例 做一个网络编程相关的案例,想着用利用UDP的快速且不用连接的优点做一个聊天室,我们一个聊天程序需要可以接收消息,也要可以发送消息,所以我们的DatagramSocket对象不但需要 ...
- Angular-----代码风格指南!!!(很重要)
一:文件结构 1).单一规则:坚持每个文件只定义一样东西(例如服务或组件),考虑把文件大小限制在 400 行代码以内. 单组件文件非常容易阅读.维护,并能防止在版本控制系统里与团队冲突: 单组件文件可 ...
- Tesseract.js 一个几乎能识别出图片中所有语言的JS库
Tesseract.js 一个几乎能识别出图片中所有语言的JS库. 官网:http://tesseract.projectnaptha.com/ git:https://github.com/napt ...
- Android使用ActivityLifecycleCallbacks管理Activity和区分App前后台
一.ActivityLifecycleCallbacks接口介绍 官方地址:https://developer.android.com/reference/android/app/Applicatio ...
- 提速企业应用开发,Ntaub 3极速开发平台发布
企业管理系统搞了这么多年,还是以表单.数据增删改这些功能为主.唯一的变化就是“变化”,企业的业务模式和流程越来越多样化,开发需求变更越来越频繁,开发周期却要求越来越短. 无代码.低代码开发平台开始流行 ...
- linux离线安装mysql5.7
下载安装包 下载地址:https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7.27-1.el7.x86_64.rpm-bundle.tar 上传到 / ...