arm32 arm64 读取PMCCNTR cpu cycle counter

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

本来写了两个,arm32一个,arm64一个,方便对比合在了一起。

只测试了32位cortex-a9双核, 还有 个64位a76 a55。

enpmu.c

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

c 复制代码
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

直接

c 复制代码
make
c 复制代码
insmod enpmu.ko
rmmod enpmu

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

test.c

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);
}
c 复制代码
gcc test.c
./a.out
taskset -c 1 ./a.out

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

附录

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
相关推荐
大柏怎么被偷了13 分钟前
【Linux】文件系统
linux·运维·数据库
Guistar~~30 分钟前
【Linux驱动开发IMX6ULL】交叉编译环境安装
linux·驱动开发
KingRumn1 小时前
Linux进程间通信之消息队列(POSIX)
linux·服务器
唐墨1231 小时前
linux kernel源码解析之:smp系统cpu热插拔
linux
开开心心就好2 小时前
免费卸载工具,可清理残留批量管理启动项
linux·运维·服务器·windows·随机森林·pdf·1024程序员节
智算菩萨2 小时前
摩擦电纳米发电机近期进展的理论脉络梳理:从接触起电到统一建模与能量转换
linux·人工智能·算法
Lbwnb丶2 小时前
检测服务器是否是虚拟化,如KVM,VM等
linux·运维·服务器
老猿讲编程2 小时前
【车载信息安全系列4】基于Linux中UIO的HSE应用实现
linux·运维·服务器
wanhengidc3 小时前
巨椰 云手机 云游戏稳定运行
运维·服务器·arm开发·游戏·云计算
林政硕(Cohen0415)3 小时前
ARM Qt 字体过小的问题
arm开发·qt