diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 20:00:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 20:00:20 +0000 |
commit | fcb4cb5c3d0fec0fede160d565134d553d783fb2 (patch) | |
tree | 7be42535554ca6badc1847d83ef123f4dc3c5506 /src/parameters/learn.cpp | |
parent | Initial commit. (diff) | |
download | powertop-fcb4cb5c3d0fec0fede160d565134d553d783fb2.tar.xz powertop-fcb4cb5c3d0fec0fede160d565134d553d783fb2.zip |
Adding upstream version 2.15.upstream/2.15upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/parameters/learn.cpp')
-rw-r--r-- | src/parameters/learn.cpp | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/src/parameters/learn.cpp b/src/parameters/learn.cpp new file mode 100644 index 0000000..aaef5a2 --- /dev/null +++ b/src/parameters/learn.cpp @@ -0,0 +1,282 @@ +/* + * Copyright 2010, Intel Corporation + * + * This file is part of PowerTOP + * + * This program file 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; version 2 of the License. + * + * 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 in a file named COPYING; if not, write to the + * Free Software Foundation, Inc, + * 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * or just google for it. + * + * Authors: + * Arjan van de Ven <arjan@linux.intel.com> + */ +#include "parameters.h" +#include "../measurement/measurement.h" + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> + +extern int debug_learning; + +double calculate_params(struct parameter_bundle *params) +{ + unsigned int i; + + params->score = 0; + + + for (i = 0; i < past_results.size(); i++) + compute_bundle(params, past_results[i]); + + return params->score; +} + + +/* + * gradual linear convergence of non-independent variables works better if once in a while + * you make a wrong move.... + */ +static int random_disturb(int retry_left) +{ + if (retry_left < 10) + return 0; + + if ( (rand() % 500) == 7) + return 1; + return 0; +} + +static int try_zero(double value) +{ + if (value > 0.01) + if ( (rand() % 100) == 1) + return 1; + + if ( (rand() % 5) == 1) + return 1; + return 0; +} + +static unsigned int previous_measurements; + +static void weed_empties(struct parameter_bundle *best_so_far) +{ + double best_score; + unsigned int i; + + best_score = best_so_far->score; + + + for (i = 0; i < best_so_far->parameters.size(); i++) { + double orgvalue; + + orgvalue = best_so_far->parameters[i]; + + + best_so_far->parameters[i] = 0.0; + + calculate_params(best_so_far); + if (best_so_far->score > best_score) { + best_so_far->parameters[i] = orgvalue; + } else { + best_score = best_so_far->score; + } + + } + calculate_params(best_so_far); + +} + +/* leaks like a sieve */ +void learn_parameters(int iterations, int do_base_power) +{ + struct parameter_bundle *best_so_far; + double best_score = 10000000000000000.0; + int retry = iterations; + int prevparam = -1; + int locked = 0; + static unsigned int bpi = 0; + unsigned int i; + time_t start; + + /* don't start fitting anything until we have at least 1 more measurement than we have parameters */ + if (past_results.size() <= all_parameters.parameters.size()) + return; + + + +// if (past_results.size() == previous_measurements) +// return; + + precompute_valid(); + + + previous_measurements = past_results.size(); + + double delta = 0.50; + + best_so_far = &all_parameters; + + if (!bpi) + bpi = get_param_index("base power"); + + calculate_params(best_so_far); + best_score = best_so_far->score; + + delta = 0.001 / pow(0.8, iterations / 2.0); + if (iterations < 25) + delta = 0.001 / pow(0.5, iterations / 2.0); + + if (delta > 0.2) + delta = 0.2; + + if (1.0 * best_score / past_results.size() < 4 && delta > 0.05) + delta = 0.05; + + if (debug_learning) + printf("Delta starts at %5.3f\n", delta); + + if (best_so_far->parameters[bpi] > min_power * 0.9) + best_so_far->parameters[bpi] = min_power * 0.9; + + /* We want to give up a little of base power, to give other parameters room to change; + base power is the end post for everything after all + */ + if (do_base_power && !debug_learning) + best_so_far->parameters[bpi] = best_so_far->parameters[bpi] * 0.9998; + + start = time(NULL); + + while (retry--) { + int changed = 0; + int bestparam; + double newvalue = 0; + double orgscore; + double weight; + + bestparam = -1; + + if (time(NULL) - start > 1 && !debug_learning) + retry = 0; + + calculate_params(best_so_far); + orgscore = best_score = best_so_far->score; + + + for (i = 1; i < best_so_far->parameters.size(); i++) { + double value, orgvalue; + + weight = delta * best_so_far->weights[i]; + + orgvalue = value = best_so_far->parameters[i]; + if (value <= 0.001) { + value = 0.1; + } else + value = value * (1 + weight); + + if (i == bpi && value > min_power) + value = min_power; + + if (i == bpi && orgvalue > min_power) + orgvalue = min_power; + + if (value > 5000) + value = 5000; + +// printf("Trying %s %4.2f -> %4.2f\n", param.c_str(), best_so_far->parameters[param], value); + best_so_far->parameters[i] = value; + + calculate_params(best_so_far); + if (best_so_far->score < best_score || random_disturb(retry)) { + best_score = best_so_far->score; + newvalue = value; + bestparam = i; + changed++; + } + + value = orgvalue * 1 / (1 + weight); + + if (value < 0.0001) + value = 0.0; + + if (try_zero(value)) + value = 0.0; + + + if (value > 5000) + value = 5000; + + +// printf("Trying %s %4.2f -> %4.2f\n", param.c_str(), orgvalue, value); + + if (orgvalue != value) { + best_so_far->parameters[i] = value; + + calculate_params(best_so_far); + + if (best_so_far->score + 0.00001 < best_score || (random_disturb(retry) && value > 0.0)) { + best_score = best_so_far->score; + newvalue = value; + bestparam = i; + changed++; + } + } + best_so_far->parameters[i] = orgvalue; + + } + if (!changed) { + double mult; + + if (!locked) { + mult = 0.8; + if (iterations < 25) + mult = 0.5; + delta = delta * mult; + } + locked = 0; + prevparam = -1; + } else { + if (debug_learning) { + printf("Retry is %i \n", retry); + printf("delta is %5.4f\n", delta); + printf("Best parameter is %i \n", bestparam); + printf("Changing score from %4.3f to %4.3f\n", orgscore, best_score); + printf("Changing value from %4.3f to %4.3f\n", best_so_far->parameters[bestparam], newvalue); + } + best_so_far->parameters[bestparam] = newvalue; + if (prevparam == bestparam) + delta = delta * 1.1; + prevparam = bestparam; + locked = 1; + } + + if (delta < 0.001 && !locked) + break; + + if (retry % 50 == 49) + weed_empties(best_so_far); + } + + + /* now we weed out all parameters that don't have value */ + if (iterations > 50) + weed_empties(best_so_far); + + if (debug_learning) + printf("Final score %4.2f (%i points)\n", best_so_far->score / past_results.size(), (int)past_results.size()); +// dump_parameter_bundle(best_so_far); +// dump_past_results(); +} |