免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12
最近访问板块 发新帖
楼主: cnlostain

[时钟管理] [求助][ARM]统计中断关闭时间 [复制链接]

论坛徽章:
9
辰龙
日期:2014-08-18 20:38:42未羊
日期:2014-09-04 08:50:45丑牛
日期:2014-09-06 00:12:55寅虎
日期:2014-12-22 20:50:56摩羯座
日期:2015-01-14 22:28:15巳蛇
日期:2015-01-23 20:39:272015年辞旧岁徽章
日期:2015-03-03 16:54:1515-16赛季CBA联赛之青岛
日期:2016-03-13 23:37:1915-16赛季CBA联赛之深圳
日期:2016-03-29 18:52:38
发表于 2014-10-15 20:41 |显示全部楼层
回复 8# cnlostain

PMU操作需要CP15,操作是烦一点。我们现在是通过timer计时的。

   

论坛徽章:
0
发表于 2014-10-16 14:49 |显示全部楼层
多谢各位回复,  我正在调试一个基于PMU的方法, ARMv7以上的架构的PMU的设计基本是一致的。
目前发现结果有点不是很可靠, 但是流程基本能通。
后面调个差不多的时候在发出来给有相同需求的做参考。

另外还有一个叫做 arm_arch_timer 的定时器, 貌似可以直接读取, 但是看起来精度不是很高。 不知到是不是有分频可调这种特性。

论坛徽章:
0
发表于 2014-10-16 14:52 |显示全部楼层
多谢各位回复,  我正在调试一个基于PMU的方法, ARMv7以上的架构的PMU的设计基本是一致的。
目前发现结果有点不是很可靠, 但是流程基本能通。
后面调个差不多的时候在发出来给有相同需求的做参考。

另外还有一个叫做 arm_arch_timer 的定时器, 貌似可以直接读取, 但是看起来精度不是很高。 不知到是不是有分频可调这种特性。

论坛徽章:
0
发表于 2014-10-16 14:54 |显示全部楼层
回复 10# comba_sellie


Hi 哥们, 能不能把你的方法涉及的代码简单给描述下? 我不是很明白你说的意思


   

论坛徽章:
0
发表于 2014-10-16 17:35 |显示全部楼层
回复 10# comba_sellie


我看了下代码, 还是对时间子系统不是很熟悉。
你是只得在系统所有注册的clocksource里面选择一个rating最高的吗?

clocksource应该是对系统当中所有计时设备的一个封装, 里面有read方法, 还有后续的clocksource_cyc2ns之类的转换。
不知到你用的是不是这个方法, 还是有更底层的直接操作硬件的方法?

在clocksource里面发现有这样一个函数获取当前最高精度的clocksource
static struct clocksource *clocksource_find_best(bool oneshot, bool skipcur)
{
        struct clocksource *cs;

        if (!finished_booting || list_empty(&clocksource_list))
                return NULL;

        /*   
         * We pick the clocksource with the highest rating. If oneshot
         * mode is active, we pick the highres valid clocksource with
         * the best rating.
         */
        list_for_each_entry(cs, &clocksource_list, list) {
                if (skipcur && cs == curr_clocksource)
                        continue;
                if (oneshot && !(cs->flags & CLOCK_SOURCE_VALID_FOR_HRES))
                        continue;
                return cs;
        }   
        return NULL;
}

   

论坛徽章:
0
发表于 2014-10-17 01:27 |显示全部楼层
以linux-2.6.32.63为例
时钟都是通过clocksource_register函数 按rate值从大到小注册到clocksource_list
注册过程会选择best的时钟 即rate 值最高的 并保存在全局变量timekeeper里面
所以do_gettimeofday函数读时钟 就是从精度最高的时钟源读取的。

补充说明:
网上有人写过《 Linux时间子系统》的文章 写的非常赞 可以参考
http://blog.csdn.net/droidphone?viewmode=contents

论坛徽章:
0
发表于 2014-10-21 11:59 |显示全部楼层
感谢各位回复,  经过测试pmu单元用于高精度短时间测量还是可行的。 下面是我写的一个例子, 希望对有相同需求的有所帮助。
在我r8a7791的测试结果为:

loops: 100 cnt1: 0 cnt2: 4 cycles: 4
loops: 1000 cnt1: 0 cnt2: 32 cycles: 32
loops: 10000 cnt1: 0 cnt2: 318 cycles: 318
loops: 100000 cnt1: 0 cnt2: 3126 cycles: 3126
loops: 1000000 cnt1: 0 cnt2: 31251 cycles: 31251
loops: 10000000 cnt1: 0 cnt2: 313670 cycles: 313670

对于1.5G的主频, 313670 * 64 * 0.67 = 13450169.6ns = 13.45ms 这个时间跟我用arch_sys_counter测出来的数据差不多。
-----------------
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/preempt.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("chaiw.fnst@cn.fujitsu.com");

static unsigned int loops = 100;
module_param(loops, uint, S_IRUGO);

