diff options
author | Sameer Nanda <snanda@chromium.org> | 2012-07-27 15:33:21 -0700 |
---|---|---|
committer | Gerrit <chrome-bot@google.com> | 2012-07-30 14:15:03 -0700 |
commit | c846102714e5b31abe19330f9102762c89910ed7 (patch) | |
tree | 51c501df9e396266471684b763d441854dceb07d | |
parent | 7d06db201fb2eded0bd45a10a460756007eb0679 (diff) | |
download | chrome-ec-c846102714e5b31abe19330f9102762c89910ed7.tar.gz |
Add a userland thermal loop
This is a temporary hack to implement a userland thermal loop. This
code really belongs in the BIOS and will move there once we have
gathered enough data to prove the efficacy (or otherwise) of doing such
throttling. So, please pardon the ugliness of the code -- it's meant to
be short-lived and therefore we wouldn't want to spend too much time on
optimizing it or making it pretty.
BUG=none
TEST="initctl start temp_metrics" and then monitor various parameters
such as CPU min/max frequency, GPU frequency, duty cycle and package
power limits to ensure they are doing the right thing.
Change-Id: I407e4826b4db801298f08fa72c4f2330e127322b
Signed-off-by: Sameer Nanda <snanda@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/28634
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r-- | util/temp_metrics.conf | 196 |
1 files changed, 194 insertions, 2 deletions
diff --git a/util/temp_metrics.conf b/util/temp_metrics.conf index be8138aea3..6a2aa3fc30 100644 --- a/util/temp_metrics.conf +++ b/util/temp_metrics.conf @@ -2,21 +2,213 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -description "Temporary, quick-hack metrics collection daemon" +description "Temporary, quick-hack metrics collection & thermal daemon" author "chromium-os-dev@chromium.org" # This is for quickly adding UMA stats that we may need for # short-term experiments, when we don't have the time to add # stuff to metrics_daemon. That's where it should go in the # long term. +# +# This is also currently doing a userland thermal loop to allow +# for quick experimentation. This thermal loop will eventually +# move to the BIOS once the data from experiments help prove its +# efficacy. + start on started system-services stop on stopping system-services respawn script TEMP_OFFSET=273 # difference between K (reported by EC) and C (used in UMA) + PECI_TEMP_THRESHOLD=77 # CPU temperature threshold + + # Thermal loop fields + CPU_MAX_FREQ_FIELD=1 + CPU_MIN_FREQ_FIELD=2 + GPU_MAX_FREQ_FIELD=3 + CPU_DUTY_CYCLE_FIELD=4 + PKG_POWER_LIMIT_FIELD=5 + + # Thermal loop steps + all_steps=" + 1801000 800000 1150 0 0x180aa00dd8088 # no throttling + 1801000 800000 1150 0 0x180aa00dd8080 # cap pkg to 16W + 1801000 800000 1150 0 0x180aa00dd8078 # cap pkg to 15W + 1801000 800000 1150 0 0x180aa00dd8070 # cap pkg to 14W + 1801000 800000 1150 0 0x180aa00dd8068 # cap pkg to 13W + 1800000 800000 900 0 0x180aa00dd8068 # disable turbo + 1600000 800000 800 0 0x180aa00dd8068 # cap CPU & GPU frequency + 1400000 800000 700 0 0x180aa00dd8068 # cap CPU & GPU frequency + 1200000 800000 600 0 0x180aa00dd8068 # cap CPU & GPU frequency + 1000000 800000 500 0 0x180aa00dd8068 # cap CPU & GPU frequency + 800000 800000 400 0 0x180aa00dd8068 # cap CPU & GPU frequency + 800000 800000 350 0 0x180aa00dd8068 # cap CPU & GPU frequency + 800000 800000 350 0x1c 0x180aa00dd8068 # duty cycle CPU + 800000 800000 350 0x18 0x180aa00dd8068 # duty cycle CPU + " + max_steps=$(($(echo "$all_steps" | wc -l) - 3)) + + get_step() { + row=$(($1 + 2)) + out=$(echo "$all_steps" | awk "{if (NR==$row) print}") + echo "$out" + } + + get_field() { + #out=$(echo "$2" | awk -v z=$1 '{print $z}') + out=$(echo "$2" | awk "{print \$$1}") + echo $out + } + + get_peci_temp() { + tempk=$(ectool temps 9 | sed 's/[^0-9]//g') + tempc=$((tempk - $TEMP_OFFSET)) + echo $tempc + } + + set_cpu_freq() { + max_freq=$1 + min_freq=$2 + for cpu in /sys/devices/system/cpu/cpu?/cpufreq; do + echo 800000 > $cpu/scaling_min_freq + echo 800000 > $cpu/scaling_max_freq + echo $max_freq > $cpu/scaling_max_freq + echo $min_freq > $cpu/scaling_min_freq + done + } + + set_gpu_freq() { + gpu_freq=$1 + echo $gpu_freq > /sys/kernel/debug/dri/0/i915_max_freq + } + + set_duty_cycle() { + duty_cycle=$1 + for i in 0 1 2 3; do + wrmsr $i 0x19a $duty_cycle + done + } + + set_pkg_power_limit() { + pwr_limit=$1 + wrmsr 0 0x610 $pwr_limit + } + + disable_external_prochot() { + wrmsr 0 0x1fc 0x000000000004005e + } + + current_step=1 + new_step=0 + + thermal_loop() { + peci_temp=$1 + if [ $peci_temp -gt $PECI_TEMP_THRESHOLD ]; then + if [ $current_step -ne $max_steps ]; then + new_step=$(($current_step + 1)) + fi + elif [ $peci_temp -lt $PECI_TEMP_THRESHOLD ]; then + if [ $current_step -gt 0 ]; then + new_step=$(($current_step - 1)) + fi + else + new_step=$current_step + fi + + if [ $new_step -eq $current_step ]; then + return + fi + + current_step=$new_step + step=$(get_step $new_step) + + cpu_max_freq=$(get_field $CPU_MAX_FREQ_FIELD "$step") + cpu_min_freq=$(get_field $CPU_MIN_FREQ_FIELD "$step") + gpu_max_freq=$(get_field $GPU_MAX_FREQ_FIELD "$step") + cpu_duty_cycle=$(get_field $CPU_DUTY_CYCLE_FIELD "$step") + pkg_power_limit=$(get_field $PKG_POWER_LIMIT_FIELD "$step") + + set_cpu_freq $cpu_max_freq $cpu_min_freq + set_gpu_freq $gpu_max_freq + set_duty_cycle $cpu_duty_cycle + set_pkg_power_limit $pkg_power_limit + } + + fan_reset_thresholds() { + temp_low1=105 + temp_low2=105 + temp_low3=105 + temp_low4=105 + temp_low5=105 + } + + last_rpm=10 + temp_low1=105 + temp_low2=105 + temp_low3=105 + temp_low4=105 + temp_low5=105 + + fan_loop() { + peci_temp=$1 + + if [ $peci_temp -gt 77 ] || [ $peci_temp -gt $temp_low1 ]; then + rpm=9300 + fan_reset_thresholds + temp_low1=68 + elif [ $peci_temp -gt 68 ] || [ $peci_temp -gt $temp_low2 ]; then + rpm=7725 + fan_reset_thresholds + temp_low2=61 + elif [ $peci_temp -gt 61 ] || [ $peci_temp -gt $temp_low3 ]; then + rpm=6150 + fan_reset_thresholds + temp_low3=54 + elif [ $peci_temp -gt 54 ] || [ $peci_temp -gt $temp_low4 ]; then + rpm=4575 + fan_reset_thresholds + temp_low4=47 + elif [ $peci_temp -gt 47 ] || [ $peci_temp -gt $temp_low5 ]; then + rpm=3000 + fan_reset_thresholds + temp_low5=41 + else + rpm=0 + fan_reset_thresholds + fi + + if [ $last_rpm -eq $rpm ]; then + return + fi + + last_rpm=$rpm + ectool pwmsetfanrpm $rpm + } + + # External prochot misfires occasionally. Disable it. + disable_external_prochot + + loop_count=0 while true; do - sleep 30 + sleep 1 + loop_count=$(($loop_count + 1)) + + # read the CPU temperature + cpu_temp=$(get_peci_temp) + + # run the fan loop once a second + fan_loop $cpu_temp + + # run the thermal loop once a second + thermal_loop $cpu_temp + + # report the metrics once every 30 seconds + if [ $loop_count -lt 30 ]; then + continue + fi + loop_count=0 + ectool temps all | while read line; do index=$(printf "%02d" "${line%%:*}") tempk="${line##* }" |