Skip to content

power: coalesce backlight helper writes, stop blocking on every step - #469

Open
rumours86 wants to merge 1 commit into
linuxmint:masterfrom
rumours86:power-coalesce-backlight-writes
Open

power: coalesce backlight helper writes, stop blocking on every step#469
rumours86 wants to merge 1 commit into
linuxmint:masterfrom
rumours86:power-coalesce-backlight-writes

Conversation

@rumours86

Copy link
Copy Markdown

The bug. Holding a brightness key makes brightness keep changing for seconds after the key is released, and pressing the opposite key has no effect until the backlog drains. Single presses behave fine.

Why. Every Screen.StepUp/StepDown runs up to three synchronous g_spawn_command_line_sync() round-trips — csd-backlight-helper --get-brightness, --get-max-brightness, then pkexec csd-backlight-helper --set-brightness with a polkit round-trip — blocking the daemon's main loop for 60–400 ms per step. Keyboard autorepeat produces a step every ~33 ms, so the calls pile up in the daemon's D-Bus queue and are processed strictly FIFO: brightness "runs on" after release, and an opposite press waits behind the whole accumulated tail.

The fix (same approach gnome-settings-daemon took in gsd-backlight):

  • keep the last requested value (backlight_helper_target) and step from it instead of re-reading hardware; answer the D-Bus call immediately;
  • write asynchronously (g_spawn_async + child watch) with a one-slot queue: at most one helper in flight, and on completion only the latest requested value is written — a burst of N steps costs 1–2 helper invocations instead of N;
  • cache get-max-brightness (never changes at runtime, was re-read via the helper on every step);
  • GetPercentage reports the target while a write is in flight, keeping OSD/applet sliders in sync with what the user asked for;
  • fix backlight_set_percentage falling through to the helper even after a successful xrandr write (step functions already had the corresponding goto).

Measured on Mint 22.3 (intel_backlight, max=120000), built at tag 6.6.4 and run live:

before after
one StepDown D-Bus call 60–90 ms ~1 ms (+ client overhead)
burst of 15 StepDown ~1.4 s serialized pkexec spawns, queue drains long after all answered in ~15 ms total, exactly 2 helper writes (first + coalesced final)
opposite step right after a burst waits for the whole tail takes effect immediately

Helper-write log from the live test showing the coalescing:

backlight write started: 31800
backlight write done, pending=2400   <- 14 steps arrived meanwhile, folded into one
backlight write started: 2400
backlight write done, pending=-1

(the g_message debug lines are not part of this PR)

🤖 Generated with Claude Code

Every Screen.StepUp/StepDown call ran up to three synchronous
g_spawn_command_line_sync() round-trips (get-brightness,
get-max-brightness, then 'pkexec csd-backlight-helper --set-brightness'
with a polkit round-trip), blocking the daemon's main loop for
60-400 ms per step.  Keyboard autorepeat produces steps every ~33 ms,
so holding a brightness key piled the calls up in the daemon's D-Bus
queue: brightness kept 'running' for seconds after the key was
released, and pressing the opposite key had no effect until the whole
tail of the queue was processed.  (Single presses were fine - one cycle
completes before the next press.)

Fix, following the approach gnome-settings-daemon took in gsd-backlight:

- keep the last requested value (backlight_helper_target) and step from
  it instead of re-reading the hardware, answering the D-Bus call
  immediately;
- write asynchronously (g_spawn_async + child watch) with a one-slot
  queue: at most one helper runs at a time, and when it finishes only
  the latest requested value is written.  A burst of N steps now costs
  one or two helper invocations instead of N;
- cache get-max-brightness - the maximum never changes at runtime, yet
  it was re-read through the helper on every single step;
- GetPercentage reports the target while writes are in flight, so OSD
  and applet sliders stay in sync with what the user requested;
- fix backlight_set_percentage falling through to the helper even after
  a successful xrandr write (the step functions already had the
  corresponding goto).

Measured on a Mint 22.3 laptop (intel_backlight): a burst of 15
StepDown calls used to take ~1.4 s of serialized pkexec spawns and left
the queue draining long after; now every call answers in ~1 ms, the
burst results in exactly two helper writes (first + coalesced final
value), and an opposite step right after the burst takes effect
immediately.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@rumours86

Copy link
Copy Markdown
Author

Following the same standard requested on the cinnamon PRs: now verified against git master as well. Built master csd-power (with master schemas) and ran it live in place of the system daemon on Mint 22.3 / intel_backlight:

  • a burst of 15 StepUp calls: every call answered in 14–23 ms (that's mostly gdbus client overhead), final brightness landed exactly at start + 15 × step — no steps lost while stepping from the target;
  • the whole burst plus one opposite StepDown produced 3 helper spawns total instead of 16 (first write + coalesced tail + the down step);
  • the opposite StepDown right after the burst answered in 12 ms and took effect immediately.

Previously posted numbers were from the same patch built at tag 6.6.4; behavior is identical on master.

🤖 Addressed by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant