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

电器网站建设目的360关键词推广

电器网站建设目的,360关键词推广,江西论坛,保险网站 源码博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持! 博主链接 本人就职于国际知名终端厂商,负责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.tj-hxxt.cn/news/11367.html

相关文章:

  • 江西省委网站作风建设seoshanghai net
  • 哪些网站做外链外包推广服务
  • 网站怎么做隐藏内容宁波网站推广运营公司
  • 昆明电子商务网站郑州网站seo外包
  • 开公司怎么做网站百度认证营销顾问
  • 淘宝联盟推广可以做网站吗百度推广助手app
  • 嘉兴网站关键词推广免费网站流量统计
  • 北京大兴区网站建设淘宝排名查询工具
  • 站群wordpress搜狗网站收录
  • 免费0代码开发平台萌新seo
  • 树形菜单网站怎么引流推广
  • asp+php+mysql+aspx环境搭建与6种网站安装2免费建站有哪些
  • 网站建设服务有哪些方面超级外链自动发布工具
  • aspcms开源企业网站建设系统爱站网权重查询
  • 酒店网站建设目标长沙免费网站建站模板
  • wordpress wp mail smtp苏州关键词优化seo
  • 传奇私服网站花生壳怎么做代发新闻稿的网站
  • 长沙有哪个学校可以学网站建设温州seo服务
  • 邯郸网站设计服务平台宣传软文
  • 山西网站开发二次开发天津seo推广软件
  • 武汉 酒店 网站制作百度答主招募入口官网
  • 高端网站建设公司哪家服务态度好seo 工具
  • 授权登录网站怎么做泉州百度网络推广
  • 动漫做视频在线观看网站网店运营的工作内容
  • 网站建设的目标与期望高端营销型网站制作
  • iis的网站默认端口站长工具查询seo
  • 专业刷单网站建设抖音seo优化公司
  • 河南做网站汉狮网络十大品牌营销策划公司
  • wordpress 4.6关键词首页排名优化
  • 做旅游网站毕设任务书百度一下百度网页版