前天我正在看代码的时候,一个同事跑过来问我,“/proc/cpuinfo中的CPU频率是怎么来的,我在跑performance测试的时候,通过/proc/cpuinfo 查看CPU频率只有1.2G,但是我的CPU最高频率可以到2.7G。”我让他去把cpufreq governor设置成performance之后,再去执行performance测试。虽然他在做出修改之后,performance测试没有问题了,不过他的第一个问题却让我心生疑问,就去查了一下相关代码。

在linux kernel中,可以通过以下三个接口获取CPU frequency信息

1) /proc/cpuinfo

2) /sys/devices/system/cpu/cpuX/cpufreq/scaling_cur_freq

3) /sys/devices/system/cpu/cpuX/cpufreq/cpuinfo_cur_freq

那么,这3个接口究竟反应的是什么样的频率信息呢?它们的值是否都相同呢?我们直接使用cat看看

在比较早期的kernel(3.16)版本中,设置当前频率为1.6G,通过以上3个接口查询的结果如下:

#cat /proc/cpuinfo |grep MHz

cpu MHz         : 1600.000
cpu MHz         : 1600.000
cpu MHz         : 1600.000
cpu MHz         : 1600.000
#cat  /sys/devices/system/cpu/cpuX/cpufreq/scaling_cur_freq

1600000
1600000
1600000
1600000

#cat  /sys/devices/system/cpu/cpuX/cpufreq/cpuinfo_cur_freq

1600000
1600000
1600000
1600000
从上面的结果可以看出,在3.16 kernel上,以上3个接口读出来的CPU frequency都是相同的,就是我们设定的1.6GHz。

在Ubuntu1804-自带的kernel4.15上,同样设置频率为1.6G,也通过以上3个接口查询,结果如下:

#cat /proc/cpuinfo |grep MHz

cpu MHz         : 1596.330
cpu MHz         : 1596.307
cpu MHz         : 1596.313
cpu MHz         : 1596.330

#cat  /sys/devices/system/cpu/cpuX/cpufreq/scaling_cur_freq

1596340
1596348
1596368
1596333

#cat  /sys/devices/system/cpu/cpuX/cpufreq/cpuinfo_cur_freq

1600000
1600000
1600000
1600000

以上测试结果表明:

1)只有cpuinfo_cur_freq的值跟我们的设定值一致,为1.6GHz;

2)scaling_cur_freq和/proc/cpuinfo 多次查询出来的结果都不太一样,而且跟设定值有一个小的误差;

以上测试说明了不同版本的kernel也会有不同,我们去kernel change log中找跟这些改动相关的patch,主要有:

1)跟scaling_cur_freq改动相关的patch:commit 4815d3c56d1e10449a44089a47544d9ba84fad0d

cpufreq: x86: Make scaling_cur_freq behave more as expected

该patch通过APEF和MPERF计算CPU在一段时间内的平均频率,能够摒除CPU进入到idle state的影响。

使用APERF-MPERF的方式,不管CPU 频率是由HW-controlled,还是firmware-controlled,抑或是由linux cpufreq subsystem控制,甚至是没有frequency控制的情况下,user通过scaling_cur_freq sysfs接口都能获得有一个有意义的频率信息。

2)跟/proc/cpuinfo改动相关的patch:commit 7d5905dc14a87805a59f3c5bf70173aac2bb18f8

x86 / CPU: Always show current CPU frequency in /proc/cpuinfo

在这个patch之前,/proc/cpuinfo中的频率信息,只是一个象征意义,根据平台实现不同,可能是cpufreq governor之前写下去的requested cpufreq,并不表示CPU实际的运行频率。这个patch也是使用APERF和MPERF来计算CPU频率,像scaling_cur_freq一样能够反映CPU的实际频率信息。

最后,我们来看一下,有了这些patch(kernel 4.15)之后,以上这3个接口具体是如何实现的。

我以acpi_cpufreq driver为例进行分析,我们先来看一下跟这三个接口相关的,acpi_cpufreq driver的一些关键的callback是如何实现的:

1)频率切换是通过target/target_index还是setpolicy来完成呢?

acpi_cpufreq只能在fixed predefined frequency point中间调整,使用target_index callback完成实际的频率切换,setpolicy callback为NULL;

2)acpi_cpufreq_driver.get = get_cur_freq_on_cpu,通过读取MSR 0x199获取当前的requested frequency

/proc/cpuinfo 对应的code在arch/x86/kernel/cpu/proc.c中

