Blog

Chasing Black Windows

After a driver update, newly opened windows sometimes became black under KWin’s OpenGL compositor. The same windows were fine with XRender. Turning off every effect changed nothing, which at least got the animations out of the suspect list.

The useful split was the texture-from-pixmap path. Under X11 compositing, the server redirects a window into a pixmap. KWin’s OpenGL path then uses the driver’s texture-from-pixmap support to bind that pixmap as a texture for the scene. XRender composites the pixmap through a different route. Applications had painted the right pixels; the OpenGL path was failing to present them.

I could make it happen by opening two terminals, covering one, and uncovering it. Damage arrived, but the exposed window stayed black or returned in strips. Switching to the previous driver fixed that exact sequence. The newer driver also behaved if I disabled its acceleration option, slowly.

That made a much better report than “KWin draws black windows.” I included the X server, Mesa, kernel and driver versions, the OpenGL backend, hardware identifiers, and the short cover/uncover sequence. I also noted that XRender worked. That last fact tells a driver developer far more than a screenshot of a black rectangle.

Screenshots were awkward: some captured the correct window even while the display showed black. The redirected pixmap could be fine while the texture or final scanout was stale. A camera photo was ugly but honest.

I am using XRender for normal work and keeping the failing setup available for testing. Reinstalling KWin would only replace the code that asks the driver to bind the same pixmap. The break is farther down the path, and now there is a reproducible way to reach it.

QtDBus and the Silent Reply

I wrote a tiny QtDBus client to ask a desktop service for its current state. The call returned immediately with an empty string, so I spent an hour changing service names and object paths. They were correct.

My naive mistake was treating an asynchronous call as a strangely fast synchronous one. I sent the message and read my result before the reply had travelled back through the bus. Adding a sleep appeared to fix it, which is how bad ideas acquire supporters.

QtDBus offers both blocking calls and asynchronous replies. A blocking call is simple, but doing it from the graphical thread can freeze the interface while another process is slow or absent. An asynchronous call returns a pending reply; completion must be observed later, after the event loop receives it. Errors are replies too, and ignoring them turns a useful complaint into an empty value.

I changed the client to watch the pending call and handle success and error explicitly. The window remains responsive, and stopping the service now produces an intelligible message instead of mysterious silence. I also registered the one custom type crossing the boundary rather than hoping QVariant would develop telepathy.

The bus is attractive because applications can expose small interfaces without linking directly to each other. That boundary is also real: names may be unavailable, processes may exit, and types must have a declared wire representation.

My conclusion is to use asynchronous calls for desktop interactions unless startup absolutely depends on the answer. Never repair an event-driven mistake with a delay. Sleeping makes the race less visible, not less present, rather like closing one’s eyes during a compiler warning.

KVM Needs the Right Bottleneck

I created a KVM guest to test packages without sacrificing another partition. The installer booted, the guest saw a disk, and I congratulated myself until copying files inside it reduced the entire machine to sludge.

My first attempt was to add more guest memory and another virtual processor. The copy became no faster, while the host began swapping. This is a reliable way to make two operating systems unhappy with one setting.

KVM uses the processor’s virtualization extensions to run guest code directly in a special execution mode. That avoids translating every ordinary instruction, but devices are a different matter. The guest still talks to emulated hardware, and each operation may require work in the userspace machine emulator and the host kernel. My slow copy was dominated by the virtual disk path, not by a shortage of arithmetic.

Moving the guest image off the host’s busy system disk helped. Using a simpler virtual disk setup and avoiding unnecessary host caching also made behavior more consistent, though the safest setting depends on what guarantees the storage actually provides. I am not going to trade filesystem integrity for a prettier benchmark. The benchmark will not visit me in hospital.

Preallocating space also avoided some pauses caused by repeatedly extending a sparse image during installation.

Processor support also needs verification rather than assumption. The KVM modules must load, virtualization must be enabled by firmware, and the host kernel needs the appropriate architecture module. Once that path works, compute-heavy tasks can be surprisingly close to native speed. Graphics and storage remain much more obviously virtual.

For my package-testing guest, one virtual processor and enough memory to avoid guest swapping are sufficient. The host must retain enough memory for its own cache and applications. I now measure CPU, host disk activity and swapping separately before changing the virtual machine configuration.

KVM is already useful because it fits into Linux rather than requiring a separate host operating environment. It is not a declaration that every emulated device is free. My practical conclusion is to size the guest modestly and find the actual bottleneck. Adding virtual hardware to cure slow virtual I/O only creates a more lavishly furnished traffic jam.

CFS After the First Week

I upgraded my workstation to Linux 2.6.23 mainly to try the Completely Fair Scheduler. The machine compiles code, plays music, runs a browser with an unreasonable number of pages, and occasionally hosts a virtual machine. Under a large parallel build, the old setup could make switching desktops feel as though the keyboard had been sent by post.

My first test was not clever. I started a build, dragged windows around and declared the new scheduler smoother. Then I rebooted into the older kernel and it also seemed smooth. Human perception is a wonderful measurement instrument if the desired unit is confidence.

For a better comparison, I repeated the same build with the same compiler jobs, timed it, and introduced an interactive task that periodically needed a small amount of processor time. Total build time changed little. The interesting difference was the delay before the interactive task ran when all cores were busy. Large stalls became less frequent with 2.6.23, though disk activity could still make the desktop miserable for entirely different reasons.

