PASS uses 'CPUHP' indicating 'CPU Hotplug Manager' module.
'governor' is too abstract and old expression. Replace 'governor'
with 'cpuhp' expression in order to improve the readability.
Change-Id: Ib7c6509e200cd7603739bace6bcf913bea22475b
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
SET(SRCS
src/pass/pass.c
- src/pass/pass-gov.c
- src/pass/pass-gov-radiation.c
- src/pass/pass-gov-step.c
+ src/pass/pass-cpuhp.c
+ src/pass/pass-cpuhp-radiation.c
+ src/pass/pass-cpuhp-step.c
src/pass/pass-parser.c
src/pass/pass-hal.c
src/pass/pass-rescon.c
--- /dev/null
+/*
+ * PASS (Power Aware Systerm Service) Radiation governor
+ *
+ * Copyright (c) 2012 - 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "pass.h"
+
+/*
+ * pass_cpuhp_radiation_governor - Check cpu state and determine the amount of resource
+ *
+ * @stats: structure for getting cpu frequency state from kerncel
+ *
+ * This function check periodically current following state of system
+ * and then determine whether pass level up or down according to pass
+ * policy with gathered data.
+ * - current cpu frequency
+ * - the number of nr_running
+ * - the number of busy_cpu
+ */
+int pass_cpuhp_radiation_governor(struct pass_resource *res)
+{
+ struct pass_level *levels = res->config_data.levels;
+ struct pass_cpuhp *cpuhp = &res->cpuhp;
+ struct pass_cpu_stats *cpu_stats = cpuhp->pass_cpu_stats;
+ int up_threshold = cpuhp->up_threshold;
+ int down_threshold = cpuhp->down_threshold;
+ int num_pass_gov = 0;
+ int level = res->rescon.curr_level;
+ int up_count = 0;
+ int down_count = 0;
+ int left_count = 0;
+ int right_count = 0;
+ bool up_condition;
+ bool down_condition;
+ bool left_condition;
+ bool right_condition;
+ int freq;
+ int nr_running;
+ int busy_cpu;
+ int i;
+ int j;
+ int64_t time;
+
+ for (i = 0; i < cpuhp->num_pass_cpu_stats; i++) {
+ time = cpu_stats[i].time;
+ freq = cpu_stats[i].freq;
+ nr_running = cpu_stats[i].nr_runnings;
+ busy_cpu = cpu_stats[i].num_busy_cpu;
+ up_condition = true;
+ down_condition = true;
+ left_condition = true;
+ right_condition = true;
+
+ if (cpuhp->last_time >= time)
+ continue;
+ cpuhp->last_time = time;
+ num_pass_gov++;
+
+ /*
+ _I("[Level%d][%d][%lld] %d | %d | %d", level, i, time, freq,
+ nr_running, busy_cpu);
+ */
+
+ /* Check level up condition */
+ for (j = 0; j < levels[level].num_up_cond && up_condition; j++) {
+ if (levels[level].up_cond[j].freq &&
+ !(freq >= levels[level].up_cond[j].freq))
+ up_condition = false;
+ }
+
+ if (levels[level].num_up_cond && up_condition) {
+ up_count++;
+
+ /*
+ _I("[Level%d] [up_count : %2d] \
+ freq(%d), nr_running(%d), busy_cpu(%d)",
+ level, up_count,
+ levels[level].up_cond[j].freq ? freq : -1,
+ */
+ }
+
+ /* Check level down condition */
+ for (j = 0; j < levels[level].num_down_cond && down_condition; j++) {
+ if (levels[level].down_cond[j].freq
+ && !(freq <= levels[level].down_cond[j].freq))
+ down_condition = false;
+ }
+
+ if (levels[level].num_down_cond && down_condition) {
+ down_count++;
+
+ /*
+ _I("[Level%d] [dw_count : %2d] \
+ freq(%d), nr_running(%d), busy_cpu(%d)",
+ level, down_count,
+ levels[level].down_cond[j].freq ? freq : -1,
+ */
+ }
+
+ /* Check level right condition */
+ for (j = 0; j < levels[level].num_right_cond && right_condition; j++) {
+ /*
+ * If one more conditions are false among following
+ * conditions, don't increment right_count.
+ */
+ if (levels[level].right_cond[j].nr_running
+ && !(nr_running > levels[level].right_cond[j].nr_running))
+ right_condition = false;
+
+ if (levels[level].right_cond[j].busy_cpu
+ && !(busy_cpu >= levels[level].right_cond[j].busy_cpu))
+ right_condition = false;
+ }
+
+ if (levels[level].num_right_cond && right_condition) {
+ right_count++;
+
+ /*
+ _I("[Level%d] [right_count : %2d] \
+ nr_running(%d), busy_cpu(%d)",
+ level, right_count,
+ levels[level].right_cond[j].nr_running ? nr_running : -1,
+ levels[level].right_cond[j].busy_cpu ? busy_cpu : -1);
+ */
+ }
+
+ /* Check level left condition */
+ for (j = 0; j < levels[level].num_left_cond && left_condition; j++) {
+ /*
+ * If one more conditions are false among following
+ * conditions, don't increment left_count.
+ */
+ if (levels[level].left_cond[j].nr_running
+ && !(nr_running <= levels[level].left_cond[j].nr_running))
+ left_condition = false;
+
+ if (levels[level].left_cond[j].busy_cpu
+ && !(busy_cpu < levels[level].left_cond[j].busy_cpu))
+ left_condition = false;
+ }
+
+ if (levels[level].num_left_cond && left_condition) {
+ left_count++;
+
+ /*
+ _I("[Level%d] [ left_count : %2d] \
+ nr_running(%d), busy_cpu(%d)",
+ level, left_count,
+ levels[level].left_cond[j].nr_running ? nr_running : -1,
+ levels[level].left_cond[j].busy_cpu ? busy_cpu : -1);
+ */
+ }
+ }
+
+ if (!num_pass_gov)
+ return level;
+
+ if (up_count * 100 >= num_pass_gov * up_threshold) {
+ level += cpuhp->hotplug->num_cpus;
+
+ if (level > res->rescon.max_level)
+ level -= cpuhp->hotplug->num_cpus;
+ } else if (down_count * 100 >= num_pass_gov * down_threshold) {
+ level -= cpuhp->hotplug->num_cpus;
+ }
+
+ if (right_count * 100 >= num_pass_gov * up_threshold) {
+ level += 1;
+
+ if (level > res->rescon.max_level)
+ level -= 1;
+ } else if (left_count * 100 >= num_pass_gov * down_threshold) {
+ level -= 1;
+ }
+
+ /*
+ if (level == res->prev_level) {
+ for (i = num_pass_gov; i < cpuhp->num_pass_cpu_stats; i++) {
+ time = cpu_stats[i].time;
+ freq = cpu_stats[i].freq;
+ nr_running = cpu_stats[i].nr_runnings;
+ busy_cpu = cpu_stats[i].num_busy_cpu;
+
+ _I("[Level%d][%d][%lld] %d | %d | %d",
+ level, i, time, freq,
+ nr_running, busy_cpu);
+ }
+ }
+
+ if (level != res->rescon.curr_level) {
+ _I("\n[Level%d] num_pass_gov: [%2d]", level, num_pass_gov);
+ _I("[Level%d] down_count : %2d (%3d >= %3d)", level, down_count,
+ down_count * 100, num_pass_gov * down_threshold);
+ _I("[Level%d] up_count : %2d (%3d >= %3d)", level, up_count,
+ up_count * 100, num_pass_gov * up_threshold);
+ _I("[Level%d] left_count : %2d (%3d >= %3d)", level, left_count,
+ left_count * 100, num_pass_gov * down_threshold);
+ _I("[Level%d] right_count : %2d (%3d >= %3d)", level, right_count,
+ right_count * 100, num_pass_gov * up_threshold);
+ }
+ */
+
+ return level;
+}
--- /dev/null
+/*
+ * PASS (Power Aware System Service) Step governor
+ *
+ * Copyright (c) 2012 - 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "pass.h"
+
+/*
+ * pass_cpuhp_step_governor - Check cpu state and determine the amount of resource
+ *
+ * @stats: structure for getting cpu frequency state from kerncel
+ *
+ * This function check periodically current following state of system
+ * and then determine whether pass level up or down according to pass
+ * policy with gathered data.
+ * - current cpu frequency
+ * - the number of nr_running
+ * - the number of busy_cpu
+ */
+int pass_cpuhp_step_governor(struct pass_resource *res)
+{
+ struct pass_level *levels = res->config_data.levels;
+ struct pass_cpuhp *cpuhp = &res->cpuhp;
+ struct pass_cpu_stats *cpu_stats = cpuhp->pass_cpu_stats;
+ int up_threshold = cpuhp->up_threshold;
+ int down_threshold = cpuhp->down_threshold;
+ int num_pass_gov = 0;
+ int level = res->rescon.curr_level;
+ int up_count = 0;
+ int up_max_count = 0;
+ int down_count = 0;
+ bool up_condition;
+ bool down_condition;
+ int freq;
+ int nr_running;
+ int busy_cpu;
+ int i;
+ int j;
+ int64_t time;
+
+ for (i = 0; i < cpuhp->num_pass_cpu_stats; i++) {
+ time = cpu_stats[i].time;
+ freq = cpu_stats[i].freq;
+ nr_running = cpu_stats[i].nr_runnings;
+ busy_cpu = cpu_stats[i].num_busy_cpu;
+ up_condition = false;
+ down_condition = false;
+
+ if (cpuhp->last_time >= time)
+ continue;
+ cpuhp->last_time = time;
+ num_pass_gov++;
+
+ /* Check level up condition */
+ for (j = 0; j < levels[level].num_up_cond; j++) {
+ /*
+ * If one more conditions are false among following
+ * conditions, don't increment up_count.
+ */
+ if (freq >= levels[level].up_cond[j].freq
+ && nr_running >= levels[level].up_cond[j].nr_running
+ && busy_cpu >= levels[level].up_cond[j].busy_cpu)
+ up_condition = true;
+ }
+
+ if (levels[level].num_up_cond && up_condition) {
+ up_count++;
+
+ /*
+ _I("[Level%d] [up_count : %2d] \
+ freq(%d), nr_running(%d), busy_cpu(%d)",
+ level, up_count,
+ levels[level].up_cond[0].freq ? freq : -1,
+ levels[level].up_cond[0].nr_running ? nr_running : -1,
+ levels[level].up_cond[0].busy_cpu ? busy_cpu : -1);
+ */
+ }
+
+ /* Check level down condition */
+ for (j = 0; j < levels[level].num_down_cond; j++) {
+ /*
+ * If one more conditions are false among following
+ * conditions, don't increment down_count.
+ */
+ if (freq <= levels[level].down_cond[j].freq
+ && nr_running < levels[level].down_cond[j].nr_running
+ && busy_cpu < levels[level].down_cond[j].busy_cpu)
+ down_condition = true;
+ }
+
+ if (levels[level].num_down_cond && down_condition) {
+ down_count++;
+
+ /*
+ _I("[Level%d] [dw_count : %2d] \
+ freq(%d), nr_running(%d), busy_cpu(%d)",
+ level, down_count,
+ levels[level].down_cond[0].freq ? freq : -1,
+ levels[level].down_cond[0].nr_running ? nr_running : -1,
+ levels[level].down_cond[0].busy_cpu ? busy_cpu : -1);
+ */
+ }
+
+ if (level < res->rescon.max_level &&
+ freq == levels[level].limit_max_freq)
+ up_max_count++;
+ }
+
+ if (!num_pass_gov)
+ return level;
+
+ if (up_count && level < res->rescon.max_level &&
+ up_count * 100 >= num_pass_gov * up_threshold) {
+ level += 1;
+ } else if (down_count && level > res->rescon.min_level &&
+ down_count * 100 >= num_pass_gov * down_threshold) {
+ level -= 1;
+ }
+
+ return level;
+}
--- /dev/null
+/*
+ * PASS (Power Aware System Service) Governor
+ *
+ * Copyright (c) 2012 - 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include <pass/device-notifier.h>
+#include <pass/config-parser.h>
+
+#include "pass.h"
+#include "pass-hal.h"
+#include "pass-rescon.h"
+
+extern int pass_cpuhp_step_governor(struct pass_resource *res);
+extern int pass_cpuhp_radiation_governor(struct pass_resource *res);
+static int cpuhp_governor_update(struct pass_resource *, enum pass_state);
+
+#define PASS_DEFAULT_CPU_THRESHOLD 20
+#define PASS_DEFAULT_LEVEL_UP_THRESHOLD 30
+#define PASS_DEFAULT_LEVEL_DOWN_THRESHOLD 80
+#define PASS_CPU_STATS_MAX_COUNT 20
+
+struct pass_cpuhp_governor {
+ char name[BUFF_MAX];
+ enum pass_state state;
+
+ int (*init)(struct pass_resource *res);
+ int (*exit)(struct pass_resource *res);
+ int (*update)(struct pass_resource *res, enum pass_state state);
+ int (*governor)(struct pass_resource *res);
+};
+
+static bool is_enabled(struct pass_cpuhp *cpuhp)
+{
+ if (cpuhp->state != PASS_ON)
+ return false;
+
+ return true;
+}
+
+static void cpuhp_hotplug_stop(struct pass_resource *res)
+{
+ struct pass_level *levels = res->config_data.levels;
+ int level = res->rescon.max_level;
+
+ if (!res->cpuhp.hotplug || !levels)
+ return;
+
+ res->cpuhp.hotplug->online = levels[level].limit_min_cpu;
+}
+
+static int cpuhp_hotplug_dummy_governor(struct pass_resource *res)
+{
+ int level = res->rescon.curr_level;
+
+ return res->config_data.levels[level].limit_min_cpu;
+}
+
+static struct pass_hotplug* cpuhp_get_hotplug(struct pass_resource *res,
+ enum pass_gov_type type)
+{
+ struct pass_hotplug *hotplug;
+
+ switch (type) {
+ case PASS_GOV_DUMMY:
+ case PASS_GOV_BASIC:
+ /* Don't use Hotplug interface */
+ return NULL;
+ case PASS_GOV_HOTPLUG_ONLY:
+ case PASS_GOV_STEP:
+ case PASS_GOV_RADIATION:
+ /* Use Hotplug interface */
+ hotplug = calloc(1, sizeof(struct pass_hotplug));
+ if (!hotplug) {
+ _E("cannot allocate the memory of struct pass_hotplug");
+ return NULL;
+ }
+ hotplug->governor = cpuhp_hotplug_dummy_governor;
+ return hotplug;
+ default:
+ _E("Unknown hotplug type");
+ break;
+ };
+
+ return NULL;
+}
+
+static void cpuhp_calculate_busy_cpu(struct pass_resource *res)
+{
+ struct pass_cpuhp *cpuhp = &res->cpuhp;
+ struct pass_level *levels = res->config_data.levels;
+ struct pass_resource_config_data *config_data = &res->config_data;
+ struct pass_cpu_stats *stats = cpuhp->pass_cpu_stats;
+ unsigned int level = res->rescon.curr_level;
+ unsigned int cpu_threshold = 0;
+ unsigned int busy_cpu;
+ unsigned int cur_freq;
+ unsigned int load;
+ unsigned int sum_load;
+ unsigned int sum_runnable_load;
+ unsigned int nr_runnings;
+ int limit_min_cpu;
+ int i;
+ int j;
+
+ limit_min_cpu = levels[level].limit_min_cpu;
+
+ for (i = 0; i < cpuhp->num_pass_cpu_stats; i++) {
+ cur_freq = stats[i].freq;
+ nr_runnings = stats[i].nr_runnings;
+
+ stats[i].num_busy_cpu = 0;
+ stats[i].avg_load = 0;
+ stats[i].avg_runnable_load = 0;
+ stats[i].avg_thread_load = 0;
+ stats[i].avg_thread_runnable_load = 0;
+
+ busy_cpu = 0;
+ sum_load = 0;
+ sum_runnable_load = 0;
+
+ /* Calculate the number of busy cpu */
+ for (j = 0; j < config_data->num_cpus; j++) {
+ load = stats[i].load[j];
+ sum_load += stats[i].load[j];
+ sum_runnable_load += stats[i].runnable_load[j];
+ if (!load)
+ continue;
+
+ cpu_threshold =
+ (unsigned int)(cur_freq * load)
+ / cpuhp->freq.max_freq;
+ if (load == 100
+ || cpu_threshold >= cpuhp->pass_cpu_threshold)
+ busy_cpu++;
+ }
+
+ stats[i].num_busy_cpu = busy_cpu;
+ stats[i].avg_load = sum_load / limit_min_cpu;
+ stats[i].avg_runnable_load = sum_runnable_load / limit_min_cpu;
+ if (nr_runnings) {
+ stats[i].avg_thread_load
+ = (sum_load * 100) / nr_runnings;
+ stats[i].avg_thread_runnable_load
+ = (sum_runnable_load * 100) / nr_runnings;
+ }
+ }
+}
+
+static gboolean cpuhp_governor_timer_cb(gpointer data)
+{
+ struct pass_resource *res = (struct pass_resource *)data;
+ struct pass_level *levels = res->config_data.levels;
+ struct pass_cpuhp *cpuhp = &res->cpuhp;
+ static int count = 0;
+ double curr_gov_timeout, next_gov_timeout;
+ int level, ret;
+
+ if (!res) {
+ _E("cannot call the governor timeout callback\n");
+ return FALSE;
+ }
+
+ /*
+ * Collect data related to system state
+ * - the current frequency
+ * - the number of nr_running
+ * - the resource utilization
+ */
+ ret = pass_get_cpu_stats(res);
+ if (ret < 0) {
+ if (count++ < PASS_CPU_STATS_MAX_COUNT)
+ return TRUE;
+
+ count = 0;
+
+ _E("cannot read the 'pass_cpu_stats' sysfs entry");
+ cpuhp_governor_update(res, PASS_OFF);
+
+ return FALSE;
+ }
+
+ /* Calculate the number of busy cpu */
+ cpuhp_calculate_busy_cpu(res);
+
+ /* Store current governor timeout */
+ curr_gov_timeout = levels[res->rescon.curr_level].gov_timeout;
+
+ /* Determine the amount of proper resource */
+ if (cpuhp->governor->governor) {
+ level = cpuhp->governor->governor(res);
+
+ pass_rescon_set_level(res, level);
+ } else {
+ _E("cannot call the governor function");
+ cpuhp_governor_update(res, PASS_OFF);
+ return FALSE;
+ }
+
+ /* Get the governor timeout interval for the next */
+ next_gov_timeout = levels[res->rescon.curr_level].gov_timeout;
+
+ /*
+ * Change the governor timeout interval when the next interval is not
+ * same as the current one
+ */
+ if (curr_gov_timeout != next_gov_timeout) {
+ _I("Change the period of governor timer from %fs to %fs\n",
+ curr_gov_timeout,
+ next_gov_timeout);
+ g_source_remove(cpuhp->gov_timeout_id);
+ cpuhp->gov_timeout_id = g_timeout_add(
+ (guint)(next_gov_timeout * 1000),
+ cpuhp_governor_timer_cb,
+ (gpointer)res);
+ }
+
+ return TRUE;
+}
+
+static void cpuhp_governor_start(struct pass_resource *res)
+{
+ struct pass_cpuhp *cpuhp = &res->cpuhp;
+
+ if (!cpuhp->governor) {
+ _E("cannot start PASS governor");
+ return;
+ }
+
+ if (is_enabled(cpuhp)) {
+ _E("PASS governor is already active state");
+ return;
+ }
+
+ /* Add callback function for each governor timeout */
+ if (res->config_data.gov_timeout > 0) {
+ cpuhp->gov_timeout_id = g_timeout_add(
+ (guint)(res->config_data.gov_timeout * 1000),
+ (GSourceFunc)cpuhp_governor_timer_cb,
+ (gpointer)res);
+ if (!cpuhp->gov_timeout_id) {
+ _E("cannot add core timer for governor");
+ cpuhp_governor_update(res, PASS_OFF);
+ return;
+ }
+ } else {
+ cpuhp->gov_timeout_id = 0;
+ }
+
+ /*
+ * Set default pass level when starting pass
+ * - default pass level according to res->init_level
+ */
+ res->rescon.curr_level = -1;
+ if (res->rescon.init_level > res->rescon.max_level)
+ res->rescon.init_level = res->rescon.max_level;
+
+ pass_rescon_set_level(res, res->rescon.init_level);
+
+ /* Set PASS state as PASS_ON */
+ cpuhp->state = PASS_ON;
+
+ _I("Start governor for '%s' resource", res->config_data.res_name);
+}
+
+static void cpuhp_governor_stop(struct pass_resource *res)
+{
+ struct pass_cpuhp *cpuhp = &res->cpuhp;
+ struct pass_resource_config_data *config_data = &res->config_data;
+
+ if (!cpuhp->governor) {
+ _E("cannot stop PASS governor");
+ return;
+ }
+
+ if (cpuhp->state == PASS_OFF) {
+ _E("PASS governor is already inactive state");
+ return;
+ }
+
+ cpuhp_hotplug_stop(res);
+
+ if (cpuhp->gov_timeout_id) {
+ g_source_remove(cpuhp->gov_timeout_id);
+ cpuhp->gov_timeout_id = 0;
+ }
+
+ /* Set PASS state as PASS_OFF */
+ cpuhp->state = PASS_OFF;
+
+ _I("Stop governor for '%s' resource", config_data->res_name);
+}
+
+static int cpuhp_governor_init(struct pass_resource *res)
+{
+ struct pass_cpuhp *cpuhp = &res->cpuhp;
+
+ if (res->config_data.gov_timeout < 0) {
+ _E("invalid timeout value [%d]!", res->config_data.gov_timeout);
+ cpuhp_governor_update(res, PASS_OFF);
+ return -EINVAL;
+ }
+
+ /* Set default PASS state */
+ cpuhp->state = PASS_OFF;
+
+ if (res->config_data.state == PASS_ON)
+ cpuhp_governor_update(res, PASS_ON);
+
+ return 0;
+}
+
+static int cpuhp_governor_exit(struct pass_resource *res)
+{
+ struct pass_cpuhp *cpuhp = &res->cpuhp;
+ int i;
+
+ /*
+ * Stop timer and
+ * Restore the frequency and the number of online resources
+ */
+ cpuhp_governor_update(res, PASS_OFF);
+
+ /* Free allocated memory */
+ for (i = 0; i < cpuhp->num_pass_cpu_stats; i++) {
+ free(cpuhp->pass_cpu_stats[i].load);
+ free(cpuhp->pass_cpu_stats[i].nr_running);
+ free(cpuhp->pass_cpu_stats[i].runnable_load);
+ }
+ free(cpuhp->pass_cpu_stats);
+
+ if (cpuhp->hotplug)
+ free(cpuhp->hotplug->sequence);
+
+ /* Set pass_cpuhp structure as default value */
+ cpuhp->pass_cpu_threshold = 0;
+ cpuhp->up_threshold = 0;
+ cpuhp->down_threshold = 0;
+ cpuhp->level_up_threshold = 0;
+ cpuhp->num_pass_cpu_stats = 0;
+ cpuhp->governor = NULL;
+
+ return 0;
+}
+
+static int cpuhp_governor_update(struct pass_resource *res,
+ enum pass_state state)
+{
+ switch (state) {
+ case PASS_ON:
+ cpuhp_governor_start(res);
+ break;
+ case PASS_OFF:
+ cpuhp_governor_stop(res);
+ break;
+ default:
+ _E("Unknown governor state");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Define CPUHP governor
+ *
+ * - Step governor
+ * - Radiation governor
+ */
+static struct pass_cpuhp_governor pass_gov_dummy = {
+ .name = "pass_dummy",
+ .init = cpuhp_governor_init,
+ .exit = cpuhp_governor_exit,
+ .update = cpuhp_governor_update,
+ .governor = NULL,
+};
+
+static struct pass_cpuhp_governor pass_gov_step = {
+ .name = "pass_step",
+ .init = cpuhp_governor_init,
+ .exit = cpuhp_governor_exit,
+ .update = cpuhp_governor_update,
+ .governor = pass_cpuhp_step_governor,
+};
+
+static struct pass_cpuhp_governor pass_gov_radiation = {
+ .name = "pass_radiation",
+ .init = cpuhp_governor_init,
+ .exit = cpuhp_governor_exit,
+ .update = cpuhp_governor_update,
+ .governor = pass_cpuhp_radiation_governor,
+};
+
+/*
+ * pass_get_governor - Return specific governor instance according to type
+ * @type: the type of PASS governor
+ */
+static struct pass_cpuhp_governor* cpuhp_get_governor(struct pass_resource *res,
+ enum pass_gov_type type)
+{
+ switch (type) {
+ case PASS_GOV_DUMMY:
+ return NULL;
+ case PASS_GOV_BASIC:
+ case PASS_GOV_HOTPLUG_ONLY:
+ /* Use the Resource controller only */
+ return &pass_gov_dummy;
+ case PASS_GOV_STEP:
+ /* Use the Resource controller and Step governor. */
+ return &pass_gov_step;
+ case PASS_GOV_RADIATION:
+ /* Use the Resource controller and Radiation governor. */
+ return &pass_gov_radiation;
+ default:
+ _E("Unknown governor type");
+ break;
+ };
+
+ return NULL;
+}
+
+/*
+ * pass_cpuhp_init - Initialize CPUHP (CPU Hotplug Manager) module
+ *
+ * @res: the instance of struct pass_resource
+ */
+int pass_cpuhp_init(struct pass_resource *res)
+{
+ struct pass_cpuhp *cpuhp;
+ int max_freq = 0;
+ int i;
+
+ if (!res)
+ return -EINVAL;
+
+ cpuhp = &res->cpuhp;
+
+ if (!cpuhp->pass_cpu_threshold)
+ cpuhp->pass_cpu_threshold = PASS_DEFAULT_CPU_THRESHOLD;
+
+ if (!cpuhp->up_threshold)
+ cpuhp->up_threshold = PASS_DEFAULT_LEVEL_UP_THRESHOLD;
+
+ if (!cpuhp->down_threshold)
+ cpuhp->down_threshold = PASS_DEFAULT_LEVEL_DOWN_THRESHOLD;
+
+ if (!cpuhp->level_up_threshold)
+ cpuhp->level_up_threshold = 0;
+
+ if (!cpuhp->num_pass_cpu_stats)
+ cpuhp->num_pass_cpu_stats = PASS_CPU_STATS_MAX_COUNT;
+
+ for (i = 0; i < res->config_data.num_levels; i++)
+ if (max_freq < res->config_data.levels[i].limit_max_freq)
+ max_freq = res->config_data.levels[i].limit_max_freq;
+ cpuhp->freq.max_freq = max_freq;
+
+
+ /* Allocate memory according to the number of data and cpu */
+ cpuhp->pass_cpu_stats = calloc(cpuhp->num_pass_cpu_stats,
+ sizeof(struct pass_cpu_stats));
+
+ for (i = 0; i < cpuhp->num_pass_cpu_stats; i++) {
+ cpuhp->pass_cpu_stats[i].load =
+ calloc(res->config_data.num_cpus, sizeof(unsigned int));
+ cpuhp->pass_cpu_stats[i].nr_running =
+ calloc(res->config_data.num_cpus, sizeof(unsigned int));
+ cpuhp->pass_cpu_stats[i].runnable_load =
+ calloc(res->config_data.num_cpus, sizeof(unsigned int));
+ }
+
+ /* Get the instance of CPU Hotplug's policy */
+ cpuhp->hotplug = cpuhp_get_hotplug(res, res->config_data.gov_type);
+ if (cpuhp->hotplug) {
+ cpuhp->hotplug->sequence = calloc(res->config_data.num_cpus,
+ sizeof(int));
+ for (i = 0; i < res->config_data.num_cpus; i++)
+ cpuhp->hotplug->sequence[i] = i + res->config_data.cpu;
+
+ cpuhp->hotplug->num_cpus = res->config_data.num_cpus;
+ }
+
+ /* Get the instance of CPUHP governor */
+ cpuhp->governor = cpuhp_get_governor(res, res->config_data.gov_type);
+ if (!cpuhp->governor) {
+ _E("cannot get the instance of PASS governor");
+ return -1;
+ }
+
+ if (!cpuhp->governor || !cpuhp->governor->init)
+ return -EINVAL;
+
+ return cpuhp->governor->init(res);
+}
+
+/*
+ * pass_cpuhp_exit - Exit CPUHP (CPU Hotplug Manager) module
+ *
+ * @res: the instance of struct pass_resource
+ */
+int pass_cpuhp_exit(struct pass_resource *res)
+{
+ struct pass_cpuhp *cpuhp;
+
+ if (!res)
+ return -EINVAL;
+
+ cpuhp = &res->cpuhp;
+
+ if (!cpuhp->governor || !cpuhp->governor->exit)
+ return -EINVAL;
+
+ return cpuhp->governor->exit(res);
+}
+++ /dev/null
-/*
- * PASS (Power Aware Systerm Service) Radiation governor
- *
- * Copyright (c) 2012 - 2018 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the License);
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "pass.h"
-
-/*
- * pass_radiation_governor - Check cpu state and determine the amount of resource
- *
- * @stats: structure for getting cpu frequency state from kerncel
- *
- * This function check periodically current following state of system
- * and then determine whether pass level up or down according to pass
- * policy with gathered data.
- * - current cpu frequency
- * - the number of nr_running
- * - the number of busy_cpu
- */
-int pass_radiation_governor(struct pass_resource *res)
-{
- struct pass_level *levels = res->config_data.levels;
- struct pass_cpuhp *cpuhp = &res->cpuhp;
- struct pass_cpu_stats *cpu_stats = cpuhp->pass_cpu_stats;
- int up_threshold = cpuhp->up_threshold;
- int down_threshold = cpuhp->down_threshold;
- int num_pass_gov = 0;
- int level = res->rescon.curr_level;
- int up_count = 0;
- int down_count = 0;
- int left_count = 0;
- int right_count = 0;
- bool up_condition;
- bool down_condition;
- bool left_condition;
- bool right_condition;
- int freq;
- int nr_running;
- int busy_cpu;
- int i;
- int j;
- int64_t time;
-
- for (i = 0; i < cpuhp->num_pass_cpu_stats; i++) {
- time = cpu_stats[i].time;
- freq = cpu_stats[i].freq;
- nr_running = cpu_stats[i].nr_runnings;
- busy_cpu = cpu_stats[i].num_busy_cpu;
- up_condition = true;
- down_condition = true;
- left_condition = true;
- right_condition = true;
-
- if (cpuhp->last_time >= time)
- continue;
- cpuhp->last_time = time;
- num_pass_gov++;
-
- /*
- _I("[Level%d][%d][%lld] %d | %d | %d", level, i, time, freq,
- nr_running, busy_cpu);
- */
-
- /* Check level up condition */
- for (j = 0; j < levels[level].num_up_cond && up_condition; j++) {
- if (levels[level].up_cond[j].freq &&
- !(freq >= levels[level].up_cond[j].freq))
- up_condition = false;
- }
-
- if (levels[level].num_up_cond && up_condition) {
- up_count++;
-
- /*
- _I("[Level%d] [up_count : %2d] \
- freq(%d), nr_running(%d), busy_cpu(%d)",
- level, up_count,
- levels[level].up_cond[j].freq ? freq : -1,
- */
- }
-
- /* Check level down condition */
- for (j = 0; j < levels[level].num_down_cond && down_condition; j++) {
- if (levels[level].down_cond[j].freq
- && !(freq <= levels[level].down_cond[j].freq))
- down_condition = false;
- }
-
- if (levels[level].num_down_cond && down_condition) {
- down_count++;
-
- /*
- _I("[Level%d] [dw_count : %2d] \
- freq(%d), nr_running(%d), busy_cpu(%d)",
- level, down_count,
- levels[level].down_cond[j].freq ? freq : -1,
- */
- }
-
- /* Check level right condition */
- for (j = 0; j < levels[level].num_right_cond && right_condition; j++) {
- /*
- * If one more conditions are false among following
- * conditions, don't increment right_count.
- */
- if (levels[level].right_cond[j].nr_running
- && !(nr_running > levels[level].right_cond[j].nr_running))
- right_condition = false;
-
- if (levels[level].right_cond[j].busy_cpu
- && !(busy_cpu >= levels[level].right_cond[j].busy_cpu))
- right_condition = false;
- }
-
- if (levels[level].num_right_cond && right_condition) {
- right_count++;
-
- /*
- _I("[Level%d] [right_count : %2d] \
- nr_running(%d), busy_cpu(%d)",
- level, right_count,
- levels[level].right_cond[j].nr_running ? nr_running : -1,
- levels[level].right_cond[j].busy_cpu ? busy_cpu : -1);
- */
- }
-
- /* Check level left condition */
- for (j = 0; j < levels[level].num_left_cond && left_condition; j++) {
- /*
- * If one more conditions are false among following
- * conditions, don't increment left_count.
- */
- if (levels[level].left_cond[j].nr_running
- && !(nr_running <= levels[level].left_cond[j].nr_running))
- left_condition = false;
-
- if (levels[level].left_cond[j].busy_cpu
- && !(busy_cpu < levels[level].left_cond[j].busy_cpu))
- left_condition = false;
- }
-
- if (levels[level].num_left_cond && left_condition) {
- left_count++;
-
- /*
- _I("[Level%d] [ left_count : %2d] \
- nr_running(%d), busy_cpu(%d)",
- level, left_count,
- levels[level].left_cond[j].nr_running ? nr_running : -1,
- levels[level].left_cond[j].busy_cpu ? busy_cpu : -1);
- */
- }
- }
-
- if (!num_pass_gov)
- return level;
-
- if (up_count * 100 >= num_pass_gov * up_threshold) {
- level += cpuhp->hotplug->num_cpus;
-
- if (level > res->rescon.max_level)
- level -= cpuhp->hotplug->num_cpus;
- } else if (down_count * 100 >= num_pass_gov * down_threshold) {
- level -= cpuhp->hotplug->num_cpus;
- }
-
- if (right_count * 100 >= num_pass_gov * up_threshold) {
- level += 1;
-
- if (level > res->rescon.max_level)
- level -= 1;
- } else if (left_count * 100 >= num_pass_gov * down_threshold) {
- level -= 1;
- }
-
- /*
- if (level == res->prev_level) {
- for (i = num_pass_gov; i < cpuhp->num_pass_cpu_stats; i++) {
- time = cpu_stats[i].time;
- freq = cpu_stats[i].freq;
- nr_running = cpu_stats[i].nr_runnings;
- busy_cpu = cpu_stats[i].num_busy_cpu;
-
- _I("[Level%d][%d][%lld] %d | %d | %d",
- level, i, time, freq,
- nr_running, busy_cpu);
- }
- }
-
- if (level != res->rescon.curr_level) {
- _I("\n[Level%d] num_pass_gov: [%2d]", level, num_pass_gov);
- _I("[Level%d] down_count : %2d (%3d >= %3d)", level, down_count,
- down_count * 100, num_pass_gov * down_threshold);
- _I("[Level%d] up_count : %2d (%3d >= %3d)", level, up_count,
- up_count * 100, num_pass_gov * up_threshold);
- _I("[Level%d] left_count : %2d (%3d >= %3d)", level, left_count,
- left_count * 100, num_pass_gov * down_threshold);
- _I("[Level%d] right_count : %2d (%3d >= %3d)", level, right_count,
- right_count * 100, num_pass_gov * up_threshold);
- }
- */
-
- return level;
-}
+++ /dev/null
-/*
- * PASS (Power Aware System Service) Step governor
- *
- * Copyright (c) 2012 - 2018 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the License);
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "pass.h"
-
-/*
- * pass_step_governor - Check cpu state and determine the amount of resource
- *
- * @stats: structure for getting cpu frequency state from kerncel
- *
- * This function check periodically current following state of system
- * and then determine whether pass level up or down according to pass
- * policy with gathered data.
- * - current cpu frequency
- * - the number of nr_running
- * - the number of busy_cpu
- */
-int pass_step_governor(struct pass_resource *res)
-{
- struct pass_level *levels = res->config_data.levels;
- struct pass_cpuhp *cpuhp = &res->cpuhp;
- struct pass_cpu_stats *cpu_stats = cpuhp->pass_cpu_stats;
- int up_threshold = cpuhp->up_threshold;
- int down_threshold = cpuhp->down_threshold;
- int num_pass_gov = 0;
- int level = res->rescon.curr_level;
- int up_count = 0;
- int up_max_count = 0;
- int down_count = 0;
- bool up_condition;
- bool down_condition;
- int freq;
- int nr_running;
- int busy_cpu;
- int i;
- int j;
- int64_t time;
-
- for (i = 0; i < cpuhp->num_pass_cpu_stats; i++) {
- time = cpu_stats[i].time;
- freq = cpu_stats[i].freq;
- nr_running = cpu_stats[i].nr_runnings;
- busy_cpu = cpu_stats[i].num_busy_cpu;
- up_condition = false;
- down_condition = false;
-
- if (cpuhp->last_time >= time)
- continue;
- cpuhp->last_time = time;
- num_pass_gov++;
-
- /* Check level up condition */
- for (j = 0; j < levels[level].num_up_cond; j++) {
- /*
- * If one more conditions are false among following
- * conditions, don't increment up_count.
- */
- if (freq >= levels[level].up_cond[j].freq
- && nr_running >= levels[level].up_cond[j].nr_running
- && busy_cpu >= levels[level].up_cond[j].busy_cpu)
- up_condition = true;
- }
-
- if (levels[level].num_up_cond && up_condition) {
- up_count++;
-
- /*
- _I("[Level%d] [up_count : %2d] \
- freq(%d), nr_running(%d), busy_cpu(%d)",
- level, up_count,
- levels[level].up_cond[0].freq ? freq : -1,
- levels[level].up_cond[0].nr_running ? nr_running : -1,
- levels[level].up_cond[0].busy_cpu ? busy_cpu : -1);
- */
- }
-
- /* Check level down condition */
- for (j = 0; j < levels[level].num_down_cond; j++) {
- /*
- * If one more conditions are false among following
- * conditions, don't increment down_count.
- */
- if (freq <= levels[level].down_cond[j].freq
- && nr_running < levels[level].down_cond[j].nr_running
- && busy_cpu < levels[level].down_cond[j].busy_cpu)
- down_condition = true;
- }
-
- if (levels[level].num_down_cond && down_condition) {
- down_count++;
-
- /*
- _I("[Level%d] [dw_count : %2d] \
- freq(%d), nr_running(%d), busy_cpu(%d)",
- level, down_count,
- levels[level].down_cond[0].freq ? freq : -1,
- levels[level].down_cond[0].nr_running ? nr_running : -1,
- levels[level].down_cond[0].busy_cpu ? busy_cpu : -1);
- */
- }
-
- if (level < res->rescon.max_level &&
- freq == levels[level].limit_max_freq)
- up_max_count++;
- }
-
- if (!num_pass_gov)
- return level;
-
- if (up_count && level < res->rescon.max_level &&
- up_count * 100 >= num_pass_gov * up_threshold) {
- level += 1;
- } else if (down_count && level > res->rescon.min_level &&
- down_count * 100 >= num_pass_gov * down_threshold) {
- level -= 1;
- }
-
- return level;
-}
+++ /dev/null
-/*
- * PASS (Power Aware System Service) Governor
- *
- * Copyright (c) 2012 - 2018 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the License);
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/time.h>
-
-#include <pass/device-notifier.h>
-#include <pass/config-parser.h>
-
-#include "pass.h"
-#include "pass-hal.h"
-#include "pass-rescon.h"
-
-extern int pass_step_governor(struct pass_resource *res);
-extern int pass_radiation_governor(struct pass_resource *res);
-static int __pass_governor_update(struct pass_resource *, enum pass_state);
-
-#define PASS_DEFAULT_CPU_THRESHOLD 20
-#define PASS_DEFAULT_LEVEL_UP_THRESHOLD 30
-#define PASS_DEFAULT_LEVEL_DOWN_THRESHOLD 80
-#define PASS_CPU_STATS_MAX_COUNT 20
-
-struct pass_governor {
- char name[BUFF_MAX];
- enum pass_state state;
-
- int (*init)(struct pass_resource *res);
- int (*exit)(struct pass_resource *res);
- int (*update)(struct pass_resource *res, enum pass_state state);
- int (*governor)(struct pass_resource *res);
-};
-
-/*
- * is_enabled - Check the state of PASS governor
- * @cpuhp: the instance of struct pass_cpuhp
- *
- * Return true if the state of PASS is PASS_ON
- * Return false if the state of PASS is PASS_OFF
- */
-static bool is_enabled(struct pass_cpuhp *cpuhp)
-{
- if (cpuhp->state != PASS_ON)
- return false;
-
- return true;
-}
-
-/*
- * pass_hotplug_stop - Stop PASS hotplug
- * @res: the instance of struct pass_resource
- */
-static void pass_hotplug_stop(struct pass_resource *res)
-{
- struct pass_level *levels = res->config_data.levels;
- int level = res->rescon.max_level;
-
- if (!res->cpuhp.hotplug || !levels)
- return;
-
- res->cpuhp.hotplug->online = levels[level].limit_min_cpu;
-}
-
-static int pass_hotplug_dummy_governor(struct pass_resource *res)
-{
- int level = res->rescon.curr_level;
-
- return res->config_data.levels[level].limit_min_cpu;
-}
-
-static struct pass_hotplug* get_hotplug(struct pass_resource *res,
- enum pass_gov_type type)
-{
- struct pass_hotplug *hotplug;
-
- switch (type) {
- case PASS_GOV_DUMMY:
- case PASS_GOV_BASIC:
- /* Don't use Hotplug interface */
- return NULL;
- case PASS_GOV_HOTPLUG_ONLY:
- case PASS_GOV_STEP:
- case PASS_GOV_RADIATION:
- /* Use Hotplug interface */
- hotplug = calloc(1, sizeof(struct pass_hotplug));
- if (!hotplug) {
- _E("cannot allocate the memory of struct pass_hotplug");
- return NULL;
- }
- hotplug->governor = pass_hotplug_dummy_governor;
- return hotplug;
- default:
- _E("Unknown hotplug type");
- break;
- };
-
- return NULL;
-}
-
-/*
- * pass_calculate_busy_cpu - Count a number of busy cpu among NR_CPUS by using
- * runnable_avg_sum/runnable_avg_period
- * @res: the instance of struct pass_resource
- */
-static void pass_calculate_busy_cpu(struct pass_resource *res)
-{
- struct pass_cpuhp *cpuhp = &res->cpuhp;
- struct pass_level *levels = res->config_data.levels;
- struct pass_resource_config_data *config_data = &res->config_data;
- struct pass_cpu_stats *stats = cpuhp->pass_cpu_stats;
- unsigned int level = res->rescon.curr_level;
- unsigned int cpu_threshold = 0;
- unsigned int busy_cpu;
- unsigned int cur_freq;
- unsigned int load;
- unsigned int sum_load;
- unsigned int sum_runnable_load;
- unsigned int nr_runnings;
- int limit_min_cpu;
- int i;
- int j;
-
- limit_min_cpu = levels[level].limit_min_cpu;
-
- for (i = 0; i < cpuhp->num_pass_cpu_stats; i++) {
- cur_freq = stats[i].freq;
- nr_runnings = stats[i].nr_runnings;
-
- stats[i].num_busy_cpu = 0;
- stats[i].avg_load = 0;
- stats[i].avg_runnable_load = 0;
- stats[i].avg_thread_load = 0;
- stats[i].avg_thread_runnable_load = 0;
-
- busy_cpu = 0;
- sum_load = 0;
- sum_runnable_load = 0;
-
- /* Calculate the number of busy cpu */
- for (j = 0; j < config_data->num_cpus; j++) {
- load = stats[i].load[j];
- sum_load += stats[i].load[j];
- sum_runnable_load += stats[i].runnable_load[j];
- if (!load)
- continue;
-
- cpu_threshold =
- (unsigned int)(cur_freq * load)
- / cpuhp->freq.max_freq;
- if (load == 100
- || cpu_threshold >= cpuhp->pass_cpu_threshold)
- busy_cpu++;
- }
-
- stats[i].num_busy_cpu = busy_cpu;
- stats[i].avg_load = sum_load / limit_min_cpu;
- stats[i].avg_runnable_load = sum_runnable_load / limit_min_cpu;
- if (nr_runnings) {
- stats[i].avg_thread_load
- = (sum_load * 100) / nr_runnings;
- stats[i].avg_thread_runnable_load
- = (sum_runnable_load * 100) / nr_runnings;
- }
- }
-}
-
-/*
- * pass_governor_timeout_cb - Callback for each timeout interval of the governor
- * @data: the instance of struct pass_resource
-*/
-static gboolean pass_governor_timeout_cb(gpointer data)
-{
- struct pass_resource *res = (struct pass_resource *)data;
- struct pass_level *levels = res->config_data.levels;
- struct pass_cpuhp *cpuhp = &res->cpuhp;
- static int count = 0;
- double curr_gov_timeout, next_gov_timeout;
- int level, ret;
-
- if (!res) {
- _E("cannot call the governor timeout callback\n");
- return FALSE;
- }
-
- /*
- * Collect data related to system state
- * - the current frequency
- * - the number of nr_running
- * - the resource utilization
- */
- ret = pass_get_cpu_stats(res);
- if (ret < 0) {
- if (count++ < PASS_CPU_STATS_MAX_COUNT)
- return TRUE;
-
- count = 0;
-
- _E("cannot read the 'pass_cpu_stats' sysfs entry");
- __pass_governor_update(res, PASS_OFF);
-
- return FALSE;
- }
-
- /* Calculate the number of busy cpu */
- pass_calculate_busy_cpu(res);
-
- /* Store current governor timeout */
- curr_gov_timeout = levels[res->rescon.curr_level].gov_timeout;
-
- /* Determine the amount of proper resource */
- if (cpuhp->governor->governor) {
- level = cpuhp->governor->governor(res);
-
- pass_rescon_set_level(res, level);
- } else {
- _E("cannot call the governor function");
- __pass_governor_update(res, PASS_OFF);
- return FALSE;
- }
-
- /* Get the governor timeout interval for the next */
- next_gov_timeout = levels[res->rescon.curr_level].gov_timeout;
-
- /*
- * Change the governor timeout interval when the next interval is not
- * same as the current one
- */
- if (curr_gov_timeout != next_gov_timeout) {
- _I("Change the period of governor timer from %fs to %fs\n",
- curr_gov_timeout,
- next_gov_timeout);
- g_source_remove(cpuhp->gov_timeout_id);
- cpuhp->gov_timeout_id = g_timeout_add(
- (guint)(next_gov_timeout * 1000),
- pass_governor_timeout_cb,
- (gpointer)res);
- }
-
- return TRUE;
-}
-
-/*
- * __pass_governor_start - Start PASS governor through D-Bus
- * @res: the instance of struct pass_resource
- */
-static void __pass_governor_start(struct pass_resource *res)
-{
- struct pass_cpuhp *cpuhp = &res->cpuhp;
-
- if (!cpuhp->governor) {
- _E("cannot start PASS governor");
- return;
- }
-
- if (is_enabled(cpuhp)) {
- _E("PASS governor is already active state");
- return;
- }
-
- /* Add callback function for each governor timeout */
- if (res->config_data.gov_timeout > 0) {
- cpuhp->gov_timeout_id = g_timeout_add(
- (guint)(res->config_data.gov_timeout * 1000),
- (GSourceFunc)pass_governor_timeout_cb,
- (gpointer)res);
- if (!cpuhp->gov_timeout_id) {
- _E("cannot add core timer for governor");
- __pass_governor_update(res, PASS_OFF);
- return;
- }
- } else {
- cpuhp->gov_timeout_id = 0;
- }
-
- /*
- * Set default pass level when starting pass
- * - default pass level according to res->init_level
- */
- res->rescon.curr_level = -1;
- if (res->rescon.init_level > res->rescon.max_level)
- res->rescon.init_level = res->rescon.max_level;
-
- pass_rescon_set_level(res, res->rescon.init_level);
-
- /* Set PASS state as PASS_ON */
- cpuhp->state = PASS_ON;
-
- _I("Start governor for '%s' resource", res->config_data.res_name);
-}
-
-/*
- * __pass_governor_stop - Stop PASS governor through D-Bus
- * @res: the instance of struct pass_resource
- */
-static void __pass_governor_stop(struct pass_resource *res)
-{
- struct pass_cpuhp *cpuhp = &res->cpuhp;
- struct pass_resource_config_data *config_data = &res->config_data;
-
- if (!cpuhp->governor) {
- _E("cannot stop PASS governor");
- return;
- }
-
- if (cpuhp->state == PASS_OFF) {
- _E("PASS governor is already inactive state");
- return;
- }
-
- pass_hotplug_stop(res);
-
- if (cpuhp->gov_timeout_id) {
- g_source_remove(cpuhp->gov_timeout_id);
- cpuhp->gov_timeout_id = 0;
- }
-
- /* Set PASS state as PASS_OFF */
- cpuhp->state = PASS_OFF;
-
- _I("Stop governor for '%s' resource", config_data->res_name);
-}
-
-static int __pass_governor_init(struct pass_resource *res)
-{
- struct pass_cpuhp *cpuhp = &res->cpuhp;
-
- if (res->config_data.gov_timeout < 0) {
- _E("invalid timeout value [%d]!", res->config_data.gov_timeout);
- __pass_governor_update(res, PASS_OFF);
- return -EINVAL;
- }
-
- /* Set default PASS state */
- cpuhp->state = PASS_OFF;
-
- if (res->config_data.state == PASS_ON)
- __pass_governor_update(res, PASS_ON);
-
- return 0;
-}
-
-static int __pass_governor_exit(struct pass_resource *res)
-{
- struct pass_cpuhp *cpuhp = &res->cpuhp;
- int i;
-
- /*
- * Stop timer and
- * Restore the frequency and the number of online resources
- */
- __pass_governor_update(res, PASS_OFF);
-
- /* Free allocated memory */
- for (i = 0; i < cpuhp->num_pass_cpu_stats; i++) {
- free(cpuhp->pass_cpu_stats[i].load);
- free(cpuhp->pass_cpu_stats[i].nr_running);
- free(cpuhp->pass_cpu_stats[i].runnable_load);
- }
- free(cpuhp->pass_cpu_stats);
-
- if (cpuhp->hotplug)
- free(cpuhp->hotplug->sequence);
-
- /* Set pass_cpuhp structure as default value */
- cpuhp->pass_cpu_threshold = 0;
- cpuhp->up_threshold = 0;
- cpuhp->down_threshold = 0;
- cpuhp->level_up_threshold = 0;
- cpuhp->num_pass_cpu_stats = 0;
- cpuhp->governor = NULL;
-
- return 0;
-}
-
-static int __pass_governor_update(struct pass_resource *res,
- enum pass_state state)
-{
- switch (state) {
- case PASS_ON:
- __pass_governor_start(res);
- break;
- case PASS_OFF:
- __pass_governor_stop(res);
- break;
- default:
- _E("Unknown governor state");
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * Define PASS governor
- *
- * - Step governor
- * - Radiation governor
- */
-static struct pass_governor pass_gov_dummy = {
- .name = "pass_dummy",
- .init = __pass_governor_init,
- .exit = __pass_governor_exit,
- .update = __pass_governor_update,
- .governor = NULL,
-};
-
-static struct pass_governor pass_gov_step = {
- .name = "pass_step",
- .init = __pass_governor_init,
- .exit = __pass_governor_exit,
- .update = __pass_governor_update,
-
- .governor = pass_step_governor,
-};
-
-static struct pass_governor pass_gov_radiation = {
- .name = "pass_radiation",
- .init = __pass_governor_init,
- .exit = __pass_governor_exit,
- .update = __pass_governor_update,
-
- .governor = pass_radiation_governor,
-};
-
-/*
- * pass_get_governor - Return specific governor instance according to type
- * @type: the type of PASS governor
- */
-static struct pass_governor* get_governor(struct pass_resource *res,
- enum pass_gov_type type)
-{
- switch (type) {
- case PASS_GOV_DUMMY:
- return NULL;
- case PASS_GOV_BASIC:
- case PASS_GOV_HOTPLUG_ONLY:
- /* Use the Resource controller only */
- return &pass_gov_dummy;
- case PASS_GOV_STEP:
- /* Use the Resource controller and Step governor. */
- return &pass_gov_step;
- case PASS_GOV_RADIATION:
- /* Use the Resource controller and Radiation governor. */
- return &pass_gov_radiation;
- default:
- _E("Unknown governor type");
- break;
- };
-
- return NULL;
-}
-
-/*
- * pass_governor_init - Initialize PASS governor
- * @res: the instance of struct pass_resource
- */
-int pass_governor_init(struct pass_resource *res)
-{
- struct pass_cpuhp *cpuhp;
- int max_freq = 0;
- int i;
-
- if (!res)
- return -EINVAL;
-
- cpuhp = &res->cpuhp;
-
- if (!cpuhp->pass_cpu_threshold)
- cpuhp->pass_cpu_threshold = PASS_DEFAULT_CPU_THRESHOLD;
-
- if (!cpuhp->up_threshold)
- cpuhp->up_threshold = PASS_DEFAULT_LEVEL_UP_THRESHOLD;
-
- if (!cpuhp->down_threshold)
- cpuhp->down_threshold = PASS_DEFAULT_LEVEL_DOWN_THRESHOLD;
-
- if (!cpuhp->level_up_threshold)
- cpuhp->level_up_threshold = 0;
-
- if (!cpuhp->num_pass_cpu_stats)
- cpuhp->num_pass_cpu_stats = PASS_CPU_STATS_MAX_COUNT;
-
- for (i = 0; i < res->config_data.num_levels; i++)
- if (max_freq < res->config_data.levels[i].limit_max_freq)
- max_freq = res->config_data.levels[i].limit_max_freq;
- cpuhp->freq.max_freq = max_freq;
-
-
- /* Allocate memory according to the number of data and cpu */
- cpuhp->pass_cpu_stats = calloc(cpuhp->num_pass_cpu_stats,
- sizeof(struct pass_cpu_stats));
-
- for (i = 0; i < cpuhp->num_pass_cpu_stats; i++) {
- cpuhp->pass_cpu_stats[i].load =
- calloc(res->config_data.num_cpus, sizeof(unsigned int));
- cpuhp->pass_cpu_stats[i].nr_running =
- calloc(res->config_data.num_cpus, sizeof(unsigned int));
- cpuhp->pass_cpu_stats[i].runnable_load =
- calloc(res->config_data.num_cpus, sizeof(unsigned int));
- }
-
- /* Get the instance of CPU Hotplug's policy */
- cpuhp->hotplug = get_hotplug(res, res->config_data.gov_type);
- if (cpuhp->hotplug) {
- cpuhp->hotplug->sequence = calloc(res->config_data.num_cpus,
- sizeof(int));
- for (i = 0; i < res->config_data.num_cpus; i++)
- cpuhp->hotplug->sequence[i] = i + res->config_data.cpu;
-
- cpuhp->hotplug->num_cpus = res->config_data.num_cpus;
- }
-
- /* Get the instance of CPUHP governor */
- cpuhp->governor = get_governor(res, res->config_data.gov_type);
- if (!cpuhp->governor) {
- _E("cannot get the instance of PASS governor");
- return -1;
- }
-
- if (!cpuhp->governor || !cpuhp->governor->init)
- return -EINVAL;
-
- return cpuhp->governor->init(res);
-}
-
-/*
- * pass_governor_exit - Exit PASS governor
- * @res: the instance of struct pass_resource
- */
-int pass_governor_exit(struct pass_resource *res)
-{
- struct pass_cpuhp *cpuhp;
-
- if (!res)
- return -EINVAL;
-
- cpuhp = &res->cpuhp;
-
- if (!cpuhp->governor || !cpuhp->governor->exit)
- return -EINVAL;
-
- return cpuhp->governor->exit(res);
-}
extern int pass_rescon_init(struct pass_resource *res);
extern int pass_rescon_exit(struct pass_resource *res);
-extern int pass_governor_init(struct pass_resource *res);
-extern int pass_governor_exit(struct pass_resource *res);
+extern int pass_cpuhp_init(struct pass_resource *res);
+extern int pass_cpuhp_exit(struct pass_resource *res);
extern int pass_pmqos_init(struct pass_resource *res);
extern int pass_pmqos_exit(struct pass_resource *res);
return ret;
}
- ret = pass_governor_init(res);
+ ret = pass_cpuhp_init(res);
if (ret < 0) {
- _E("cannot initialize PASS governor");
+ _E("cannot initialize PASS CPUHP");
goto err_cpuhp;
}
return 0;
err_pmqos:
- if (pass_governor_exit(res) < 0)
- _E("cannot exit PASS governor");
+ if (pass_cpuhp_exit(res) < 0)
+ _E("cannot exit PASS CPUHP");
err_cpuhp:
if (pass_rescon_exit(res) < 0)
_E("cannot exit PASS Resource-Controller");
/* Put configuration of each resource from pass-resource*.conf */
pass_put_each_resource_config(res);
- ret = pass_governor_exit(res);
+ ret = pass_cpuhp_exit(res);
if (ret < 0) {
- _E("cannot exit PASS governor");
+ _E("cannot exit PASS CPUHP");
return -1;
}
#define PASS_LEVEL_COND_MAX 3
struct pass_resource;
-struct pass_governor;
+struct pass_cpuhp_governor;
/*
* PASS Governor type
int64_t last_time;
- struct pass_governor *governor;
+ struct pass_cpuhp_governor *governor;
guint gov_timeout_id;
struct pass_hotplug *hotplug;