Sweets
Running

Performance diagnostics

Measure per-output frame, render, damage, and presentation cost without per-frame log spam.

Sweets has an opt-in per-output render profiler for comparing compositor workloads. It does not enable blur or any other visual effect.

Start Sweets with the profiler in its inherited environment:

SWEETS_PROFILE_RENDER=1 sweets

The values 1 and true enable it. This is a startup diagnostic, not a Lua option. Calling sweets.env() cannot enable it because that API changes the environment inherited by programs Sweets launches, not Sweets itself.

Profiling changes the workload by collecting timestamps and, when the renderer supports them, GPU timer queries. Keep it disabled for normal use and compare runs with the same renderer, output mode, scale, clients, animations, and duration.

Reading a summary

Each active output emits at most one render-profile interval summary every two seconds. Reports are driven by rendered frames; the profiler creates no periodic timer and produces no interval log while the output is idle. A final partial summary is written when an output is removed or Sweets exits.

Duration fields use this order:

mean/p50/p95/p99/max(n=observed/stored)

The fixed sample store retains at most 512 values per metric. Means and extrema cover the full interval; percentiles cover the retained samples.

FieldMeaning
budget_msNominal refresh interval, or unavailable when the backend does not report one
animation_msCPU time advancing animation and layout preparation
scene_msCPU time building the wlroots scene output state
test_msCPU time testing a requested tearing page flip; unavailable when no tearing test ran
commit_msCPU time submitting the output state
combined_msAvailable wlroots pre-render plus renderer/GPU completion duration
blur_combined_msThe same combined duration split by partial and full blur-damage frames; each side is unavailable when no matching frame was presented
damage_pctDamaged output-buffer area as a percentage
present_latency_msFrame-start to presentation time only when the backend supplies a hardware clock

damage_pixels is shown over the total output pixels observed in the interval. full_damage counts full-output fallback frames. present separates matched frame commits, shown and not-shown updates, unrelated output commits, and the presentation flags supplied by the backend.

unavailable is not zero. render_unknown, pending_expired, damage_unknown, and timestamp_unknown count samples Sweets could not measure authoritatively. Combined render timers are queried only after the matching presentation event, never synchronously from the frame being rendered.

tearing_rejected counts actual backend tests, not every later frame from the same client. After a successful normal fallback, one rejection suppresses repeat async tests until the fullscreen surface, its tearing eligibility, or the output configuration changes. Later intervals therefore normally show no test_ms samples and tearing_rejected=0 while that backoff remains active.

Direct-scanout transitions

The profiler also observes wlroots' public root-buffer sampling signal for managed windows. It writes direct-scanout-audit records only when a buffer enters or leaves direct scanout, plus one summary for a window that entered it; there is no per-frame scanout log.

An event=enabled record includes the output, window mode, whether blur is requested, and the active ordinary-window, close-snapshot, and layer blur-node counts. blur_clear=1 means no live Sweets blur participant was present when wlroots selected that buffer for direct scanout. A fullscreen transition while blur is enabled increments fullscreen_restorations. Any direct sample with a live blur participant increments blur_violations and should be reported as a bug.

event=disabled records the return to normal composition or the end of the buffer lifetime. After the window closes, its summary should have matching enabled and disabled counts, blur_violations=0, and active=0.

Page-flip transitions

On the DRM/KMS backend, the profiler also correlates Sweets' committed page-flip mode with wlroots' matching presentation event. page-flip-audit records are transition-only; normal frames do not produce one log each.

event=tearing-enabled ... vsync=0 proves that a committed tearing request was presented asynchronously. The first later vsynced normal commit emits event=normal-restored ... vsync=1. If the driver rejects an async test, the successfully presented normal retry emits event=normal-fallback ... vsync=1 instead. The existing tearing backoff bounds fallback records to eligibility or output-state changes.

The output-lifetime summary reports attempted and rejected async tests, tearing, fallback, normal, and vsynced-normal presentations, not-presented updates, transitions, mode mismatches, and whether tearing remained active. After leaving fullscreen and closing the client, expect mode_mismatch=0 and active=0. A rejected fallback proves safe normal presentation, not that the hardware supports tearing.

Multi-output blur isolation

Effects builds also audit blur storage ownership while profiling. Each output emits one blur-output-isolation event=overlap-active record when it first prepares a blur frame while another output also has live blur work. The record reports the number of active outputs and whether the output-local cache and renderer targets passed the isolation check.

The lifetime summary counts prepared blur frames, concurrent frames, resource/cache checks, peer comparisons, and maximum concurrent outputs. An exercised multi-output run should finish with nonzero concurrent_frames, peer_checks, and cache_checks, plus invalid=0. The audit compares only opaque identities; it never logs pointer values or creates additional renderer resources.

Nested and headless backends do not expose authoritative DRM page-flip flags, so the profiler startup record reports page_flip_audit=unavailable there and does not emit page-flip audit results.

Blur recovery after output changes

Optimized blur owns one lazy renderer-qualified cache on each output. Output mode, scale, transform, power, hotplug, renderer, session, background content, or blur-strength changes rebuild only the affected output when it still has a consumer. Noise changes do not rebuild the source, and an output with no optimized effect retains no cache resources.

Preparation or sampling failure leaves that output unblurred and emits one warning for the unchanged failure generation. Sweets retries after relevant renderer, source-topology, output, clear-color, or strength changes. Animated content commits do not repeatedly retry an already-failed cache, and there is no repaint timer or retry loop.

Sweets skips preparation when bounded committed opaque regions in front of an optimized effect cover its complete physical mask. Rounded, translucent, unknown, or excessively fragmented coverage stays on the conservative render path. Hidden, minimized, clipped, empty, and off-output effects allocate no blur resources.

Native SWEETS_PROFILE_RENDER=1 summaries include interval deltas for optimized_resource_sets, optimized_source_renders, optimized_blur_renders, optimized_releases, optimized_failures, and optimized_occlusion_culls. A settled static scene adds no source or blur renders. A background commit can rerender and reblur without allocating a new resource set. A noise-only edit changes none of those work counters. The existing bounded summary is the only log site; there is no per-frame cache message.

Animation lifecycle and snapshot ownership

The same opt-in setting enables one backend-neutral animation lifecycle profile summary at most every five seconds while frames are being processed. It works on both nested and native backends and creates no timer or idle redraw.

The summary reports submitted, no-damage, and endpoint-cleanup frames; transition starts and interruption retargets; active transition/output maxima; renderer fallbacks; and offscreen animation-snapshot create, reuse, release, failure, live-count, and pixel maxima. Separate close_snapshots_* fields cover retained closing-window content. Counts are aggregate and never include window IDs, titles, application IDs, or pixels.

max_failure_latches shows the largest renderer-local set of failed snapshot qualifications. failure_overflow_latched=true means that set reached its hard bound: unseen snapshot requests then take the ordinary non-animated fallback until transition cleanup frees a latch slot. They are not retried once per frame. A settled workload should show no new starts, snapshots, failures, or submissions; cumulative creates and releases should converge after the final cleanup frame.

Overhead and privacy

When disabled, the profiler allocates no per-output sample state or per-window scanout audit, creates no render timers, registers no profiling listeners, and writes no profiler log. When enabled, each output owns about 37 KiB of fixed aggregation state, a bounded ring of 16 pending render timers, and small page-flip and cursor-composition audit state. Each managed window owns one small scanout audit with two lifecycle-bound listeners. Work and log volume stay bounded.

Reports include connector names and aggregate timing/counter data. They do not include application IDs, window titles, commands, client pixels, or other client content. Scanout transition records include only the shell type and window mode.

On this page