CFS approaches scheduling without the old collection of active and expired priority arrays. It tracks each runnable task’s virtual runtime, an adjusted measure of how much processor service that task has received. The task with the smallest virtual runtime is the one most entitled to run next. Runnable tasks are kept in a red-black tree, making that leftmost choice efficient as tasks arrive, block and wake.

The word “fair” needs care. Equal nice levels should receive roughly equal shares over time; it does not mean every task receives an identical slice at every instant. Nice values weight the virtual runtime, so a task with lower priority accumulates entitlement differently and receives a smaller share. Sleeper behavior emerges because a task that blocks stops consuming processor time. When it wakes, it may be behind its competitors and therefore run promptly, within limits intended to prevent absurd advantages.

My naive mental model was that CFS simply gives tiny slices to interactive programs and large slices to compilers. That is not how it identifies interactivity. There is no reliable label saying “this is the music player.” Instead, the accounting rewards tasks that use little processor time and wake to perform brief work. A music player, terminal or window manager often behaves that way, but so can a less noble process.

The scheduler also has to balance two competing costs. Switching too often improves apparent responsiveness but loses time to context switches and cache disruption. Waiting too long lets a runnable task monopolise a processor. CFS uses a target scheduling latency and derives slices from the number and weights of runnable tasks, subject to a minimum granularity. As the run queue grows, it cannot promise that every task runs within the same tiny interval without turning the processor into a context-switching demonstration.

This explains one of my results. With a modest build load, interactive delays stayed short. With a deliberately ridiculous number of runnable jobs, latency grew again. Fair scheduling cannot manufacture processor time. It can distribute scarcity coherently, which is less exciting but more useful.

Another misleading result came from I/O. During linking, the desktop paused even though CFS was selecting processor tasks correctly. The disk queue was saturated and applications blocked waiting for files. Changing the CPU scheduler did not cure that. Likewise, swapping overwhelmed every subtle scheduler difference. Before blaming CFS, I now check whether the delayed task is actually runnable rather than sleeping on storage.

Nice levels behaved more predictably in my tests than before, but group fairness remains a practical concern. If one user starts one processor-bound task and another starts twenty, scheduling every task independently can grant the second user most of the machine. There is work around grouping tasks, but the default desktop case still mostly exposes per-task fairness. The name should not be read as a constitutional guarantee.

I also tried changing scheduler tunables because numbers invite interference. Reducing latency made window feedback slightly sharper under synthetic load and increased context switches. Increasing it helped throughput by an amount too small to distinguish confidently while making the terminal occasionally sticky. The defaults survived my experiments, an outcome that wounded my pride but spared my configuration files.

After a week, I am keeping 2.6.23. The improvement is not that compilations finish magically sooner. They do not. The improvement is that short, waking tasks more often get service without elaborate interactivity heuristics, and nice values map onto a cleaner accounting model. That makes a loaded workstation feel less capricious.

The practical conclusion is to test CFS with repeatable mixed workloads, not window wiggling alone. Separate CPU delay from disk delay, compare distributions of latency rather than one lucky run, and resist tuning until a real workload demonstrates a problem. CFS is a substantial scheduler change, not a performance patch that makes every number smaller. On my machine it makes contention more orderly. Given what computers usually do under pressure, orderly is a fairly ambitious achievement.

KDE 4 Beta Is a Construction Site

I tried to use the KDE 4 beta for a complete workday. This was not an especially fair test, but fairness rarely survives curiosity. By lunch I had restarted Plasma twice and learned that my preferred panel arrangement could not yet be reproduced.

I began by importing settings from my normal KDE 3 account. The desktop behaved strangely: duplicated services appeared in menus, an application opened with the wrong font, and one configuration tool crashed. A clean user account fixed all three. Carrying years of configuration into a beta is not migration testing; it is inviting every old assumption to the same small party.

With clean settings, the underlying session is more stable than the desktop shell suggests. Applications launch, KWin manages windows reliably without effects, and Dolphin handles ordinary file work. Plasma remains the obvious construction site. Widgets can be added but are awkward to position precisely. Panel sizing is limited, and occasionally a widget stops responding until the shell is restarted.

That distinction matters because Plasma replaces several previously separate pieces: desktop icons, panels, applets and their containment. A failure in that young shell makes the whole environment appear dead even when applications and window management continue normally. It is a large architectural bet concentrated in the most visible square centimetres of the screen.

Restarting only Plasma from a terminal usually restored the workspace, which is useful for testing even if it is not a reasonable daily ritual.

I also encountered unfinished integration. Notifications differ between applications, removable devices do not always produce a useful action, and some settings change only after restarting a component. These are not dramatic crashes, but they interrupt the sense that one system is in charge.

After the experiment I returned to KDE 3 for work and kept the beta under a separate account for testing. KDE 4 is close enough that ordinary use finds valuable bugs, but not close enough that an ordinary user should be expected to diagnose them. My conclusion is candid: the beta contains a promising desktop framework and several usable applications, but it is not yet a dependable desktop. Calling it ready would be marketing; calling it hopeless would require ignoring everything beneath the panel.