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.虽然内核的版本不断地提升,不 ...
随机推荐
- Unity 依赖注入容器的AOP扩展
使用EntLib\PIAB Unity 实现动态代理 using System; using Unity; using Unity.Interception; using Unity.Intercep ...
- Password Management:Hardcoded Password 密码管理:硬编码密码
- Centos 下安装 PHP (新)
今天重新实践了下 CentOS 7.6 下安装 PHP7 并完成配置,总结了一条可以照其实现的套路. 安装 PHP 所需扩展 # yum install libxml2 libxml2-devel o ...
- CSS(2)---css字体、文本样式属性
css字体.文本样式属性 这篇主要讲CSS文本属性中的:字体样式属性 和 文本样式属性. 一.字体样式属性 CSS 字体属性主要包括:字体设置(font-family).字号大小(font-size) ...
- 什么是 AQS?简单说一下 ReentrantLock 的原理?
AQS 简介 java的内置锁一直都是备受争议的,在JDK 1.6之前,synchronized这个重量级锁其性能一直都是较为低下,虽然在1.6后,进行大量的锁优化策略,但是与Lock相比synchr ...
- 关于 IIS Express 常用设置
关于 IIS Express 常用设置 站点绑定 IIS Express Web 服务器默认只绑定了 localhost 的主机名,这就意味着无法通过内网或其他自定义域名进行访问,可通过如下操作添加其 ...
- Vue初始化过程
用vue也有一两年了,始终对vue一知半解,不怎么了解内部的执行过程,最近在看vue源码,还是不少收获的,其中不乏浏览器事件轮询机制.闭包.设计模式等,还是非常值得一读.本篇简要记录下vue的初始化过 ...
- 部署vue-element-admin流程
1.修改环境变量: 在以下两个文件: .env_staging [如果修改这个,需要以npm run build:stage启动] .env_production [如果修改这个,需要以npm run ...
- Dockerfile编写
Dockerfile 是一个文本文件,其内包含了一条条的指令,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建编写命令: 1.FROM作用:声明使用哪个基础镜像格式:FROM IMA ...
- JAVA工程师技能要求
近期做了个JAVA工程师分类, JAVA工程师可能是市场上最多类的程序员: 初级JAVA工程师的基本要求 Good basic programming skills 良好基本编程技能 Founda ...