blob: 17cfee40ea71e3af47f21bca92588e25d2f38451 [file] [log] [blame]
/**
* @file op_cpufreq.c
* get cpu frequency definition
*
* @remark Copyright 2011 OProfile authors
* @remark Read the file COPYING
*
* @author John Levon
* @author Philippe Elie
* @author Suravee Suthikulpanit
*/
#include <stdio.h>
#include <stdlib.h>
#include "op_fileio.h"
/*
* Use frequency information from /proc/cpuinfo. This should be available in most case.
* However, this number is the current cpu frequency which could be in the idle state.
* We should actually report the max frequency because the cpu should switch into the
* highest power state when running.
*/
static double op_cpu_freq_cpuinfo(void)
{
double fval = 0.0;
unsigned long uval;
char * line = NULL;
FILE * fp = op_try_open_file("/proc/cpuinfo", "r");
if (!fp)
return 0.0;
while (1) {
line = op_get_line(fp);
if (!line)
break;
if (line[0] == '\0') {
free(line);
continue;
}
/* x86/parisc/ia64/x86_64 */
if (sscanf(line, "cpu MHz : %lf", &fval) == 1)
break;
/* ppc/ppc64 */
if (sscanf(line, "clock : %lfMHz", &fval) == 1)
break;
/* alpha */
if (sscanf(line, "cycle frequency [Hz] : %lu", &uval) == 1) {
fval = uval / 1E6;
break;
}
/* sparc64 if CONFIG_SMP only */
if (sscanf(line, "Cpu0ClkTck : %lx", &uval) == 1) {
fval = uval / 1E6;
break;
}
/* mips including loongson2 */
if (sscanf(line, "BogoMIPS : %lu", &uval) == 1) {
fval = uval * 3 / 2;
break;
}
/* s390 doesn't provide cpu freq, checked up to 2.6-test4 */
free(line);
}
if (line)
free(line);
op_close_file(fp);
return fval;
}
/*
* Use frequency information from /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
* This number is the maximum cpu frequency of the processor.
*/
static double op_cpu_freq_sys_devices(void)
{
double fval = 0.0;
char * line = NULL;
FILE * fp = op_try_open_file("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", "r");
if (!fp)
return 0.0;
while (1) {
line = op_get_line(fp);
if (!line)
break;
if (line[0] == '\0') {
free(line);
continue;
}
if (sscanf(line, "%lf", &fval) == 1)
break;
free(line);
}
if (line)
free(line);
op_close_file(fp);
return fval;
}
double op_cpu_frequency(void)
{
/*
* Typically, system changes the frequency scaling of the cpus
* based on the workload. /proc/cpuinfo reports the current
* frequency value which might not be at the maximum at the time
* of query. Since cpu switch into running state with max frequency
* when under workload, we should make sure to report the max frequency
* value acquiring from /sys/devices when available.
*/
double freq = op_cpu_freq_sys_devices();
if (freq == 0) {
freq = op_cpu_freq_cpuinfo();
}
return freq;
}