Skip to content

v0.1.9 spins at ~500k ppoll/s and saturates the Wayland compositor (fixed on main; release PR #11 still open) #12

Open

Description

@Roytayo

Summary

The released v0.1.9 binary keeps one tokio-runtime-worker thread spinning on
ppoll(), issuing roughly 250,000–500,000 syscalls per second indefinitely.
Because each wake-up round-trips to the Wayland compositor, the compositor itself
is dragged to ~40% CPU.

The rewritten runtime on main (4f4ea8a) fixes this completely, and the release
is already prepared: the changesets are in .changes/, and PR #11
(chore(release): bump versions) has been open since 10 August
. So there is
nothing to implement — this issue is a request to merge #11 and publish, since
the AUR binary package still ships the February v0.1.9 build and every user of it
is running the spinning version.

Environment

clip-bridge v0.1.9, prebuilt release binary (AUR package)
Compositor Hyprland 0.56.2, wlr-data-control
Platform x86_64 Linux, Arch-based
Use case synchronising plain text from an XWayland application to a native Wayland client

Measurements

After about an hour of daemon uptime, the busy thread:

wchan:                      __x64_sys_ppoll.cold
voluntary_ctxt_switches:    1,111,426,794      ->  ~252,000/s

A shorter sample taken right after startup measured ~500,000/s. Over that period
the daemon accumulated roughly 3x more CPU time than the wall-clock time it had
been running
, i.e. several threads spinning at once.

Stopping and restarting the daemon isolates the effect on the compositor:

daemon running daemon stopped
compositor CPU 39.8% 0.6%
clip-bridge CPU ~50% —
system load average, idle desktop 4.61 0.11

The process also holds two anon_inode:sync_file descriptors open for its whole
lifetime. That may be relevant — a permanently-ready descriptor that is polled but
never consumed would produce exactly this pattern — but I did not confirm it, so
please treat it as an observation rather than a diagnosis.

Why this matters beyond CPU usage

Hyprland composites on a single thread. At high refresh rates the per-frame budget
is only a few milliseconds, so spending ~40% of it servicing clipboard round-trips
made compositing irregular: visible stutter and input latency on every composited
window
. Fullscreen applications were unaffected, because direct scan-out bypasses
the compositor entirely.

That asymmetry is worth highlighting, because it makes the bug hard to attribute:
the desktop appears to stutter everywhere except in fullscreen, which points away
from a clipboard daemon. I spent a long time looking at graphics drivers and
launcher settings before measuring /proc and finding this.

Root cause is already documented upstream

docs/DESIGN.md on main describes exactly this behaviour in the 0.1.x code:

X11 uses fixed sleep polling, and polls global events again inside the selection
request function; this swallows unrelated events, blocks normal dispatch

Wayland repeatedly uses roundtrip to drive long-term event loops

Verification that main fixes it

I built main (4f4ea8a) and ran it in the same session, under the same workload:

v0.1.9 main @ 4f4ea8a
syscalls/s ~500,000 20
clip-bridge CPU ~50% 0.0% (TIME+ 00:00:00 after 30 min)
compositor CPU 39.8% 0.4%
idle load average 4.61 0.83

Both event loops now block on poll() with a 100 ms timeout, which is the correct
shape.

Functionally verified on the rewritten build:

  • XWayland → Wayland: a few KB of plain text copied out of an XWayland
    application pasted correctly into a native Wayland browser.
  • Wayland → XWayland: works.
  • A separate v0.1.9 bug also disappeared: it advertised text/plain three
    times
    (text/plain text/plain text/plain;charset=utf-8 TEXT STRING UTF8_STRING),
    which froze Chromium-based browsers on paste-as-plain-text (Ctrl+Shift+V).
    main advertises only text/plain;charset=utf-8 and text/plain, and the
    freeze is gone.

Request

Merging PR #11 would publish the rewritten runtime and resolve this for every
user of the AUR binary package. Until then, building from git is the only way to
avoid the spin.

I appreciate there may be a reason the release is being held — if main is not
considered ready to ship, it would still help to know, so downstream packagers can
decide whether to carry a git build in the meantime.

Thanks for the tool — it is the only thing that makes XWayland → Wayland clipboard
work reliably here. Clipboard managers built on wl-clipboard (cliphist,
wl-clip-persist, clipman) cannot substitute for it, since they never observe
selections originating from XWayland.


Minor and unrelated: clip-bridge --help is not recognised — the argument is
ignored and the daemon starts instead, which hangs non-interactive shells. Happy to
file that separately if you prefer.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions