- 论坛徽章:
- 0
|
感谢各位回复, 经过测试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);
|
|