You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdepowersave/src/hardware_cpu.cpp

314 lines
8.3 KiB

/**************************************************************************
* Copyright (C) 2006 by Daniel Gollub *
* <dgollub@suse.de> *
* Danny Kukawka *
* <dkukawka@suse.de>, <danny.kukawka@web.de> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of version 2 of the GNU General Public License *
* as published by the Free Software Foundation. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
/*!
* \file hardware_cpu.cpp
* \brief In this file can be found the CPU information related code.
* \author Danny Kukawka, <dkukawka@suse.de>, <danny.kukawka@web.de>
* \author Daniel Gollub, <dgollub@suse.de>
* \author
* \date 2006
*/
// include own header
#include "hardware_cpu.h"
#include "hardware_cpu.moc"
// QT Header
#include <tqdir.h>
#include <tqtimer.h>
// system header
#include <fcntl.h>
#include <unistd.h>
/*! The default constructor of the class CPUInfo */
CPUInfo::CPUInfo() {
kdDebugFuncIn(trace);
update_info_cpufreq_speed_changed = true;
numOfCPUs = -1;
kdDebugFuncOut(trace);
}
/*! The default desctuctor of the class CPUInfo */
CPUInfo::~CPUInfo() {
kdDebugFuncIn(trace);
}
/*!
* This function counts all online/offline CPUS.
* Returns the total count of CPUs - _not_ the last CPU ID!
*/
int CPUInfo::getCPUNum() {
kdDebugFuncIn(trace);
int cpu_id=0;
TQDir tmp_dir;
TQString cpu_path = "/sys/devices/system/cpu/cpu0/";
#ifdef FAKE_CPU
cpu_path.prepend("/tmp/foo");
#endif
// let check if we support cpufreq in general
if (tmp_dir.exists(tmp_dir.absFilePath(cpu_path + "cpufreq/scaling_cur_freq", true))) {
cpuFreqHW = true;
} else {
cpuFreqHW = false;
}
TQString tmp_path = tmp_dir.absFilePath(cpu_path, true);
while (tmp_dir.exists(tmp_path)) {
int tmp = cpu_id;
cpu_id++;
cpu_path.replace(TQString::number(tmp), TQString::number(cpu_id));
tmp_path = tmp_dir.absFilePath(cpu_path, true);
}
kdDebug() << "getCPUNum() return: '" << cpu_id << "'" << endl;
kdDebugFuncOut(trace);
return cpu_id;
}
/*!
* The function checks the current CPU Speed. The current cpu speed needs to be read out from
* sysfs and currently not be obtained through the daemon. If the CPUFreg changed the new value
* is set to \ref cpufreq_speed .
* \return Information if something changed or if there are errors as an interger value
* \retval -1 if there are error by reading from /sys/..
* \retval 0 if nothing changed
* \retval 1 if something changed
*/
int CPUInfo::checkCPUSpeed(){
kdDebugFuncOut(trace);
bool speed_changed = false;
int new_value = -1;
int fd;
char buf[15];
TQString cpu_device = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq";
#ifdef FAKE_CPU
cpu_device.prepend("/tmp/foo");
#endif
// first check path for the kernel on-demand-govenour then
// for the use userspace case
update_info_cpufreq_speed_changed = false;
cpufreq_speed.clear();
if (numOfCPUs == -1)
numOfCPUs = getCPUNum();
for (int cpu_id=0; cpu_id < numOfCPUs; cpu_id++) {
new_value = -1;
fd = open(cpu_device.ascii(), O_RDONLY);
if (read(fd, buf, 14) > 0){
new_value = strtol(buf, NULL, 10)/1000;
close(fd);
}
else{
close(fd);
speed_changed = true;
// CPU disabeld -> set Freq to -1
cpufreq_speed.append(-1);
}
if (new_value != cpufreq_speed[cpu_id]) {
speed_changed = true;
cpufreq_speed.append(new_value);
}
cpu_device.replace(TQString::number(cpu_id), TQString::number(cpu_id+1));
}
if (speed_changed) {
update_info_cpufreq_speed_changed = true;
kdDebugFuncOut(trace);
return 1;
}
kdDebugFuncOut(trace);
return 0;
}
/*!
* The function checks the Speed of throttling CPU(s). The cpu speed needs to be read out from
* /proc/cpuinfo.
* \return Success or error while reading /proc/cpuinfo
* \retval 0 successful
* \retval -1 reading problem
*/
int CPUInfo::checkCPUSpeedThrottling() {
kdDebugFuncOut(trace);
TQString cpu_file = "/proc/cpuinfo";
#ifdef FAKE_CPU
cpu_file.prepend("/tmp/foo");
#endif
TQFile cpu_info(cpu_file);
// clear cpufreq list
cpufreq_speed.clear();
if ( !cpu_info.open(IO_ReadOnly) ) {
cpu_info.close();
kdDebugFuncOut(trace);
return -1;
}
TQTextStream stream( &cpu_info );
TQString line;
while ( !stream.atEnd() ) {
line = stream.readLine();
if (line.startsWith("cpu MHz : ")) {
line.remove("cpu MHz : ");
line = line.remove(line.length() - 4, 4);
cpufreq_speed.append(line.toInt());
}
}
while ((int) cpufreq_speed.count() < numOfCPUs) {
cpufreq_speed.append(-1);
}
cpu_info.close();
kdDebugFuncOut(trace);
return 0;
}
/*!
* The function gets the current throttling state of the CPU(s). The throttling state needs to be
* read out from /proc/acpi/processor/CPUX/throttling.
* \return boolean with info if throttling is supported
* \retval true if throttling is supported
* \retval false if not supported or on any other error
*/
bool CPUInfo::getCPUThrottlingState() {
kdDebugFuncIn(trace);
int id = 0;
TQFileInfo *fi;
TQString cpu_dirname;
TQString dir_acpi_processor = "/proc/acpi/processor/";
#ifdef FAKE_CPU
dir_acpi_processor.prepend("/tmp/foo");
#endif
TQDir d_throttling(dir_acpi_processor);
if (!d_throttling.exists()) {
kdDebugFuncOut(trace);
return false;
}
d_throttling.setFilter( TQDir::Dirs );
d_throttling.setNameFilter("CPU*");
const TQFileInfoList *list = d_throttling.entryInfoList();
TQFileInfoListIterator it( *list );
// clear throttling value list
cpu_throttling.clear();
while ((fi = it.current()) != 0 ) {
cpu_dirname = fi->fileName();
TQString throttling_device = d_throttling.absPath();
throttling_device.append("/").append(cpu_dirname).append("/throttling");
kdDebug() << "Throttling state file for CPU" << id << " will be: " << throttling_device << endl;
TQFile throttling(throttling_device);
// open throttling state file
if ( throttling.open(IO_ReadOnly) ) {
TQTextStream stream( &throttling );
TQString line;
do {
line = stream.readLine();
} while (!line.startsWith(" *T") && !stream.atEnd() );
if (line.startsWith(" *T")) {
line = line.right(3);
line.remove("%");
cpu_throttling.append(line.toInt());
kdDebug () << "CPU " << id
<< ": cpu_throttling is set to: " << cpu_throttling[id] << endl;
} else {
cpu_throttling.append(0);
}
}
throttling.close();
++it; // next entry
id++; // count cpu id
}
kdDebugFuncOut(trace);
return true;
}
/*!
* The function gets the Max CPU Speed. The max cpu speed needs to be read out from
* sysfs and currently not be obtained through the daemon.
*/
void CPUInfo::getCPUMaxSpeed() {
kdDebugFuncIn(trace);
int fd;
int maxfreq;
char buf[15];
TQString cpu_device_max = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
#ifdef FAKE_CPU
cpu_device_max.prepend("/tmp/foo");
#endif
cpufreq_max_speed.clear();
if (numOfCPUs == -1)
numOfCPUs = getCPUNum();
// while (!access(cpu_device_max, R_OK)) {
for (int cpu_id=0; cpu_id < numOfCPUs; cpu_id++) {
fd = open(cpu_device_max.ascii(), O_RDONLY);
if (read(fd, buf, 14) > 0){
maxfreq = strtol(buf, NULL, 10)/1000;
cpufreq_max_speed.append(maxfreq);
close(fd);
} else {
cpufreq_max_speed.append(-1);
close(fd);
}
cpu_device_max.replace(TQString::number(cpu_id), TQString::number(cpu_id+1));
}
kdDebugFuncOut(trace);
}