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,以达到在不同频率下测试标的的目的。

  1. 选取不同频率的load
  2. echo n > /proc/interrupt_stats
  3.  
  4. 读取Timer中断统计信息:
  5. cat /proc/interrupt_stats > interrupt_xxx.txt

proc文件提供设置Load和读取标的结果的接口。

  1. //===================================================
  2. #include <asm/uaccess.h>
  3.  
  4. extern unsigned int interrupt_statiscs[][];
  5. extern unsigned int interrupt_period_count;
  6.  
  7. extern void interrupt_set_period(unsigned int cycles);
  8.  
  9. static int interrupts_proc_show(struct seq_file *m, void *v)
  10. {
  11. int i;
  12.  
  13. for(i = ; i < sizeof(interrupt_statiscs)/sizeof(interrupt_statiscs[]); i++)
  14. seq_printf(m, "%u, %u, %u\n", interrupt_period_count, interrupt_statiscs[i][], interrupt_statiscs[i][]);
  15.  
  16. return ;
  17. }
  18.  
  19. static ssize_t interrupts_proc_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
  20. {
  21. unsigned int period_cycles;
  22. char buf[];
  23.  
  24. if (copy_from_user(buf, user_buf, ))
  25. return -EFAULT;
  26. sscanf(buf, "%u", &period_cycles);
  27. printk("%s period_cycles %u\n", __func__, period_cycles);
  28.  
  29. if (period_cycles > && period_cycles < )
  30. {
  31. switch(period_cycles)
  32. {
  33. case :
  34. period_cycles = ;
  35. break;
  36. case :
  37. period_cycles = ;
  38. break;
  39. case :
  40. period_cycles = ;
  41. break;
  42. case :
  43. period_cycles = ;
  44. break;
  45. case :
  46. period_cycles = ;
  47. break;
  48. default:
  49. period_cycles = ;
  50. }
  51.  
  52. interrupt_set_period(period_cycles);
  53. printk("%s set interrupt period to %u\n", __func__, period_cycles);
  54. }
  55. return ;
  56. }
  57.  
  58. static int interrupts_proc_open(struct inode *inode, struct file *file)
  59. {
  60. return single_open(file, interrupts_proc_show, NULL);
  61. }
  62.  
  63. static const struct file_operations interrupt_stats_proc_fops = {
  64. .open = interrupts_proc_open,
  65. .write = interrupts_proc_write,
  66. .read = seq_read,
  67. .llseek = seq_lseek,
  68. .release = single_release,
  69. };
  70.  
  71. //===================================================
  72.  
  73. static int __init proc_uptime_init(void)
  74. {
  75. proc_create("uptime", , NULL, &uptime_proc_fops);
  76.  
  77. proc_create("interrupt_stats", , NULL, &interrupt_stats_proc_fops);
  78. return ;
  79. }
  80. 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/...文件中。

  1. , ,
  2. , ,
  3. , ,
  4. , ,
  5. , ,
  6. , ,
  7. , ,
  8. , ,
  9. , ,
  10. , ,
  11. ...

