Güç Yönetimi & Thermal
TEKNİK REHBER GÜÇ YÖNETİMİ CPUIDLE 2026

cpuidle —
CPU uyku halleri.

C-state latency/residency dengelemi, PSCI ile ARM koordinasyonu, menu ve TEO governor'ları — boşta geçen her mikrosaniyeyi enerji tasarrufuna dönüştür.

00 cpuidle nedir — C-states ve idle driver

CPU boşta kaldığında — çalışacak görev yokken — enerji tüketmeye devam eder. cpuidle subsystem, boşta geçen süreyi güce çevirme fırsatı olarak görür ve CPU'yu farklı "uyku derinliği" kademelerine sokar.

Bu kademelere C-state (veya idle state) denir. C0 tamamen aktif, C1'den itibaren giderek daha derin uyku. Her uyku derinliği daha az güç tüketir ama uyanma için daha uzun süre harcar.

clock gating vs power gating

Clock gating (sığ uyku)
CPU'nun clock sinyali durdurulur; devreler güçlendirilmiş kalır. Uyanma çok hızlı (<1 µs), güç tasarrufu az.
Power gating (derin uyku)
CPU'nun güç kaynağı kesilir; register içeriği SRAM'e kaydedilir. Uyanma yavaş (100-1000 µs), güç tasarrufu büyük.
Cluster power-down
Tüm cluster (birden fazla CPU) kapanır; paylaşılan L2 cache flush gerekir. En derin uyku — PSCI ile koordine edilir.

idle driver türleri

bash
# aktif cpuidle driver
cat /sys/devices/system/cpu/cpuidle/current_driver
# arm_idle  (veya psci, acpi_idle, intel_idle)

# mevcut governor
cat /sys/devices/system/cpu/cpuidle/current_governor
# menu

# kullanılabilir governor'lar
cat /sys/devices/system/cpu/cpuidle/available_governors
# ladder menu teo

01 C-state anatomisi — latency, residency, tradeoff

Her C-state dört temel parametreyle tanımlanır. Governor, bu parametrelerle beklenen boş kalma süresini karşılaştırarak en uygun uyku derinliğini seçer.

exit latency
C-state'ten çıkıp CPU'nun tekrar görev çalıştırabilir hale gelmesi için gereken süre (µs). Gecikme toleransı için üst sınır.
target residency
Bu C-state'e girmenin "kârlı" olması için gereken minimum bekleme süresi (µs). exit latency'den büyük olmalı.
power (idle power)
Bu C-state'te tüketilen güç (mW veya uW). Derin uyku = düşük güç.
flags
CPUIDLE_FLAG_TIMER_STOP: bu state'te local timer durur. CPUIDLE_FLAG_COUPLED: cluster-level uyku.

Örnek: Cortex-A53 C-state tablosu

Cortex-A53 (tipik değerler)
State  Name           Exit Lat  Residency  Power
 C0    WFI (wait)        1 µs       2 µs   ~80% aktif
 C1    CPU idle         10 µs      20 µs   ~30% aktif
 C2    Cluster idle    200 µs     400 µs   ~5% aktif
 C3    SoC sleep      1000 µs    2000 µs   ~1% aktif

Tradeoff: derin uyku her zaman daha iyi değil

Eğer CPU 50 µs sonra yeniden uyanacaksa, 200 µs exit latency'li C2'ye girmenin anlamı yoktur. Governor bu kararı beklenen idle süresini tahmin ederek verir. Yanlış tahmin performansı düşürür.

Maliyet analizi örneği
# Senaryo: 300 µs boş kalma beklentisi
# C1: exit_lat=10µs, power_saving=50µW × 300µs = 15nJ tasarruf
# C2: exit_lat=200µs, power_saving=75µW × (300-200)µs = 7.5nJ tasarruf
# Sonuç: C1 daha kârlı, C2'ye girme!

# Senaryo: 5000 µs boş kalma beklentisi
# C2: 75µW × (5000-200)µs = 360nJ tasarruf — C2 mantıklı

02 idle governor — menu, ladder, TEO

idle governor, CPU'nun boşta kalma süresini tahmin eder ve en uygun C-state'i seçer. Üç ana governor mevcuttur.

menu governor (varsayılan)

