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

深圳外贸网站设计网页界面设计视觉空间的三维可视化

深圳外贸网站设计,网页界面设计视觉空间的三维可视化,舟山网站建设有限公司,深圳市建设局官方网站博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持! 博主链接 本人就职于国际知名终端厂商,负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。 博客…

博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持!
博主链接

本人就职于国际知名终端厂商,负责modem芯片研发。
在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。


博客内容主要围绕:
       5G/6G协议讲解
       算力网络讲解(云计算,边缘计算,端计算)
       高级C语言讲解
       Rust语言讲解

文章目录

  • 如何在ARM上实现x86的rdtsc()函数
  • 一、使用ARMv8提供的独立定时器CNTVCT_EL0
  • 二、使用ARMv8的PMU计数器PMCCNTR_EL0
    • 2.1 关键寄存器介绍
      • PMCCNTR_EL0(Performance Monitors Cycle Count Register)
      • PMCR_EL0(Performance Monitors Control Register)
      • PMUSERENR_EL0(Performance Monitors User Enable Register)
      • PMCNTENCLR_EL0(Performance Monitors Count Enable Clear register)
    • 2.2 内核使能代码
    • 2.3 用户态代码
    • 2.4 测试时遇到的问题



如何在ARM上实现x86的rdtsc()函数


在这里插入图片描述

一、使用ARMv8提供的独立定时器CNTVCT_EL0

       System counter是Arm64下独立于CPU core的计数器,在系统上电时,会给此计数器设置固定的频率。一个映射System counter计数器内容的寄存器为CNTVCT_EL0,可在用户态下读取此寄存器获取counter值。而CNTFRQ_EL0保存的是counter的频率值(详细内容参考《【ARMv8】通用定时器总结》)。通过下面的函数实现获取counter值及频率值:

static inline uint64_t 
arm64_cntvct(void) 
{   uint64_t tsc;   asm volatile("mrs %0, cntvct_el0" : "=r" (tsc));   return tsc; 
} static inline uint64_t 
arm64_cntfrq(void)
{   uint64_t freq;   asm volatile("mrs %0, cntfrq_el0" : "=r" (freq));   return freq; 
} static inline uint64_t 
rdtsc(void) 
{return arm64_cntvct();
}

但是System counter的精度从Armv8.0到Armv8.5,范围通常在1-50MHz;从Armv8.6开始,以1GHz的固定频率递增。虽然1GHz的频率已经足够高了,但是还是达不到CPU cycle级别的精度


二、使用ARMv8的PMU计数器PMCCNTR_EL0

       在ARMv8中,有Performance Monitors Control Register系列寄存器,其中PMCCNTR_EL0就类似于x86的TSC寄存器。但是如果想在用户态访问这些寄存器,需要在内核代码中开启PMU用户态访问开关。

2.1 关键寄存器介绍

PMCCNTR_EL0(Performance Monitors Cycle Count Register)

保存了处理器周期计数器的值,其结构如下:
在这里插入图片描述

PMCR_EL0(Performance Monitors Control Register)

PMU配置寄存器,其结果如下:

在这里插入图片描述
其中和我们关系密切的几个参数含义:

  • LC:设置为1,表示开启64bit的周期计数器;否则,使用32bit的计数器(32bit的已经摒弃);
  • D:设置为1,表示每64个时钟周期,计时器累加一次(已经摒弃);否则,每个时钟周期计数器累加一次;
  • C:设置为1,表示重置计数器;
  • E:设置为1,表示开启计数器PMCCNTR_EL0;

PMUSERENR_EL0(Performance Monitors User Enable Register)

用于开启或关闭用户态下是否可以访问PMU寄存器,相关结构如下:

在这里插入图片描述
其中和我们关系密切的几个参数含义:

  • ER:设置为1,表示用户态下可以读写PMU寄存器;否则不可以读写;
  • EN:设置为1,表示用户态软件可以访问所有PMU特定的寄存器;

PMCNTENCLR_EL0(Performance Monitors Count Enable Clear register)

设置启用的计数器和事件计数器,相关结构如下:

在这里插入图片描述
其中和我们关系密切的几个参数含义:

  • C:设置为1,表示启用PMCCNTR_EL0计数器;

2.2 内核使能代码

