当前位置: 首页 > news >正文

arm32 arm64 读取PMCCNTR cpu cycle counter

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
#endifstatic void en_access(void*)
{ulint i=0,tmpvar=0;#ifdef __aarch64__asm volatile("mrs %0, mpidr_el1 ":"=r"(i));i =  (i >>8) &0xff;
#elseasm 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;
#elseasm volatile("mrc p15,0,%0,c0,c0,5 \n" : "=r"(i));i =  i & 3;
#endifasm 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));
#endifprintf("%lx\n",(unsigned long)ct);
}
gcc test.c
./a.out
taskset -c 1 ./a.out

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

附录

CNTVCT_EL0pmcntenset_el0  Performance Monitors Count Enable Set registerpurpose Enables the Cycle Count Register·
C [31]·
0x1 »   PMCCNTR_EL0 enable·
P<m>»   PMEVCNTR<n>_EL0 enable
0xFFFFFFFFpmuserenr_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
0xFPMCR_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 affectedD [3] clock divider··0 pmccntr_el0 counts every clock cycle
E  [0] enable1 Affected counters are enabled by pmcntenset_el0mrc/mcr  Op1 CRm Op2 Name Type Reset Description
0 	c12 0 PMCR RW 0x41093000 Performance Monitor Control Register1 PMCNTENSET RW 0x00000000 Count Enable Set Register2 PMCNTENCLR RW 0x00000000 Count Enable Clear Register3 PMOVSR RW - Overflow Flag Status Register4 PMSWINC WO - Software Increment Register5 PMSELR RW 0x00000000 Event Counter Selection Registerc13 0 PMCCNTR RW - Cycle Count Register1 PMXEVTYPER RW - Event Type Selection Register2 PMXEVCNTR RW - Event Count Registersc14 0 PMUSERENR RWa 0x00000000 User Enable Register1 PMINTENSET RW 0x00000000 Interrupt Enable Set Register2 PMINTENCLR RW 0x00000000 Interrupt Enable Clear Register
http://www.lryc.cn/news/267169.html

相关文章:

  • vue 项目/备案网页/ip网页打包成 apk 安装到平板/手机(含vue项目跨域代理打包成apk后无法访问接口的解决方案)
  • 面试复盘4——后端开发——一面
  • 使用 Postman 进行并发请求:实用教程与最佳实践
  • 河南工程学院第六届程序设计竞赛-A组-题解
  • 韩版传奇 2 源码分析与 Unity 重制(二)客户端启动与交互流程
  • JVM面试——运行时数据区
  • ssh工具 向指定的ssh服务器配置公钥
  • uni-app pages.json之globalStyle全局页面样式配置
  • Blazor 混合开发_MAUI+Vue_WPF+Vue
  • udp异步方式接收消息
  • 【RocketMQ笔记01】安装RocketMQ消息队列运行环境
  • 使用 Privoxy 实现对多域名的定向转发
  • 《PySpark大数据分析实战》-19.NumPy介绍ndarray介绍
  • 图解LRU缓存
  • FFmpeg常见命令行
  • 智能优化算法应用:基于斑马算法3D无线传感器网络(WSN)覆盖优化 - 附代码
  • 《C++避坑神器·二十五》简单搞懂json文件的读写之遍历json文件读写
  • 使用 fixture 机制重构 appium_helloworld
  • 基于python的excel检查和读写软件
  • Podman配置mongodb
  • java实现矩阵谱峰搜索算法
  • Jenkins的特殊操作定时自动执行任务以及测试报告调优
  • 【Grafana】Grafana匿名访问以及与LDAP连接
  • elasticsearch-py 8.x的一些优势
  • RK3588平台开发系列讲解(AI 篇)RKNN 数据结构详解
  • 2023版本QT学习记录 -6- UDP通信之UDP接收端
  • C预处理 | pragma详解
  • 轻松搭建知识付费小程序:让知识传播更便捷
  • 沉浸式go-cache源码阅读!
  • 伪协议和反序列化 [ZJCTF 2019]NiZhuanSiWei