历史上的今天
返回首页

历史上的今天

今天是:2025年02月03日(星期一)

2020年02月03日 | ARM-Linux中断系统

2020-02-03 来源:eefocus

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


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, %un", 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 %un", __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 %un", __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  |

推荐阅读

史海拾趣

CST Master Electronic Co Ltd公司的发展小趣事

随着市场的不断发展,CST Master意识到只有不断创新才能在激烈的竞争中立足。公司投入大量资源用于研发,积极探索新技术、新工艺和新材料。经过多次试验和失败,团队终于取得了一项重要的技术突破,推出了一款具有行业领先水平的新产品,赢得了客户的广泛认可。

CONTRINEX公司的发展小趣事

除了上述重要事件外,Contrinex还一直致力于产品创新和技术研发。多年来,公司不断推出新型传感器产品,如防磁防焊型电感式传感器、扩展型纤细型安全光幕等,以满足不同客户的需求。同时,Contrinex还积极与OEM和系统集成商合作,共同开发定制化解决方案,为客户提供更加全面和专业的服务。

这些故事只是Contrinex在电子行业发展历程中的一部分。作为一个不断追求卓越和创新的企业,Contrinex将继续致力于为客户提供高品质、高精度的传感器产品和解决方案,推动电子行业的持续发展。

BELDEN公司的发展小趣事

在20世纪初,BELDEN公司在技术创新方面取得了显著突破。公司不仅将塑料绝缘材料应用于电线和电缆制造,还着眼于精密和高质量产品的需求,致力于高附加值的绝缘材料、电缆、防护和护套材料的生产。这些技术创新使得BELDEN的产品在性能和质量上都有了显著提升,进一步巩固了公司在市场中的地位。同时,公司还不断扩大产品线,增加了橡胶绝缘材料等多种新产品,满足了不同客户的需求。

EPCOS (TDK)公司的发展小趣事

在国际化布局方面,TDK-EPC公司始终保持着积极开放的态度。公司通过设立海外研发中心、生产基地和销售网络等方式,不断拓展国际市场。同时,公司还积极参与国际竞争和合作,与全球众多知名企业建立了长期稳定的合作关系。这些举措不仅提升了TDK-EPC公司的品牌影响力和市场竞争力,也为公司的长期发展提供了有力保障。

泽耀科技(Ashining)公司的发展小趣事

随着市场的不断变化和消费者需求的升级,泽耀科技(Ashining)意识到只有不断创新才能在竞争中立于不败之地。公司加大了对研发的投入,引进了一批高素质的研发人才,并建立了完善的研发体系。经过多次尝试和实验,泽耀科技成功突破了某项关键技术,并推出了升级版的产品。这些新产品不仅性能更加优越,而且具有更高的性价比,深受消费者的喜爱。

Big-Sun Electronics Co Ltd公司的发展小趣事

品质是Big-Sun Electronics Co Ltd公司一直以来的核心竞争力。公司建立了严格的质量管理体系,从原材料采购到生产流程控制,再到产品出厂检验,每一个环节都严格把关。同时,Big-Sun还注重品牌建设,通过广告宣传和客户服务,不断提升品牌知名度和美誉度。

问答坊 | AI 解惑

扬声器感冒了

扬声器型号:BSTC  8530  -273  2A, 器件质量没问题,焊好后在酒精里超声冲洗, 完了上电一试,声音变得很小。 是不是超声损坏了扬声器啊?…

查看全部问答>

玩网页游戏会关机

电脑进入正常,玩中游也正常,但只要是一玩网页游戏就会自动关机,检测电源显卡正常…

查看全部问答>

招聘Senior wince/windows mobile应用开发工程师!

精通C/C++,理解面向对象思想,有良好的编程习惯。 3~5年Windows/Windows Mobile程序开发经验,精通Windows编程,熟悉Win32API, COM。 熟悉TCP/IP等通信协议,熟悉Socket应用,多线程和进程间通讯编程。 熟悉数据库开发, 有实际数据库开发经验 ...…

查看全部问答>

如何防止WINCE 5.0 多镜像地址空间重叠?

在config.bib中把CE镜像划分为了4个部分,例如: KERNEL.BIN,DRIVER.BIN,APP.BIN,NK.BIN 这样做以便后期对单个镜像文件升级,现在问题来了,每个BIN文件中的DLL在SLOT0,SLOT1中所占用的地址空间都是在编译器时计算好的。如果后面我的APP.BIN变化 ...…

查看全部问答>

那位高手用过ads1210芯片呀,能给个程序么。

那位高手用过ads1210芯片呀,能给个程序么。…

查看全部问答>

菜鸟提问:关于触摸屏驱动加载的问题

本人在研华的PCM3350上移植WinCE4.2,目前触摸屏驱动一直加不上   具体情况如下:触摸屏光盘上提供了两个dll:TOUCHP.DLL  USBPort.dll  我先修改了project.bib文件在MODULES里加入   TOUCHP.DLL  ...…

查看全部问答>

无铅制造时代,恒温烙铁焊台大可借鉴蓄水池效应

    很多价格昂贵的无铅焊台都喜欢强调和炫耀瞬间强大的温度恢复能力,其实这个有一些钻牛角尖的做法,虽然性能是上去了,但焊台本身的总体制造成本以及使用成本也跟着抬高,势必转嫁到最终用户身上。       &nb ...…

查看全部问答>

分享给看国嵌视频的朋友, 课程5-内核驱动进阶班更新啦!

replyreload += \',\' + 1344538;         看国嵌视频的朋友有部分可能也和我一样,在看完国嵌内核模块和驱动程序的视频后,没办法自己写,感觉自己是听懂了,能理解,但就是没办法写。这个很郁闷啊。 但是 ...…

查看全部问答>

如何解决MSP430的复位问题

MSP430有时候在整个系统断电之后,不能马上复位,需要在断电之后将整个系统的电源短路几分钟才能让MSP430复位,要不然程序都没法下载。…

查看全部问答>