Blog

Following the Device Through sysfs

A USB card reader prompted today’s trip through /sys. I wanted one answer: which physical device sits behind the block-class entry /sys/block/sda?

The useful relationship is the device symlink. /sys/block/sda presents the disk as a member of the block class; its device link points into the physical device hierarchy. Those are two views of one kernel object, not two devices.

I started at the block entry and followed its device link rather than guessing from the node name:

$ readlink -f /sys/block/sda/device
/sys/devices/pci0000:00/0000:00:10.4/usb2/2-2/2-2:1.0/host1/1:0:0:0

The exact target is machine-specific. Here it says that the block disk came through a SCSI host attached to USB interface 2-2:1.0, itself below a PCI USB controller. On another machine the chain will differ, but the link still joins the class view to the device that implements it.

Walking upward from that target lets me inspect the parents that actually own bus attributes. The block entry doesn’t need to copy USB details into its own directory; the parent links already express the relationship.

I don’t parse the punctuation in the resolved path. Directory names and topology are useful while diagnosing a machine, but exported links and attributes are the interface. Hard-coding every component would just trade /dev/sda for a longer accidental name.

This also explains why /dev/sda isn’t a hardware biography. The node names a block interface; sysfs supplies the link back to the device model when I need to ask where that interface came from.

The service corridors are a little dim, but this one symlink answers the question without guesswork.

Qt 3.3 Signals Without Magic

I had a small Qt 3.3 utility that refreshed a list after reading a directory. It worked until I renamed a slot, at which point clicking the button did precisely nothing. No crash, no compiler error, just a very calm refusal to cooperate.

My naive fix was to add qDebug() calls everywhere except the place that mattered. The button emitted its signal and the refresh function worked when called directly. After too much staring, I finally checked the return value from connect() and ran the program with Qt warnings visible.

bool connected = connect(refreshButton, SIGNAL(clicked()),
                         this, SLOT(reloadDirectory()));
Q_ASSERT(connected);

The slot declaration and the string in SLOT() no longer agreed. Qt’s meta-object compiler records the signal and slot information that ordinary C++ does not provide. The connection is therefore checked at runtime, not by the compiler. Once I remembered that mechanism, the silence stopped being mysterious.

The generated meta-object code also explains why a class using signals or slots needs the Q_OBJECT macro and must pass through moc. Forgetting that step can produce linker errors rather than a friendly explanation. With the normal Qt build tools, the extra generation is automatic; with a handmade makefile, it is another dependency that must be stated correctly.

I tested disconnection and destruction as well. Qt removes connections involving a destroyed object, which is safer than retaining callbacks into dead C++ instances. That convenience still depends on the receiver actually being a QObject with a well-defined lifetime.

I now keep signals and slots in the appropriate class section, inspect the generated warnings, and assert important connections during development. I also avoid clever overloads unless they buy something substantial. The old string syntax is useful, but it can turn a typo into a tiny mime performance.

Small executable tests help here too: create the sender and receiver, emit once, and verify the resulting state before involving the whole window.

Qt 3.3 remains pleasant C++ because it removes a great deal of event plumbing. It does not remove the need to understand that plumbing. Framework convenience is best treated as compressed machinery: use it freely, but know where to open the panel when it stops.

KDE 3.3 Feels Settled

I upgraded my main workstation to KDE 3.3 because I wanted the newer applications, not because I was looking for excitement. Desktop upgrades have supplied quite enough excitement already.

My first attempt was the usual impatient one: replace the packages, keep every old setting, and hope. The desktop started, but a couple of panels behaved oddly and Konqueror inherited some settings that no longer made much sense. I briefly blamed KDE. Then I tried a fresh user account and discovered that my carefully accumulated configuration was the real antique.

What impressed me was how little else needed attention. Session restoration brought back the applications I expected. The file manager, terminal, editor, and control modules felt like parts of one desktop rather than strangers sharing a theme. Even mundane details such as keyboard shortcuts were consistent enough that I stopped thinking about them.

That is what maturity looks like to me. It is not a spectacular new dialog. It is being able to spend the afternoon in C++ rather than repairing the environment used to write it.

I copied only the settings I understood into the fresh account and left the archaeological layers behind. KDE 3.3 may not make for dramatic dinner conversation, but a desktop that gets out of the way is doing its job very well.

Watching Latency on Linux 2.6

