mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 20:28:32 +09:00
- 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
140 lines
8.5 KiB
Bash
140 lines
8.5 KiB
Bash
# Device profile: Oppo PLG110 / ColorOS, MediaTek MT6993 (Dimensity 9500),
|
|
# Mali (gpufreqv2 + ged), adb serial 3B159D009VZ00000.
|
|
#
|
|
# The second of the two devices the disaggregation campaign is measured on (the other is
|
|
# devices/xiaomi-adreno830.env). Same purpose: keep the pinning and thermal protocol in the
|
|
# repository rather than in one operator's shell history.
|
|
#
|
|
# ============================== 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 for all three policies and the ged GPU
|
|
# frequency 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.
|
|
#
|
|
# READ THIS BEFORE USING IT WITH bench.sh / session.sh
|
|
# ----------------------------------------------------
|
|
# The old draft of this profile said PIN_STYLE=ppm on the reasoning that "this is a MediaTek
|
|
# SoC, so the harness's existing /proc/ppm + /proc/gpufreq pin path is probably the right one".
|
|
# It is not. On MT6993:
|
|
# /proc/ppm/ does not exist
|
|
# /proc/gpufreq/ does not exist (superseded by /proc/gpufreqv2/)
|
|
# So bench.sh's pin_freqs() writes four ppm lines and one gpufreq line into nothing, exits 0,
|
|
# and reports a run it believes was pinned - the failure the PROFILE_VERIFIED guard describes,
|
|
# on the device the guard's own comment guessed was safe. PROFILE_VERIFIED=1 below certifies
|
|
# THE NODES AND THE PINS IN THIS FILE, not that bench.sh can drive them.
|
|
#
|
|
# Until bench.sh grows a PIN_STYLE switch, drive the pin out of band:
|
|
# tools/device_bench/pin_device.sh 3B159D009VZ00000 pin
|
|
# tools/device_bench/bench.sh --device <this> --backend X --no-pin
|
|
# tools/device_bench/pin_device.sh 3B159D009VZ00000 check # non-zero on drift
|
|
# tools/device_bench/pin_device.sh 3B159D009VZ00000 unpin
|
|
# =============================================================================
|
|
PROFILE_VERIFIED=1
|
|
PIN_STYLE=mtk-gpufreqv2
|
|
|
|
DEVICE_SERIAL=3B159D009VZ00000
|
|
|
|
# --- CPU -------------------------------------------------------------------------------------
|
|
# MT6993 is a 4+3+1 part, THREE policies - which is the trap on this device:
|
|
# policy0 = cpus 0-3, 300000..2700000 kHz <- the protocol's "little"
|
|
# policy4 = cpus 4-6, 300000..3500000 kHz <- the protocol's "big"
|
|
# policy7 = cpu 7, 300000..4210000 kHz <- must ALSO be pinned, see below
|
|
# policy4 is chosen as "big" over the single-core policy7 because it is the structural analogue
|
|
# of the Xiaomi's 2-core policy6: a multi-core cluster the game's render and worker threads can
|
|
# actually share. But policy7 cannot simply be left alone - an unpinned 4.21 GHz core silently
|
|
# defeats the whole pin the moment the scheduler puts a hot thread on it, so the protocol pins
|
|
# it to the SAME target as policy4 and the device then behaves as 4 little + 4 big.
|
|
#
|
|
# Neither campaign target is an exact OPP here; both are the NEAREST available step:
|
|
# big 1958400 -> policy4 has 2000000 (D +41600, +2.1%) vs 1900000 (D -58400) -> 2000000
|
|
# little 1555200 -> policy0 has 1600000 (D +44800, +2.9%) vs 1500000 (D -55200) -> 1600000
|
|
# policy7 offers 2000000 exactly, so the big pin transfers to it unrounded.
|
|
# Record this 2-3% offset when comparing absolute per-thread CPU cost against the Xiaomi.
|
|
#
|
|
# Pin method: scaling_min_freq = scaling_max_freq = target, stock `sugov_ext` governor left in
|
|
# place. Verified to hold for 30 s under load on all three policies with no drift; the ColorOS
|
|
# performance daemons did not contend for the cpufreq nodes during the window. The nodes are
|
|
# 0660 system:system, so every read AND write has to go through su - a plain `adb shell cat
|
|
# scaling_governor` returns "Permission denied" and an unwary script reads that as an empty
|
|
# governor.
|
|
CPU_BIG_POLICY=policy4
|
|
CPU_BIG_FREQ=2000000
|
|
CPU_LITTLE_POLICY=policy0
|
|
CPU_LITTLE_FREQ=1600000
|
|
# The third policy. Pinned to CPU_BIG_FREQ; not reported as big_cur, but if it is not pinned
|
|
# the run is not pinned.
|
|
CPU_EXTRA_POLICY=policy7
|
|
CPU_EXTRA_FREQ=2000000
|
|
|
|
# Stock values sampled 2026-09-07 (screen on, idle), for the restore path. Note that policy0's
|
|
# and policy7's stock maxima (2100000 / 3200000) are BELOW cpuinfo_max_freq (2700000 / 4210000):
|
|
# ColorOS is already holding a limit there, so restore to these, not to cpuinfo_max_freq.
|
|
# Governor is `sugov_ext` on all three and is never written.
|
|
#
|
|
# THESE ARE NOT CONSTANTS. Observed directly: an unpin restored policy4 to 300000-3500000 and
|
|
# within seconds a ColorOS daemon had lowered its max to 3200000 by itself. So they are good
|
|
# enough to hand the range back to the governor with (which is all the restore path needs), but
|
|
# a verification that asserts "the device is released" by exact-matching them will report a
|
|
# false failure. pin_device.sh therefore asserts only against OUR pins, never against these.
|
|
CPU_BIG_STOCK_MIN=300000
|
|
CPU_BIG_STOCK_MAX=3500000
|
|
CPU_LITTLE_STOCK_MIN=300000
|
|
CPU_LITTLE_STOCK_MAX=2100000
|
|
CPU_EXTRA_STOCK_MIN=300000
|
|
CPU_EXTRA_STOCK_MAX=3200000
|
|
|
|
# --- GPU -------------------------------------------------------------------------------------
|
|
# 57 working OPPs (indices 0..56), index 0 fastest:
|
|
# [00] 1716000 kHz ... [56] 390000 kHz
|
|
# Pin at the top OPP with the gpufreqv2 hard override:
|
|
# echo 0 > /proc/gpufreqv2/fix_target_opp_index # pin (fixes GPU and STACK to index 0)
|
|
# echo -1 > /proc/gpufreqv2/fix_target_opp_index # restore DVFS
|
|
# Confirmed: after the write the node reads "fix GPU/STACK OPP index: 0/0" and
|
|
# /sys/kernel/ged/hal/current_freqency reads "0 1716000"; after `echo -1` it reads
|
|
# "fix GPU/STACK OPP index is disabled".
|
|
#
|
|
# Deliberately NOT the ged custom_boost_gpu_freq / custom_upbound_gpu_freq pair, even though it
|
|
# is the usual MTK route. Two reasons, both visible in the node: (a) on this kernel they take an
|
|
# OPP INDEX, not a kHz value (stock reads boost=56, upbound=0 - a floor at the slowest OPP and a
|
|
# ceiling at the fastest), so an operator porting odinlite's kHz-valued GPU_PIN would write
|
|
# garbage; (b) `cat` on them prints a request log showing /odm/bin/hw/vendor.oplus.hardware.urcc-
|
|
# service writing the same nodes, so a pin there is one voter among several and can be revised
|
|
# by the vendor daemon. fix_target_opp_index has no such contention.
|
|
GPU_PIN_OPP_INDEX=0
|
|
GPU_PIN_KHZ=1716000
|
|
GPU_CURFREQ_UNIT=khz
|
|
GPU_STOCK_BOOST_INDEX=56
|
|
GPU_STOCK_UPBOUND_INDEX=0
|
|
|
|
# ged nodes are unchanged from odinlite and parse the same way: gpu_utilization prints
|
|
# "7 0 100" ($1 = busy%), current_freqency prints "<opp_index> <freq_khz>" ($NF = kHz).
|
|
GPU_UTIL_NODE=/sys/kernel/ged/hal/gpu_utilization
|
|
GPU_CURFREQ_NODE=/sys/kernel/ged/hal/current_freqency
|
|
|
|
# CAVEAT on the GPU verification: the pinned window was a CPU load, so the GPU was power-
|
|
# collapsed throughout (gpufreq_status showed PowerCount: 0). The pin was therefore confirmed at
|
|
# the DVFS-request level - ged reported OPP index 0 / 1716000 kHz for the whole window - and not
|
|
# by observing the GPU actually clocking 1716 MHz under graphics load. Note also that while
|
|
# powered down, /proc/gpufreqv2/gpufreq_status keeps printing "Freq: 26000" for the fixed OPP
|
|
# entry; that is a parked-rail readout, not the pin failing. current_freqency is the node to
|
|
# believe, and it is the one bench.sh already samples.
|
|
|
|
# --- Thermal ---------------------------------------------------------------------------------
|
|
# 87 thermal zones. `soc_max` (thermal_zone14) is the SoC-wide max aggregate - the right meaning
|
|
# for a "SoC temperature" gate, and the strictest of the candidates. Type strings are unique, so
|
|
# bench.sh's match-first-zone-by-type loop resolves it unambiguously.
|
|
# 40 C is reachable but only just: it settles to 36-37 C at rest with the screen awake, and it
|
|
# was still reading 42.4 C several minutes after ordinary use. Expect the gate to actually wait.
|
|
# Under the load test it went 52.8 -> 62.0 C in 30 s.
|
|
THERMAL_ZONE_TYPE=soc_max
|
|
THERMAL_START_MAX_MC=40000
|
|
|
|
# ColorOS traps that belong with this device, and cost a run each when forgotten:
|
|
# * the first install of a not-yet-installed package blocks on
|
|
# com.oplus.appdetail InstallGuideActivity until "continue install" is tapped
|
|
# (`input tap 353 2349` on the 1272x2772 panel);
|
|
# * a foreign-signed APK has to be uninstalled before a rebuild will install;
|
|
# * pass MSYS_NO_PATHCONV=1 on every adb invocation from Git Bash, or a /data/... argument is
|
|
# rewritten into a Windows path.
|
|
# * every cpufreq read needs su (0660 system:system), unlike the Xiaomi where reads are open.
|