主页 > 手机  > 

arm32arm64读取PMCCNTRcpucyclecounter

arm32arm64读取PMCCNTRcpucyclecounter

ARM 的时钟周期计数保存在PMCCNTR 寄存器,不像x86用户态可以直接读取,需内核态使能,一种是在内核中使能,比如init,比较简单的是在模块中使能。

本来写了两个,arm32一个,arm64一个,方便对比合在了一起。 只测试了32位cortex-a9双核, 还有 个64位a76 a55。 enpmu.c

#include <linux/module.h> #include <linux/kernel.h> #include <linux/smp.h> MODULE_AUTHOR("cn"); MODULE_LICENSE("GPL"); MODULE_VERSION("0.0"); #if !defined(__arm__) && !defined(__aarch64__) #error module only support arm32 arm64. #endif #ifdef __aarch64__ typedef unsigned long ulint; //64 #elif defined __arm__ typedef unsigned int ulint; //32 #endif static void en_access(void*) { ulint i=0,tmpvar=0; #ifdef __aarch64__ asm volatile("mrs %0, mpidr_el1 ":"=r"(i)); i = (i >>8) &0xff; #else asm volatile("mrc p15,0,%0,c0,c0,5 ":"=r"(i)); i = i & 3; #endif asm volatile ( #ifdef __aarch64__ "mrs %0,pmuserenr_el0 \n" "orr %0, %0,%1 \n" "msr pmuserenr_el0,%0" #else "mrc p15, 0, %0, c9, c14, 0 \n" "orr %0, %0,%1 \n" "mcr p15, 0, %0, c9, c14, 0 \n" #endif :"+r"(tmpvar):"r"(0xf)); asm volatile( #ifdef __aarch64__ "mrs %0, pmcr_el0 \n" "orr %0, %0, %1 \n" //32 0x41 "bic %0, %0, %2 \n" "msr pmcr_el0,%0 \n" #else "mrc p15, 0, %0, c9, c12, 0 \n" "orr %0, %0,%1 \n" "bic %0, %0, %2 \n" "mcr p15, 0, %0, c9, c12, 0 \n" #endif :"+r"(tmpvar):"r"(0x81),"r"(0x28)); asm volatile( #ifdef __aarch64__ "msr pmcntenset_el0,%1 \n" "mrs %0, cntvct_el0 \n" #else "mcr p15, 0, %1, c9, c12, 1 \n" "mrc p15, 0, %0, c9, c13, 0 \n" #endif :"=r"(tmpvar) :"r"(0xffffffff)); printk("core %lu tsc = %lx",(unsigned long)i, (unsigned long)tmpvar ); } static void restore_access(void*) { ulint i,tmpvar=0; #ifdef __aarch64__ asm volatile( "mrs %0, mpidr_el1": "=r"(i)); i = (i >> 8)&0xff; #else asm volatile("mrc p15,0,%0,c0,c0,5 \n" : "=r"(i)); i = i & 3; #endif asm volatile ( #ifdef __aarch64__ "mrs %0,pmcr_el0 \n" "bic %0,%0, %2 \n" "msr pmcr_el0,%0\n" "msr pmuserenr_el0,%1\n" "mrs %0, cntvct_el0 \n" #else "mrc p15, 0, %0, c9, c14, 0 \n" "bic %0,%0, %2 \n" "mcr p15, 0, %0, c9, c14, 0 \n" "mcr p15, 0, %1, c9, c12, 1 \n" "mrc p15, 0, %0, c9, c13, 0 \n" #endif :"+r" (tmpvar):"r"(0),"r"(1)); printk("un core %lx tsc = %lx",(unsigned long)i, (unsigned long)tmpvar ); } static int __init start(void) { on_each_cpu(en_access, NULL, 1); printk(KERN_INFO "pmu access enabled\n"); return 0; } static void __exit stop(void) { on_each_cpu(restore_access, NULL, 1); printk(KERN_INFO "pmu access disabled\n"); } module_init(start); module_exit(stop);

Makefile

obj-m = enpmu.o all: make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

直接

make insmod enpmu.ko rmmod enpmu

然后就可以读取了 以下arm32 arm64 x86_64读取方法 test.c

#include <stdio.h> #ifndef __arm__ typedef unsigned long ulint; #else typedef unsigned int ulint; #endif int main() { ulint ct = 0; #ifdef __aarch64__ asm volatile("mrs %0, cntvct_el0" :"=r"(ct)); #elif defined __arm__ asm volatile("mrc p15,0,%0, c9, c13, 0":"=r"(ct)); #elif defined __x86_64__ asm volatile("rdtsc ; shl $32, %%rdx ; or %%rdx, %0": "=a"(ct)); #endif printf("%lx\n",(unsigned long)ct); } gcc test.c ./a.out taskset -c 1 ./a.out

taskset -c 选择在哪个核上运行。

附录

CNTVCT_EL0 pmcntenset_el0 Performance Monitors Count Enable Set register purpose Enables the Cycle Count Register· C [31]· 0x1 » PMCCNTR_EL0 enable· P<m>» PMEVCNTR<n>_EL0 enable 0xFFFFFFFF pmuserenr_el0 Performance Monitors User Enable Register Enable or disables EL0 access to the performance Monitors; ER [3] » Event counters Read enable, » 1 en rw CR [2] » Cycle counter Read enable· » 32 MRC read PMCCNTR MRRC read PMCCNTR SW[1] software increment register Write enable » 1 En [0] Enable » Enables EL0 read/write access to PMU registers 0xF PMCR_EL0 bit[9] Freeze-on-overflow 0 LC [6] 1 aarch32 supported long cycle » 0x1 DP [5] Disable cycle counter when event counting is prohibited· 0x0 not affected D [3] clock divider·· 0 pmccntr_el0 counts every clock cycle E [0] enable 1 Affected counters are enabled by pmcntenset_el0 mrc/mcr Op1 CRm Op2 Name Type Reset Description 0 c12 0 PMCR RW 0x41093000 Performance Monitor Control Register 1 PMCNTENSET RW 0x00000000 Count Enable Set Register 2 PMCNTENCLR RW 0x00000000 Count Enable Clear Register 3 PMOVSR RW - Overflow Flag Status Register 4 PMSWINC WO - Software Increment Register 5 PMSELR RW 0x00000000 Event Counter Selection Register c13 0 PMCCNTR RW - Cycle Count Register 1 PMXEVTYPER RW - Event Type Selection Register 2 PMXEVCNTR RW - Event Count Registers c14 0 PMUSERENR RWa 0x00000000 User Enable Register 1 PMINTENSET RW 0x00000000 Interrupt Enable Set Register 2 PMINTENCLR RW 0x00000000 Interrupt Enable Clear Register
标签:

arm32arm64读取PMCCNTRcpucyclecounter由讯客互联手机栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“arm32arm64读取PMCCNTRcpucyclecounter