I have been comparing two Linux 2.6 configurations for a workstation: one with kernel preemption enabled and one without it. Looking only at total build time made them appear nearly identical, while using the machine made them feel different. The missing measurement was latency.

Throughput asks how much work finishes in an interval. Latency asks how long a particular piece of work waits. A kernel build is a reasonable throughput load, but its completion time does not reveal that an audio process waited long enough to miss a deadline or that keyboard input paused for a fraction of a second.

My crude but useful test runs the same build while playing audio, copying a large file, and interacting with KDE. I record build time, note audio underruns reported by the application, and repeat enough times to distinguish a pattern from one lucky run.

time make -j2 bzImage

The O(1) scheduler helps when many tasks are runnable. Its priority arrays and per-CPU run queues keep selection costs predictable, while interactive heuristics favour tasks that sleep and wake frequently. But the scheduler cannot run a task until the current execution context can be switched.

That is where kernel preemption matters. With it enabled, ordinary kernel code can be preempted when no lock or other critical condition forbids it. An interactive task awakened during a long system call may run sooner. Interrupt handlers and protected sections remain non-preemptible, so a poor driver can still dominate worst-case delay.

On my machine, enabling preemption does not materially improve the build time. It does reduce occasional input stalls and audio trouble under mixed I/O load. That is the result I expected: better responsiveness, not newly manufactured processor cycles.

Thread behaviour can alter the picture too. NPTL mutexes stay in userspace when uncontended and use futex operations when a thread must sleep or wake. A heavily contended threaded program may therefore create a very different scheduling load from one with mostly private work. Counting threads alone says little; runnable and blocked states matter.

I also test without excessive parallelism. Starting far more compile jobs than processors can turn the test into a contest between memory pressure, disk traffic, and scheduling. That may resemble a real workload, but it is a poor way to isolate one mechanism.

The caveat is that my observations are not hard real-time guarantees. General-purpose Linux still has sources of unbounded or hardware-dependent delay, and an average hides the worst pause. For desktop tuning, however, repeated underrun counts and interaction under a controlled load tell me more than one impressive jobs-per-minute number.

I am keeping preemption enabled on the workstation and evaluating it separately on servers. A server handling many requests may care about response-time distribution, but a batch machine may prefer the smallest scheduling overhead. There is no universally fast switch. First decide whether the itch is throughput or latency; only then does the benchmark know what question to answer.

Small KDE 3.2 Habits That Save Time

After several months with KDE 3.2, the features saving me time aren’t the ones that make attractive release screenshots. They’re small habits around Konqueror, the Run Command dialog, and reusable KDE components.

The first is using location protocols directly. Konqueror is not limited to local paths and HTTP URLs. Typing an sftp:// location gives me a remote file view through the normal interface. I can keep local and remote views open and copy between them without teaching every application a separate transfer procedure.

I still use command-line scp for scripted or large transfers. A graphical view is convenient, not evidence that errors no longer occur. If a copy matters, I verify its size or checksum at the destination.

The second habit is splitting Konqueror’s view when comparing directories. One window with two linked views is easier to reason about than two overlapping windows. Because the file view is a component, the shell can arrange it without becoming a separate file manager for every layout.

The third is assigning keyboard shortcuts only after noticing repeated actions. KDE permits a heroic quantity of customisation, but configuring twenty speculative shortcuts creates a keyboard dialect I will forget by Friday. I add one shortcut when an action has annoyed me several times, then use it until it becomes natural.

Profiles are useful for the same reason. A Konqueror profile can restore a practical arrangement of views and locations. I keep one for file work and another for browsing rather than forcing one toolbar and sidebar arrangement to serve both jobs.

Finally, I use KDE’s Run Command dialog—the minicli utility—for applications I already know by name. Navigating a menu helps while discovering software; pressing Alt-F2 and typing the program name is faster afterward. Command history makes repeated invocations painless.

None of this is revolutionary. That is the point. KDE’s strength is the common infrastructure beneath applications: URL handling, parts, shortcuts, and session behaviour. Once I use those facilities consistently, individual programs require fewer special habits.

There is a danger in turning desktop configuration into a hobby that prevents desktop work. I avoid changes that save two seconds once and require an evening of maintenance. The useful tweaks survive upgrades, use standard KDE facilities, and are easy to explain six months later.

KDE 3.2 gives me plenty of choices. The trick isn’t exercising all of them. It’s finding the few that remove recurring friction, then leaving the control centre alone long enough to get something done.