Blog

KWin Compositing Without the Circus

I used to respond to a sluggish desktop by disabling compositing. That made the lag disappear, but also threw away the only useful fact: something in the composed path was expensive. It did not say whether the problem was KWin, one effect, the backend, or the driver.

This week I used a repeatable little test instead. I dragged the same terminal across the same busy screen for thirty seconds, watched KWin’s Show FPS display for missed frames, and recorded KWin and X CPU use. It is not a laboratory benchmark, but it is consistent enough to compare one setting at a time.

With all effects enabled, resizing caused regular stalls. Suspending compositing was the baseline, not the fix. I turned composition back on and disabled effects one by one. Blur was the expensive one on this hardware; the compositor with shadows and ordinary transitions stayed smooth. Disabling everything had hidden that distinction.

The FPS overlay needs some skepticism. A high frame count does not prove input feels responsive, and displaying the counter adds work of its own. I care more about visible pauses during the same action and whether CPU time changes in the same direction. Numbers are useful here as comparisons, not medals.

I repeated the run with OpenGL and XRender. XRender used a little more CPU but had steadier frame delivery with this driver. That is a local result, not a declaration that one backend is universally faster. Different cards and drivers can reverse it.

So compositing stays on, blur stays off, and I have notes I can repeat after the next driver update. “Feels slow” gave me one giant switch. A crude measurement found the smaller one.

Plasma Is Not Just a Panel

I wanted a tiny display for a script: one number, updated every few seconds, sitting in the panel. My first thought was to write another panel applet, which is exactly the sort of thought one has after years of assuming the panel is a special little kingdom.

Plasma makes that model obsolete. The desktop and panels are containments, and the things placed in them are applets. An applet does not have to know whether it lives beside the clock or floats on the desktop. The containment supplies geometry and constraints; the applet supplies its representation and behavior.

That distinction explained several things I had mistaken for needless abstraction. An applet receives constraint changes when its size or location changes. A wide desktop representation can become a compact panel representation without maintaining two unrelated implementations. It can also publish actions to the shell instead of building its own private collection of buttons.

Data comes through another layer. A Plasma data engine gathers and names information, while applets subscribe to sources. This keeps the code that reads a device, queries a service or runs a command away from the code that paints it. Several applets can consume one engine, and the engine controls update intervals rather than allowing every widget to wake the machine whenever inspiration strikes.

For my number display, this meant writing less code than expected. The engine owned the script result and timer. The applet listened for updates and painted the value. Moving it from desktop to panel changed layout constraints, not the source of the data. I had originally put the timer in the applet, because apparently I enjoy rediscovering coupling by hand.

The package structure is useful too. Metadata describes the applet, resources travel with it, and the shell can discover it without a hard-coded list. Scripted applets lower the cost of small experiments, while C++ remains available when the job needs libraries or tighter control.

There is a price. Debugging a small widget now involves understanding the applet, its containment and perhaps a data engine. Plasma’s vocabulary can sound grandiose when all I want is a number beside the clock. For one fixed panel, the old model was simpler.

I still prefer Plasma’s separation for anything that may grow or be reused. It treats the desktop as a collection of cooperating components rather than a panel plus decorative exceptions. The implementation is young and occasionally reminds me of that fact, but the mechanism is much more interesting than the collection of wobbly widgets suggests.

KDE 4.1 Feels Like a Desktop Again

I installed KDE 4.0 on a spare partition earlier this year and lasted about two days. It was interesting in the same sense that taking apart a toaster is interesting: there were clever pieces everywhere, but I still could not make breakfast.

KDE 4.1 is different. I have been using it for ordinary work since the release and, for the first time, I am spending more time in applications than arranging the desktop around them. That sounds like faint praise. For a desktop, however, becoming boring enough to disappear is a real achievement.

The panel is finally manageable. I can resize it, move it, add launchers and arrange the system tray without feeling that I am negotiating with a prototype. Plasma still exposes some rough edges, especially when widgets make optimistic assumptions about available space, but the basic shell now holds together.