2. 编写分析脚本

  1. import pandas as pd
  2. import numpy as np
  3. import os
  4. import re
  5. import matplotlib.pyplot as plt
  6. import matplotlib
  7. matplotlib.style.use('ggplot')
  8.  
  9. cnames = ['index', 'count', 'duration']
  10.  
  11. output = []
  12. output_cycles = []
  13.  
  14. timer_freq =
  15. p = re.compile('^interrupts_([0-9]*).txt$')
  16.  
  17. filenames = os.listdir('.')
  18. for file in filenames:
  19. if p.match(file):
  20. data = []
  21. interrupt_data = []
  22. interrupt_stats = []
  23.  
  24. duration_data = []
  25.  
  26. interrupt_stats = pd.read_csv(file, names = cnames)--------------------读取数据源
  27.  
  28. #Show the plotting of interrupts time consumption
  29. ts = pd.Series(interrupt_stats['count'], index=range(len(interrupt_stats['count'])))
  30. ts.plot(title='%s'%file)
  31. fig = plt.gcf()
  32. fig.set_size_inches(, )
  33. plt.ylabel('Cycles from trigger to ISR.')
  34. plt.show()
  35.  
  36. #Convert to time consumption
  37. for i in interrupt_stats['count'].tolist():
  38. data.append(float(i)*/timer_freq)------------------------转换成时间单位us
  39.  
  40. #Calc the timer duration
  41. for i in interrupt_stats['duration'].tolist():
  42. duration_data.append(i)
  43.  
  44. #Statistics of interrupts
  45. interrupt_data = np.array(data)
  46. output.append([interrupt_data.mean(), interrupt_data.max(), interrupt_data.min(), interrupt_data.std()])----每个case的统计信息
  47. output_cycles.append([interrupt_stats['count'].mean(),
  48. interrupt_stats['count'].max(),
  49. interrupt_stats['count'].min(),
  50. interrupt_stats['count'].std()])------------------------------------------------------cycles形式的统计信息
  51.  
  52. df = pd.DataFrame(output, columns=['mean(us)','max(us)','min(us)', 'std(us)'], index=['', '', '', '', ''])
  53. df.to_csv('interrupt.csv')
  54. 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进行统计。

  1. /sys/kernel/debug/tracing/events/irq/irq_handler_entry
  2. /sys/kernel/debug/tracing/events/irq/irq_handler_exit
  3. /sys/kernel/debug/tracing/events/irq/softirq_entry
  4. /sys/kernel/debug/tracing/events/irq/softirq_exit
  5. /sys/kernel/debug/tracing/events/irq/softirq_raise

下面是一个中断例程执行耗时统计信息。

平均值大说明例程需要优化,因为在中断例程执行期间是屏蔽中断的,屏蔽时间太长容易丢中断。

如果均方差大,说明中断例程内流程差异较大,可能存在隐患。

  1. +------------------------+-------+--------+-------+-------+--------+------------------+
  2. | name | mean | max | min | count | sum | std |
  3. +------------------------+-------+--------+-------+-------+--------+------------------+
  4. | dwc_otg_pcd | 0.457 | 32.196 | 0.0 | | 47.516 | 3.26191450776 |
  5. | xxxxxxx | 0.004 | 0.031 | 0.0 | | 2.903 | 0.0106282606939 |
  6. | dwc_otg_powerdown_up | 7.644 | 7.66 | 7.629 | | 15.289 | 0.0155 |
  7. | icp_ps | 0.006 | 0.031 | 0.0 | | 0.031 | 0.0124 |
  8. | xxxx_i2c. | 0.010 | 0.031 | 0.0 | | 0.459 | 0.0141861232812 |
  9. | xxxx_timer | 0.003 | 0.092 | 0.0 | | 4.305 | 0.00947335198132 |
  10. | dwc_otg_powerdown down | 5.264 | 6.5 | 4.028 | | 10.528 | 1.236 |
  11. +------------------------+-------+--------+-------+-------+--------+------------------+

下面是这些中断在时间轴上的分不情况,长度表示耗时。可以看出他们的频率,以及相互之间的关系。

