1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
|
/***************************************************************************
* *
* Powersave Daemon *
* *
* Copyright (C) 2004,2005,2006 SUSE Linux Products GmbH *
* *
* Author(s): Holger Macht <hmacht@suse.de> *
* *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at you *
* option) any later version. *
* *
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA *
* *
***************************************************************************/
#include <sstream>
#include <fstream>
#include <cpufreq.h>
#include "cpufreq_interface.h"
CPUFreq_Kernel::CPUFreq_Kernel(list< int > cpu_list, unsigned long rate)
: CPUFreq_Interface(cpu_list)
{
_sampling_rate = rate;
POWERSAVE_STRING = "powersave";
PERFORMANCE_STRING = "performance";
ON_DEMAND_STRING = "ondemand";
}
CPUFreq_Kernel::~CPUFreq_Kernel()
{
}
bool CPUFreq_Kernel::init()
{
if (setGovernor(ON_DEMAND_STRING) < 0) {
/* no ondemand governor set */
pDebug(DBG_INFO, "Can not set ondemand governor, maybe your cpufreq driver is too slow.");
return false;
}
return true;
}
bool CPUFreq_Kernel::readFrequencies()
{
if (!online())
return false;
/* this just returns the maximum frequency step to get the value
* for downstepping the cpu
*/
int freq_hi = 0, freq_lo = 0;
float ratio = 0, tmp_ratio = 0;
cpufreq_available_frequencies *freqs = cpufreq_get_available_frequencies(_cpu_base);
if (freqs == NULL) {
return false;
}
freq_hi = freqs->frequency;
freqs = freqs->next;
while (freqs != NULL) {
freq_lo = freqs->frequency;
tmp_ratio = ((float)freq_hi / (float)freq_lo);
pDebug(DBG_INFO, "freq_hi: %d freq_lo: %d, ratio: %4.2f", freq_hi, freq_lo, tmp_ratio);
freq_hi = freq_lo;
if (tmp_ratio > ratio)
ratio = tmp_ratio;
if (freqs->next == NULL) {
cpufreq_put_available_frequencies(freqs->first);
break;
}
else {
freqs = freqs->next;
}
}
_down_threshold = (int)((float)_cpu_max / ratio) - _cpu_hysteresis;
pDebug(DBG_DIAG, "cpu_max: %d, ratio: %4.3f, hysteresis: %d => down_threshold ((m/r)-h): %d", _cpu_max, ratio,
_cpu_hysteresis, _down_threshold);
return true;
}
int CPUFreq_Kernel::writeOndemand(const string &name, int value)
{
ostringstream strstr("");
string ondemand_config_file;
strstr << SYSFS_FILES << "cpu" << _cpu_base << "/cpufreq/ondemand/" << name;
ondemand_config_file = strstr.str();
if (access(ondemand_config_file.c_str(), F_OK)) {
pDebug(DBG_DIAG, "ondemand config file '%s' does not exist.", ondemand_config_file.c_str());
return -1;
}
if (access(ondemand_config_file.c_str(), W_OK)) {
pDebug(DBG_WARN, "Could not write ondemand config file %s: %s",
ondemand_config_file.c_str(), strerror(errno));
return 1;
}
if (!write_line(ondemand_config_file.c_str(), "%d", value)) {
pDebug(DBG_WARN, "Failed writing value of %d to ondemand-config %s", value, name.c_str());
return 1;
}
pDebug(DBG_INFO, "wrote '%d' to file '%s'", value, ondemand_config_file.c_str());
return 0;
}
unsigned int CPUFreq_Kernel::readOndemand(const string &name)
{
ostringstream strstr("");
string ondemand_config_file;
strstr << SYSFS_FILES << "cpu" << _cpu_base << "/cpufreq/ondemand/" << name;
ondemand_config_file = strstr.str();
if (access(ondemand_config_file.c_str(), F_OK)) {
pDebug(DBG_DIAG, "ondemand config file '%s' does not exist.", ondemand_config_file.c_str());
return 0;
}
if (access(ondemand_config_file.c_str(), R_OK)) {
pDebug(DBG_WARN, "Could not read ondemand config file %s: %s",
ondemand_config_file.c_str(), strerror(errno));
return 0;
}
return read_value(ondemand_config_file.c_str());
}
void CPUFreq_Kernel::setOndemandConfig()
{
/* probably forgot some ondemand configs ?
Current powersaved configs:
int CPUFreq_Interface::cpu_max = 90;
int CPUFreq_Interface::cpu_hysteresis = 5;
int CPUFreq_Interface::high_cpu_limit = 0;
int CPUFreq_Interface::consider_nice = 1;
Current ondemand config files:
down_threshold
sampling_down_factor
sampling_rate
sampling_rate_max
sampling_rate_min
up_threshold
Current dynamic vs. ondemand config mapping:
cpu_max == up_threshold
sampling_rate == poll_interval * 1000
*/
unsigned long _sampling_rate_max;
unsigned long _sampling_rate_min;
/* this reads the maximum and minimum sampling rate to be used */
if ((_sampling_rate_min = readOndemand("sampling_rate_min")) == 0) {
pDebug(DBG_WARN, "Could not read sampling_rate_min of ondemand governor.");
_sampling_rate_min = _sampling_rate; //setting to current rate, so setOndemandConfig could still work
}
if ((_sampling_rate_max = readOndemand("sampling_rate_max")) == 0) {
pDebug(DBG_WARN, "Could not read sampling_rate_max of ondemand governor.");
_sampling_rate_max = _sampling_rate; //setting to current rate, so setOndemandConfig could still work
}
/* up_threshold is always there, even in "old" kernels (2.6.11)
if not, there is something wrong and we return early. */
if (writeOndemand("up_threshold", _cpu_max)) {
pDebug(DBG_WARN, "Problems with ondemand governor, could not write up_threshold.");
return;
}
/* ingore_nice sysfs-file should probably be named "consider nice":
0 = niced processes do not count for cpufreq calculation
1 = niced processes _do_ count for cpufreq calculation
Let me tell you that this confused me quite a bit :-)
in recent kernels, it was actually fixed. The file is now called
"ignore_nice_load" and it does actually do what the name suggests:
0 = niced processes do count
1 = niced processes do not count
Only one of those 2 files is present
*/
if ((writeOndemand("ignore_nice_load", !_consider_nice) < 0) &&
(writeOndemand("ignore_nice", _consider_nice) < 0)) {
/* if the kernel is even older, it does not have neither
of those, but then it has "down_treshold" (which is auto-
calculated in newer kernels), so we at least set that.
*/
writeOndemand("down_threshold", _down_threshold);
}
writeOndemand("sampling_down_factor", 1); // todo: use define or configure it.
/* check if sampling_rate is in boundaries and write it to sysfs */
if (_sampling_rate < _sampling_rate_min) {
pDebug(DBG_WARN, "Set sampling_rate (%lu) for ondemand governor is lower than minimum (%lu) which will be used now.",
_sampling_rate, _sampling_rate_min);
_sampling_rate = _sampling_rate_min;
} else if (_sampling_rate > _sampling_rate_max) {
pDebug(DBG_WARN, "Set sampling_rate (%lu) for ondemand governor is higher than maximumg (%lu) which will be used now.",
_sampling_rate, _sampling_rate_max);
_sampling_rate = _sampling_rate_max;
}
writeOndemand("sampling_rate", _sampling_rate);
return;
}
void CPUFreq_Kernel::setConfig()
{
}
int CPUFreq_Kernel::adjustSpeed()
{
switch (_mode) {
case _DYNAMIC:
if (setGovernor(ON_DEMAND_STRING) < 0) {
pDebug(DBG_WARN, "Could not set ondemand governor.");
return -1;
}
// after switching back to ondemand, the config needs to be re-set
setOndemandConfig();
break;
case _PERFORMANCE:
if (setGovernor("performance") < 0) {
pDebug(DBG_WARN, "Could not set performance governor.");
return -1;
}
break;
case _POWERSAVE:
if (setGovernor("powersave") < 0) {
pDebug(DBG_WARN, "Could not set powersave governor.");
return -1;
}
break;
default:
pDebug(DBG_WARN, "Unknown cpufreq kernel governor requested");
return -1;
}
return 1;
}
void CPUFreq_Kernel::reinitSpeed()
{
/* dummy inplementation */
}
|