2 * Copyright 2010, Intel Corporation
4 * This file is part of PowerTOP
6 * This program file is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * You should have received a copy of the GNU General Public License
16 * along with this program in a file named COPYING; if not, write to the
17 * Free Software Foundation, Inc,
18 * 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
20 * or just google for it.
23 * Arjan van de Ven <arjan@linux.intel.com>
25 #include "parameters.h"
26 #include "../measurement/measurement.h"
35 struct parameter_bundle all_parameters;
36 struct result_bundle all_results;
38 vector <struct result_bundle *> past_results;
40 map <string, int> param_index;
41 static int maxindex = 1;
42 map <string, int> result_index;
43 static int maxresindex = 1;
45 int get_param_index(const char *name)
47 std::map<string, int>::iterator it;
50 it = param_index.find(name);
51 if (it == param_index.end()) {
52 param_index[name] = ++maxindex;
62 int get_result_index(const char *name)
64 std::map<string, int>::iterator it;
67 it = result_index.find(name);
68 if (it == result_index.end()) {
69 result_index[name] = ++maxresindex;
78 void register_parameter(const char *name, double default_value, double weight)
82 index = get_param_index(name);
84 if (index >= (int)all_parameters.parameters.size()) {
85 all_parameters.parameters.resize(index+1, 0.0);
86 all_parameters.weights.resize(index+1, 1.0);
89 if (all_parameters.parameters[index] <= 0.0001)
90 all_parameters.parameters[index] = default_value;
92 all_parameters.weights[index] = weight;
95 void set_parameter_value(const char *name, double value, struct parameter_bundle *bundle)
99 index = get_param_index(name);
101 if (index >= (int)bundle->parameters.size()) {
102 bundle->parameters.resize(index+1, 0.0);
103 bundle->weights.resize(index+1, 1.0);
106 bundle->parameters[index] = value;
109 double get_parameter_value(const char *name, struct parameter_bundle *the_bundle)
112 index = get_param_index(name);
113 return get_parameter_value(index, the_bundle);
116 double get_parameter_value(unsigned int index, struct parameter_bundle *the_bundle)
118 if (index >= the_bundle->parameters.size()) {
119 fprintf(stderr, "BUG: requesting unregistered parameter %d\n", index);
122 return the_bundle->parameters[index];
125 double get_parameter_weight(int index, struct parameter_bundle *the_bundle)
127 return the_bundle->weights[index];
130 double get_result_value(const char *name, struct result_bundle *the_bundle)
132 return get_result_value(get_result_index(name), the_bundle);
135 void set_result_value(const char *name, double value, struct result_bundle *the_bundle)
137 unsigned int index = get_result_index(name);
138 if (index >= the_bundle->utilization.size())
139 the_bundle->utilization.resize(index+1);
140 the_bundle->utilization[index] = value;
143 void set_result_value(unsigned int index, double value, struct result_bundle *the_bundle)
145 if (index >= the_bundle->utilization.size())
146 the_bundle->utilization.resize(index+1);
147 the_bundle->utilization[index] = value;
150 double get_result_value(int index, struct result_bundle *the_bundle)
154 if (index >= (int) the_bundle->utilization.size())
156 return the_bundle->utilization[index];
160 int result_device_exists(const char *name)
163 for (i = 0; i < all_devices.size(); i++) {
164 if (strcmp(all_devices[i]->device_name(), name) == 0)
170 void report_utilization(const char *name, double value, struct result_bundle *bundle)
172 set_result_value(name, value, bundle);
174 void report_utilization(int index, double value, struct result_bundle *bundle)
176 set_result_value(index, value, bundle);
181 double compute_bundle(struct parameter_bundle *parameters, struct result_bundle *results)
189 bpi = get_param_index("base power");
191 for (i = 0; i < all_devices.size(); i++)
192 power += all_devices[i]->power_usage(results, parameters);
194 parameters->actual_power = results->power;
195 parameters->guessed_power = power;
196 /* scale the squared error by the actual power so that non-idle data points weigh heavier */
197 parameters->score += results->power * (power - results->power) * (power - results->power);
198 parameters->parameters[bpi] = power;
202 static int precomputed_valid = 0;
203 void precompute_valid(void)
208 for (i = 0; i < all_devices.size(); i++) {
209 all_devices[i]->cached_valid = all_devices[i]->power_valid();
211 precomputed_valid = 1;
214 double bundle_power(struct parameter_bundle *parameters, struct result_bundle *results)
221 bpi = get_param_index("base power");
223 if (!precomputed_valid)
227 power = parameters->parameters[bpi];
229 for (i = 0; i < all_devices.size(); i++) {
231 if (all_devices[i]->cached_valid)
232 power += all_devices[i]->power_usage(results, parameters);
239 void dump_parameter_bundle(struct parameter_bundle *para)
241 map<string, int>::iterator it;
245 printf("Parameter state \n");
246 printf("----------------------------------\n");
247 printf("Value\t\tName\n");
248 for (it = param_index.begin(); it != param_index.end(); it++) {
250 printf("%5.2f\t\t%s (%i)\n", para->parameters[index], it->first.c_str(), index);
254 printf("Score: %5.1f (%5.1f)\n", sqrt(para->score / (0.001 + past_results.size()) / average_power()), para->score);
255 printf("Guess: %5.1f\n", para->guessed_power);
256 printf("Actual: %5.1f\n", para->actual_power);
258 printf("----------------------------------\n");
261 void dump_result_bundle(struct result_bundle *res)
263 map<string, int>::iterator it;
267 printf("Utilisation state \n");
268 printf("----------------------------------\n");
269 printf("Value\t\tName\n");
270 for (it = result_index.begin(); it != result_index.end(); it++) {
271 index = get_result_index(it->first.c_str());
272 printf("%5.2f%%\t\t%s(%i)\n", res->utilization[index], it->first.c_str(), index);
276 printf("Power: %5.1f\n", res->power);
278 printf("----------------------------------\n");
281 struct result_bundle * clone_results(struct result_bundle *bundle)
283 struct result_bundle *b2;
284 map<string, double>::iterator it;
287 b2 = new struct result_bundle;
292 b2->power = bundle->power;
293 b2->utilization.resize(bundle->utilization.size());
295 for (i = 0; i < bundle->utilization.size(); i++) {
296 b2->utilization[i] = bundle->utilization[i];
303 struct parameter_bundle * clone_parameters(struct parameter_bundle *bundle)
305 struct parameter_bundle *b2;
308 b2 = new struct parameter_bundle;
314 b2->guessed_power = 0;
315 b2->actual_power = bundle->actual_power;
316 b2->parameters.resize(bundle->parameters.size());
317 for (i = 0; i < bundle->parameters.size(); i++) {
318 b2->parameters[i] = bundle->parameters[i];
325 void store_results(double duration)
329 global_joules_consumed();
330 if (all_results.power > 0.01) {
331 unsigned int overflow_index;
332 overflow_index = 50 + (rand() % MAX_KEEP);
333 if (past_results.size() >= MAX_PARAM) {
334 /* memory leak, must free old one first */
335 past_results[overflow_index] = clone_results(&all_results);
337 past_results.push_back(clone_results(&all_results));
339 if ((past_results.size() % 10) == 0)
340 save_all_results("saved_results.powertop");
347 void dump_past_results(void)
351 struct result_bundle *result;
353 for (j = 0; j < past_results.size(); j+=10) {
355 for (i = j; i < past_results.size() && i < j + 10; i++) {
356 result = past_results[i];
357 printf("%6.2f ", bundle_power(&all_parameters, result));
361 for (i = j; i < past_results.size() && i < j + 10; i++) {
362 result = past_results[i];
363 printf("%6.2f ", result->power);
369 double average_power(void)
373 for (i = 0; i < past_results.size(); i++)
374 sum += past_results[i]->power;
376 if (past_results.size())
377 sum = sum / past_results.size() + 0.0001;
383 int utilization_power_valid(const char *u)
389 index = get_result_index(u);
393 first_value = past_results[0]->utilization[index];
394 for (i = 1; i < past_results.size(); i++) {
395 if (get_result_value(index, past_results[i]) < first_value - 0.0001)
397 if (get_result_value(index, past_results[i]) > first_value + 0.0001)
404 int utilization_power_valid(int index)
412 if (past_results.size() == 0)
415 if (index >= (int)past_results[0]->utilization.size())
417 first_value = past_results[0]->utilization[index];
418 for (i = 1; i < past_results.size(); i++) {
419 if (get_result_value(index, past_results[i]) < first_value - 0.0001)
421 if (get_result_value(index, past_results[i]) > first_value + 0.0001)
429 /* force power data to be valid to the rest of the system */
430 int global_power_override = 0;
433 * only report power numbers once we have 3* more measurements than
434 * we have parameters; anything less and our model fit is highly suspect
436 int global_power_valid(void)
438 if (past_results.size() > 3 * all_parameters.parameters.size())
442 return global_power_override;
445 /* find the directory to store powertop results/parameters based on distribution*/
446 char* get_param_directory(const char *filename)
448 static char tempfilename[4096];
450 if (access("/var/cache/powertop", W_OK ) == 0)
451 sprintf(tempfilename, "/var/cache/powertop/%s", filename);
452 if (access("/data/local/powertop", W_OK ) == 0)
453 sprintf(tempfilename, "/data/local/powertop/%s", filename);