/*                                                                             * Enable user-mode ARM performance counter access.                            */                                                                           
#include <linux/kernel.h>                                                      
#include <linux/module.h>                                                      
#include <linux/smp.h>                                                         #define ARMV8_PMCR_MASK         0x3f                                                                    
#define ARMV8_PMCR_E            (1 << 0) /* Enable all counters */                                      
#define ARMV8_PMCR_P            (1 << 1) /* Reset all counters */                                       
#define ARMV8_PMCR_C            (1 << 2) /* Cycle counter reset */                                      
#define ARMV8_PMCR_D            (1 << 3) /* CCNT counts every 64th cpu cycle */                         
#define ARMV8_PMCR_X            (1 << 4) /* Export to ETM */                                            
#define ARMV8_PMCR_DP           (1 << 5) /* Disable CCNT if non-invasive debug*/                        
#define ARMV8_PMCR_LC           (1 << 6) /* Cycle Counter 64bit overflow*/
#define ARMV8_PMCR_N_SHIFT      11       /* Number of counters supported */                             
#define ARMV8_PMCR_N_MASK       0x1f                                                                    #define ARMV8_PMUSERENR_EN_EL0  (1 << 0) /* EL0 access enable */                                        
#define ARMV8_PMUSERENR_CR      (1 << 2) /* Cycle counter read enable */                                
#define ARMV8_PMUSERENR_ER      (1 << 3) /* Event counter read enable */                                static inline u32 armv8pmu_pmcr_read(void)                                                              
{                                                                                                       u64 val=0;                                                                                      asm volatile("mrs %0, pmcr_el0" : "=r" (val));                                                  return (u32)val;                                                                                
}                                                                                                       
static inline void armv8pmu_pmcr_write(u32 val)                                                         
{                                                                                                       val &= ARMV8_PMCR_MASK;                                                                         isb();                                                                                          asm volatile("msr pmcr_el0, %0" : : "r" ((u64)val));                                            
}       static void                                                                                            
enable_cpu_counters(void* data)                                                                         
{                                                                                                       u32 val=0;                                                         asm volatile("msr pmuserenr_el0, %0" : : "r"(0xf));                                                   asm volatile("msr PMCNTENSET_EL0, %0" :: "r" ((u32)(1<<31)));armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMCR_E|ARMV8_PMCR_LC);   printk("\nCPU:%d ", smp_processor_id());
}                                                                                                       static void                                                                                            
disable_cpu_counters(void* data)                                                                        
{                                                                                                                                                                                                   printk(KERN_INFO "\ndisabling user-mode PMU access on CPU #%d",                       smp_processor_id());                                                                                   /* Program PMU and disable all counters */                                                            armv8pmu_pmcr_write(armv8pmu_pmcr_read() |~ARMV8_PMCR_E);                                              asm volatile("msr pmuserenr_el0, %0" : : "r"((u64)0));                                                                                                                                                
}                                                                                                       static int __init                                                                                       
init(void)                                                                                              
{                                                                       isb();on_each_cpu(enable_cpu_counters, NULL, 1);                                                             printk(KERN_INFO "Enable Access PMU Initialized");                                                       return 0;                                                                                              
}                                                                                                       static void __exit                                                                                      
fini(void)                                                                                              
{                                                                                                       on_each_cpu(disable_cpu_counters, NULL, 1);                                                            printk(KERN_INFO "Access PMU Disabled");                                                          
}                                                                                                       module_init(init);                                                                                      
module_exit(fini);
module_license("GPL");

2.3 用户态代码

#include <stdio.h>#define u64 unsigned long long
#define isb()       asm volatile("isb" : : : "memory")static inline u64 arch_counter_get_cntpct(void)
{u64 cval;isb();asm volatile("mrs %0, PMCCNTR_EL0" : "+r"(cval));return cval;
}

2.4 测试时遇到的问题

可能有同学会用下面的代码测试定时精度,

int main()
{u64 begin,end;begin = arch_counter_get_cntpct();sleep(1);end= arch_counter_get_cntpct();printf("The count is %llu.\n",end-begin);return 0;
}

但是会发现使用统计的计数值与CPU当前的始终频率计算后,时间不是1s。这是因为Linux的省电功能导致的,sleep会使当前进程让出CPU,如果此时CPU任务队列中没有任务,就会进入低功耗(例如,WFI)甚至offline,如果进入上述状态PMU计数器就会停止计数,导致计数值不准确。

毕竟PMU是为调式使用的,如果此时CPU没有任务,也确实没有必要继续统计了。所以使用PMU寄存器计数是,不应该有主动让出CPU的行为,可能会导致计数不准确。

可以尝试关闭省电模式:

echo 1 > /sys/devices/system/cpu/cpu<X>/cpuidle/state<Y>/disable


在这里插入图片描述

http://www.yayakq.cn/news/723434/

相关文章:

  • 昆明二级站seo整站优化排名html5公司网站欣赏
  • vs2017js网站开发方法重庆网站推广效果
  • 网站制作报价开电子商务网站建设的风险分析
  • 网站和网页不同吗宽屏网站欣赏
  • 网站建设印花税网页管理平台
  • 网站设计的优化欧模网
  • 微信小程序 连接网站wordpress4.9.4 模版修改
  • 怎样做网站个人简介做设计图的网站
  • 百度打网站名称就显示 如何做手机版怎么用百度快照
  • 菏泽定陶网页设计培训妇科医院网站优化服务商
  • 北辰做网站公司如何管理公司网站后台
  • 内蒙古自治区建设厅网站做微信广告网站有哪些内容
  • 电商平台定制开发公司江西短视频搜索seo哪家好
  • html5网站欣赏 国内网络规划设计师教程(第2版)
  • 做网站网站多久会被抓1核1g可以做几个网站
  • 单页网站利润贵州网站建设套餐
  • 建设企业网站官网u盾登录怎么制作网站教程电商
  • 恒辉建设集团网站淘宝刷单网站建设
  • 我想建个网站网站开发用主要软件
  • 学习电子商务网站建设与管理的感想工程建设指挥部网站
  • 网站开发工程师是干什么的淘宝标题优化工具推荐
  • 东至县住房和城乡建设网站大型机械网站建设公司
  • 茂名企业网站建设开发政务网站建设的功能模块
  • 公司建站详细步骤知名室内设计网站
  • 买房子最好的网站做网站开发的集团
  • 福州网站建设优化郑州加盟网站建设
  • 做房地产资质是什么网站查wordpress 聘用
  • 网站建设和信息更新的通知北京网站优化公司 卓立海创
  • 网站 单页官方网站开发需要几个技术人员
  • 国外设计工作室网站广告传媒公司有哪些