diff --git a/power/Android.mk b/power/Android.mk index 329f273d..7230ee00 100644 --- a/power/Android.mk +++ b/power/Android.mk @@ -7,6 +7,7 @@ ifeq ($(call is-vendor-board-platform,QCOM),true) include $(CLEAR_VARS) LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_MULTILIB := both LOCAL_SHARED_LIBRARIES := liblog libcutils libdl LOCAL_SRC_FILES := power.c metadata-parser.c utils.c list.c hint-data.c diff --git a/power/power-8992.c b/power/power-8992.c index d2728412..0855de03 100644 --- a/power/power-8992.c +++ b/power/power-8992.c @@ -35,8 +35,10 @@ #include #include #include +#include +#include -#define LOG_TAG "QCOM PowerHAL" +#define LOG_TAG "QCOMPowerHAL" #include #include #include @@ -47,6 +49,50 @@ #include "performance.h" #include "power-common.h" +pthread_mutex_t video_encode_lock = PTHREAD_MUTEX_INITIALIZER; +uintptr_t video_encode_hint_counter = 0; +bool video_encode_hint_should_enable = false; +bool video_encode_hint_is_enabled = false; + +static int new_hint_id = DEFAULT_VIDEO_ENCODE_HINT_ID; +static int cur_hint_id = DEFAULT_VIDEO_ENCODE_HINT_ID; + +static const time_t VIDEO_ENCODE_DELAY_SECONDS = 2; +static const time_t VIDEO_ENCODE_DELAY_NSECONDS = 0; + +static void* video_encode_hint_function(void* arg) { + struct timespec tv = {0}; + tv.tv_sec = VIDEO_ENCODE_DELAY_SECONDS; + tv.tv_nsec = VIDEO_ENCODE_DELAY_NSECONDS; + int nanosleep_ret = 0; + uintptr_t expected_counter = (uintptr_t)arg; + + // delay the hint for two seconds + // the hint hotplugs the large CPUs, so this prevents the large CPUs from + // going offline until the camera has had time to startup + TEMP_FAILURE_RETRY(nanosleep(&tv, &tv)); + pthread_mutex_lock(&video_encode_lock); + + // check to ensure we should still turn on hint from this particular thread + // if should_enable is true but counter is different, another thread owns hint + // if should_enable is false, we've already quit the camera + if (video_encode_hint_should_enable == true && video_encode_hint_counter == expected_counter) { + /* sched and cpufreq params + A53: 4 cores online at 1.2GHz max, 960 min + A57: 4 cores online at 384 max, 384 min + */ + int resource_values[] = {0x150C, 0x1F03, 0x2303}; + perform_hint_action(new_hint_id, + resource_values, sizeof(resource_values)/sizeof(resource_values[0])); + cur_hint_id = new_hint_id; + video_encode_hint_is_enabled = true; + video_encode_hint_should_enable = false; + } + + pthread_mutex_unlock(&video_encode_lock); + return NULL; +} + static int display_hint_sent; static int process_video_encode_hint(void *metadata) @@ -78,22 +124,37 @@ static int process_video_encode_hint(void *metadata) if (video_encode_metadata.state == 1) { if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) && (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) { - /* sched and cpufreq params - * hispeed freq - 768 MHz - * target load - 90 - * above_hispeed_delay - 40ms - * sched_small_tsk - 50 - */ - int resource_values[] = {0x2C07, 0x2F5A, 0x2704, 0x4032}; + pthread_t video_encode_hint_thread; + pthread_mutex_lock(&video_encode_lock); + new_hint_id = video_encode_metadata.hint_id; + if (video_encode_hint_counter < 65535) { + video_encode_hint_counter++; + } else { + video_encode_hint_counter = 0; + } + // start new thread to launch hint + video_encode_hint_should_enable = true; + if (pthread_create(&video_encode_hint_thread, NULL, video_encode_hint_function, (void*)video_encode_hint_counter) != 0) { + ALOGE("Error constructing hint thread"); + video_encode_hint_should_enable = false; + pthread_mutex_unlock(&video_encode_lock); + return HINT_NONE; + } + pthread_detach(video_encode_hint_thread); + pthread_mutex_unlock(&video_encode_lock); - perform_hint_action(video_encode_metadata.hint_id, - resource_values, sizeof(resource_values)/sizeof(resource_values[0])); return HINT_HANDLED; } } else if (video_encode_metadata.state == 0) { if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) && (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) { - undo_hint_action(video_encode_metadata.hint_id); + pthread_mutex_lock(&video_encode_lock); + video_encode_hint_should_enable = false; + if (video_encode_hint_is_enabled == true) { + undo_hint_action(cur_hint_id); + video_encode_hint_is_enabled = false; + } + pthread_mutex_unlock(&video_encode_lock); return HINT_HANDLED; } } @@ -107,6 +168,83 @@ int power_hint_override(struct power_module *module, power_hint_t hint, void *da case POWER_HINT_VIDEO_ENCODE: ret_val = process_video_encode_hint(data); break; + case POWER_HINT_INTERACTION: + { + int duration_hint = 0; + static unsigned long long previous_boost_time = 0; + + // little core freq bump for 1.5s + int resources[] = {0x20C}; + int duration = 1500; + static int handle_little = 0; + + // big core freq bump for 500ms + int resources_big[] = {0x2312, 0x1F08}; + int duration_big = 500; + static int handle_big = 0; + + // sched_downmigrate lowered to 10 for 1s at most + // should be half of upmigrate + int resources_downmigrate[] = {0x4F00}; + int duration_downmigrate = 1000; + static int handle_downmigrate = 0; + + // sched_upmigrate lowered to at most 20 for 500ms + // set threshold based on elapsed time since last boost + int resources_upmigrate[] = {0x4E00}; + int duration_upmigrate = 500; + static int handle_upmigrate = 0; + + // set duration hint + if (data) { + duration_hint = *((int*)data); + } + + struct timeval cur_boost_timeval = {0, 0}; + gettimeofday(&cur_boost_timeval, NULL); + unsigned long long cur_boost_time = cur_boost_timeval.tv_sec * 1000000 + cur_boost_timeval.tv_usec; + double elapsed_time = (double)(cur_boost_time - previous_boost_time); + if (elapsed_time > 750000) + elapsed_time = 750000; + // don't hint if it's been less than 250ms since last boost + // also detect if we're doing anything resembling a fling + // support additional boosting in case of flings + else if (elapsed_time < 250000 && duration_hint <= 750) + return; + + // keep sched_upmigrate high when flinging + if (duration_hint >= 750) + upmigrate_value = 20; + + // 95: default upmigrate for phone + // 20: upmigrate for sporadic touch + // 750ms: a completely arbitrary threshold for last touch + int upmigrate_value = 95 - (int)(75. * ((elapsed_time*elapsed_time) / (750000.*750000.))); + previous_boost_time = cur_boost_time; + resources_upmigrate[0] = resources_upmigrate[0] | upmigrate_value; + resources_downmigrate[0] = resources_downmigrate[0] | (upmigrate_value / 2); + + // modify downmigrate duration based on interaction data hint + // 1000 <= duration_downmigrate <= 5000 + // extend little core freq bump past downmigrate to soften downmigrates + if (duration_hint > 1000) { + if (duration_hint < 5000) { + duration_downmigrate = duration_hint; + duration = duration_hint + 750; + } else { + duration_downmigrate = 5000; + duration = 5750; + + } + } + + handle_little = interaction_with_handle(handle_little,duration, sizeof(resources)/sizeof(resources[0]), resources); + handle_big = interaction_with_handle(handle_big, duration_big, sizeof(resources_big)/sizeof(resources_big[0]), resources_big); + handle_downmigrate = interaction_with_handle(handle_downmigrate, duration_downmigrate, sizeof(resources_downmigrate)/sizeof(resources_downmigrate[0]), resources_downmigrate); + handle_upmigrate = interaction_with_handle(handle_upmigrate, duration_upmigrate, sizeof(resources_upmigrate)/sizeof(resources_upmigrate[0]), resources_upmigrate); + ret_val = HINT_HANDLED; + } + break; default: break; } @@ -127,7 +265,9 @@ int set_interactive_override(struct power_module *module, int on) /* Display off */ if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) && (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) { - int resource_values[] = {0x777}; /* 4+0 core config in display off */ + // sched upmigrate = 99, sched downmigrate = 95 + // keep the big cores around, but make them very hard to use + int resource_values[] = {0x4E63, 0x4F5F}; if (!display_hint_sent) { perform_hint_action(DISPLAY_STATE_HINT_ID, resource_values, sizeof(resource_values)/sizeof(resource_values[0])); diff --git a/power/power-8994.c b/power/power-8994.c index 296fd7fa..8ad9def8 100644 --- a/power/power-8994.c +++ b/power/power-8994.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2015, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -35,8 +35,10 @@ #include #include #include +#include +#include -#define LOG_TAG "QCOM PowerHAL" +#define LOG_TAG "QCOMPowerHAL" #include #include #include @@ -47,6 +49,50 @@ #include "performance.h" #include "power-common.h" +pthread_mutex_t video_encode_lock = PTHREAD_MUTEX_INITIALIZER; +uintptr_t video_encode_hint_counter = 0; +bool video_encode_hint_should_enable = false; +bool video_encode_hint_is_enabled = false; + +static int new_hint_id = DEFAULT_VIDEO_ENCODE_HINT_ID; +static int cur_hint_id = DEFAULT_VIDEO_ENCODE_HINT_ID; + +static const time_t VIDEO_ENCODE_DELAY_SECONDS = 2; +static const time_t VIDEO_ENCODE_DELAY_NSECONDS = 0; + +static void* video_encode_hint_function(void* arg) { + struct timespec tv = {0}; + tv.tv_sec = VIDEO_ENCODE_DELAY_SECONDS; + tv.tv_nsec = VIDEO_ENCODE_DELAY_NSECONDS; + int nanosleep_ret = 0; + uintptr_t expected_counter = (uintptr_t)arg; + + // delay the hint for two seconds + // the hint hotplugs the large CPUs, so this prevents the large CPUs from + // going offline until the camera has had time to startup + TEMP_FAILURE_RETRY(nanosleep(&tv, &tv)); + pthread_mutex_lock(&video_encode_lock); + + // check to ensure we should still turn on hint from this particular thread + // if should_enable is true but counter is different, another thread owns hint + // if should_enable is false, we've already quit the camera + if (video_encode_hint_should_enable == true && video_encode_hint_counter == expected_counter) { + /* sched and cpufreq params + A53: 4 cores online at 1.2GHz max, 960 min + A57: 4 cores online at 384 max, 384 min + */ + int resource_values[] = {0x150C, 0x1F03, 0x2303}; + perform_hint_action(new_hint_id, + resource_values, sizeof(resource_values)/sizeof(resource_values[0])); + cur_hint_id = new_hint_id; + video_encode_hint_is_enabled = true; + video_encode_hint_should_enable = false; + } + + pthread_mutex_unlock(&video_encode_lock); + return NULL; +} + static int display_hint_sent; static int process_video_encode_hint(void *metadata) @@ -78,35 +124,131 @@ static int process_video_encode_hint(void *metadata) if (video_encode_metadata.state == 1) { if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) && (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) { - /* sched and cpufreq params - * hispeed freq - 768 MHz - * target load - 90 - * above_hispeed_delay - 40ms - * sched_small_tsk - 50 - */ - int resource_values[] = {0x2C07, 0x2F5A, 0x2704, 0x4032}; + pthread_t video_encode_hint_thread; + pthread_mutex_lock(&video_encode_lock); + new_hint_id = video_encode_metadata.hint_id; + if (video_encode_hint_counter < 65535) { + video_encode_hint_counter++; + } else { + video_encode_hint_counter = 0; + } + // start new thread to launch hint + video_encode_hint_should_enable = true; + if (pthread_create(&video_encode_hint_thread, NULL, video_encode_hint_function, (void*)video_encode_hint_counter) != 0) { + ALOGE("Error constructing hint thread"); + video_encode_hint_should_enable = false; + pthread_mutex_unlock(&video_encode_lock); + return HINT_NONE; + } + pthread_detach(video_encode_hint_thread); + pthread_mutex_unlock(&video_encode_lock); - perform_hint_action(video_encode_metadata.hint_id, - resource_values, sizeof(resource_values)/sizeof(resource_values[0])); return HINT_HANDLED; } } else if (video_encode_metadata.state == 0) { if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) && (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) { - undo_hint_action(video_encode_metadata.hint_id); + pthread_mutex_lock(&video_encode_lock); + video_encode_hint_should_enable = false; + if (video_encode_hint_is_enabled == true) { + undo_hint_action(cur_hint_id); + video_encode_hint_is_enabled = false; + } + pthread_mutex_unlock(&video_encode_lock); return HINT_HANDLED; } } return HINT_NONE; } -int power_hint_override(struct power_module *module, power_hint_t hint, void *data) +/* Declare function before use */ +int interaction(int duration, int num_args, int opt_list[]); +int interaction_with_handle(int lock_handle, int duration, int num_args, int opt_list[]); + +static void power_hint_override(struct power_module *module, power_hint_t hint, void *data) { int ret_val = HINT_NONE; switch(hint) { case POWER_HINT_VIDEO_ENCODE: ret_val = process_video_encode_hint(data); break; + case POWER_HINT_INTERACTION: + { + int duration_hint = 0; + static unsigned long long previous_boost_time = 0; + + // little core freq bump for 1.5s + int resources[] = {0x20C}; + int duration = 1500; + static int handle_little = 0; + + // big core freq bump for 500ms + int resources_big[] = {0x2312, 0x1F08}; + int duration_big = 500; + static int handle_big = 0; + + // sched_downmigrate lowered to 10 for 1s at most + // should be half of upmigrate + int resources_downmigrate[] = {0x4F00}; + int duration_downmigrate = 1000; + static int handle_downmigrate = 0; + + // sched_upmigrate lowered to at most 20 for 500ms + // set threshold based on elapsed time since last boost + int resources_upmigrate[] = {0x4E00}; + int duration_upmigrate = 500; + static int handle_upmigrate = 0; + + // set duration hint + if (data) { + duration_hint = *((int*)data); + } + + struct timeval cur_boost_timeval = {0, 0}; + gettimeofday(&cur_boost_timeval, NULL); + unsigned long long cur_boost_time = cur_boost_timeval.tv_sec * 1000000 + cur_boost_timeval.tv_usec; + double elapsed_time = (double)(cur_boost_time - previous_boost_time); + if (elapsed_time > 750000) + elapsed_time = 750000; + // don't hint if it's been less than 250ms since last boost + // also detect if we're doing anything resembling a fling + // support additional boosting in case of flings + else if (elapsed_time < 250000 && duration_hint <= 750) + return; + + // 95: default upmigrate for phone + // 20: upmigrate for sporadic touch + // 750ms: a completely arbitrary threshold for last touch + int upmigrate_value = 95 - (int)(75. * ((elapsed_time*elapsed_time) / (750000.*750000.))); + + // keep sched_upmigrate high when flinging + if (duration_hint >= 750) + upmigrate_value = 20; + + previous_boost_time = cur_boost_time; + resources_upmigrate[0] = resources_upmigrate[0] | upmigrate_value; + resources_downmigrate[0] = resources_downmigrate[0] | (upmigrate_value / 2); + + // modify downmigrate duration based on interaction data hint + // 1000 <= duration_downmigrate <= 5000 + // extend little core freq bump past downmigrate to soften downmigrates + if (duration_hint > 1000) { + if (duration_hint < 5000) { + duration_downmigrate = duration_hint; + duration = duration_hint + 750; + } else { + duration_downmigrate = 5000; + duration = 5750; + } + } + + handle_little = interaction_with_handle(handle_little,duration, sizeof(resources)/sizeof(resources[0]), resources); + handle_big = interaction_with_handle(handle_big, duration_big, sizeof(resources_big)/sizeof(resources_big[0]), resources_big); + handle_downmigrate = interaction_with_handle(handle_downmigrate, duration_downmigrate, sizeof(resources_downmigrate)/sizeof(resources_downmigrate[0]), resources_downmigrate); + handle_upmigrate = interaction_with_handle(handle_upmigrate, duration_upmigrate, sizeof(resources_upmigrate)/sizeof(resources_upmigrate[0]), resources_upmigrate); + ret_val = HINT_HANDLED; + } + break; default: break; } @@ -127,7 +269,9 @@ int set_interactive_override(struct power_module *module, int on) /* Display off */ if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) && (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) { - int resource_values[] = {0x777}; /* 4+0 core config in display off */ + // sched upmigrate = 99, sched downmigrate = 95 + // keep the big cores around, but make them very hard to use + int resource_values[] = {0x4E63, 0x4F5F}; if (!display_hint_sent) { perform_hint_action(DISPLAY_STATE_HINT_ID, resource_values, sizeof(resource_values)/sizeof(resource_values[0])); diff --git a/power/power.c b/power/power.c index ba09319d..025f6f7f 100644 --- a/power/power.c +++ b/power/power.c @@ -195,6 +195,11 @@ int __attribute__ ((weak)) power_hint_override(struct power_module *module, powe return HINT_NONE; } + +/* Declare function before use */ +int interaction(int duration, int num_args, int opt_list[]); +int interaction_with_handle(int lock_handle, int duration, int num_args, int opt_list[]); + static void power_hint(struct power_module *module, power_hint_t hint, void *data) { diff --git a/power/utils.c b/power/utils.c index d750d3cf..d7755dd2 100644 --- a/power/utils.c +++ b/power/utils.c @@ -39,7 +39,7 @@ #include "hint-data.h" #include "power-common.h" -#define LOG_TAG "QCOM PowerHAL" +#define LOG_TAG "QCOMPowerHAL" #include char scaling_gov_path[4][80] ={ @@ -198,12 +198,12 @@ int get_scaling_governor_check_cores(char governor[], int size,int core_num) return 0; } -void interaction(int duration, int num_args, int opt_list[]) +int interaction(int duration, int num_args, int opt_list[]) { - static int lock_handle = 0; + int lock_handle = 0; if (duration < 0 || num_args < 1 || opt_list[0] == NULL) - return; + return 0; if (qcopt_handle) { if (perf_lock_acq) { @@ -212,6 +212,22 @@ void interaction(int duration, int num_args, int opt_list[]) ALOGE("Failed to acquire lock."); } } + return lock_handle; +} + +int interaction_with_handle(int lock_handle, int duration, int num_args, int opt_list[]) +{ + if (duration < 0 || num_args < 1 || opt_list[0] == NULL) + return 0; + + if (qcopt_handle) { + if (perf_lock_acq) { + lock_handle = perf_lock_acq(lock_handle, duration, opt_list, num_args); + if (lock_handle == -1) + ALOGE("Failed to acquire lock."); + } + } + return lock_handle; } void perform_hint_action(int hint_id, int resource_values[], int num_resources)