Linux'un varsayılan idle governor'ıdır. Tahmin için iki girdi kullanır: (1) bir sonraki zamanlayıcı olayına kalan süre, (2) geçmişteki boşta kalma sürelerinin istatistiksel ortalaması. Gerçek zamanlı olmayan sistemlerin büyük çoğunluğu için en iyi seçenektir.

bash — menu governor seç
echo menu > /sys/devices/system/cpu/cpuidle/current_governor

ladder governor

ACPI sistemler için tasarlanmış basit bir governor. Her idle geçişinde bir sonraki derinlik kademesine iner (ladder = merdiven). Çok kısa idle sürelerinde aşırı derin uyku girme riski vardır; tickful HZ=100/250 sistemlerde kullanılır.

TEO — Timer Events Oriented governor

Linux 5.1'de eklendi. Sadece timer'a değil, interrupt gelme örüntüsüne de bakar. NO_HZ_IDLE (tickless) sistemlerde timer dışı wakeup'ları daha iyi modelleyerek menu'den daha isabetli kararlar verebilir.

bash
# TEO governor'a geç
echo teo > /sys/devices/system/cpu/cpuidle/current_governor

# governor değişikliğini doğrula
cat /sys/devices/system/cpu/cpuidle/current_governor
# teo

Governor seçim rehberi

Senaryo → Governor
Genel amaçlı (HZ=250/CONFIG_HZ_250)  → menu
Tickless (CONFIG_NO_HZ_IDLE)          → teo (dene, karşılaştır)
ACPI tabanlı eski x86               → ladder (kernel default)
Gerçek zamanlı (PREEMPT_RT)         → menu + pm_qos kısıtı

03 PSCI — Power State Coordination Interface

PSCI (ARM Specification IHI0054), birden fazla CPU'lu ARM sistemlerde uyku/uyanma işlemlerini güvenli biçimde koordine eden bir firmware arayüzüdür. Linux cpuidle bu arayüzü kullanarak ARM Trusted Firmware veya U-Boot SPL ile iletişim kurar.

PSCI sürümleri ve fonksiyonlar

CPU_SUSPEND (0x84000001)
Tek CPU'yu belirtilen power state'e sokar. Kernel cpuidle'ın temel çağrısı.
CPU_OFF (0x84000002)
CPU'yu tamamen kapatır. Hotplug ile kullanılır.
CPU_ON (0xC4000003)
Kapalı CPU'yu belirtilen entry point'ten başlatır.
AFFINITY_INFO (0xC4000004)
Bir CPU veya cluster'ın güç durumunu sorgular (ON/OFF/ON_PENDING).
SYSTEM_SUSPEND (0x8400000E)
Tüm sistemi suspend-to-RAM için hazırlar. suspend-resume subsystem ile kullanılır.

DT PSCI node tanımı

dts
/ {
    psci {
        compatible = "arm,psci-1.0";
        method = "smc";   /* Secure Monitor Call; bazı SoC'larda "hvc" */
    };

    cpus {
        cpu@0 {
            compatible = "arm,cortex-a53";
            enable-method = "psci";   /* PSCI kullan */
            cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
        };
    };

    idle-states {
        entry-method = "arm,psci";

        CPU_SLEEP_0: cpu-sleep-0 {
            compatible = "arm,idle-state";
            arm,psci-suspend-param = <0x0010000>;  /* power state encoding */
            entry-latency-us  = <40>;
            exit-latency-us   = <100>;
            min-residency-us  = <150>;
        };

        CLUSTER_SLEEP_0: cluster-sleep-0 {
            compatible = "arm,idle-state";
            arm,psci-suspend-param = <0x1010000>;
            entry-latency-us  = <500>;
            exit-latency-us   = <1000>;
            min-residency-us  = <2500>;
            local-timer-stop; /* cluster sleep sırasında timer durur */
        };
    };
};
bash — PSCI doğrulama
# PSCI versiyon ve özellikleri
cat /sys/kernel/debug/psci
# PSCI version: 1.1
# SYSTEM_SUSPEND: supported

# ya da dmesg'de
dmesg | grep -i psci
# [    0.000000] psci: probing for conduit method from DT.
# [    0.000000] psci: PSCIv1.1 detected in firmware.

04 sysfs arayüzü — state kontrolü

/sys/devices/system/cpu/cpu0/cpuidle/ altında her C-state için bir dizin bulunur. Bu arayüzden state istatistikleri izlenebilir ve bireysel state'ler devre dışı bırakılabilir.

bash
# CPU0 idle state'leri listele
ls /sys/devices/system/cpu/cpu0/cpuidle/
# state0  state1  state2

# state1 bilgilerini oku
cat /sys/devices/system/cpu/cpu0/cpuidle/state1/name
# cpu-sleep-0

cat /sys/devices/system/cpu/cpu0/cpuidle/state1/latency
# 100  (µs)

cat /sys/devices/system/cpu/cpu0/cpuidle/state1/residency
# 150  (µs)

cat /sys/devices/system/cpu/cpu0/cpuidle/state1/usage
# 42831  (kaç kez girildi)

cat /sys/devices/system/cpu/cpu0/cpuidle/state1/time
# 1847392  (toplam geçirilen süre, µs)

# state1'i devre dışı bırak
echo 1 > /sys/devices/system/cpu/cpu0/cpuidle/state1/disable

# tüm CPU'larda state2'yi kapat (yüksek gecikme durumunu engelle)
for cpu in /sys/devices/system/cpu/cpu*/cpuidle/state2/disable; do
    echo 1 > "$cpu"
done

# tüm state'leri görüntüle (tüm CPU)
for state in /sys/devices/system/cpu/cpu0/cpuidle/state*/; do
    name=$(cat "${state}name")
    lat=$(cat  "${state}latency")
    usage=$(cat "${state}usage")
    echo "  $name  latency=${lat}µs  usage=${usage}"
done
DİKKAT

Derin C-state'leri (cluster sleep) devre dışı bırakmak güç tüketimini artırır ama wakeup latency'yi garanti altına alır. Gerçek zamanlı görevlerin bulunduğu sistemlerde pm_qos ile daha kontrollü bir yaklaşım tercih edilmelidir.

05 Ölçüm araçları — cpupower, powertop, perf

C-state kullanım oranlarını ve etkinliğini ölçmek için birden fazla araç mevcuttur. Her biri farklı bir perspektif sunar.

cpupower idle-info

bash
cpupower idle-info
# CPUIdle driver: arm_idle
# CPUIdle governor: menu
# Number of idle states: 3
#
# Idle state name            : WFI
#   Flags/Description        : ARM WFI
#   Exit latency             : 1 us
#   Power usage              : 1 mW
#   Residency                : 1 us
#   Usage                    : 2847391
#   Duration                 : 8291827 us
#
# Idle state name            : cpu-sleep-0
#   Exit latency             : 100 us
#   Usage                    : 47821
#   Duration                 : 9182736 us

powertop — C-state dağılımı

bash
# interaktif arayüz (Tab ile sekmeler arası geç)
powertop

# 30 saniye CSV raporu
powertop --csv=idle_report.csv --time=30

# HTML raporu
powertop --html=idle_report.html --time=30

perf ile C-state geçişleri

bash
# cpu-cycles sayacı (idle'da 0 olması gerekir)
perf stat -e cpu/cpu-cycles/,cpu/instructions/ sleep 5

# idle tracepoint'leri izle
perf trace -e cpu_idle sleep 5
# cpu_idle: state=1 cpu_id=0
# cpu_idle: state=4294967295 cpu_id=0  (wakeup: state=-1)

# C-state istatistiklerini sysfs'ten hızlı oku
for cpu in 0 1 2 3; do
  total=0
  for st in /sys/devices/system/cpu/cpu${cpu}/cpuidle/state*/time; do
    t=$(cat "$st")
    total=$((total + t))
  done
  echo "CPU$cpu toplam idle süre: ${total} µs"
done

06 Latency kısıtları — pm_qos ve real-time

Bazı uygulamalar (gerçek zamanlı kontrol döngüleri, ağ paket işleme) öngörülemeyen wakeup gecikmelerine tahammül edemez. pm_qos (Power Management Quality of Service) bu uygulamaların maksimum kabul edilebilir gecikmeyi sisteme bildirmesine olanak tanır.

cpu_latency_qos_request API

c — pm_qos latency kısıtı
#include <linux/pm_qos.h>

/* Driver içinde */
static struct pm_qos_request latency_req;

/* Başlatma: maksimum 100 µs wakeup latency isteği */
cpu_latency_qos_add_request(&latency_req, 100);  /* µs */

/* Kısıtı güncelle */
cpu_latency_qos_update_request(&latency_req, 50);

/* Kısıtı kaldır */
cpu_latency_qos_remove_request(&latency_req);

Userspace'den pm_qos

bash / c — userspace pm_qos
# /dev/cpu_dma_latency'e istenen max latency'yi yaz (µs, binary int32)
# Dosya açık olduğu sürece kısıt aktif kalır

python3 -c "
import struct, time
# 100 µs max latency iste
fd = open('/dev/cpu_dma_latency', 'wb', buffering=0)
fd.write(struct.pack('i', 100))
print('pm_qos kısıtı aktif (100 µs)')
time.sleep(30)   # 30 saniye boyunca derin C-state'ler engellenir
fd.close()
print('kısıt kaldırıldı')
"
c — sürekli çalışan RT görev
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>

int main(void) {
    int fd = open("/dev/cpu_dma_latency", O_RDWR);
    if (fd < 0) { perror("open"); return 1; }

    int32_t target_us = 50;  /* 50 µs max wakeup latency */
    write(fd, &target_us, sizeof(target_us));

    /* ... gerçek zamanlı işlem döngüsü ... */

    close(fd);   /* kısıt otomatik kaldırılır */
    return 0;
}

Latency kısıtlarını izle

bash
# mevcut CPU latency QoS kısıtlarını görüntüle
cat /sys/kernel/debug/pm_qos/cpu_dma_latency
# Default value: 2147483647
# CPU 0 (task: rt_task, pid: 1842): 50
PREEMPT_RT İLE BİRLİKTE

PREEMPT_RT çekirdeği kullanıyorsanız, yüksek öncelikli RT görevlerinizin bulunduğu CPU'larda derin C-state'leri pm_qos ile sınırlamanız önerilir. Aksi takdirde 1 ms'lik wakeup gecikmesi bile zamanlama ihlallerine yol açabilir.

07 Kernel config — platform driver

cpuidle subsystem'ini etkinleştirmek için birkaç temel Kconfig seçeneği gerekir. Platform driver seçimi SoC'a bağlıdır.

Kconfig
CONFIG_CPU_IDLE=y
CONFIG_CPU_IDLE_GOV_LADDER=y
CONFIG_CPU_IDLE_GOV_MENU=y
CONFIG_CPU_IDLE_GOV_TEO=y           # Linux 5.1+
CONFIG_CPU_IDLE_GOV_HALTPOLL=y      # sanal makine için

# ARM platform-specific
CONFIG_ARM_CPUIDLE=y                 # generic ARM idle driver
CONFIG_ARM64_CPUIDLE=y               # ARM64 için
CONFIG_ARM_PSCI_CPUIDLE=y            # PSCI tabanlı idle

# x86 / ACPI
CONFIG_INTEL_IDLE=y                  # Intel-specific idle driver
CONFIG_ACPI_PROCESSOR=y

# İstatistik ve hata ayıklama
CONFIG_CPU_IDLE_STAT=y

Platform-specific notlar

Platform → Driver
Raspberry Pi 4 (BCM2711)  → arm_idle + PSCI (firmware gerekli)
BeagleBone Black (AM335x) → cpuidle-am335x veya arm_idle
i.MX8 (NXP)               → arm_idle + PSCI (ATF gerekli)
RK3568 (Rockchip)         → arm_idle + PSCI
x86 Intel                 → intel_idle
x86 AMD                   → acpi_idle veya amd_idle
DİKKAT

ARM64 sistemlerde derin C-state'ler (cluster sleep) için ARM Trusted Firmware'in (ATF/TF-A) doğru şekilde yapılandırılmış ve çalışır halde olması gerekir. ATF yoksa veya yanlış derlenirse PSCI çağrıları başarısız olur ve kernel sadece WFI düzeyinde idle yapar.

08 Pratik: idle latency ölçümü ve Cortex-A53 C-state profili

İki pratik: cyclictest ile C-state'lerin wakeup latency'ye etkisini ölçmek, ve ARM Cortex-A53 sistemde C-state profilini çıkarmak.

1 — cyclictest ile idle latency ölçümü

bash — cyclictest + cpuidle
# rt-tests paketi: apt install rt-tests

# Baseline: tüm C-state'ler etkin, menu governor
cyclictest --mlockall --smp --priority=99 \
           --interval=1000 --duration=30s \
           --histogram=50 --histfile=hist_cstates_on.txt
# # Min Latencies: 00014 00015 00016 00014
# # Avg Latencies: 00024 00026 00022 00025
# # Max Latencies: 00847 01023 00912 00788

# C-state'leri kapat (performans baseline)
for st in /sys/devices/system/cpu/cpu*/cpuidle/state*/disable; do
    echo 1 > "$st"
done

cyclictest --mlockall --smp --priority=99 \
           --interval=1000 --duration=30s \
           --histogram=50 --histfile=hist_cstates_off.txt
# # Min Latencies: 00012 00012 00013 00012
# # Avg Latencies: 00015 00016 00014 00015
# # Max Latencies: 00045 00052 00038 00041
# Sonuç: C-state'ler kapalıyken max latency ~20x daha düşük!

# Sadece derin state'i kapat (C2/cluster sleep)
for cpu in /sys/devices/system/cpu/cpu*/cpuidle/state2/disable; do
    echo 1 > "$cpu"
done

# pm_qos ile 100 µs latency kısıtı koy (C-state'ler açık ama derin girişler engellenir)
echo 100 | python3 -c "import sys,struct; open('/dev/cpu_dma_latency','wb').write(struct.pack('i',int(sys.stdin.read().strip())))" &

2 — Cortex-A53 C-state profil scripti

bash — C-state profil scripti
#!/bin/bash
# Cortex-A53 C-state profil çıkarma
# Kullanım: ./cstate_profile.sh [saniye]

DURATION=${1:-30}
echo "=== cpuidle C-state Profil ($DURATION saniye) ==="
echo ""

# Başlangıç değerlerini kaydet
declare -A start_usage start_time
for cpu in 0 1 2 3; do
    for state_dir in /sys/devices/system/cpu/cpu${cpu}/cpuidle/state*/; do
        key="${cpu}_$(basename $state_dir)"
        start_usage[$key]=$(cat "${state_dir}usage" 2>/dev/null || echo 0)
        start_time[$key]=$(cat  "${state_dir}time"  2>/dev/null || echo 0)
    done
done

sleep "$DURATION"

# Delta hesapla ve raporla
echo "CPU | State        | Giriş/sn | Toplam%"
echo "----|--------------|-----------|--------"
for cpu in 0 1 2 3; do
    for state_dir in /sys/devices/system/cpu/cpu${cpu}/cpuidle/state*/; do
        name=$(cat "${state_dir}name" 2>/dev/null)
        key="${cpu}_$(basename $state_dir)"
        end_usage=$(cat "${state_dir}usage" 2>/dev/null || echo 0)
        end_time=$(cat  "${state_dir}time"  2>/dev/null || echo 0)
        delta_usage=$(( end_usage - ${start_usage[$key]} ))
        delta_time=$(( end_time - ${start_time[$key]} ))
        per_sec=$(( delta_usage / DURATION ))
        pct=$(( delta_time / (DURATION * 10000) ))
        printf " %d  | %-12s | %9d | %5d%%\n" \
               "$cpu" "$name" "$per_sec" "$pct"
    done
done
Örnek çıktı — boşta sistem
=== cpuidle C-state Profil (30 saniye) ===

CPU | State        | Giriş/sn | Toplam%
----|--------------|-----------|--------
 0  | WFI          |      1203 |    12%
 0  | cpu-sleep-0  |       847 |    71%
 0  | cluster-slp  |        23 |    14%
 1  | WFI          |       998 |     9%
 1  | cpu-sleep-0  |       901 |    78%
 1  | cluster-slp  |        19 |    11%
YORUM

Sağlıklı bir gömülü sistemde boşta CPU, zamanının büyük çoğunluğunu (>80%) orta veya derin C-state'lerde geçirmelidir. WFI (C1) oranı çok yüksekse, daha derin state'lere geçişi engelleyen bir pm_qos kısıtı veya yüksek frekanslı interrupt kaynağı olabilir.