00 Linux thermal framework mimarisi
Linux thermal framework, sıcaklık sensörlerini, soğutma eylemlerini ve politika kararlarını birbirine bağlayan üç bileşenli bir altyapıdır.
┌──────────────────────────────────────────────────────┐
│ thermal core │
│ │
│ thermal_zone_device thermal_cooling_device │
│ │ │ │
│ trip_points cooling ops │
│ │ │ │
│ └───── governor ────────┘ │
│ (step_wise) │
└──────────┬────────────────────────┬─────────────────┘
│ │
┌──────▼──────┐ ┌──────▼──────┐
│ Temp Sensor │ │ Cooling Dev │
│ (NTC/SoC) │ │(cpufreq/fan)│
└─────────────┘ └─────────────┘
Temel bileşenler
Trip point türleri
01 DT thermal zone tanımı
Thermal zone'lar Device Tree'de tanımlanır. Sensör, trip point'ler ve cooling map'ler bir arada belirtilir.
/ {
thermal-zones {
cpu_thermal: cpu-thermal {
polling-delay-passive = <250>; /* ms, passive trip kontrolü */
polling-delay = <1000>; /* ms, normal polling */
/* Sıcaklık sensörü */
thermal-sensors = <&cpu_tsens 0>;
trips {
cpu_alert0: cpu-alert-0 {
temperature = <70000>; /* 70°C — milli-celsius */
hysteresis = <2000>; /* 2°C histerezis */
type = "passive";
};
cpu_alert1: cpu-alert-1 {
temperature = <80000>; /* 80°C */
hysteresis = <2000>;
type = "passive";
};
cpu_hot: cpu-hot {
temperature = <85000>; /* 85°C */
hysteresis = <2000>;
type = "hot";
};
cpu_crit: cpu-crit {
temperature = <95000>; /* 95°C — kritik */
hysteresis = <5000>;
type = "critical";
};
};
cooling-maps {
map0 {
trip = <&cpu_alert0>;
cooling-device = <&cpu0 THERMAL_NO_LIMIT 2>;
/* cooling state 0→2: frekansı %33 düşür */
};
map1 {
trip = <&cpu_alert1>;
cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
/* maksimum soğutma */
};
map2 {
trip = <&cpu_alert0>;
cooling-device = <&fan0 1 3>;
/* fan state 1→3: düşük→yüksek hız */
};
};
};
};
};
Çoklu thermal zone
thermal-zones {
cpu_thermal: cpu-thermal { thermal-sensors = <&tsens 0>; ... };
gpu_thermal: gpu-thermal { thermal-sensors = <&tsens 1>; ... };
board_thermal: board-thermal { thermal-sensors = <&ntc_sensor>; ... };
};
02 Cooling device türleri
Cooling device, bir sıcaklık eşiği aşıldığında sistemin sıcaklığını düşürmek için aldığı somut eylemdir. Her cihazın N+1 adet "state"i vardır (0 = soğutma yok, N = maksimum soğutma).
cpufreq cooling (cpu-thermal)
# cpu-thermal cooling device state'leri
cat /sys/class/thermal/cooling_device0/type
# thermal-cpufreq-0
cat /sys/class/thermal/cooling_device0/max_state
# 4 (4 = en yüksek throttling)
cat /sys/class/thermal/cooling_device0/cur_state
# 0 (şu an throttling yok)
# elle state değiştir (test için)
echo 2 > /sys/class/thermal/cooling_device0/cur_state
PWM fan cooling
fan0: pwm-fan {
compatible = "pwm-fan";
pwms = <&pwm1 0 10000 0>; /* 100Hz PWM */
#cooling-cells = <2>;
cooling-levels = <0 64 128 192 255>; /* 5 state: kapalı→tam */
};
# fan cooling device
cat /sys/class/thermal/cooling_device1/type
# pwm-fan
cat /sys/class/thermal/cooling_device1/max_state
# 4
# fan'ı orta hıza al (state 2)
echo 2 > /sys/class/thermal/cooling_device1/cur_state
devfreq cooling
gpu: gpu@ff300000 {
compatible = "rockchip,rk3399-mali";
#cooling-cells = <2>;
operating-points-v2 = <&gpu_opp_table>;
};
/* thermal zone cooling-map'te */
map_gpu {
trip = <&cpu_alert1>;
cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
};
03 Thermal governor — step_wise, bang_bang, fair_share
Thermal governor, sıcaklık trip'lerle karşılaşıldığında cooling device state'ini nasıl ayarlayacağına karar verir.
# mevcut governor
cat /sys/class/thermal/thermal_zone0/policy
# step_wise
# mevcut seçenekler
cat /sys/class/thermal/thermal_zone0/available_policies
# step_wise fair_share bang_bang user_space
# user_space moduna geç (thermald için)
echo user_space > /sys/class/thermal/thermal_zone0/policy
step_wise algoritması
for each trip_point (high → low sıcaklık):
if temp >= trip_temp:
if cur_state < max_state:
cur_state++ /* bir adım daha soğut */
break
else if temp < (trip_temp - hysteresis):
if cur_state > 0:
cur_state-- /* bir adım gevşet */
04 sysfs arayüzü — okuma ve kontrol
/sys/class/thermal/ altında her thermal zone ve cooling device için ayrı bir dizin bulunur.
# tüm thermal zone'ları listele
ls /sys/class/thermal/
# cooling_device0 cooling_device1 thermal_zone0 thermal_zone1
# zone0 sıcaklığını oku (milli-Celsius)
cat /sys/class/thermal/thermal_zone0/temp
# 52000 → 52°C
# zone0 tipi
cat /sys/class/thermal/thermal_zone0/type
# cpu-thermal
# trip point'leri oku
cat /sys/class/thermal/thermal_zone0/trip_point_0_temp
# 70000 → 70°C
cat /sys/class/thermal/thermal_zone0/trip_point_0_type
# passive
# tüm zone'ların sıcaklığını tek satırda izle
watch -n1 'for z in /sys/class/thermal/thermal_zone*/; do
name=$(cat "${z}type" 2>/dev/null)
temp=$(cat "${z}temp" 2>/dev/null)
echo "${name}: $((temp/1000))°C"
done'
# cooling device durumu
for cd in /sys/class/thermal/cooling_device*/; do
type=$(cat "${cd}type")
cur=$(cat "${cd}cur_state")
max=$(cat "${cd}max_state")
echo "$type: $cur/$max"
done
Trip point'leri sysfs'ten değiştir
# trip_point sıcaklığını değiştir (root gerekli)
echo 75000 > /sys/class/thermal/thermal_zone0/trip_point_0_temp
# thermal zone'u izleme moduna al veya devre dışı bırak
cat /sys/class/thermal/thermal_zone0/mode
# enabled
echo disabled > /sys/class/thermal/thermal_zone0/mode
echo enabled > /sys/class/thermal/thermal_zone0/mode
05 Ölçüm ve test — stress-ng, thermald
Thermal sistemini test etmek için CPU'yu ısıtmak ve throttling başlangıcını gözlemlemek gerekir.
stress-ng ile ısınma testi
# 4 CPU worker ile 60 saniye yükle
stress-ng --cpu 4 --timeout 60s &
# eş zamanlı sıcaklık ve frekans izle
while true; do
temp=$(cat /sys/class/thermal/thermal_zone0/temp)
freq=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq)
cstate=$(cat /sys/class/thermal/cooling_device0/cur_state 2>/dev/null || echo N/A)
printf "[%s] Temp: %d°C Freq: %dMHz CoolState: %s\n" \
"$(date +%T)" "$((temp/1000))" "$((freq/1000))" "$cstate"
sleep 1
done
thermald daemon
# Ubuntu/Debian
apt install thermald
# thermald başlat
systemctl enable --now thermald
# durum
systemctl status thermald
# ● thermald.service - Thermal Daemon Service
# Loaded: loaded (/lib/systemd/system/thermald.service)
# Active: active (running)
# özel thermal konfigürasyon
cat /etc/thermald/thermal-conf.xml
# thermald politikasını özelleştirmek için XML dosyasını düzenle
# debug modu
thermald --no-daemon --loglevel=debug 2>&1 | grep -E "(zone|trip|cool)"
Thermal event izleme (NETLINK)
#!/usr/bin/env python3
"""Kernel thermal event'lerini NETLINK üzerinden izle"""
import socket, struct
NETLINK_KOBJECT_UEVENT = 15
sock = socket.socket(socket.AF_NETLINK,
socket.SOCK_RAW,
NETLINK_KOBJECT_UEVENT)
sock.bind((0, 1))
print("Thermal event'ler bekleniyor...")
while True:
data = sock.recv(4096).decode('utf-8', errors='ignore')
if 'thermal' in data.lower() or 'TEMP' in data:
events = [e for e in data.split('\x00') if e]
for e in events:
if any(k in e for k in ['TEMP', 'thermal', 'trip']):
print(f" {e}")
06 ACPI thermal — laptop senaryosu
x86 laptop/sunucu sistemlerde thermal zone'lar ACPI BIOS tabloları tarafından tanımlanır. Linux bu bilgileri ACPI _TZ (Thermal Zone) metodları aracılığıyla okur.
# ACPI thermal zone'ları listele
ls /sys/bus/acpi/devices/ | grep TZ
# ACPI0008:00 TZ00 TZ01
# ACPI thermal zone bilgisi
cat /sys/class/thermal/thermal_zone0/type
# acpitz
# acpi_dump ile ACPI tablolarını oku
acpidump | acpixtract -a
iasl -d DSDT.dat
grep -A20 "ThermalZone" DSDT.dsl | head -40
# thermal ACPI event'lerini izle
acpi_listen
# ACPI group thermal PNP0C14:00 0000005c 00000000
07 Kernel config ve sensor driver
Thermal framework için temel Kconfig seçenekleri ve yaygın sensör driver'ları.
CONFIG_THERMAL=y
CONFIG_THERMAL_OF=y # Device Tree binding
CONFIG_THERMAL_STATISTICS=y # sysfs istatistikleri
CONFIG_THERMAL_WRITABLE_TRIPS=y # sysfs'ten trip değiştirme
# Governor'lar
CONFIG_THERMAL_GOV_STEP_WISE=y
CONFIG_THERMAL_GOV_BANG_BANG=y
CONFIG_THERMAL_GOV_FAIR_SHARE=y
CONFIG_THERMAL_GOV_USER_SPACE=y
# Cooling device'lar
CONFIG_CPU_THERMAL=y # cpufreq cooling
CONFIG_DEVFREQ_THERMAL=y # devfreq cooling
CONFIG_THERMAL_EMULATION=y # test için sıcaklık emülasyonu
# Platform sensor driver'ları
CONFIG_IMX_THERMAL=y # i.MX6/7/8 TMPMON
CONFIG_ROCKCHIP_THERMAL=y # RK3368/3399/3568
CONFIG_BCM2711_THERMAL=y # Raspberry Pi 4
# Harici sensörler (hwmon bridge)
CONFIG_NTC_THERMISTOR=y # NTC termistör
CONFIG_SENSORS_BD70528=y # ROHM BD718xx PMIC sensörü
NTC termistör DT tanımı
/ {
/* Sabit voltaj bölücü için */
ntc_vref: ntc-vref {
compatible = "voltage-divider";
io-channels = <&adc 0>;
output-ohms = <10000>; /* pull-up R: 10kΩ */
full-ohms = <20000>; /* tam ölçek R */
};
ntc_temp: ntc-thermistor {
compatible = "epcos,b57891s0103"; /* NTC B57891S0103A010 */
io-channels = <&ntc_vref>;
#thermal-sensor-cells = <0>;
};
thermal-zones {
board_thermal: board-thermal {
thermal-sensors = <&ntc_temp>;
polling-delay = <5000>;
trips {
board_hot {
temperature = <60000>;
type = "hot";
hysteresis = <2000>;
};
};
};
};
};
08 Pratik: i.MX8 cooling chain · RPi overtemp · custom policy
Üç pratik senaryo: i.MX8'de CPU freq cooling zinciri inceleme, Raspberry Pi'de overtemp uyarısı ve özel thermal policy scripti.
1 — i.MX8 Thermal Zone + CPU Freq Cooling Chain
# i.MX8 TMPMON thermal zone'ları
ls /sys/class/thermal/
# cooling_device0 thermal_zone0 thermal_zone1
cat /sys/class/thermal/thermal_zone0/type
# imx_thermal_zone
cat /sys/class/thermal/thermal_zone1/type
# imx_thermal_zone
# trip point yapısını oku
for i in 0 1 2; do
temp=$(cat /sys/class/thermal/thermal_zone0/trip_point_${i}_temp 2>/dev/null)
type=$(cat /sys/class/thermal/thermal_zone0/trip_point_${i}_type 2>/dev/null)
echo "trip$i: ${temp}m°C ($((temp/1000))°C) — $type"
done
# trip0: 85000m°C (85°C) — passive
# trip1: 95000m°C (95°C) — hot
# trip2: 105000m°C (105°C) — critical
# cooling zincirini test et (stress ile)
stress-ng --cpu 4 --timeout 120s &
STRESS_PID=$!
while kill -0 $STRESS_PID 2>/dev/null; do
temp=$(cat /sys/class/thermal/thermal_zone0/temp)
freq=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq)
cstate=$(cat /sys/class/thermal/cooling_device0/cur_state)
echo "[$(date +%T)] ${temp}m°C | ${freq}kHz | cooling_state=$cstate"
sleep 2
done
2 — Raspberry Pi Overtemp Uyarısı
# RPi'de iki yöntem: vcgencmd ve sysfs
vcgencmd measure_temp
# temp=52.1'C
cat /sys/class/thermal/thermal_zone0/temp
# 52104
# RPi throttling eşikleri:
# 80°C → CPU freq cap başlar
# 85°C → CPU throttle (1.5GHz → 600MHz)
# 90°C → ARM freq drop
# 95°C → critical
# overtemp LED göstergesi scripti
cat <<'EOF' > /usr/local/bin/thermal_led.sh
#!/bin/bash
TEMP_WARN=75000 # 75°C
TEMP_CRIT=85000 # 85°C
LED=/sys/class/leds/ACT/trigger
while true; do
temp=$(cat /sys/class/thermal/thermal_zone0/temp)
if [ "$temp" -ge "$TEMP_CRIT" ]; then
echo "timer" > $LED # hızlı yanıp sönme
logger -p daemon.warning "CPU CRITICAL TEMP: $((temp/1000))C"
elif [ "$temp" -ge "$TEMP_WARN" ]; then
echo "heartbeat" > $LED # yavaş yanıp sönme
else
echo "none" > $LED # normal
fi
sleep 5
done
EOF
chmod +x /usr/local/bin/thermal_led.sh
3 — Özel Thermal Policy Scripti
#!/usr/bin/env python3
"""
Özel thermal policy: sıcaklığa göre fan hızı + CPU freq kombinasyonu.
Gereksinim: thermal_zone0 user_space policy, fan ve cpufreq cooling device.
"""
import time, os, subprocess
ZONE = "/sys/class/thermal/thermal_zone0"
FAN_CD = "/sys/class/thermal/cooling_device1" # pwm-fan
CPU_CD = "/sys/class/thermal/cooling_device0" # cpufreq
def read_temp():
with open(f"{ZONE}/temp") as f:
return int(f.read().strip()) // 1000 # °C
def set_cooling(device, state):
with open(f"{device}/cur_state", 'w') as f:
f.write(str(state))
def get_max_state(device):
with open(f"{device}/max_state") as f:
return int(f.read().strip())
def policy(temp_c):
"""Sıcaklığa göre fan ve CPU state döndür"""
if temp_c < 50: return 0, 0 # fan kapalı, CPU tam hız
elif temp_c < 60: return 1, 0 # fan düşük, CPU normal
elif temp_c < 70: return 2, 1 # fan orta, CPU hafif throttle
elif temp_c < 80: return 3, 2 # fan yüksek, CPU throttle
else: return 4, 4 # fan max, CPU min
# user_space policy aktifleştir
with open(f"{ZONE}/policy", 'w') as f:
f.write("user_space")
FAN_MAX = get_max_state(FAN_CD)
CPU_MAX = get_max_state(CPU_CD)
print("Thermal policy başlatıldı")
while True:
temp = read_temp()
fan_state, cpu_state = policy(temp)
# state'leri sınırla
fan_state = min(fan_state, FAN_MAX)
cpu_state = min(cpu_state, CPU_MAX)
set_cooling(FAN_CD, fan_state)
set_cooling(CPU_CD, cpu_state)
print(f"[{time.strftime('%H:%M:%S')}] "
f"Temp={temp}°C Fan={fan_state}/{FAN_MAX} "
f"CPU_throttle={cpu_state}/{CPU_MAX}")
time.sleep(5)
Özel policy script'i systemd service olarak çalıştırmak için Restart=always ve RestartSec=5 ekle. Policy daemon çöktüğünde sistem çok yüksek sıcaklıkta sınırsız çalışabilir; bu kritik bir güvenlik riskidir. Watchdog entegrasyonu zorunludur.