KWin’s compositing also behaves much better on my Intel machine. Effects are not the important part; being able to leave compositing enabled without wondering whether the next window resize will turn into a slide show is. The new cover switch is amusing for several minutes, while smoother painting remains useful all day.

Dolphin has improved enough that I no longer immediately start Konqueror for every file operation. The tree view, tabs and saner selection behavior remove many small annoyances. There are still missing conveniences from KDE 3.5, and anyone depending on a particular panel applet should check before moving. “Newer” is not a substitute for “contains the thing I need.”

What changed my mind is not one large feature. It is the accumulation of small repairs: configuration modules that work, widgets that remember where they belong, fewer painting glitches and applications that look like parts of the same system. KDE 4’s new architecture was always ambitious; 4.1 is where some of that ambition starts paying rent.

I would now choose 4.1 for a machine I use myself, with a KDE 3.5 session nearby for emergencies. I would not yet migrate a room full of people who regard a moved icon as a personal attack. Progress is real, but so are users.

Idle Host, Busy Guest

My laptop stayed warm with an apparently idle KVM guest running. The guest reported nearly no processor use, and the host showed only small bursts, so I first blamed inaccurate temperature sensors. Sensors are convenient suspects because they cannot write rebuttals.

I stopped services in the guest one by one. A periodic timer user was waking it frequently, but even a minimal guest produced more activity than expected. Virtual timer interrupts, emulated devices and host-side handling all require exits from guest execution. An idle guest is therefore not necessarily an idle host.

Tickless operation helps when the guest kernel can avoid unnecessary periodic ticks and when KVM presents timers accurately enough for longer idle periods. It cannot eliminate device emulation or a program requesting frequent wakeups. The host must also be tickless while idle; saving ticks in one layer and generating them in the other is elaborate bookkeeping, not power management.

After using a tickless guest kernel and disabling a polling monitor, host wakeups dropped and the machine cooled. Timekeeping remained the thing to watch: aggressive experiments are worthless if the guest clock drifts or timers fire late.

My conclusion is to shut down unused guests on battery and to measure host wakeups, not merely guest CPU percentage. For a guest that must remain available, remove polling and use appropriate virtual devices where supported. Virtualization can make a machine appear to be doing nothing in two operating systems simultaneously while the processor is, with admirable professionalism, doing work for both.

Proxy Models Instead of Copied Lists

I added filtering to a Qt 4.3 table by copying matching records into a second list. It worked until an edit in the filtered table changed the copy but not the original. I fixed that by copying changes backward, after which sorting ensured I copied them to the wrong row.

The obvious approach had created two sources of truth and an index-translation problem. Row seven in the filtered list was not row seven in the source, and after sorting it might not remain row seven in either list. Storing both numbers beside every record only made the confusion durable.

QSortFilterProxyModel exists to represent that transformation without duplicating the data. The view uses indexes from the proxy. The proxy maps them to source indexes when it asks for data or applies an edit. Sorting changes the proxy order, while the source model retains its own structure.

My second mistake was keeping a proxy index for later use. When the filter changed, that index became invalid. A model index is a temporary address into a particular model, not a permanent record identifier. For short-lived view operations, map indexes at the boundary with mapToSource() or mapFromSource(). For lasting references, store an identifier from the data and locate it again, or use persistent indexes only when the model can support their semantics correctly.

Filtering also taught me not to perform expensive parsing in filterAcceptsRow() on every request. I exposed normalized searchable text through a custom role in the source model and let the proxy compare that. Invalidating the filter after relevant data changes is cheaper than reconstructing a duplicate list and less likely to produce stale rows.

The model/view mechanism is initially more formal than copying strings into a table, but the formality identifies ownership. The source owns records, the proxy owns presentation order and inclusion, and the view owns selection and display.

My practical conclusion is to reach for a proxy whenever the same data needs another ordering or subset. Do not copy records merely to make a view convenient. Copies are friendly right up to the first edit, whereupon they become competing historical accounts.