x86上 /proc/cpuinfo中的cpufreq和scaling_cur_freq怎么算
前天我正在看代码的时候,一个同事跑过来问我,“/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怎么算相关推荐
- /proc/cpuinfo_Linux中的/ proc / cpuinfo和/ proc / meminfo文件
/proc/cpuinfo /proc is a directory in the Linux system that contains information about the system. / ...
- 通过cat /proc/cpuinfo看处理器特点
2019独角兽企业重金招聘Python工程师标准>>> 在我的服务器上执行cat /proc/cpuinfo得到如下信息(摘录最后一项,从0-23共24项): processor: ...
- linux 下/proc/cpuinfo三级缓存,linux /proc/cpuinfo文件分析
基于不同指令集(ISA)的CPU产生的/proc/cpuinfo文件不一样,基于X86指令集CPU的/proc/cpuinfo文件包含如下内容: processor : 0 vendor_id :Ge ...
- linux /proc/cpuinfo文件分析
为什么80%的码农都做不了架构师?>>> 基于不同指令集(ISA)的CPU产生的/proc/cpuinfo文件不一样,基于X86指令集CPU的/proc/cpuinfo文件包含 ...
- linux 下/proc/cpuinfo三级缓存,51CTO博客-专业IT技术博客创作平台-技术成就梦想
在Linux系统中,提供了proc文件系统显示系统的软硬件信息.如果想了解系统中CPU的提供商和相关配置信息,则可以通过/proc/cpuinfo文件得到.本文章针对该文件进行简单的总结. 基于不同指 ...
- linux下/proc/cpuinfo 文件分析
/proc/cpuinfo文件分析 在Linux系统中,提供了proc文件系统显示系统的软硬件信息.如果想了解系统中CPU的提供商和相关配置信息,则可以通过/proc/cpuinfo文件得到.本文章针 ...
- /proc/cpuinfo文件分析(查看CPU信息)
2019独角兽企业重金招聘Python工程师标准>>> 在Linux系统中,提供了proc文件系统显示系统的软硬件信息.如果想了解系统中CPU的提供商和相关配置信息,则可以通过/pr ...
- Linux下查看CPU信息[/proc/cpuinfo]
最近在研究linux系统负载的时候,接触到一些关于CPU信息查看的知识,和大家分享一下.通过对/proc/cpuinfo文件中的参数的分析,也学到了不少东西. 在linux操作系统中,CPU的信息在启 ...
- /proc/cpuinfo 里的 CPU flags
Linux 上的 /proc是一个虚拟文件系统,在系统启动后挂载在 /proc 上,/proc 包含了很多内核和系统信息用来展示 Linux 内核是如何展示硬件的,比如在 /proc/cpuinfo ...
最新文章
- nodejs文件上传报错总结
- Shell的一些基本用法
- python函数必背知识点_必背函数——python学习第四次总结
- Linux CPU数、物理核、逻辑核的查看方法及线程进程的绑定方法
- 阿里云Redis (安装包安装篇)
- 文本内容之间的关键词提取和相似度计算
- 47.QT-QChart之曲线图,饼状图,条形图使用
- django-关于a标签路径的测试
- application.properties 中文乱码问题解决
- 翱文中华灯谜大全 v1.1 免费下载--IT man
- visual_c++外挂教程(较详细)
- STM32F407获取OV5640摄像头图像及上位机解码(一维码二维码)
- 单细胞测序系列之二:单细胞基因组测序
- 计算机基本信息分别代表什么意思,视频基本信息格式不正确是什么意思
- linux执行 ifconfig 命令 eth0没有IP地址(intet addr、Bcast、Mask)
- [北航软工教学] 教学计划大纲
- selenium之判断是否定位正确
- 分析| AI智能生图前景几何?
- 轴流风机和离心风机有什么区别?
- <JVM上篇:内存与垃圾回收篇>13-垃圾回收器