static unsigned int get_pmcr_val(void)
{
        unsigned int val;
       
        __asm__ __volatile__ ("MRC p15, 0, %0, c9, c12, 0\n\t" : "=r"(val));
        return val;
}

static unsigned int get_pmccntr_val(void)
{
        unsigned int val;

        __asm__ __volatile__ ("MRC p15, 0, %0, c9, c13, 0\n\t" : "=r"(val));
        return val;
}

static inline void start_perf_cpu_cycle(void)
{
        unsigned int value;

        value = get_pmcr_val();
        /* access PMCR to enable events, enable PMCCNTR - the cycle counter register */
        /* PMCR is a triger register */

        value |= 0xD; /* cycles divide 64
                       * reset PMCCNTR to 0
                       * do not touch other event counter
                       * enable all counters
                       */
        __asm__ __volatile__ ("MCR p15, 0, %0, c9, c12, 0\n\t" :: "r"(value));
}

static inline void stop_perf_cpu_cycle(void)
{
        unsigned int value;

        value = get_pmcr_val();

        value &= ~(0x1U);
        value |= 0x2;
        __asm__ __volatile__ ("MCR p15, 0, %0, c9, c12, 0\n\t" :: "r"(value));

        /* clear the overflow flag for all counters */
        __asm__ __volatile__("MCR p15, 0, %0, c9, c12, 3\n\t" :: "r"(0x8000001f));   
}

static inline void init_cpu_cycle_counter(void)
{
        unsigned int value;


        /* disable all possible interrupt request, C14, 2, PMINTENCLR register*/
        __asm__ __volatile__("MCR p15, 0, %0, c9, c14, 2\n\t" :: "r"(0x8000001f));

        value = get_pmcr_val();
        value |= 0xF; /* enable cycle divide
                     * reset PMCCNTR to 0
                     * reset all other counters to 0
                     * enable all counters */
        __asm__ __volatile__ ("MCR p15, 0, %0, c9, c12, 0\n\t" :: "r"(value));

        /* c12, 1 PMCNTENSET is a condition register, not a triger register */
        __asm__ __volatile__ ("MCR p15, 0, %0, c9, c12, 1\n\t" :: "r"(0x8000001f));
   
        /* clear the overflow flag for all counters */
        __asm__ __volatile__("MCR p15, 0, %0, c9, c12, 3\n\t" :: "r"(0x8000001f));   
}

static inline void cleanup_cpu_cycles_counter(void)
{
        stop_perf_cpu_cycle();
        /* access PMCR to disable events, disable cycle counter register */
        __asm__ __volatile__ ("MCR p15, 0, %0, c9, c12, 2\n\t" :: "r"(0x80000000));
}

static int __init apis_pmu_init(void)
{
        unsigned int cnt1, cnt2;
        unsigned int i;       
       
        init_cpu_cycle_counter();
       
        /* -------------------------------- */
        start_perf_cpu_cycle();
        preempt_disable();
        cnt1 = get_pmccntr_val();
        for (i = 0; i < loops; i++) {
                __asm__ __volatile__ ("mov r0, r0\n\t");
        }
        cnt2 = get_pmccntr_val();
        stop_perf_cpu_cycle();
        preempt_enable();
        printk("loops: %u cnt1: %u cnt2: %u cycles: %u\n", loops, cnt1, cnt2, cnt2 - cnt1);


#if 0
        /* changing on system works fine */
        /* -------------------------------- */
        start_perf_cpu_cycle();
        cnt1 = get_pmccntr_val();
        for (i = 0; i < 1000; i++) {
                __asm__ __volatile__ ("mov r0, r0\n\t");
        }
        cnt2 = get_pmccntr_val();
        stop_perf_cpu_cycle();
        printk("loops: %u cnt1: %u cnt2: %u cycles: %u\n", loops, cnt1, cnt2, cnt2 - cnt1);

        /* -------------------------------- */
        start_perf_cpu_cycle();
        cnt1 = get_pmccntr_val();
        for (i = 0; i < 10000; i++) {
                __asm__ __volatile__ ("mov r0, r0\n\t");
        }
        cnt2 = get_pmccntr_val();
        stop_perf_cpu_cycle();
        printk("loops: %u cnt1: %u cnt2: %u cycles: %u\n", loops, cnt1, cnt2, cnt2 - cnt1);

        /* -------------------------------- */
        start_perf_cpu_cycle();
        cnt1 = get_pmccntr_val();
        for (i = 0; i < 100000; i++) {
                __asm__ __volatile__ ("mov r0, r0\n\t");
        }
        cnt2 = get_pmccntr_val();
        stop_perf_cpu_cycle();
        printk("loops: %u cnt1: %u cnt2: %u cycles: %u\n", loops, cnt1, cnt2, cnt2 - cnt1);
#endif
        return -1;
}

static void __exit apis_pmu_exit(void)
{
        printk("bye\n");
}

module_init(apis_pmu_init);
module_exit(apis_pmu_exit);
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP