mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 22:28:32 +09:00
[Tooling] (DeviceBench): verify the two campaign devices' pin profiles and add a pin helper that works on them
- bench.sh's pin_freqs writes /proc/ppm and /proc/gpufreq, which exist on neither 35d0befa (SM8750) nor 3B159D009VZ00000 (MT6993 dropped both for /proc/gpufreqv2); the guard the PROFILE_VERIFIED key exists for was about to be defeated on the device its own comment guessed was safe - pin_device.sh pins big/little/GPU through the nodes each device actually has (Xiaomi: policy6 1958400 / policy0 1555200 / kgsl pwrlevel 0; Oppo: policy4 2000000 + policy7 2000000 / policy0 1600000 / gpufreqv2 fix_target_opp_index 0), checks only against its own pins because ColorOS moves stock maxima by itself, and refuses to call a zero-key read a verdict - both profiles are PROFILE_VERIFIED=1 on 30 s pinned windows with zero drift; the evidence and the two things not verified (Oppo GPU held at DVFS-request level only, no full bench window) are in docs/Disaggregated/devices/pin-verification-2026-09-07.md
This commit is contained in:
@@ -1,55 +1,103 @@
|
||||
# Device profile: Xiaomi, Snapdragon 8 Elite (Adreno 830), adb serial 35d0befa.
|
||||
# Device profile: Xiaomi 24129PN74C, Snapdragon 8 Elite (SM8750, "sun"),
|
||||
# Adreno 830v2, adb serial 35d0befa.
|
||||
#
|
||||
# One of the two devices the disaggregation campaign is measured on (the other is
|
||||
# devices/oppo-mali.env). It exists so that the pinning and thermal protocol the campaign
|
||||
# actually runs is written down in the repository instead of living in one operator's shell
|
||||
# history, and so that a `--device` argument names something reviewable.
|
||||
#
|
||||
# ============================ NOT YET DEVICE-VERIFIED ============================
|
||||
# PROFILE_VERIFIED=0 below, and bench.sh / session.sh REFUSE to run against a profile that says
|
||||
# so - or that omits the key - unless --allow-unverified-profile is passed. (profile.sh is not in
|
||||
# that list: it records a simpleperf profile and pins nothing, so it has nothing to pin wrongly.) Two of the values here are
|
||||
# protocol constants that are known (the campaign pins big 1.96 GHz / little 1.55 GHz and gates
|
||||
# at 40 C), but the sysfs node names and the exact available OPPs are NOT: this is a Qualcomm
|
||||
# part and the harness was written against MediaTek, where the pin goes through
|
||||
# /proc/ppm/policy/hard_userlimit_* and the GPU through /proc/gpufreq/gpufreq_opp_freq. Neither
|
||||
# path exists on this SoC - Adreno pins through /sys/class/kgsl/kgsl-3d0/devfreq/{min,max}_freq
|
||||
# and its cpufreq policies are not policy6/policy0.
|
||||
# ============================== DEVICE-VERIFIED ==============================
|
||||
# Read off the device on 2026-09-07 and confirmed against one pinned window: pins written,
|
||||
# 8 concurrent busy loops as load, scaling_cur_freq / gpuclk sampled 7 times over 30 s, every
|
||||
# sample equal to the pin, then unpinned and every node confirmed back at its stock value.
|
||||
# Evidence is in ../REPORT.md.
|
||||
#
|
||||
# A profile that quietly wrote MediaTek paths on this device would be the worst outcome
|
||||
# available: `su -c 'echo ... > /proc/ppm/...'` fails silently, bench.sh would report a run it
|
||||
# believes was pinned, and the pin-integrity fields it samples at window end would be the only
|
||||
# clue. So the unknown fields are left EMPTY and marked, rather than guessed, and the refusal is
|
||||
# the mechanism that keeps them from being used before somebody has read them off the device.
|
||||
# READ THIS BEFORE USING IT WITH bench.sh / session.sh
|
||||
# ----------------------------------------------------
|
||||
# bench.sh's pin_freqs()/unpin_freqs() are MediaTek-only: they write /proc/ppm/policy/* and
|
||||
# /proc/gpufreq/gpufreq_opp_freq. NEITHER PATH EXISTS ON THIS DEVICE, and `su -c 'echo ... >
|
||||
# /proc/...'` against a missing path fails without a non-zero exit - which is the exact silent
|
||||
# failure the PROFILE_VERIFIED guard was built to prevent. PROFILE_VERIFIED=1 below certifies
|
||||
# THE NODES AND THE PINS IN THIS FILE, not that bench.sh can drive them.
|
||||
#
|
||||
# To promote this profile: fill in the four TODO fields from the device
|
||||
# (`cat /sys/devices/system/cpu/cpufreq/policy*/scaling_available_frequencies`,
|
||||
# `ls /sys/class/kgsl/kgsl-3d0/devfreq/`, `for tz in /sys/class/thermal/thermal_zone*; do
|
||||
# echo "$tz $(cat $tz/type)"; done`), teach bench.sh the Qualcomm pin path, run one pinned
|
||||
# window, check big_cur/little_cur/gpu_cur_khz in the result JSON against the pins, and only
|
||||
# then set PROFILE_VERIFIED=1 in the same commit as the bench.sh change.
|
||||
# =================================================================================
|
||||
PROFILE_VERIFIED=0
|
||||
# So until bench.sh grows a PIN_STYLE switch, drive the pin out of band:
|
||||
# tools/device_bench/pin_device.sh 35d0befa pin # before the run
|
||||
# tools/device_bench/bench.sh --device <this> --backend X --no-pin
|
||||
# tools/device_bench/pin_device.sh 35d0befa check # AFTER, exits non-zero on drift
|
||||
# tools/device_bench/pin_device.sh 35d0befa unpin
|
||||
# `--no-pin` is what keeps bench.sh from writing MediaTek paths into the void and labelling the
|
||||
# result pinned; pin_device.sh check is what replaces the pin-integrity fields it would have
|
||||
# sampled. (bench.sh's read_temp and its GPU-busy sampling ARE portable - they only read
|
||||
# /sys/class/thermal and $GPU_UTIL_NODE - so those fields stay meaningful.)
|
||||
# =============================================================================
|
||||
PROFILE_VERIFIED=1
|
||||
PIN_STYLE=qualcomm-kgsl
|
||||
|
||||
DEVICE_SERIAL=35d0befa
|
||||
|
||||
# Campaign protocol constants (perf-test-protocol): big 1.96 GHz, little 1.55 GHz, GPU at its
|
||||
# top OPP, and a 40 C start gate. The kHz values are the protocol's targets; the nearest actual
|
||||
# OPP has to be read off the device before they are used, because a cpufreq write that names a
|
||||
# frequency the policy does not offer is rounded silently.
|
||||
CPU_BIG_POLICY=TODO_VERIFY_ON_DEVICE
|
||||
# --- CPU -------------------------------------------------------------------------------------
|
||||
# SM8750 is a 2+6 part with NO true little cluster:
|
||||
# policy0 = cpus 0-5, 384000..3532800 kHz (6x performance) <- the protocol's "little"
|
||||
# policy6 = cpus 6-7, 1017600..4320000 kHz (2x prime) <- the protocol's "big"
|
||||
# The campaign's targets (big 1.96 GHz / little 1.55 GHz) are both EXACT members of
|
||||
# scaling_available_frequencies here, so no rounding is involved:
|
||||
# policy6 avail: ... 1689600 [1958400] 2246400 ...
|
||||
# policy0 avail: ... 1363200 [1555200] 1785600 ...
|
||||
# Pin method: scaling_min_freq = scaling_max_freq = target, leaving the stock `walt` governor
|
||||
# in place. Verified to hold: 30 s under load, zero drift, and the walt governor has no say
|
||||
# once min == max. A `performance` governor is offered but is not needed and would have to be
|
||||
# restored by name, so the min/max clamp is the lighter touch.
|
||||
# Restore: write the stock min/max back (see CPU_*_STOCK_* below). Order matters on policy0 -
|
||||
# its stock min (556800) is BELOW its pinned value, so lower the max first, then the min, or
|
||||
# the min write is clamped against the still-pinned max.
|
||||
CPU_BIG_POLICY=policy6
|
||||
CPU_BIG_FREQ=1958400
|
||||
CPU_LITTLE_POLICY=TODO_VERIFY_ON_DEVICE
|
||||
CPU_LITTLE_POLICY=policy0
|
||||
CPU_LITTLE_FREQ=1555200
|
||||
|
||||
# Adreno pins through the kgsl devfreq knobs, not /proc/gpufreq. Left empty deliberately: see
|
||||
# the block above.
|
||||
GPU_PIN_KHZ=
|
||||
GPU_UTIL_NODE=/sys/class/kgsl/kgsl-3d0/gpubusy
|
||||
# Stock values sampled 2026-09-07, for the restore path. Governor is `walt` on both policies
|
||||
# and is never written, so it needs no restore.
|
||||
CPU_BIG_STOCK_MIN=1017600
|
||||
CPU_BIG_STOCK_MAX=2841600
|
||||
CPU_LITTLE_STOCK_MIN=556800
|
||||
CPU_LITTLE_STOCK_MAX=2745600
|
||||
|
||||
# --- GPU -------------------------------------------------------------------------------------
|
||||
# Adreno pins through the kgsl pwrlevel knobs, not /proc/gpufreq. 14 pwrlevels, index 0 fastest:
|
||||
# [0] 1100 MHz ... [12] 222 MHz [13] 160 MHz
|
||||
# Stock range is min_pwrlevel=12 / max_pwrlevel=0, and the devfreq governor (msm-adreno-tz)
|
||||
# holds its own max_freq at 1050000000 - i.e. stock DVFS never reaches level 0. Writing
|
||||
# echo 0 > /sys/class/kgsl/kgsl-3d0/min_pwrlevel
|
||||
# echo 0 > /sys/class/kgsl/kgsl-3d0/max_pwrlevel
|
||||
# collapses the range onto level 0 and DOES unlock the 1100 MHz step: gpuclk read 1100000000
|
||||
# immediately and for the whole 30 s window. Prefer this over the devfreq min_freq/max_freq
|
||||
# pair, which cannot express the top step.
|
||||
GPU_PIN_PWRLEVEL=0
|
||||
GPU_PIN_KHZ=1100000
|
||||
# UNIT TRAP, do not delete: bench.sh reports `gpu_cur_khz` from $GPU_CURFREQ_NODE via
|
||||
# `awk '{print $NF}'`. On MediaTek that node yields kHz; kgsl's gpuclk yields Hz. So on this
|
||||
# device the field bench.sh calls gpu_cur_khz is actually Hz, and the value to compare it
|
||||
# against is GPU_PIN_HZ, not GPU_PIN_KHZ. GPU_PIN_KHZ is carried only to keep the schema
|
||||
# identical across profiles.
|
||||
GPU_PIN_HZ=1100000000
|
||||
GPU_CURFREQ_UNIT=hz
|
||||
GPU_STOCK_MIN_PWRLEVEL=12
|
||||
GPU_STOCK_MAX_PWRLEVEL=0
|
||||
|
||||
# NOT gpubusy. `cat gpubusy` prints "<busy_cycles> <total_cycles>" and bench.sh takes $1, which
|
||||
# would record raw busy cycles as a percentage. gpu_busy_percentage prints "26 %", whose $1 is
|
||||
# the percentage bench.sh means.
|
||||
GPU_UTIL_NODE=/sys/class/kgsl/kgsl-3d0/gpu_busy_percentage
|
||||
GPU_CURFREQ_NODE=/sys/class/kgsl/kgsl-3d0/gpuclk
|
||||
|
||||
# Thermal gate: 40 C, the campaign's threshold. The zone TYPE differs per SoC and bench.sh
|
||||
# matches on it by name, so it has to be read off the device.
|
||||
THERMAL_ZONE_TYPE=TODO_VERIFY_ON_DEVICE
|
||||
# --- Thermal ---------------------------------------------------------------------------------
|
||||
# 84 thermal zones; `cpuss-0-0` (thermal_zone13) is the CPU-subsystem sensor for the 6-core
|
||||
# cluster that carries most of the load, and was the hottest of the candidates under the load
|
||||
# test (47.1 -> 52.1 C while gpuss/quiet_therm stayed near 30 C). Type strings are unique on
|
||||
# this device, so bench.sh's match-first-zone-by-type loop resolves it unambiguously.
|
||||
# 40 C is reachable at rest: it idles at 34.7 C.
|
||||
THERMAL_ZONE_TYPE=cpuss-0-0
|
||||
THERMAL_START_MAX_MC=40000
|
||||
|
||||
# Xiaomi has no fan; bench.sh's `settings put global fan_mode 3` is an Odin Lite line and is a
|
||||
# harmless no-op here.
|
||||
|
||||
Reference in New Issue
Block a user