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 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
|
/***************************************************************************
* *
* 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 *
* *
***************************************************************************/
#ifndef POWERSAVE_CPUFREQ_H
#define POWERSAVE_CPUFREQ_H
#include "pm_interface.h"
#include "cpu.h"
#ifdef CPUFREQ_MEASURE
#include <time.h>
#endif
/* code in to test available speeds (initFreqsViaTesting())
is converted from cpuspeed from Carl Thompson
cpufreq.cc -> getspeeds() */
#define MAX_SPEEDS 20
#define MIN_SPEED_STEP 25000 /* in kHz, minimum step between 2 speeds */
#define SYSFS_FILES \
"/sys/devices/system/cpu/"
class CPUFreq_Interface : public CPU {
public:
/** @brief constructor
*
* @param cpu_list stl list containing all cores the object has to
* care about
*/
CPUFreq_Interface(std::list< int > cpu_list);
/** @brief destructor */
virtual ~CPUFreq_Interface();
/** @brief checks if current cpu_id has a cpufreq directory
* and that it is no symlink
*
* @return true on success, false on error
*/
virtual bool init() = 0;
/** @brief adjusts speeds
*
* @return
* - -1 if speed has been decreased
* - 1 if speed has been increased
* - 0 if speed has not been modified
*/
virtual int adjustSpeed() = 0;
/** @brief reinits speeds
*
* function for suspend workaround. after resuming the frequency
* might have changed and we haven't recognized. This could
* possibly break old PowerNow! machines, but as far as I know
* jumping more than one frequency at once is fixed in kernel
* module for that machines
*/
virtual void reinitSpeed() = 0;
/** @brief set configuration in initialize values */
virtual void setConfig() = 0;
/** @brief Update configs and apply them
*
* @param high_cpu increase frequency if CPU load exceeds this value
* @param max_limit directly jump to the highest available frequency
* if the difference between CPU Load and last
* measured CPU load exceeds this value (only valid for
* userspace governor
* @param hysters hysteresis value to not oscillate between two
* frequencies if CPU Load does not change createHysteresisArray()
* @param consider_nice consider niced processes values as CPU load or not
*/
void setConfigs(int high_cpu, int max_limit, int hysters, int consider_nice);
/** @brief set a ne cpufreq governor */
int setGovernor(const std::string &new_governor);
/** @brief set the current cpufreq policy
*
* _PERFORMANCE, _DYNAMIC, _POWERSAVE
*
* @param mode @ref CPUFREQ_MODE
*
* @return
* - 0 on success
* - -1 on failure
*
* Always test the return value as the kernel
* class might loose the powersave or performance governor
*
* If the call fails the cpufreq classes are destroyed, isSupported
* will return false and you must not call any CPUFreq functions any
* more (in fact these calls should be just ignored, but better
* be careful)
*/
int setMode(CPUFREQ_MODE mode);
/** @brief reads out frequencies
*
* @return false on error
*/
virtual bool readFrequencies() = 0;
/** @brief get current cpufreq policy
*
* @return @ref CPUFREQ_MODE
*/
CPUFREQ_MODE getMode();
/** @brief read a line from a file
*
* @param filename the filename to read from
* @param line char pointer to store the read line
* @param len chars to read
*
* @return false on error
*/
static bool read_line(const char *filename, char *line, unsigned len);
/** @brief write a line to a file
*
* @param filename the filename to read from
* @param fmt format to write
* @param ... variable argument list to write
*
* @return false on error
*/
static bool write_line(const char *filename, const char *fmt, ...);
protected:
/** @brief read an integer value from a file
*
* @param filename filename to read from
*
* @return the value read or 0 on error
*/
static unsigned read_value(const char *filename);
/** @brief file where active governor is in */
string GOVERNOR_FILE;
/** @brief file containing the minimum freq */
string MIN_SPEED_FILE;
/** @brief file containing the maximum freq */
string MAX_SPEED_FILE;
/** @brief file containing available frequencies */
string AVAILABLE_FREQS_FILE;
/** @brief value specifying when to switch up */
int _cpu_max;
/** @brief value avoiding constant up/down switching */
int _cpu_hysteresis;
/** @brief if the load difference is higher than this
* go directly for full speed */
int _high_cpu_limit;
/** @brief if niced processes should also count
*
* not all of those work with "kernel" methods.
*/
int _consider_nice;
/** @brief stores the current cpufreq policy
*
* (powersave, performance, dynamic)
*/
CPUFREQ_MODE _mode;
/** @brief list holding all cores which are affected by this
* interface*/
std::list< int > _cpu_cores;
};
/** @brief Class to control one CPU's frequency by the powersave daemon */
class CPUFreq_Userspace:public CPUFreq_Interface {
public:
/** @brief constructor
*
* @param cpu_cores stl list containing all cores the object has to
* care about
*/
CPUFreq_Userspace(std::list< int > cpu_cores);
/** @brief destructor */
~CPUFreq_Userspace();
/** @brief init cpufreq interface and set userspace governor
*
* @return true on success, false otherwise
*/
bool init();
#ifdef CPUFREQ_MEASURE
unsigned long time_spent[MAX_SPEEDS + 1];
unsigned int count;
unsigned long cpu_load_sum;
static time_t *start_time;
static unsigned long polling_interval;
/** @brief append measure output to /tmp/cpufreq.log statically for now */
static void startMeasures();
/** @brief append measure output to /tmp/cpufreq.log statically for now */
static void stopMeasures();
/** @brief need polling interval for time measures */
#endif
private:
/** @brief get the minimum and maximum available speeds
*
* This is currently only used by the userspace class
* to test frequencies if available_frequencies file
* is not exported by the kernel's low-level driver
*
* @param min value is set to the minimum speed
* @param max value is set to the maximum speed
*
* @return false if speedstepping is not supported
*/
bool getMinMaxSpeeds(unsigned long *min, unsigned long *max);
/** @brief get the current CPU speed
*
* @return the speed or 0 on error
*/
unsigned getSpeed();
/** @brief set speed to the next higher supported value
*
* @return integer with result of increase speed
* @retval 0 if maximum is already reached
* @retval 1 if new speed could be set
* @retval -1 if mode is not userspace
*/
int increaseSpeed();
/** @brief set speed to the next lower supported value
*
* @return integer with result of increase speed
* @retval 0 if maximum is already reached
* @retval 1 if new speed could be set
* @retval -1 if mode is not userspace
*/
int decreaseSpeed();
/** @brief set the current CPU speed
*
* @param kHz the speed in kHz to set
*
* @return false if speed could not be set
*/
bool setSpeed(unsigned kHz);
/** @brief set the speed smoothly in steps
*
* This code smoothly transitions the CPU speed from 'current' to
* 'target' instead of jumping directly to the new speed because
* some AMD Mobile Athlon parts seem to choke on large
* differentials causing kernel panics.
*
* @param current the current speed
* @param target the target speed
*/
void setSpeed(unsigned current, unsigned target);
/** @brief creates the hysteresis array */
void createHysteresisArray();
bool readFrequencies();
int adjustSpeed();
void reinitSpeed();
/** @brief inits the available speeds via reading from file
*
* @return < 0 on error
*/
int initFreqsViaFile();
/** @brief inits the available speeds via testing
*
* @return < 0 on error
*/
int initFreqsViaTesting();
void setConfig();
/** @brief speed file to get or set current speed */
string CURRENT_SPEED_FILE;
/** @brief array containing available speeds */
unsigned _speeds_kHz[MAX_SPEEDS + 1];
/** @brief demotion */
unsigned _demotion[MAX_SPEEDS + 1];
/** @brief the current set speed */
unsigned _current_speed;
/** @brief the new speed requested to set */
unsigned _new_speed;
/** @brief the last step set */
unsigned _last_step;
/** @brief set last cpu load */
int _last_cpu_load;
/** @brief name of userspace governor to write to governor file */
string USERSPACE_STRING;
};
/** @brief Class to control one CPU's frequency by a kernel governor */
class CPUFreq_Kernel:public CPUFreq_Interface {
public:
/** @brief constructor
*
* @param cpu_list stl list containing all cores the object has to
* care about
* @param sampling_rate the sampling rate to use
*/
CPUFreq_Kernel(std::list< int > cpu_list, unsigned long sampling_rate = 333000);
/** @brief destructor */
~CPUFreq_Kernel();
/** @brief init cpufreq interface and set kernel governor
*
* @return true on success, false otherwise
*/
bool init();
private:
bool readFrequencies();
int adjustSpeed();
void reinitSpeed();
void setConfig();
/** @brief sets the ondemand governor configuration */
void setOndemandConfig();
/** @brief write a value to an ondemand file
*
* write value to a file in /sys/.../cpufreq/ondemand/
*
* @param name the name of the file to write to
* @param value the value to write
*
* @return 0 on success
* @retval -1 if file does not exist
* @retval 1 if writing failed
* @retval 0 on success
*/
int writeOndemand(const string &name, int value);
/** @brief read a value from an ondemand file
*
* read value from a file in /sys/.../cpufreq/ondemand/
*
* @param name the name of the file to read
*
* @return read value
* @retval 0 if reading failed
*/
unsigned int readOndemand(const string &name);
/** @brief the sampling rate to use */
unsigned long _sampling_rate;
/** @brief down threshold */
int _down_threshold;
/** @brief _sampling down factor */
int _sampling_down_factor;
/** @brief name of ondemand governor to write to governor file */
string ON_DEMAND_STRING;
/** @brief name of powersave governor to write to governor file */
string POWERSAVE_STRING;
/** @brief name of performance governor to write to governor file */
string PERFORMANCE_STRING;
};
#endif /* POWERSAVE_CPUFREQ_H */
|