show_cpuinfo
{if(cpu_has(c, X86_FEATURE_TSC)){unsigned int freq = aperfmperf_get_khz(cpu);          //1)先用aperf-mperf snapshot的方式,统计一段时间内CPU的average frequencyif(!freq){freq = cpufreq_quick_get(cpu);                      //2)若1)失败,使用cpufreq_driver->get获取当前频率{if(cpufreq_driver && cpufreq_driver->setpolicy && cpufreq_driver->get) //对于acpi_cpufreq而言,setpolicy callback为NULL{freq = cpufreq_driver->get(cpu);return freq;}policy = cpufreq_cpu_get(cpu);      //3)返回scaling governor上一次选中的target frequency;if(policy)return policy->cur;}}if(!freq)freq = cpu_khz;                         //4)如果1、2、3都失败,返回TSC的cpu_khz信息;seq_printf(m, "cpu MHz\t\t: %u.%03u\n", freq / 1000, (freq % 1000));}
}

/sys/devices/system/cpu/cpuX/cpufreq/cpuinfo_cur_freq和scaling_cur_freq都在drivers/cpufreq/cpufreq.c中实现

show_cpuinfo_cur_freq
{cur_freq = __cpufreq_get(policy->cpu);{cpufreq_driver->get(cpu);        //即get_cur_freq_on_cpu}
}
从MSR 0x199中获取该core的requestedFID-VID,再根据FID-VID去freq_table中查其相应的frequency
get_cur_freq_on_cpu(int cpu)
{struct cpufreq_policy *policy;struct acpi_cpufreq_data *data;u32 val;policy = cpufreq_cpu_get_raw(cpu);   data = policy->driver_data;//暂存的OS request frequency;cached_freq = policy->freq_table[to_perf_data(data)->state].frequency;//读MSR 0x199val = get_cur_val(cpumask_of(cpu), data);     {u32 val = drv_read(data, mask);           {struct acpi_processor_performance *perf = to_perf_data(data);struct drv_cmd cmd = {.reg = &perf->control_register,       //注意这里读的是control register,即MSR 0x199.func.read = data->cpu_freq_read,};smp_call_function_any(mask, do_drv_read, &cmd,1);}return val;}//把FID-VID转换成frequency,去policy->freq_table中找MSR 199中FID-VID对应的pos,返回其frequencyfreq = extract_freq(policy, val);       {struct acpi_cpufreq_data *data = policy->driver_data;switch(data->cpu_feature){case SYSTEM_INTEL_MSR_CAPABLE:case SYSTEM_AMD_MSR_CAPABLE:return extract_msr(policy,val);{struct acpi_processor_performance *perf;perf = to_perf_data(data);msr = val;cpufreq_for_each_entry(pos, policy->freq_table){if(msr == perf->states[pos->driver_data].status)return pos->frequency;}return policy->freq_table[0].frequency;}case SYSTEM_IO_CAPABLE:return extract_io(policy,val);default:return 0;}}
}
show_scaling_cur_freq
{freq = arch_freq_get_on_cpu(policy->cpu);        //1)通过APERF-MPERF获取CPU频率{if(!boot_cpu_has(X86_FEATURE_APERFMPERF))return 0;if(aperfmperf_snapshot_cpu(cpu, ktime_get(),true))return per_cpu(samples.khz, cpu);msleep(APERFMPERF_REFRESH_DELAY_MS);smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL,1);return per_cpu(samples.khz, cpu);}if(!freq)        //2)如果1)失败,通过cpufreq_driver->get callback获取CPU频率信息{if(cpufreq_driver && cpufreq_driver->setpolicy && cpufreq_driver->get)    //2.1)对于acpi_cpufreq driver而言,setpolicy callback为空,从这里跳出去;freq = cpufreq_driver->get(cpu);}if(!freq)        //3)返回scaling governor上一次选择的target frequency作为CPU频率freq = policy->cur;
}

来highlight一下结论:

MSR 0x199是per-core的,每个core都可以根据自己的load,计算一个target frequency,通过MSR 0x199写下去;但是我们知道,多个core的情况下,如果只有一个VRM,需要对多个core 的target frequency进行处理,取一个合适的频率作为实际的频率。如果有APERF-MPERF的话,那么可以通过/proc/cpuinfo 和scaling_cur_freq接口获得CPU实际频率,否则就只能看到各个core的requested frequency,而实际的频率可能跟我们读到的不一样。

x86上 /proc/cpuinfo中的cpufreq和scaling_cur_freq怎么算相关推荐

  1. /proc/cpuinfo_Linux中的/ proc / cpuinfo和/ proc / meminfo文件

    /proc/cpuinfo /proc is a directory in the Linux system that contains information about the system. / ...

  2. 通过cat /proc/cpuinfo看处理器特点

    2019独角兽企业重金招聘Python工程师标准>>> 在我的服务器上执行cat /proc/cpuinfo得到如下信息(摘录最后一项,从0-23共24项): processor: ...

  3. linux 下/proc/cpuinfo三级缓存,linux /proc/cpuinfo文件分析

    基于不同指令集(ISA)的CPU产生的/proc/cpuinfo文件不一样,基于X86指令集CPU的/proc/cpuinfo文件包含如下内容: processor : 0 vendor_id :Ge ...

  4. linux /proc/cpuinfo文件分析

    为什么80%的码农都做不了架构师?>>>    基于不同指令集(ISA)的CPU产生的/proc/cpuinfo文件不一样,基于X86指令集CPU的/proc/cpuinfo文件包含 ...

  5. linux 下/proc/cpuinfo三级缓存,51CTO博客-专业IT技术博客创作平台-技术成就梦想

    在Linux系统中,提供了proc文件系统显示系统的软硬件信息.如果想了解系统中CPU的提供商和相关配置信息,则可以通过/proc/cpuinfo文件得到.本文章针对该文件进行简单的总结. 基于不同指 ...

  6. linux下/proc/cpuinfo 文件分析

    /proc/cpuinfo文件分析 在Linux系统中,提供了proc文件系统显示系统的软硬件信息.如果想了解系统中CPU的提供商和相关配置信息,则可以通过/proc/cpuinfo文件得到.本文章针 ...

  7. /proc/cpuinfo文件分析(查看CPU信息)

    2019独角兽企业重金招聘Python工程师标准>>> 在Linux系统中,提供了proc文件系统显示系统的软硬件信息.如果想了解系统中CPU的提供商和相关配置信息,则可以通过/pr ...

  8. Linux下查看CPU信息[/proc/cpuinfo]

    最近在研究linux系统负载的时候,接触到一些关于CPU信息查看的知识,和大家分享一下.通过对/proc/cpuinfo文件中的参数的分析,也学到了不少东西. 在linux操作系统中,CPU的信息在启 ...

  9. /proc/cpuinfo 里的 CPU flags

    Linux 上的 /proc是一个虚拟文件系统,在系统启动后挂载在 /proc 上,/proc 包含了很多内核和系统信息用来展示 Linux 内核是如何展示硬件的,比如在 /proc/cpuinfo ...

最新文章

  1. nodejs文件上传报错总结
  2. Shell的一些基本用法
  3. python函数必背知识点_必背函数——python学习第四次总结
  4. Linux CPU数、物理核、逻辑核的查看方法及线程进程的绑定方法
  5. 阿里云Redis (安装包安装篇)
  6. 文本内容之间的关键词提取和相似度计算
  7. 47.QT-QChart之曲线图,饼状图,条形图使用
  8. django-关于a标签路径的测试
  9. application.properties 中文乱码问题解决
  10. 翱文中华灯谜大全 v1.1 免费下载--IT man
  11. visual_c++外挂教程(较详细)
  12. STM32F407获取OV5640摄像头图像及上位机解码(一维码二维码)
  13. 单细胞测序系列之二:单细胞基因组测序
  14. 计算机基本信息分别代表什么意思,视频基本信息格式不正确是什么意思
  15. linux执行 ifconfig 命令 eth0没有IP地址(intet addr、Bcast、Mask)
  16. [北航软工教学] 教学计划大纲
  17. selenium之判断是否定位正确
  18. 分析| AI智能生图前景几何?
  19. 轴流风机和离心风机有什么区别?
  20. <JVM上篇:内存与垃圾回收篇>13-垃圾回收器

热门文章

  1. 我的股票交易成长经历
  2. ubuntu20.04 开启休眠(hibernate)功能的成功解决以及各种尝试的过程全记录
  3. 2D转换分页按钮的制作流程(12)
  4. 信息安全系列(3)--从王宝*离婚案论个人信息安全
  5. 在这个云时代,如何选择性价比更高的云服务器
  6. 批处理bat修改文件后缀
  7. 系统(层次)聚类法及Spss实现
  8. 2023 年 10 大最佳技术职业 ,十大 IT 职业是什么?
  9. 在RSS服务器上订阅网站,快速服务器上的RSS订阅实现
  10. 1-计算机系统概述(CO)