-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsetup-undervolt.sh
More file actions
executable file
·318 lines (269 loc) · 12.3 KB
/
setup-undervolt.sh
File metadata and controls
executable file
·318 lines (269 loc) · 12.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
#!/usr/bin/env bash
set -euo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
DIM='\033[2m'
NC='\033[0m'
die() { echo -e "${RED}FATAL: $*${NC}" >&2; exit 1; }
[[ $EUID -eq 0 ]] || die "Run with sudo: sudo $0"
SERVICE_FILE="/etc/systemd/system/cpu-undervolt.service"
STATE_FILE="/etc/cpu-undervolt-state"
BASHRC="$( eval echo ~${SUDO_USER:-$USER} )/.bashrc"
echo -e "\n${BOLD}=== Undervolt Setup ===${NC}\n"
# ---- 1. Add power function to bashrc ----------------------------------------
echo -e "${CYAN}[1/2] Adding 'power' command to bashrc...${NC}"
# Remove ALL old versions
while grep -q '# --- power: CPU undervolt manager' "$BASHRC" 2>/dev/null; do
sed -i '/^# --- power: CPU undervolt manager/,/^# --- end power ---$/d' "$BASHRC"
sed -i '/^# --- power: CPU undervolt manager/,/^}$/d' "$BASHRC"
done
sed -i '/^# --- end power ---$/d' "$BASHRC"
cat >> "$BASHRC" << 'ENDFUNC'
# --- power: CPU undervolt manager + system power stats ---
power() {
local RED="\033[0;31m" GREEN="\033[0;32m" YELLOW="\033[1;33m"
local CYAN="\033[0;36m" BOLD="\033[1m" DIM="\033[2m" NC="\033[0m"
_power_encode_msr() {
local plane=$1 mv=$2
local offset_1024=$(( (mv * 1024 + 500) / 1000 ))
if (( mv < 0 )); then
offset_1024=$(( (mv * 1024 - 500) / 1000 ))
fi
local masked=$(( offset_1024 & 0x7FF ))
local value=$(( 0x8000001100000000 | (plane << 40) | (masked << 21) ))
printf "0x%016X" "$value"
}
if [[ "${1:-}" == "-reset" ]]; then
echo -e "\n${BOLD}Resetting undervolt to 0mV...${NC}"
sudo bash -c 'modprobe msr 2>/dev/null; wrmsr -a 0x150 0x8000001100000000; wrmsr -a 0x150 0x8000021100000000; echo "0:0" > /etc/cpu-undervolt-state; systemctl stop cpu-undervolt.service 2>/dev/null; systemctl disable cpu-undervolt.service 2>/dev/null' 2>/dev/null
echo -e "${GREEN}Undervolt removed. Service disabled.${NC}"
echo -e "${DIM}Re-enable with: power -set <offset>${NC}\n"
return
fi
if [[ "${1:-}" == "-set" ]]; then
local core_mv="${2:-}"
local cache_mv="${3:-$core_mv}"
if [[ -z "$core_mv" ]]; then
echo -e "\n${BOLD}Usage:${NC}"
echo " power -set <offset> Same offset for core and cache"
echo " power -set <core> <cache> Different offsets"
echo ""
echo -e "${DIM}Examples:${NC}"
echo " power -set -100 -100mV on both"
echo " power -set -120 -100 -120mV core, -100mV cache"
echo ""
return 1
fi
if ! [[ "$core_mv" =~ ^-[0-9]+$ ]]; then
echo -e "${RED}Core offset must be a negative integer (got '$core_mv')${NC}"
return 1
fi
if ! [[ "$cache_mv" =~ ^-[0-9]+$ ]]; then
echo -e "${RED}Cache offset must be a negative integer (got '$cache_mv')${NC}"
return 1
fi
local core_hex cache_hex
core_hex=$(_power_encode_msr 0 "$core_mv")
cache_hex=$(_power_encode_msr 2 "$cache_mv")
local reset_core=$(_power_encode_msr 0 0)
local reset_cache=$(_power_encode_msr 2 0)
echo -e "\n${BOLD}Applying undervolt: core ${core_mv}mV / cache ${cache_mv}mV${NC}"
sudo bash -c "
modprobe msr 2>/dev/null
wrmsr -a 0x150 ${core_hex}
wrmsr -a 0x150 ${cache_hex}
echo '${core_mv}:${cache_mv}' > /etc/cpu-undervolt-state
cat > /etc/systemd/system/cpu-undervolt.service << SVCEOF
[Unit]
Description=Apply CPU undervolt (core ${core_mv}mV / cache ${cache_mv}mV)
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/bin/bash -c 'modprobe msr; wrmsr -a 0x150 ${core_hex}; wrmsr -a 0x150 ${cache_hex}; echo ${core_mv}:${cache_mv} > /etc/cpu-undervolt-state'
ExecStop=/bin/bash -c 'modprobe msr; wrmsr -a 0x150 ${reset_core}; wrmsr -a 0x150 ${reset_cache}; echo 0:0 > /etc/cpu-undervolt-state'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
SVCEOF
systemctl daemon-reload
systemctl enable cpu-undervolt.service
systemctl restart cpu-undervolt.service
" 2>/dev/null
echo -e "${GREEN}Undervolt applied. Service enabled for boot.${NC}"
echo -e "${DIM} Core: ${core_mv}mV (${core_hex})${NC}"
echo -e "${DIM} Cache: ${cache_mv}mV (${cache_hex})${NC}\n"
return
fi
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
echo -e "\n${BOLD}power${NC} — CPU undervolt manager + system stats"
echo ""
echo " power Show system power stats"
echo " power -set <offset> Apply offset to core + cache"
echo " power -set <core> <cache> Apply different core/cache offsets"
echo " power -reset Remove undervolt, disable service"
echo ""
echo -e "${DIM}Examples:${NC}"
echo " power -set -100 -100mV on both planes"
echo " power -set -120 -100 -120mV core, -100mV cache"
echo " power -reset Back to stock voltage"
echo ""
return
fi
# ---- Status display ----
echo ""
echo -e "${BOLD}══════════════════════════════════════${NC}"
echo -e "${BOLD} POWER STATUS${NC}"
echo -e "${BOLD}══════════════════════════════════════${NC}"
# -- Undervolt status --
local uv_state svc_active svc_enabled uv_core uv_cache
uv_state=$(cat /etc/cpu-undervolt-state 2>/dev/null || echo "unknown")
svc_active=$(systemctl is-active cpu-undervolt.service 2>/dev/null || echo "inactive")
svc_enabled=$(systemctl is-enabled cpu-undervolt.service 2>/dev/null || echo "not found")
uv_core="${uv_state%%:*}"
uv_cache="${uv_state##*:}"
echo -e "\n${CYAN} Undervolt${NC}"
if [[ "$svc_active" == "active" && "$uv_state" != "0:0" && "$uv_state" != "unknown" ]]; then
if [[ "$uv_core" == "$uv_cache" ]]; then
echo -e " Offset: ${GREEN}${uv_core}mV${NC} (Core + Cache)"
else
echo -e " Core: ${GREEN}${uv_core}mV${NC}"
echo -e " Cache: ${GREEN}${uv_cache}mV${NC}"
fi
echo -e " Service: ${GREEN}active, enabled at boot${NC}"
elif [[ "$svc_enabled" == "enabled" ]]; then
echo -e " Offset: ${YELLOW}${uv_core}:${uv_cache}mV (enabled but not confirmed active)${NC}"
echo -e " Service: ${YELLOW}${svc_active}${NC}"
else
echo -e " Offset: ${YELLOW}none${NC}"
echo -e " Service: ${YELLOW}${svc_enabled}${NC}"
fi
# -- CPU info --
echo -e "\n${CYAN} CPU${NC}"
local freqs avg_freq max_freq min_freq count=0 sum=0
while IFS= read -r f; do
local mhz=${f%%.*}
sum=$(( sum + mhz ))
count=$(( count + 1 ))
if [[ -z "${max_freq:-}" ]] || (( mhz > max_freq )); then max_freq=$mhz; fi
if [[ -z "${min_freq:-}" ]] || (( mhz < min_freq )); then min_freq=$mhz; fi
done < <(grep "cpu MHz" /proc/cpuinfo | awk '{print $4}')
if (( count > 0 )); then
avg_freq=$(( sum / count ))
echo -e " Avg freq: ${avg_freq} MHz"
echo -e " Range: ${min_freq}–${max_freq} MHz"
fi
local cpu_temp
cpu_temp=$(cat /sys/class/hwmon/hwmon6/temp1_input 2>/dev/null)
if [[ -n "$cpu_temp" ]]; then
echo -e " Pkg temp: $(( cpu_temp / 1000 ))°C"
fi
local gov
gov=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor 2>/dev/null || echo "unknown")
echo -e " Governor: ${gov}"
# -- GPU (NVIDIA) --
if command -v nvidia-smi &>/dev/null; then
local gpu_name gpu_temp gpu_power gpu_clock gpu_util
gpu_name=$(nvidia-smi --query-gpu=name --format=csv,noheader 2>/dev/null)
gpu_temp=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader,nounits 2>/dev/null)
gpu_power=$(nvidia-smi --query-gpu=power.draw --format=csv,noheader,nounits 2>/dev/null)
gpu_clock=$(nvidia-smi --query-gpu=clocks.current.graphics --format=csv,noheader,nounits 2>/dev/null)
gpu_util=$(nvidia-smi --query-gpu=utilization.gpu --format=csv,noheader,nounits 2>/dev/null)
if [[ -n "$gpu_name" ]]; then
echo -e "\n${CYAN} GPU${NC}"
echo -e " Model: ${gpu_name}"
echo -e " Temp: ${gpu_temp}°C"
echo -e " Power: ${gpu_power}W"
echo -e " Clock: ${gpu_clock} MHz"
echo -e " Usage: ${gpu_util}%"
fi
fi
# -- iGPU --
local igpu_freq
igpu_freq=$(cat /sys/class/drm/card1/gt_cur_freq_mhz 2>/dev/null)
if [[ -n "$igpu_freq" ]]; then
echo -e "\n${CYAN} iGPU${NC}"
echo -e " Freq: ${igpu_freq} MHz"
fi
# -- Battery --
local bat="/sys/class/power_supply/BAT0"
if [[ -d "$bat" ]]; then
local capacity status energy_now energy_full power_now health
capacity=$(cat "$bat/capacity" 2>/dev/null || echo "N/A")
status=$(cat "$bat/status" 2>/dev/null || echo "N/A")
energy_now=$(cat "$bat/energy_now" 2>/dev/null)
energy_full=$(cat "$bat/energy_full" 2>/dev/null)
energy_full_design=$(cat "$bat/energy_full_design" 2>/dev/null)
power_now=$(cat "$bat/power_now" 2>/dev/null)
local cycles
cycles=$(cat "$bat/cycle_count" 2>/dev/null || echo "N/A")
echo -e "\n${CYAN} Battery${NC}"
echo -e " Level: ${capacity}%"
echo -e " Status: ${status}"
if [[ -n "$power_now" && "$power_now" != "0" ]]; then
local watts
watts=$(awk "BEGIN {printf \"%.1f\", $power_now / 1000000}")
echo -e " Draw: ${watts}W"
if [[ -n "$energy_now" && "$status" == "Discharging" ]]; then
local hours_left
hours_left=$(awk "BEGIN {printf \"%.1f\", $energy_now / $power_now}")
echo -e " Remaining: ~${hours_left}h"
fi
fi
if [[ -n "$energy_full" && -n "$energy_full_design" ]]; then
health=$(awk "BEGIN {printf \"%.1f\", ($energy_full / $energy_full_design) * 100}")
echo -e " Health: ${health}%"
fi
echo -e " Cycles: ${cycles}"
fi
# -- AC power --
local ac_online
ac_online=$(cat /sys/class/power_supply/ADP0/online 2>/dev/null)
echo -e "\n${CYAN} Power Source${NC}"
if [[ "$ac_online" == "1" ]]; then
echo -e " AC: ${GREEN}plugged in${NC}"
else
echo -e " AC: ${YELLOW}on battery${NC}"
fi
# -- Memory --
local mem_info
mem_info=$(awk '/MemTotal/{t=$2} /MemAvailable/{a=$2} END{printf "%.1f / %.1f GB", (t-a)/1048576, t/1048576}' /proc/meminfo)
echo -e "\n${CYAN} Memory${NC}"
echo -e " Used: ${mem_info}"
echo -e "\n${BOLD}══════════════════════════════════════${NC}"
echo -e "${DIM} power -set <mV> | -reset | -h${NC}"
echo ""
}
# --- end power ---
ENDFUNC
echo -e " ${GREEN}Added 'power' command to $BASHRC${NC}"
# ---- 2. Remove unneeded packages --------------------------------------------
echo -e "\n${CYAN}[2/2] Cleaning up test dependencies...${NC}"
KEEP_PKGS=(msr-tools)
REMOVE_PKGS=(stress-ng s-tui)
to_remove=()
for pkg in "${REMOVE_PKGS[@]}"; do
if dpkg -l "$pkg" 2>/dev/null | grep -q "^ii"; then
to_remove+=("$pkg")
fi
done
if (( ${#to_remove[@]} > 0 )); then
echo " Removing: ${to_remove[*]}"
apt-get remove -y "${to_remove[@]}" > /dev/null 2>&1
apt-get autoremove -y > /dev/null 2>&1
echo -e " ${GREEN}Removed: ${to_remove[*]}${NC}"
else
echo -e " ${GREEN}Nothing to remove${NC}"
fi
echo -e " Keeping: ${KEEP_PKGS[*]} (needed for undervolt)"
# ---- Done --------------------------------------------------------------------
echo -e "\n${BOLD}${GREEN}=== Setup Complete ===${NC}\n"
echo " Open a new terminal and use:"
echo ""
echo " power -set -100 Apply -100mV to both planes"
echo " power -set -120 -100 Apply -120mV core, -100mV cache"
echo " power -reset Remove undervolt"
echo " power Show system stats"
echo ""