Imported Upstream version 2.5
[platform/upstream/powertop.git] / src / parameters / parameters.cpp
1 /*
2  * Copyright 2010, Intel Corporation
3  *
4  * This file is part of PowerTOP
5  *
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.
9  *
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
13  * for more details.
14  *
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.
21  *
22  * Authors:
23  *      Arjan van de Ven <arjan@linux.intel.com>
24  */
25 #include "parameters.h"
26 #include "../measurement/measurement.h"
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <math.h>
31 #include <vector>
32 #include <unistd.h>
33
34
35 struct parameter_bundle all_parameters;
36 struct result_bundle all_results;
37
38 vector <struct result_bundle *> past_results;
39
40 map <string, int> param_index;
41 static int maxindex = 1;
42 map <string, int> result_index;
43 static int maxresindex = 1;
44
45 int get_param_index(const char *name)
46 {
47         std::map<string, int>::iterator it;
48         int index = 0;
49
50         it = param_index.find(name);
51         if (it == param_index.end()) {
52                 param_index[name] = ++maxindex;
53                 index = maxindex;
54         } else
55                 index = it->second;
56
57         if (index == 0)
58                 printf("OH BLA\n");
59         return index;
60 }
61
62 int get_result_index(const char *name)
63 {
64         std::map<string, int>::iterator it;
65         int index = 0;
66
67         it = result_index.find(name);
68         if (it == result_index.end()) {
69                 result_index[name] = ++maxresindex;
70                 index = maxresindex;
71         } else
72                 index = it->second;
73
74         return index;
75 }
76
77
78 void register_parameter(const char *name, double default_value, double weight)
79 {
80         int index;
81
82         index = get_param_index(name);
83
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);
87         }
88
89         if (all_parameters.parameters[index] <= 0.0001)
90                 all_parameters.parameters[index] = default_value;
91
92         all_parameters.weights[index] = weight;
93 }
94
95 void set_parameter_value(const char *name, double value, struct parameter_bundle *bundle)
96 {
97         int index;
98
99         index = get_param_index(name);
100
101         if (index >= (int)bundle->parameters.size()) {
102                 bundle->parameters.resize(index+1, 0.0);
103                 bundle->weights.resize(index+1, 1.0);
104         }
105
106         bundle->parameters[index] = value;
107 }
108
109 double get_parameter_value(const char *name, struct parameter_bundle *the_bundle)
110 {
111         unsigned int index;
112         index = get_param_index(name);
113         return get_parameter_value(index, the_bundle);
114 }
115
116 double get_parameter_value(unsigned int index, struct parameter_bundle *the_bundle)
117 {
118         if (index >= the_bundle->parameters.size()) {
119                 fprintf(stderr, "BUG: requesting unregistered parameter %d\n", index);
120                 return 0;
121         }
122         return the_bundle->parameters[index];
123 }
124
125 double get_parameter_weight(int index, struct parameter_bundle *the_bundle)
126 {
127         return the_bundle->weights[index];
128 }
129
130 double get_result_value(const char *name, struct result_bundle *the_bundle)
131 {
132         return get_result_value(get_result_index(name), the_bundle);
133 }
134
135 void set_result_value(const char *name, double value, struct result_bundle *the_bundle)
136 {
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;
141 }
142
143 void set_result_value(unsigned int index, double value, struct result_bundle *the_bundle)
144 {
145         if (index >= the_bundle->utilization.size())
146                 the_bundle->utilization.resize(index+1);
147         the_bundle->utilization[index] = value;
148 }
149
150 double get_result_value(int index, struct result_bundle *the_bundle)
151 {
152         if (!the_bundle)
153                 return 0;
154         if (index >= (int) the_bundle->utilization.size())
155                 return 0;
156         return the_bundle->utilization[index];
157 }
158
159
160 int result_device_exists(const char *name)
161 {
162         unsigned int i;
163         for (i = 0; i < all_devices.size(); i++) {
164                 if (strcmp(all_devices[i]->device_name(), name) == 0)
165                         return 1;
166         }
167         return 0;
168 }
169
170 void report_utilization(const char *name, double value, struct result_bundle *bundle)
171 {
172         set_result_value(name, value, bundle);
173 }
174 void report_utilization(int index, double value, struct result_bundle *bundle)
175 {
176         set_result_value(index, value, bundle);
177 }
178
179
180
181 double compute_bundle(struct parameter_bundle *parameters, struct result_bundle *results)
182 {
183         double power = 0;
184         unsigned int i;
185
186         static int bpi = 0;
187
188         if (!bpi)
189                 bpi = get_param_index("base power");
190
191         for (i = 0; i < all_devices.size(); i++)
192                 power += all_devices[i]->power_usage(results, parameters);
193
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;
199         return power;
200 }
201
202 static int precomputed_valid = 0;
203 void precompute_valid(void)
204 {
205         unsigned int i;
206
207
208         for (i = 0; i < all_devices.size(); i++) {
209                 all_devices[i]->cached_valid = all_devices[i]->power_valid();
210         }
211         precomputed_valid = 1;
212 }
213
214 double bundle_power(struct parameter_bundle *parameters, struct result_bundle *results)
215 {
216         double power = 0;
217         unsigned int i;
218         static int bpi = 0;
219
220         if (!bpi)
221                 bpi = get_param_index("base power");
222
223         if (!precomputed_valid)
224                 precompute_valid();
225
226
227         power = parameters->parameters[bpi];
228
229         for (i = 0; i < all_devices.size(); i++) {
230
231                 if (all_devices[i]->cached_valid)
232                         power += all_devices[i]->power_usage(results, parameters);
233         }
234
235         return power;
236 }
237
238
239 void dump_parameter_bundle(struct parameter_bundle *para)
240 {
241         map<string, int>::iterator it;
242         int index;
243
244         printf("\n\n");
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++) {
249                 index = it->second;
250                 printf("%5.2f\t\t%s (%i)\n", para->parameters[index], it->first.c_str(), index);
251         }
252
253         printf("\n");
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);
257
258         printf("----------------------------------\n");
259 }
260
261 void dump_result_bundle(struct result_bundle *res)
262 {
263         map<string, int>::iterator it;
264         unsigned int index;
265
266         printf("\n\n");
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);
273         }
274
275         printf("\n");
276         printf("Power: %5.1f\n", res->power);
277
278         printf("----------------------------------\n");
279 }
280
281 struct result_bundle * clone_results(struct result_bundle *bundle)
282 {
283         struct result_bundle *b2;
284         map<string, double>::iterator it;
285         unsigned int i;
286
287         b2 = new struct result_bundle;
288
289         if (!b2)
290                 return NULL;
291
292         b2->power = bundle->power;
293         b2->utilization.resize(bundle->utilization.size());
294
295         for (i = 0; i < bundle->utilization.size(); i++) {
296                 b2->utilization[i] = bundle->utilization[i];
297         }
298
299         return b2;
300 }
301
302
303 struct parameter_bundle * clone_parameters(struct parameter_bundle *bundle)
304 {
305         struct parameter_bundle *b2;
306         unsigned int i;
307
308         b2 = new struct parameter_bundle;
309
310         if (!b2)
311                 return NULL;
312
313         b2->score = 0;
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];
319         }
320
321         return b2;
322 }
323
324
325 void store_results(double duration)
326 {
327         if (duration < 5)
328                 return;
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);
336                 } else {
337                         past_results.push_back(clone_results(&all_results));
338                 }
339                 if ((past_results.size() % 10) == 0)
340                         save_all_results("saved_results.powertop");
341         }
342
343 }
344
345
346
347 void dump_past_results(void)
348 {
349         unsigned int j;
350         unsigned int i;
351         struct result_bundle *result;
352
353         for (j = 0; j < past_results.size(); j+=10) {
354                 printf("Est    ");
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));
358                 }
359                 printf("\n");
360                 printf("Actual ");
361                 for (i = j; i < past_results.size() && i < j + 10; i++) {
362                         result = past_results[i];
363                         printf("%6.2f  ", result->power);
364                 }
365                 printf("\n\n");
366         }
367 }
368
369 double average_power(void)
370 {
371         double sum = 0.0;
372         unsigned int i;
373         for (i = 0; i < past_results.size(); i++)
374                 sum += past_results[i]->power;
375
376         if (past_results.size())
377                 sum = sum / past_results.size() + 0.0001;
378         else
379                 sum = 0.0001;
380         return sum;
381 }
382
383 int utilization_power_valid(const char *u)
384 {
385         unsigned int i;
386         unsigned int index;
387         double first_value;
388
389         index = get_result_index(u);
390         if (index <= 0)
391                 return 0;
392
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)
396                         return 1;
397                 if (get_result_value(index, past_results[i]) > first_value + 0.0001)
398                         return 1;
399         }
400
401         return 0;
402 }
403
404 int utilization_power_valid(int index)
405 {
406         unsigned int i;
407         double first_value;
408
409         if (index <= 0)
410                 return 0;
411
412         if (past_results.size() == 0)
413                 return 0;
414
415         if (index >= (int)past_results[0]->utilization.size())
416                 return 0;
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)
420                         return 1;
421                 if (get_result_value(index, past_results[i]) > first_value + 0.0001)
422                         return 1;
423         }
424
425         return 0;
426 }
427
428
429 /* force power data to be valid to the rest of the system  */
430 int global_power_override = 0;
431
432 /*
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
435  */
436 int global_power_valid(void)
437 {
438         if (past_results.size() > 3 * all_parameters.parameters.size())
439                 return 1;
440
441
442         return global_power_override;
443 }
444
445 /* find the directory to store powertop results/parameters based on distribution*/
446 char* get_param_directory(const char *filename)
447 {
448         static char tempfilename[4096];
449
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);
454
455         return tempfilename;
456 };