ARM-Linux中断系统的更多相关文章

  1. linux中断系统那些事之----中断处理过程【转】

    转自:http://blog.csdn.net/xiaojsj111/article/details/14129661 以外部中断irq为例来说明,当外部硬件产生中断时,linux的处理过程.首先先说 ...

  2. ARM Linux中断发生时内核堆栈切换

    转载注明出处:http://www.wowotech.net/forum/viewtopic.php?id=54 对ARM Linux中断非常简洁.精确的描述. 发生了中断,最重要的是保存现场,在中断 ...

  3. [Fw]初探linux中断系统(2)

    初探linux中断系统(2) 中断系统初始化的过程 用来初始化中断系统的函数位于arch/x86/kernel/irqinit.c,定义如下 void __init init_IRQ(void){ i ...

  4. ARM linux中断总结

    Linux异常处理体系结构 Linux异常体系之vector_stub宏解析 Linux异常体系之stubs_offset Linux中断体系结构 ARM系统调用

  5. [Fw]初探linux中断系统(1)

    1. 重要接口 LDD上说,“内核维护了一个中断信号线的注册表,该注册表类似于I/O端口的注册表.模块在使用中断前要先请求一个中断通道(或者中断请求IRQ),然后在使用后释放该通道.” 撇开系统如何遍 ...

  6. ARM+LINUX嵌入式系统的终端显示中文乱码解决

    前一段时间解决的一个问题,看起来是个小问题,实际解决这个问题却花了一个星期的晚上休息时间,记录分享一下. 问题描述: linux内核配置中NLS(native language support)已经选 ...

  7. linux中断子系统:中断号的映射与维护初始化mmap过程

    本文均属自己阅读源代码的点滴总结.转账请注明出处谢谢. 欢迎和大家交流.qq:1037701636 email:gzzaigcn2009@163.com 写在前沿: 好久好久没有静下心来整理一些东西了 ...

  8. Linux中断(interrupt)子系统之一:中断系统基本原理【转】

    转自:http://blog.csdn.net/droidphone/article/details/7445825 这个中断系列文章主要针对移动设备中的Linux进行讨论,文中的例子基本都是基于AR ...

  9. Linux中断 - ARM中断处理过程

    一.前言 本文主要以ARM体系结构下的中断处理为例,讲述整个中断处理过程中的硬件行为和软件动作.具体整个处理过程分成三个步骤来描述: 1.第二章描述了中断处理的准备过程 2.第三章描述了当发生中的时候 ...

  10. Linux中断(interrupt)子系统之一:中断系统基本原理

    这个中断系列文章主要针对移动设备中的Linux进行讨论,文中的例子基本都是基于ARM这一体系架构,其他架构的原理其实也差不多,区别只是其中的硬件抽象层.内核版本基于3.3.虽然内核的版本不断地提升,不 ...

随机推荐

  1. 【59】Quartz+Spring框架详解

    什么是Quartz Quartz是一个作业调度系统(a job scheduling system),Quartz不但可以集成到其他的软件系统中,而且也可以独立运行的:在本文中"job sc ...

  2. "C#":MySql批量数量导入

    现在对数据库(以MySql为例)的操作大多会封装成一个类,如下例所示: namespace TESTDATABASE { public enum DBStatusCode { ALL_OK, MySq ...

  3. 【37】String,StringBuffer,StringBuilder区别和概念

    基本的概念: 查看 API 会发现,String.StringBuffer.StringBuilder 都实现了 CharSequence 接口,内部都是用一个char数组实现,虽然它们都与字符串相关 ...

  4. Nginx的内部(进程)模型

    nginx是以多进程的方式来工作的,当然nginx也是支持多线程的方式的,只是我们主流的方式还是多进程的方式,也是nginx的默认方式.nginx采用多进程的方式有诸多好处. (1)nginx在启动后 ...

  5. leetcode(57)- Implement strStr()

    题目: Implement strStr(). Returns the index of the first occurrence of needle in haystack, or -1 if ne ...

  6. PhpStorm php配置环境

    如果你需要在Windows上安装PHP环境,并使用PhpStorm进行脚本编写进行编译,不需要WEB环境展示,那么本小结适合. 软件环境:Windows10+PHP7.1+PhpStorm2018 0 ...

  7. valid palindrome(回文)

    Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignori ...

  8. JavaScript四(DOM编程)

    一.绪论 DOM是文档对象模型(Document Object Module)的简称,借助DOM模型,可以将结构化文档,转换成DOM树,程序可以访问,修改,增加,删除树的节点.程序通过操作DOM树时, ...

  9. redis资源未释放引发的问题

    一.redis资源未释放的起因: N年前,在修改一个古老程序时,不小心把redis释放的这块给干掉了, if (jedis != null) { if (!isInProcess) { jedis.d ...

  10. 下载网易云VIP音乐

    有偿帮助.联系方式在个人信息里.