I’ve been asked a few times if it would be possible to use
virtnbdbackup as some kind of
“replication” utility, to keep cold standby virtual machines on other libvirt
hosts.
Usually i would tell to use underlying filesystem features (such as zfs
send/recv, with incremental snapshots) to keep cold, standby copies on other
hosts.
As for qcow based virtual machines, using the dirty bitmaps is not only a valid
feature to create backups, but to (incrementally) replicate virtual machines,
too.
I’ve released vmsync. A small golang utility
that implements a simple replication tool using the NBD protocol to sync
virtual machines to other hosts.
Some of you might have noticed that the recent (or rather: previous) version of libayatana-appindicator (v0.5.94) notified users and developers of the library being deprecated.
This short post is to notify you, that with today's libayatana-appindicator v0.6.0 release [1] this deprecation warning has now been removed again. Another new feature (added to AppIndicator without ABI breakage) is tooltip support. The new package version has just been uploaded to Debian experimental. Please test if your application (if it gets linked against libayatana-appindicator) continues to work flawlessly. Thanks!
libayatana-appindicator will receive continued support until GTK-3 becomes end-of-life (because libayatana-appindicator has a baked-in GTK-3 dependency which should not be ported to GTK-4 imho). That said, in the future, GTK-3 applications can continue using libayatana-appindicator for sending AppIndicator-like icons and menus over DBus to KStatusNotifierItem-based system tray renderers.
If you are looking for an AppIndicator implementation for GTK-4 applications (or other), I'd like to encourage you to help making libayatana-appindicator-glib [2] a new standard (can be used in GTK and Qt applications alike, implementation is using pure Glib-2.0). Currently, there is only one renderer (ayatana-indicator-application), so more work needs to be done on the renderers' side. (One of the next work items here is to get AppIndicator-Glib support working in Lomiri's desktop/windowed mode).
I backported various security fixes from 10.3 to trixie, bookworm, bullseye, buster, and stretch. For trixie, I also backported several IPQoS fixes to line up with upstream’s traffic management settings and drop a rather hacky Debian-specific patch; this needed a quick follow-up fix.
AI slop is invading the web. A recent story about disallowing LLM-generated
submissions on Lobsters triggered a lot of debate. My personal worst
offenders are LinkedIn articles with AI-generated images and uninspired
articles filled with emojis from people trying to masquerade as experts on a
subject they don’t care enough to write themselves. While I am unhappy about
this situation, I rely on LLMs for grammar, copyediting, and
translation. I don’t see this as a contradiction.
I am a native French speaker, but I blog in both English and French. When I
started writing this blog in 2011, I was composing in French and translating
to English, but I found it was better to work in the reverse order to
avoid unnatural and non-idiomatic constructions. One of my goals is to write
“good” English but I never felt it was my strong point.1 For example, verb
tenses are often an issue, even if I mostly stick with the present tense. I
learn the rules and forget them right away. I also don’t feel like hiring an
editor for something I see as a hobby.
I know that LLMs may alter the author’s voice when editing, but the
corrections in the second step are minor. The prompt asks to “apply light
stylistic edits,” with some guidance around avoiding passive voice, long
sentences, bland verbs, and filler words. It also defines the target audience:
technical with a B2 level in English.
In the following excerpt, I used “long time” instead of “long-standing.” The
former is missing a hyphen and applies to people—a long-time friend, while
the later relates to a situation—a long-standing agreement. I had a hard
time understanding the reason of the second change: the LLM prefers a
defining relative clause to provide the definition of “RIB sharding.”
As the Internet routing table contains more than 1 million routes, Akvorado
needs to scale to tens of millions of routes. This has been a long
time long-standing challenge, but I expect this issue is now
fixed by using RIB sharding, a method to split that
splits the routing database into several parts to enable concurrent
updates.
In the next modification, the LLM puts “device” instead of “equipment.” This is
correct as “equipment” is an uncountable noun. I know that, but I still fall
into this trap.
When Akvorado does not find a route from a specific device, it falls back to a
route sent by another equipment device.
I ask the LLM to use “descriptive verbs” and it complies by replacing a
multi-word predicate with a lexically rich verb:
The benchmarks demonstrate it has better performance than
outperforms other packages, both packages for
lookups, insertions, and memory usage.
It also fixes grammar errors. In the next excerpt, a “list of routes” is a
singular expression. Moreover, “stored” is a state and I should not use “into”
as it expresses a change.
The list of routes for each prefix are is not stored
directly into in the prefix tree.
As a last example, consider the following snippet. The “require” verb
accepts a noun or an object followed by a to-infinitive. I can’t use it with
just a to-infinitive.
An alternative would be to have one prefix tree for each peer but it would
require to configure configuring all routers to export
their routes.
As someone who didn’t grow up speaking English, I struggle with these grammar
rules despite reading a lot of English material.3 French is more
complex to get started but more systematic. English is full of irregularities.
On each page, I disclose in the footer whether an AI modified the content. There
are three levels:
🧠: no AI or almost no AI (e.g., grammar corrections)
✨: enhanced (e.g., copyediting)
🤖: generated (e.g., translated from another language, even if human-edited)
Hover or tap the icon to reveal the AI’s name and its role in the document.
Example of AI usage disclosure: Claude Sonnet 4.5 edited this article.
The graph below shows which tool altered each post, year by year. Recently, I
applied the grammar skill to past articles. Since 2018,
French articles have been translated with the help of DeepL first, then of
an LLM. Since 2024, English articles are copyedited.
🖼 Graph showing the AI usage over the years. Each level get its own
color.
AI usage over the years. Hover or tap a band for the details.
If you are strongly against any usage of LLMs specifically for writing, I hope
you accept my more nuanced position on the usage of these tools as a trade-off
to provide clearer and more engaging articles. Years of literature on improving
English told us it is important to choose the right word to keep the reader
engaged.
[…] Good writing consists of mastering the fundamentals (vocabulary,
grammar, the elements of style) and then filling the third level of your
toolbox with the right instruments.
― Stephen King, On Writing
Note
Unlike other recent articles, I did not use an LLM to edit this post:
an unnamed person kindly accepted to proofread it. I translated it to French
without using an LLM either.
I am quite happy with the writing tools provided by Kagi. Both the
translate tool and the dictionary are a valuable help to find
different wordings. I also lean on Kagi’s research assistant when
researching a topic. ↩
When I was ten, I played Monkey Island 2 in English without having
taken any classes. I used a dictionary to translate word by word and I found
the irregular verbs confusing—and not in the dictionary. ↩
The Voxit participation platform is originally based on the open source Polis platform developed by The Computational Democracy Project in the United States, but since its establishment in autumn 2025, the European Voxit community has been developing an independent solution, adapted to European needs.
The aim is to create an open source, interoperable and scalable participation infrastructure suited to Europe’s regulatory environment and aligned with democratic values. Through this development work, Voxit is becoming a clearly distinct fork of the original Polis platform – allowing Europe to develop participatory infrastructure at its own pace and according to its own governance needs, while the original Polis project continues to break new ground. This enables Europe to build its own open and trustworthy digital democracy tools, rooted in public governance and European democratic traditions.
Voxit 1.0 source code is now available
The source code for version 1.0 of the European community edition of the Voxit platform has now been published and is openly maintained on GitLab.com at: https://gitlab.com/voxit/voxit#
The RISC-V CPU architecture has been gaining a lot of popularity since it launched in 2014, and now that the industry is standardizing on the RVA23 level that includes vector support as a mandatory extension, we are likely to see a lot more edge- and IoT devices with the ability to run local LLMs at reasonable speed, and most importantly at very compelling prices.
SpacemiT is a Chinese RISC-V CPU manufacturer that launched on May 11th, 2026, their long-anticipated next-gen RISC-V AI chip K3. It is among the earliest RISC-V CPUs that adhere to the RVA23 standard and performance-wise it is quite capable, providing 130 KDMIPS general computing power, 60 TOPS on INT4 which translates to about 15 tokens per second when running a 30 billion parameter large language model.
the price point is within reach of home and small business users and
the overall feature set makes it an ideal platform to build local and offline AI systems.
SpacemiT also develops their own Debian-based Linux distribution Bianbu OS, and seems to have collaboration going on with the wider community. Their community site seems active, and they also have a dedicated X account @spacemit_riscv and Reddit account r/spacemit_riscv posting relevant progress info on Linux kernel upstreaming activities. The X account is also responsive, as evidenced by its replies to my questions.
Canonical lists the SpacemiT K3 pico-ITX and K3 CoM260 Kit on its official Ubuntu for RISC-V partner-built hardware page, which strengthens the perception that upstream Linux support is being taken seriously. The SpacemiT folks also gave an interesting talk at the 2026 Ubuntu Summit that includes a peek into their roadmap with future K3, K7 and K9 models.
SpacemiT does not sell anything directly to consumers. Instead you need to buy a board that includes the K3 chip from an integrator. Currently the main resellers are:
All of the above are Chinese companies that ship to customers both inside and outside China. DeepComputing stands out as the only one that actually has done real integration and ships the K3 on a custom board, while the others simply resell the SpacemiT-produced K3 pico-ITX and K3 CoM260 Kit.
Milk-V
Milk-V is a RISC-V specialized integrator, as the name already implies. They sell the K3 under the name Jupiter2. Of all the K3 pico-ITX reseller product pages, the Jupiter2 presentation is the nicest and most detailed. Unfortunately their order page at arace.tech only states that it is a “pre-order” with no information about shipping schedule, taxes, or other details like what SSD is included (if any). Based on the pictures it does ship with a Milk-V branded case. The 32 GB RAM lists at 504 EUR, which is a very reasonable price. The @MilkV_Official account on X recently promoted the K3.
Documentation and support
As of this writing, the Milk-V Jupiter2 documentation site is just a stub and has no actual content, and only two links to the SpacemiT K3 documentation site. For support there is a web forum with a dedicated Jupiter2 section. There is also a Matrix space, but unlike their other products, there is no dedicated Jupiter (neither v1 nor v2) channel.
Community size and open source involvement
At least one prior Milk-V product was certified by Canonical, which indicates there is some collaboration in progress. Canonical also lists the Milk-V Titan on its official Ubuntu for RISC-V partner-built hardware page.
Sipeed
The Sipeed K3 announcement is well written (in English) with all the relevant details and links to additional PDF manuals. However, their main page at sipeed.com says nothing about the K3, so one must know the subpage URL to access it. They offer both the K3 CoM260 kit compatible with Jetson Orin Nano carrier boards, and the stand-alone K3 pico-ITX-sized motherboard. The CoM260 kit is only 10 USD cheaper than the full pico-ITX motherboard, so choosing the latter is a no-brainer if starting from scratch. The pico-ITX model with 32 GB DDR5 RAM sells for 639 USD. The product page does not mention anything about hard disk size, so you don’t really know exactly what you will be getting if placing an order. There is no indication about case, Wi-Fi antennas or power supply either, so most likely they are not included.
Their store.sipeed.com website does not work at all, and their Taobao and AliExpress stores are not public and only accessible to registered users. The order page also says nothing about shipping time, delivery time, or taxes. The X account @SipeedIO is active and recently posted pictures of shipments in progress.
Sipeed has had at least one of their previous devices certified by Canonical, which indicates they are active in the community.
Note that the other RISC-V company SiFive that also has had hardware certified and officially supported by Canonical is a different company, despite the very similar name.
Banana Pi
Banana Pi announced that they offer both the K3 CoM260 kit and the K3 pico-ITX motherboard version. Their product page for the K3 confusingly shows a MediaTek product in the page banner rather than the SpacemiT K3. Based on the product description and the fact they renamed the product as BPI-SM10, it seems to ship with some carrier board. The product pictures look identical to the SpacemiT documentation and there is no picture of the carrier board, and details are very sparse. The pico-ITX version with 8 GB RAM and 128 GB SSD sells for 293 USD and the CoM260 developer kit with the same specs sells for 287 USD and the 32 GB RAM with 128 GB SSD model sells for 595 USD. The shop page shows only five orders so far and items are currently out of stock. As there was no 32 GB RAM version of the pico-ITX available at all, this isn’t an option for me as I want to run 30B parameter models that need the larger memory version.
Of all of these resellers, the Banana Pi website seems the most outdated. It does not have a search feature, it is not mobile-friendly, pictures can’t be pinched to zoom in and so forth. Product names are also almost all identical, and as the product listings only show the beginning of the product name, figuring out what product is what requires extra effort that just makes the online purchase experience plain bad.
Documentation and support
I was only able to find the documentation page for the CoM260 kit, but none for the pico-ITX version. For support there is a forum, but the category list does not show any section for K3, and the forum search prohibits using the search term “k3” as too short.
Community size and open source involvement
Banana Pi has a long history in the ARM single-board computer market, but their presence in the RISC-V ecosystem is still growing. Their X account @sinovoip has posted only once about the K3 and otherwise promotes their ARM boards. However, their community culture page does express a commitment to open hardware in general, but there is no visible K3-specific community activity.
Firefly
Firefly’s K3 product page is comprehensive. Based on the details, they do not offer the K3 pico-ITX variant at all, but only the K3 CoM260 board inside the AIBOX-K3 Firefly RISC-V Edge Mini PC product. This is a feature-complete offering with a Jetson Orin Nano carrier board and case. The AIBOX-K3 with 32 GB RAM and 128 GB SSD in a case sells for 689 USD in their own Firefly.store. Unfortunately it only has HDMI and there is no USB-C with DisplayPort support, which is a deal-breaker for me personally.
The wiki link on the product page is broken. The Firefly wiki does have a section for the AIBOX-K3, but it too has a broken link. It seems that as of the time of writing, there is no wiki section for this product yet.
For support there is a web forum, which does have at least one K3 thread covering guides such as Hermes Agent installation, though broader K3-specific sections are still sparse.
Community size and open source involvement
Firefly’s X account @TeeFirefly has had no posts since 2024, and their GitLab/T-Firefly shows mostly 2024 activity, with only one repository updated in 2025 and nothing in 2026. Historically they have built a moderate community around their ARM-based Rockchip boards, with active forums and wiki contributions for those product lines. Their RISC-V K3 offerings are newer, and likely need a lot more polish to be attractive products overall.
DeepComputing
Last, but certainly not least, is the laptop manufacturer DeepComputing that offers a Framework laptop compatible motherboard with the SpacemiT K3 chip. They also sell the plain motherboard, or with the Cooler Master case, which allows one to easily connect it to an external monitor and keyboard and use it as a desktop computer. The plain board with 32 GB RAM and no SSD sells for about 882 EUR. Shipping of the first batch is expected to start by end of June 2026. Their X account @DeepComputingio promotes this DC-ROMA RISC-V Mainboard III as their flagship product, so they seem to put a lot of effort into it.
The overall product design and packaging seems good. Of all the K3 resellers and integrators that I was able to find, DeepComputing is the only one that actually designs their own boards with the K3 processor, while all the other vendors above are simply reselling the vanilla K3 boards with or without a case.
After reviewing all these options I decided to buy the DC-ROMA RISC-V Mainboard III for Framework Laptop 13 with 32 GB RAM, 1 TB SSD and the Cooler Master case, totalling about 1100 EUR.
Documentation and support
DeepComputing maintains product information for their RISC-V hardware at github.com/DC-DeepComputing/Framework, with documentation of the newest Mainboard III (FML13V05) still being finalized ahead of the first batch shipment. They provide community support through Discord and web forum, although the latter has very little activity.
Community size and open source involvement
DeepComputing has established itself as a pioneer in RISC-V laptops, beginning with the DC-ROMA. I have seen their stand at FOSDEM, which shows they are genuinely active in the open source community. Canonical lists DeepComputing’s first mainboard / FML13V01 on its official Ubuntu for RISC-V partner-built hardware page, and it seems likely that they will continue to collaborate with Canonical with the new model once it ships. While the underlying Linux enablement depends on SpacemiT’s upstream efforts, DeepComputing’s involvement helps bridge the gap between reference hardware and consumer-ready products.
Conclusion
After weighing all the options, I ended up placing an order with DeepComputing for their custom K3 board with the Cooler Master case. Despite the premium price, the active community support and the properly documented promise of a complete, working system made it easy to place an order with confidence.
The SpacemiT K3 is poised to be one of the most significant RISC-V chips for local AI workloads, thanks to its RVA23 compliance and high tokens per second potential. Yet the buying experience in mid-2026 remains fragmented and incomplete. Hopefully this is just because the product is new, and they will get the purchase experience polished soon.
What struck me most during this process was how poor the customer experience is across nearly all of these vendor websites: broken links, missing search functions, outdated product banners, pages that show the wrong product entirely, and no information about shipping times, stock levels, taxes, and so on. One wonders why these companies don’t fully invest in their web presence.
Personally I would assume they likely have enough customers already, primarily through domestic channels like Taobao and JD.com, that they do not feel any pressure to improve their international-facing sites. However, I did also review what was offered on Taobao, and the product details were very incomplete there too. Taobao, however, has a built-in live chat with almost all sellers, which can be used to ask questions and thus compensate for missing product details.
I don’t fully understand why the sales process seems unpolished. The websites feel almost like an afterthought – a checkbox to claim global reach while the real business apparently happens elsewhere via closed platforms or via inaccessible reseller channels. It is a frustrating reminder that in the RISC-V hardware world, the technology may be open and global, but the purchase experience is less so.
A new minor release 0.4.27 of RQuantLib,
the first in over a year, arrived on CRAN a couple of minutes ago, has
just now been uploaded to Debian,
and is being built for r2u as well.
QuantLib is a rather
comprehensice free/open-source library for quantitative
finance. RQuantLib
connects (some parts of) it to the R environment and language, and has
been part of CRAN for nearly
twenty-three years (!!) as it was one of the first packages I uploaded
to CRAN.
This release of RQuantLib
brings an update to the interface for all equity options, vanilla and
exotics as well as implied volatilities. We now support the option
maturity via either an actual maturity date, or the (fractional
business-day years) numeric. This uses a clever little Rcpp trick I should discuss in a
separate blog post. We also re-ran compileAttributes() to
re-create the RcppExports.cpp file now using a slightly
improved way of calling Rf_error for an ongoing Rcpp transition, and did some more
standard maintenance. The details from the NEWS file follow as
usual.
Changes in RQuantLib version 0.4.27 (2026-06-07)
All equity option functions can now take either a (fractional)
time span to expiry or a given date, and accept a daycounter
setter.
Two very old schedule helpers had a superfluous
try/catch removed.
The continuous integration setup received a minor
update.
The RcppExports.cpp file was updated to aid a
Rcpp transition.
I finally carved out some time today to prepare and release debsecan-mcp v0.1.2 to PyPI. During this release, I
integrated PyPI's trusted publisher mechanism, which authenticates directly via
GitHub Actions and eliminates the need for manual uploads or static API tokens.
What is New?
There are no feature updates in this release; the changes are strictly focused
on PyPI publishing requirements. This was handled entirely within the Antigravity
IDE.
The primary change replaces the python-apt dependency with python-debian for
version comparison. PyPI rejects packages that reference external Git repositories,
and python-apt lacks an official PyPI release. The original python-apt logic
remains intact: if the system has python-apt installed, the server defaults to
it. Otherwise, it falls back to the comparison logic implemented via the
python-debian NativeVersion class.
What Next?
The next release will introduce a standalone CLI utility called debvulns. It
mirrors debsecan functionality but surfaces the cleaner, richer vulnerability
data already implemented in debsecan-mcp. The code is written, and I will
release it once testing is complete.
I also owe a post explaining my rationale for designing a CLI utility alongside
the MCP server, and my broader thoughts on CLI vs. MCP workflows. I aim to publish
that next week.
A while back, I got my first subwoofer (a surprisingly nice addition to
the movie experience, just like rear speakers were). But I live in an
apartment, and I don't want to annoy my neighbors at night (the speaker
cone points literally down into the floor, and I have no idea how much
my neighbors get to share in my enjoyment). So, what to do?
It turns out my receiver supports a sort-of documented serial protocol;
it doesn't have an actual serial port, but you can telnet into it
(only one session at a time!) and get the same two-way stream.
(It also has a HTTP version which I find less useful.) So this allows
me to impose my own policy, and of course, doing it via an existing
Home Assistant adapter or something was no fun and also thoroughly
frustrating, so I saw it as an opportunity to keep maintaining my low-key Rust skills.
(No, no LLM code generation. If I'm going to spend time on this, at least I
can learn something myself. I think I asked one for code critique at some
point, but I can't remember.)
The policy is roughly: If I'm watching TV after 22:00, then the subwoofer
is either turned off (if possible) or turned down -12 dB (the maximum).
But if I'm watching a Blu-ray or another input like that, that's presumably
a conscious tradeoff I've made and things are left at normal. Everything
gets a bit more complicated by the fact that the receiver tends to lose
state when doing certain switches, and when it boots, it takes a minute
or two before Telnet responds, and when it shuts down, it goes into this
weird limbo state where it doesn't respond to anything but the TCP connection
seems still up.
And then I figured out I also wanted to dim the display when watching
movies (again, only certain inputs), but not for a couple of seconds
after making any adjustments. And after doing that, I figured that my
access point LED should also be turned off, which happens to be some
SNMP writable stuff against the Cisco wireless controller it hangs on.
So, if you have a Denon or Marantz AVR, a Cisco access point on a controller,
and my exact preferences about what to do about the subwoofer, then you
are free to download and use my software
to impose that policy. It is “is distributed in the hope that it will be
useful”, as one says. If you have IPv6.
This was a rather strange month. The details about the embargoed exim4 issue arrived only after I already went to bed and the embargo lift was 18 hours later. Luckily Stretch was not really affected and the uploads for Bullseye and Buster went out on time.
Something similar happened with the embargoed issue of rsync. The info arrived at 8:00 in the morning and the embargo lift was on 2:00 next morning. From an Europeans point of view, the Australians do have strange time zones. But there is more to this than that. Upstream sent more than 50(!) patches for these five CVEs that needed a backport to Bullseye. As things turned out, there is a regression in the upload to Unstable and investigations are ongoing whether this regression is also available in the backported patches for Trixie, Bookworm and Bullseye. So rsync-updates for Buster and Stretch is in the works, but I am afraid they need some more time.
All good things come by threes. Two critical CVEs of hplip appeared and a new upstream version was released by HP. HP is no longer interested in working with distributions and over time more than 80 patches have been accumulated that need a rebase for a new upstream version. For that reason I avoid this package as much as I can, but two critical CVEs did apply some kind of pressure on the maintainer. So I finally managed to do this update and the latest version of hplip is now in Debian. Nevertheless, this feels good :-). Anyway, it is not over yet. HP does not have a public repository nor do they publish patches for these CVEs. So I am still searching for the correct fixes to backport them to Bullseye, Buster and Stretch. The other distributions have the same problem and a silver lining appears on the horizon.
I also prepared an update of gimp for Buster and Stretch, but due to an accident I only managed to release the corresponing ELA in June. The accident was also the reason for only half a week of FD. Thanks to Daniel who took over.
This month I continued to work on unifying packaging on Debian and Ubuntu. This makes it easier to work on those packages independent of the used platform.
I previously
wrote some
advice for developers and distributions about the upcoming
Microsoft CA Rollover, and I hope that was useful for people.
I've now also added some user-facing documentation about the CA
rollover in the Debian wiki
at https://wiki.debian.org/SecureBoot/CAChanges. I've
added guidance on managing certificate updates on Debian systems: how
to check if a system needs those updates and various ways to make them
happen. If you're running Secure Boot systems, this may be important
for you.
While the same event is the primary cause for these docs, they're
designed for different people. Again, I hope this new doc is
helpful!
I have just bought a HP Z4 G4 with W-2125 CPU for $320 and I decided it was a good time to do some benchmarks on Debian package building to see which system I should use for that.
For the initial tests of the Z4 G4 I ran them with hyper-threading enabled as 4 cores isn’t much by today’s standards and also the machine in question is going to be less exposed to hostile data and contain less secret data than most of my systems so the security risks of hyper-threading are less of a concern.
I did some tests with a couple of tasks that are very important to me, building SE Linux policy packages (something I may do a dozen times in a day) and building Warzone 2100 (which I do less often but is the most intensive build process I regularly run). At the bottom of this post there are tables with the results from building these packages on my Z640 workstation with a E5-2696 v4 CPU [3], the Z420, and the new machine.
For the Warzone 2100 package I tested building on my Z840 dual CPU system [4]. I didn’t test building the SE Linux policy on the Z840 this time because that package can’t take advantage of even 22 cores. When I initially got the Z840 running it built the policy packages faster because the Z640 had an older CPU that was slower for single core operations than the CPUs in the Z840.
BTRFS Compression
For some time I have noticed significant differences in compile time on my workstation, a factor of more than 2. I did more tests and noticed that “top” showed something like the following, those kernel threads are all BTRFS related, except for “gfx” which is probably something graphical caused by running Chrome with about 300 tabs open.
I had been running BTRFS with the mount option “compress=zstd:15” which caused much of the performance problems when building. It was also a random performance issue which I think happened due to the BTRFS 30 second write-back sometimes taking more than 30 seconds during the build process which then caused a second write-back.
I did tests on ZSTD compression levels 5, 8, 10, and 15. 15 was never good and often really bad. 10 was not unbearable but consistently slower. 8 was sometimes as fast as 5 and sometimes quite a bit slower. I didn’t test levels below 5 because I need to have some compression and it seemed that the benefits of reducing compression were dropping off below 8.
I found that the BTRFS compression delay is not counted in system time for the process. I think it’s the fsync() system calls in the semodule and dpkg-deb programs that cause the delays related to BTRFS compression waiting for kernel threads.
In the below table which has test results from building the package with and without BOINC, and with different ZSTD compression levels in BTRFS all the worst entries were from when BOINC was running apart from one where ZSTD level 15 compression was used. The really poor performance with ZSTD level 15 was an outlier, but it wasn’t an uncommon outlier so I left it in.
Running BOINC in the background configured to use all CPU cores caused a significant increase in “user CPU time” (the time a CPU core spent actually running the program). My initial thought was that it’s partly related to “turbo boost”.
Turbo boost would only be a noticeable issue for building packages like the SE Linux policy packages which doesn’t take much advantage of multi-core CPUs. For a build process to average at best 362% CPU use there has to be large parts of the process that are limited to one or two cores which can potentially give a benefit from turbo-boost.
When building the Warzone 2100 packages most of the build time is running basis-universal which is a multi-threaded program to compress GPU texture data. This usually causes a load average of 300+ on the Z640 or 600+ on the Z840. But the build time is still increased by more than 50% on both the Z640 and the Z840 when BOINC is running in the background, which seems to be an indication that it’s not related to turbo boost. I verified that BOINC is running at IDLE schedule priority with the following command:
# chrt -p $(pidof -s einstein_O4MD_2.01_x86_64-pc-linux-gnu)
pid 2974874's current scheduling policy: SCHED_IDLE
pid 2974874's current scheduling priority: 0
In theory this means that BOINC won’t affect foreground processes.
Hyper Threading on the W-2125
The best claims I’ve seen about HT are 15% to 30% performance boost. The best I’ve actually seen in the past is about 18%. Seeing a 10% benefit for building Warzone 2100 is at the low end of the range I expected. 8 virtual cores is not many for a build process that causes a load average of 600+ when running on a system with 44 real cores.
I was surprised to see a 6% performance benefit in hyper-threading for building the SE Linux policy as I didn’t think there was enough use of threading or multiple processes to allow that.
Many build scripts use a number of processes that match the number of apparent CPU cores. While “make -j 88” might give a theoretical performance benefit on a 44 core system it will also take a lot of RAM and any paging will outweigh the benefits of hyper-threading. On a system with only 4 real cores there’s less potential for using too much RAM and as security isn’t so important on that system I will leave it on.
Comparing the CPUs
The best results of the Z640 and Z4G4 are only 50% faster than the best results of the Z420.
The Z420 has a E5-2620 CPU which is far from the fastest CPU available for that system – the E5-2687W has 8 cores and rates 10,021/1,669 on passmark [8] which is far better than the 5,331/1,114 the E5-2620. The E5-2687W is the fastest CPU that HP lists as supported by the Z420 and it supports DDR3-1666 RAM as opposed to the DDR3-1333 that is the fastest that the E5-2620 supports. With suitable hardware upgrades the Z420 would probably only take about 20% longer to do builds of the SE Linux policy and other packages that can’t take advantage of more than 8 CPU cores.
The Z4G4 system has 4 RAM channels which means that you should get some performance benefits from having 4 DIMMs, my system currently has 2 and I haven’t yet managed to get more DDR4-2666 DIMMs. But I’d still expected a W-2125 CPU with 2*DDR4-2666 DIMMs outperform any E5-26xx CPU with 4*DDR4-DDR-2400 DIMMs for tasks that average less than 4 CPU cores.
In retrospect I would have been better off getting a HP Z820 (two socket server with DDR3 RAM) than the first DDR4 systems I got. It seems that for reasonable size builds a two socket system comes close to twice the speed of a single socket system. I did briefly own a HP ML350 two CPU system with DDR3 RAM but it was too noisy for my intended use as a deskside workstation so I sold it.
Things to Investigate
I plan to do more investigation on BTRFS compression, how to get the best compression without excessive delays and how to recognise when delays are happening. I have some SSDs that have sustained write speeds as low as 15MB/s (Crucial P1 series) so for those I could probably have very high compression levels without slowing the system down.
The fact that BIONC slows things down so much seems to be a bug. When processes are running with the IDLE scheduling class there shouldn’t be such significant delays. Is it due to cache thrashing? How can I best get BOINC suitably throttled when I’m sitting at my workstation, I don’t want BOINC connecting to the local X server (which it repeatedly tries to do). Do I need to tune my kernel for better handling of IDLE scheduling?
When I get more DIMMs in the Z4G4 I need to do more tests to see if it gives an overall performance boost.
Also the Z4G4 system has a BIOS option for “sub NUMA” which basically means treating the different RAM channels on a single CPU as NUMA zones, I enabled that option which does nothing presumably because I only have 2 DIMMs, the results when I have 4 DIMMs will be interesting. I will also do some NUMA tests on the Z840 to see what benefits it gives.
I have a selection of RAM speeds that will work in the Z4G4, if I have enough spare time I’ll test what difference that makes for CPU bound tasks that matter to me.
For package building fsync() is not helpful, if the system crashes before it’s done then I will just do the build again. For a build cluster it is probably a good feature and probably doesn’t affect aggregate performance when multiple packages are built at the same time, but for the single user case probably not. I will investigate libeatmydata for package building [9].
Conclusion
The progress in CPUs seems to have slowed down a lot recently. The main benefits seem to be in more CPU cores and for newer sockets with more RAM channels.
The CPUs that do have improvements in single core performance are the i9 series (which mostly doesn’t come with motherboards supporting ECC) and AMD CPUs (which is rare in enterprise class hardware). Maybe I should get a server with an i9 or AMD CPU for tasks that need a fast turn around with a small number of cores. That would probably outperform any CPU designed for large core counts for things like building the policy and setting up test VMs (which depends on package installation speed that is single core bottlenecked).
The W-21xx CPUs seem to offer little benefit over the E5-26xxv4 CPUs and not a lot of benefit over E5-26xx CPUs (with DDR3). Even the W-22xx CPUs look like they aren’t going to offer a lot as they are only an incremental improvement over the W-21xx series. I had considered making the Z4G4 my main desktop workstation after the high end W CPUs become affordable, but it looks like that won’t be worth it until such CPUs drop from the current ebay price of $900 to $100.
Uploaded labwc 0.9.7-1 to unstable;
labwc 0.20 was released upstream since then, but it requires wlroots 0.20.1
which has not landed in Debian yet
Uploaded usbguard 1.1.4+ds-3 & 1.1.4+ds-4: cleaned up the packaging and
fixed some long standing issues with the configuration; the legacy permission
system isn’t the default anymore
Uploaded foot 1.27.0-1 to unstable
Uploaded scdoc 1.11.4-2 to unstable
Uploaded cage 0.3.0-2 to unstable
Uploaded sway 1.12~rc3-2 to unstable; on the same day sway 1.12 was released
and I uploaded 1.12-1 to unstable
Uploaded swayimg 5.2-1 to unstable
Uploaded git-quick-stats 2.11.0-1 to unstable
Uploaded grim 1.5.0+ds-1 to unstable
DH Related Work
A big chunk of my DH related work went into designing & implementing a search
app for the APIS framework. Our
goal is to have a way of searching over various types of Django models. The app
introduces a search model that indexes all registered models. We use a
combination of PostgreSQLs full text
search and
Trigram Similarity to find the search results. Using a
SearchVectorField
and GinIndices for the trigram indexed fields we can reach a somewhat
acceptable performance.
We released versions 0.63 and 0.64 of the APIS framework. The 0.63 release
introduced the new entities app, which will soon hopefully replace the legacy
apis_entities & apis_metainfo modules. Version 0.64 moved some logic from
the legacy modules the entities module.
We made some progress in defining the endpoints for the
PFP
API.
These reports outline what we’ve been up to over the past month, highlighting items of news from elsewhere in the increasingly-important area of software supply-chain security. As ever, if you are interested in contributing to the Reproducible Builds project, please see the Contribute page on our website.
… we’ve decided it’s time to say that Debian must ship reproducible packages. Since yesterday, we have enabled our migration software to block migration of new packages that can’t be reproduced [on reproduce.debian.net] or existing packages in testing that regress in reproducibility.
That is to say, if newly-uploaded packages are not reproducible, they won’t be considered candidates for inclusion in the next stable release of Debian codenamed forky. (Some exceptions may be granted.)
This news generated a number of articles and comments in various news outlets:
Holger’s talk announced that Debian intends to ship only reproducible packages in forky and beyond (see above), but also talked more broadly about reproducible builds, our testing framework and the Debian archive. That is to say, moving away from testing whether a package is reproducible in a theoretical sense (eg. whether we can build it twice in different environments and achieve the same result in our test system), and attempting to reproduce the same .deb files in the official Debian archive itself. This small-sounding distinction is actually essential, as this is the only means through which the reproducible builds technique can determine whether build systems are compromised are not.
Reproducible Builds 2026 summit to be held in Gothenburg, Sweden
As initially announced in March 2026, we will be having our yearly Reproducible Builds summit 2026 in Gothenburg Sweden, from September 22 until 24, followed by two days of hacking!
André Arko and Amean Asad published a paper this month on Kettle, a build system that “produces cryptographically verifiable provenance for software built inside Trusted Execution Environments”:
A Kettle build records the source commit, dependency set, toolchain, build
environment and output artifact digests in a provenance document produced
inside a measured confidential VM. The SHA-256 digest of that document is
committed to the TEE platform’s attestation report-data field, so the
hardware-signed attestation report is itself the signature on the provenance,
with the signing identity chaining to the TEE manufacturer’s root of trust
rather than to the build infrastructure operator. Because the CVM image is
itself reproducible, its launch measurement is public and stable, which lets
a build requester pre-attest the CVM before submitting any input and
optionally deliver source over a TLS channel terminated inside it, so the
build runs end-to-end confidentially without the host ever seeing source code
in plaintext.
rebuilderd, our server designed for monitoring the official package repositories of Linux distributions and attempt to reproduce the observed results there; it powers, amongst other things, reproduce.debian.net.
A new version, 0.27.0, was released this month, with the following headline changes:
The new rebuilderd package is currently available in the extra-testing repository. Note the Arch Linux package is upgraded from v0.25.0 from v0.27.0; please be patient with the database migrations on first restart, and make
yourself familiar with the breaking changes in v0.26.0 too.
Lastly, 40 reviews of Debian packages were added, 68 were updated and 75 were removed this month adding to our knowledge about identified issues. A number of issue types were updated, such as the addition of a new sphinx_reading_durations toolchain issue […], a golang_mango_generates_manpages_with_build_date issue […] and a random_offset_id_in_cython_linetrace […]. In addition, the timestamps_in_qhc issue was “refocused” to timestamps_in_qhc […].
Perhaps rebuilderd needs a feature where GOOD packages are also periodically rebuilt in exponential back-off style and compared against current upstream build and also our last GOOD build. This would confirm whether a package is reproducible if built in a short time window but also help uncover longer time window issues that are currently hidden.
The Reproducible Builds project detects, dissects and attempts to fix as many currently-unreproducible packages as possible. We endeavour to send all of our patches upstream where applicable or possible. This month, we wrote a large number of such patches, including:
Finally, if you are interested in contributing to the Reproducible Builds project, please visit our Contribute page on our website. However, you can get in touch with us via:
It's been ten years since I configured mount on demand backups to reduce
the risk of my backups being zapped by mistake. Way back then I wanted to go
one step further and use dedicated mount namespaces for backup jobs, but
systemd didn't provide the necessary support (and still doesn't, despite the
promisingly-named JoinsNameSpaceOf= configuration option.)
I recently updated my setup to achieve this by hand. All backup jobs now have
an extra pre-start instruction ExecStartPre=mkbackupns which runs a shell
script to either set up a persistent mount namespace, or exit quietly if it
already exists.
#!/bin/bash
set -euo pipefail
nsdir=/var/namespaces
nsfile=$nsdir/backup
nsfilex="$(echo $nsfile | sed 's#/#\\/#'g)"
private_propagation() {
findmnt -o+PROPAGATION "$nsdir" | grep -q private
}
nsfs_is_mounted() {
test "nsfs" = "$(awk "/$nsfilex/ { print \$3 }" /proc/mounts)"
}
if ! nsfs_is_mounted; then
if ! private_propagation; then
mkdir -p "$nsdir"
mount --bind --make-private "$nsdir" "$nsdir"
fi
touch "$nsfile"
unshare --mount="$nsfile" true
nsenter --mount=/var/namespaces/backup mount /dev/phobos_backup/backup /backup
fi
I should note that I don't have the backup filesystem described in /etc/fstab
to reduce the risk of it being mounted errantly in the main namespace.
The other change is to prefix an invocation of nsenter for every backup
job command. E.g.:
My backup scheme has lasted a decade with few tweaks
(I moved it to Borg in 2020) which I am very grateful for. I want reliable,
boring and robust.
Persistent mount namespaces are a lot less convoluted if you have a persistent
process to associate them with. I didn't, but a subsequent improvement I am
making is introducing one, so I will likely simplify the above accordingly.
This was a particularly busy month for me in terms of Debian
contributions.
It started with a week in Hamburg for the MiniDebConf. I talked to
many colleagues face-to-face and worked on various bugs and
maintenance tasks. I’m pleased to have finally found the time to
reproduce and fix the boot-time crashes in the parallel port
subsystem that have been reported
many times recently.
A series of easily exploited kernel LPE (local privilege execution)
issues were published this month, mostly with very little coordination
with distributions. Salvatore and I had to upload fixes for these at
roughly weekly intervals. All of these fixes needed to be applied to
4 different upstream branches (currently 5.10, 6.1, 6.12, and 7.0) and
7 Debian branches (including backports).
The Steam command line client, which I need to download the game data for the Doom3 BFG shooter, is only available as an Linux i386 binary.
As my main home computer is an arm64 box, this could be an issue, but today we have no less than three different ways to run a Linux i386 binary on arm64: Fex, Box32/64 and the older qemu-user mode.
According to the Box64 benchmarks, qemu-user is the slowest of the three. But since this is only to run a command line tool downloader, where network speed is the bottleneck, this doesn’t matter a lot.
Running steamcmd outside of a chroot via qemu-user and dpkg multiarch support
was failing me with the error i386-binfmt-P: Could not open '/lib/ld-linux.so.2': No such file or directory even after installing the i386 libc.
So I went the way of qemu-user and a chroot environment, a bit more convoluted but I can run any i386 binaries there in the future.
Create a debian-i386 chroot environment via deboostrap:
Add needed mounts to run binaries inside the chroot:
$ sudo mount --bind /dev/ debian-i386/dev/
$ sudo mount --bind /dev/pts debian-i386/dev/pts
$ sudo mount -t proc none debian-i386/proc/
Install steamcmd in the chroot client:
$ sudo chroot debian-i386
# export LANG=C
# cat /etc/apt/sources.list
deb http://deb.debian.org/debian stable main contrib non-free
# apt update && apt install --yes steamcmd
# useradd --create-home --shell /bin/bash steam
# su - steam
$ steamcmd
... will download an updated version of the tool, and print a lot of tracing information
Steam> quit
This was a particularly busy month for me in terms of Debian
contributions.
It started with a week in Hamburg for the MiniDebConf. I talked to
many colleagues face-to-face and worked on various bugs and
maintenance tasks. I’m pleased to have finally found the time to
reproduce and fix the boot-time crashes in the parallel port
subsystem that have been reported
many times recently.
A series of easily exploited kernel LPE (local privilege execution)
issues were published this month, mostly with very little coordination
with distributions. Salvatore and I had to upload fixes for these at
roughly weekly intervals. All of these fixes needed to be applied to
4 different upstream branches (currently 5.10, 6.1, 6.12, and 7.0) and
7 Debian branches (including backports).
Hello and welcome to my May 2026 free software activities report.
A lot's been going on in my life offline so I took a bit of a hiatus
from doing these reports, but I've had a fairly productive month of
May so I thought it'd be nice to do another one for this month.
ffs-0.2.2: I finally polished and published my ffs package for
GNU Emacs on GNU ELPA. Many thanks to Protesilaos for rounds of
code review and feedback for improving and polishing the package
in preparation for submission to GNU ELPA.
bug#81101: Trying to visit https://www.emacswiki.org in EWW
I noticed it fails with a Somebody wants you to give them money
error due to the anti-bot challenge being served with a HTTP 402
(Payment Required) response. So I landed a patch 12eec781ed6 to
no longer do that. Thanks to Emacs comaintainer Sean Whitton
for reviewing and approving my proposed patch.
bug#81107: I noticed that in EWW, unlike <input type="submit">
HTML buttons, <button> elements were not tab-stoppable, leading
to poorer usability and accessibility. So I landed a patch
ec3d662de0b to fix that. Thanks to Emacs comaintainer Eli
Zaretskii for reviewing, providing feedback, and accepting my
proposed change.
Emacs Chat with Sacha Chua: I joined Sacha for a new episode of
her Emacs Chat podcast, where we talked about Emacs and life.
I gave a quick tour of my Emacs configuration, discussing at
length my configurations for EXWM (Emacs X Window Manager) among
other topics like Emacs's facility for visually indicating buffer
boundaries in the fringe by setting indicate-buffer-boundaries
and my convenience configuration macros.
maintainers@: I started the next long-overdue round of emails to GNU
package maintainers to confirm the contact information we have on
file for them and get a brief status update about their packages.
Emails are sent in small batches to keep the workload of handling
the responses manageable for assistant GNUisances.
GNU Spotlight: I prepared and sent the May GNU Spotlight to the FSF
campaigns team for publication on the FSF's community blog and the
monthly Free Software Supporter newsletter.
Debian
I've begun the work toward updating the Jami package in Debian
unstable again, which means I need to package new releases of its
direct and indirect dependencies. For OpenDHT, I need to update
RESTinio, and to do that I first need to package expected-lite and
sobjectizer for Debian:
#1120837: ITP: expected-lite – expected objects for C++11 and later
#1137609: ITP: sobjectizer – C++ implementation of Actor,
Publish-Subscribe, and CSP models
I've been working on packaging both and hope to have them uploaded to
the archive in the next days and weeks.
In the recent weeks I've been engaging Prot as a coach to help review
my new ffs package for GNU Emacs as I worked on preparing it for
inclusion in GNU ELPA, as well as discussing other Emacs- and
life-related topics.
In our nearly 2-hour conversation, we discussed at length and in depth
various aspects of life in the current times. For instance, feeling
overwhelmed in the face of innumerable things happening at once, with
technology changing our perception and making events feel proximate
and imminent.
We talked about seasonality and rhythms in life, including in relation
to burnout and knowing our own limitations, and descriptive vs
prescriptive thinking when reflecting on the expectations we may place
on our self when comparing our self to others through the lens of our
necessarily-incomplete impressions and glimpses of their lives. We
discussed absence or loss as a dual to presence or persistence in the
process of life. How with our memories and through embodying the
philosophy and teachings of departed loved ones their essence and
legacy continues to live on within us. But also loss in the sense of
us losing parts of our self in life-defining moments while preserving
other parts and gaining new ones, being liberated of some of the
burdens of our past self and in effect becoming someone else in the
process.
In being true to our self, we talked about humans as multi-faceted
beings and the importance of expressing and giving a voice to these
different aspects of our self, and keeping alive that child-like
sense of awe and wonder. To live a life where the pace and rhythms of
our environment are in sync with our internal rhythms, and to not give
others undue power over us or our happiness through trying to live
according to their prescribed standards or expectations.
I also learned more about Prot's practical philosophy of situational
awareness in life, not merely as a means for survival, but also as a
way of appreciating all of the beauty that surrounds us, and a method
for gaining the knowledge and skills to apply what we learn from
patterns in one area of life to other areas.
We concluded our session with a mention to the concept of sanctity, to
set aside a sacred time or place for our self wherein no distractions
are allowed, where we can unwind, rest, and recharge for whatever
comes next.
Here is the video recording of our session, which I share with Prot's
permission:
ffs provides a minor mode for simple plain text presentations in
Emacs, where the slides are separated using the page-delimiter, by
default the form feed character (^L).
I wrote ffs in early 2022 for my LibrePlanet 2022 presentation the
Net beyond the Web, and earlier this year decided to polish it towards
being a proper package and submit it to GNU ELPA. The manual still
needs some more work, but the overall package is in pretty good shape
so I submitted for inclusion in GNU ELPA.
ffs and I owe a debt of gratitude to Protesilaos for rounds of
code review and feedback for improving and polishing the package in
preparation for submission to GNU ELPA. You can watch videos of these
sessions posted earlier on my website:
The attempted build of ffs 0.2.1 within GNU ELPA build sandbox failed
with an Error: void-function (org-texinfo-kbd-macro) due to use of
#+macro: kbd (eval (org-texinfo-kbd-macro $1)) in ffs.org for better
formatting of key sequences in the exported Texinfo copy. This seems
to have happened for the specific case of generating a plain text
README using ox-ascii where ELPA didn't load ox-texinfo. To try
and mitigate this, a README.md has been added for use as the package
README instead of ffs.org. If not sufficient, a Texinfo copy of the
ffs manual will be shipped instead of the Org one in the next release.
ffs 0.2.2 also includes small fixes and improvements throughout
ffs.el from Stefan Monnier, and additional feedback to be addressed
in future releases.
Version 0.2.1 on 2026-05-20
The attempted build of ffs 0.2.0 within GNU ELPA build sandbox failed
with a "Cannot include file" error on the "#+include: fdl.org" in the
manual. So, as a workaround, we switch to using the official Texinfo
copy of the GNU FDL license rather than an Org copy.
Version 0.2.0 on 2026-05-19
First release of ffs intended for GNU ELPA.
After a few years of inactivity, in early 2026 I decided to dust off
ffs.el, polish and document it, and offer for inclusion in GNU ELPA
as a proper package.
Default value of ffs-default-face-height changed to nil
To minimize unexpected and/or unnecessary changes out-of-the-box, the
default value of ffs-default-face-height has been changed to nil.
ffs-edit-buffer-name demoted from user option to variable
This is not an important user-facing setting, so to help avoid
overwhelming users with many options, this has been demoted from a
user option to a variable.
Several new user options for customizing ffs's behaviour
As part of the effort to bring ffs more in line with the conventions
of other existing Emacs packages, the mechanisms for toggling various
parts of Emacs's interface to minimize visual clutter were changed
from being minor modes to being customizable user options. These are
the replacement new user options, with a default value of nil:
ffs-hide-cursor
ffs-hide-mode-line
ffs-hide-header-line
Their value is buffer-local, and may be set globally using
setq-default. See the sample configuration in the manual for an
example of how to customize them.
The new ffs-page-delimiter user option defines the page delimiter
inserted by ffs-edit-done when inserting a new slide. Emacs's
page-delimiter regexp should be able to match ffs-page-delimiter's
value, so if you use a custom page-delimiter be sure to customize
ffs-page-delimiter accordingly.
The new ffs-echo-progress user option controls whether to display in
echo area the progress through the slides. When non-nil, changing
slides will also display the progress through the slides in the echo
area. The format of the displayed progress can be customized using
the new ffs-echo-progress-format user option.
The new ffs-edit-display-buffer-alist user option may be used to
control the Window configuration for the ffs-edit buffer. By
default, it will display the ffs-edit buffer in the same window.
The new ffs-edit-done-hook user option may be used to define hooks
to be run at the end of ffs-edit-done after returning to the main
ffs presentation buffer.
Lastly, a new ffs-find-speaker-notes-function variable was added to
allow customizing the find function used for opening the speaker's
notes file, defaulting to find-file-other-frame.
Version 0.1.0 on 2022-05-19
Initial publication of ffs.el as part of my personal configurations
for GNU Emacs.
My first attempt at this concept was a now-archived ffsanim.el,
a major mode implementation that used Emacs's animate library to
animate slide texts onto the screen. Shortly after realizing the
shortcomings of that approach, I abandoned it in favour a minor mode
implementation and published version 0.1.0 of what is now ffs in
my personal configs repository.
I used this implementation for presenting my LibrePlanet 2022 talk,
The Net beyond the Web.
I picked "ffs" as the package name, the acronym for form feed slides.
In the recent weeks I've been engaging Prot as an Emacs coach to help
with doing review passes over my upcoming ffs package as I work on
polishing and documenting it in preparation for offering it for
inclusion in GNU ELPA.
Today we had our third session where we started by reviewing and
talking about my recent changes to ffs, then ventured to other
Emacs-related topics with the overarching theme of the flexibility
and extensibility of GNU Emacs, including display-buffer-alist,
keyboard macros, defining a custom ox-bhtml Org export backend
derived from Org's ox-html for ultimate flexibility when exporting
my site's pages from Org to HTML, Org capture, plain text files and
Emacs's diary and how it compares to org-agenda, and keeping a
journal with the help of Emacs.
Here is the video recording of our session, which I share with Prot's
permission:
In the recent weeks I've been engaging Prot as an Emacs coach to help
with doing review passes over my upcoming ffs package as I work on
polishing and documenting it in preparation for offering it for
inclusion in GNU ELPA.
Yesterday we had our second session focused on ffs, which I recorded
and share publicly with everyone with Prot's permission, so that
others can also benefit from Prot's insights and experience as we
discuss various aspects of Emacs package development with the concrete
example of ffs.
I addressed most of Prot's feedback about ffs from our first
session, and I'll be working on the changes we discussed in this
session in the next days.
In the last third of the video we switched topics to discuss a few
Emacs-related tangents including adding a 'padding' effect for the
mode line and its constructs, and distilling and separating the
easily-reusable package-like parts of one's Emacs configuration from
the actual configuration of those parts (e.g. the distinction of
prot-lisp and prot-emacs-modules in Prot's Emacs configuration).
For mode line padding, here is the snippet I'm using with Prot's
doric-themes:
Yesterday I joined Sacha Chua for a new episode of her Emacs Chat
podcast, where we talked about Emacs and life. I gave a quick tour
of my Emacs configuration, discussing at length my configurations for
EXWM (Emacs X Window Manager) among other topics like Emacs's facility
for visually indicating buffer boundaries in the fringe by setting
indicate-buffer-boundaries and my convenience configuration macros.
The above video is provided with closed captions and the below
transcript courtesy of Sacha with minor fixes and formatting by me.
I've included some of Sacha's screenshots from our chat, you can see
the rest on the episode's page on Sacha's blog.
Armadillo is a powerful
and expressive C++ template library for linear algebra and scientific
computing. It aims towards a good balance between speed and ease of use,
has a syntax deliberately close to Matlab, and is useful for algorithm
development directly in C++, or quick conversion of research code into
production environments. RcppArmadillo
integrates this library with the R environment and language–and is
widely used by (currently) 1272 other packages on CRAN, downloaded 46.6 million
times (per the partial logs from the cloud mirrors of CRAN), and the CSDA paper (preprint
/ vignette) by Conrad and myself has been cited 693 times according
to Google Scholar.
This versions updates to the 15.2.7 upstream Armadillo release made today.
The package has already been updated for Debian, and built for r2u. As the upstream was
modest, we for once skipped reverse-dependency checks. That bet paid off
as CRAN found no issues among
the over 1270 reverse dependencies. However, one package referenced a
package archived today, hence ‘invisible’ to CRAN and triggered a (false
positive) NOTE of ‘reference to non-existing package’. We came close.
Anyway, the package made it CRAN shortly thereafter following
the standard brief email exchange explaining the false-positive nature
of the NOTE.
All changes since the last CRAN release follow.
Changes in
RcppArmadillo version 15.2.7-1 (2026-05-29)
Upgraded to Armadillo release 15.2.7 (Medium Roast Deluxe)
In September 2025, I attended the annual LibreOffice conference in Budapest, Hungary. This gave me an opportunity to explore the city, which I will cover in this post.
Let’s start with the currency. Although Hungary is a part of the European Union (EU), it doesn’t use the euro as its currency. Instead, it uses Hungarian forints (denoted by “Ft”). During my time in Hungary, 1 Indian rupee was equal to 4 Hungarian forints.
After reaching the Budapest airport, I bought a 15-day public transport pass. The public transport counter is after you pass customs and immigration. The pass allows unlimited use of public transport in the city. I had to show my passport and pay 5950 Ft to get the pass. The pass had my passport number mentioned on it. The public transport passes can also be bought at any of the tram stations as well.
This is the counter from where I bought my public transport pass.
My unlimited public transport pass for Budapest. I have redacted my passport number from it.
An automatic ticket machine at a tram station in Budapest.
Budapest is a union of two cities—Buda and Pest—lying on opposite sides of the Danube River. My hotel—Corvin Hotel—was on the Pest side.
Budapest had good public transport. The buses, metros, and trams complemented each other. For example, the airport didn’t have metro or tram connectivity, but it was served by the bus. Most of the metro was on the Pest side, with only a couple of stations falling in Buda. However, both sides had an extensive network of trams.
Furthermore, the information about the public transport was easily accessible. For instance, the map of tram stops inside the trams also included the bus routes one could get after alighting at those stops.
From the airport, I took a bus followed by taking a metro on the M3 line to reach within walking distance of my hotel.
An M3 line metro in Budapest.
During the conference I would take the tram to the conference venue. The trams were modern and fast. They also had a smiley face at the front, which gave them a friendly look. It seemed like the trams were happily doing their job. The city also had a good pedestrian infrastructure along with separate cycling tracks.
A tram in Budapest having a smiley face at the front.
Budapest’s tap water is officially safe to drink, which was mentioned on a sticker posted on the wall of the bathroom of my hotel room. So, I did not need to buy any water bottles while I was there.
On the 6th of September, I went on a sightseeing tour of Budapest with my Dione. Our friend Attila, who was a local (from Hungary), joined us. We went to the central market from our hotel by metro.
If you read my post on Vienna, I mentioned that the metro stations don’t have AFC gates but ticket validators instead. Budapest’s metro also has the same system. If you buy individual tickets, you need to validate them using the validators on the station before boarding the metro. If you are using a public transport pass like I was, then you do not need to validate, and you can board the metro directly.
A ticket validator at a metro station in Budapest.
In 10-15 minutes, we reached the central market. Attila showed us around. I bought a fridge magnet and paprika powder as souvenirs. Paprika powder is a signature spice of Hungary. It is mainly available in two forms—one is sweet and the other being spicy. I wanted the spicy one, but I didn’t get that in that market. Therefore, I had to contend with buying the sweet version. The sweet version isn’t sweet though, it is just not spicy. After bringing that paprika powder home, it is mainly used for food coloring. I like it though and use it frequently in my omelets and other dishes.
Central market.
The building right behind the tram is the central market building.
At some point, Atilla had to join the The Document Foundation (TDF) sightseeing group, so we parted ways at the central market. Dione and I continued our sightseeing and decided to start with visiting the Hungarian parliament, which is a tourist attraction. It was because we were on the Pest side and the parliament was also on the same side, while other tourist attractions were on the Buda side.
So, Dione and I hopped on a tram and went to the parliament. We got off at a tram station just outside the parliament. The parliament is the icon of Budapest. The building has a gothic architecture and colored brown and white. One can buy tickets and take an inside tour. However, we didn’t have a lot of time, so we stayed outside the building.
Hungarian Parliament building.
After spending some time outside the parliament building, we took a tram to the Chain Bridge. As I mentioned earlier, Budapest has two parts—Buda and Pest—separated by the Danube River. To go from one of the sides to the other requires crossing a bridge. Although Budapest has many bridges linking the two sides, the main one is the Chain Bridge.
We walked on the chain bridge to get to the other side. The bridge gave a good view of the Danube River. It also had a statue of a lion. The Buda Castle (another major landmark of Budapest) was visible from the bridge.
A shot of Chain Bridge.
The lion statue on the Chain Bridge.
After reaching the other side of the bridge (the Buda side), we sat on a bench for some time and then planned on where to go next. We decided to go to Fisherman’s Bastion, which is another tourist attraction.
We used the OSMAnd~ app to figure out which bus to take and hopped on one. Soon we reached Fisherman’s Bastion, where we found a flight of stairs that led upwards. Upon climbing the stairs, we got a panoramic view of the city. It also gave us a good view of the Hungarian parliament across the river. Going further upstairs, we found a statue of Stephen I of Hungary. He was the first king of Hungary, getting the crown in the year 1900.
A view of Hungarian parliament from Fisherman’s bastion.
I found Fisherman’s Bastion to be the best tourist attraction in the city. As mentioned earlier, it offers a panoramic view of the city, which I liked. I liked the arhitecture and open space there. If you find yourself in Budapest, I would highly recommend that you visit Fisherman’s Bastion.
Fisherman’s Bastion.
Statue of Stephen I of Hungary at Fisherman’s Bastion.
Next, we went downstairs and returned to where the bus dropped us. From here on, we walked in random streets to see the residential and non-touristy side of Budapest. It was not so random as we walked towards Batthyány tér metro station. Upon reaching the metro station, we found a café where we stopped for a while for some coffee. After injecting some caffeine into our blood, we proceeded to find a place to have lunch.
Batthyány tér metro station.
For lunch, we decided to go to Rákóczi tér metro station after reading on the internet about the food options there. Upon exiting the metro station, we found a market inside a building that had a lot of shops, but most of them were closed.
After roaming around inside a bit, we found an Italian place open and decided to eat there. The name of this place was Matteos. We ordered an eggplant parmigiana, a lasagna artichoke, and a classic tiramisu. It wasn’t very tasty but filled us up for the day.
A picture of Matteos, where we had our lunch.
Budapest has four metro lines, and we had been to three of them, so we decided to try the remaining line, which was the M1 line. It is the oldest line in the city and has a different vibe than the modern lines. This line was opened in 1896, one of the oldest subway systems in the world.
The coaches were much smaller than the other metro lines, and the seating arrangement was something you would expect from a bus than a typical metro train. We rode all the way to the last stop, Mexikói út. Upon going outside, we found out there wasn’t much to do here.
At this point, I checked the map and realized that Heroes’ Square is just a couple of metro stations away. Heroes’ Square is a tourist attraction in Budapest. It is located in Zuglóa and is a historically significant place in Budapest. It has a monument which features the Seven chieftains of the Magyars.
M1 line station and tracks. It is the oldest metro transit of Budapest and one of the oldest in the world. It started operations in 1896.
Here, our unlimited public transport pass was handy because if it was paid per trip, we would think of the stop as a “wasted” one because we would have to buy a ticket again, but in this case we could just hop on again without any regrets.
An M1 line metro train entering the station.
So we took the M1 line again and deboarded at Hősök tere station, followed by walking to the square. After roaming around for a while, we saw a trolleybus and decided to ride on that.
Heroes’ Square.
This is the trolleybus we took in Budapest.
A trolleybus is an electric bus that is powered by overhead electric cables. It is like a tram but runs on roads instead of tracks. We got down at Dózsa György út metro station. Then we took a metro to our hotel.
Before going to the hotel, we went to a place to eat something. We had coffee and lángos. Lángos is a deep-fried Hungarian dish, which looks exactly like the Indian flatbread bhatura. I found it tasty, but since it was deep-fried, that was almost a given.
Lángos — a dish which looks like the Indian flatbread bhatura.
The next day we went to Vienna—the capital of Austria—which I have already posted about. Check it out here.
I had a good time in Budapest, and it is a beautiful city with good public transport and some amazing sites to visit.
That’s it for now, and see you next time!
Last year I blogged about using Zram for VMs [1]. That setup is still working well for VMs and for phones and laptops with no swap device.
I have just read Chris Down’s insightful blog post about Zswap vs Zram [2] which convinced me to setup Zswap on some systems. I have had some of the problems that were described in his blog post when trying to run Zram on workstation and server systems.
One limitation of zswap is that it doesn’t allow specifying the compression level. For zram I can put the following in /etc/systemd/zram-generator.conf to set the zstd compression level (this works well on my Thinkpad X1 Carbon Gen6):
[zram0]
compression-algorithm=zstd(level=10)
For the BTRFS filesystem I can put “compress=zstd:13” in the mount options to specify the compression level. They really should support different compression levels in zswap. The ideal compression level depends on the speed of the CPU and new CPUs keep getting faster.
Setup
The documentation says to use something like the following on the kernel command-line to enable zswap:
The max_pool_percent=20 setting is the default which means to use up to 20% of system RAM for compressed data. I’ve seen documentation sugesting up to 50% which seems a little excessive.
There is documentation about changing the compression algorithm via command line parameters, on Debian only lzo is linked in to the kernel and zstd (my preferred option) is a module so the kernel command line can’t be used to set zstd, but the following command works:
The shrinker_enabled option is to allow the kernel to evict cold pages without waiting for memory pressure.
You can enable zswap without rebooting by running commands like the following. You could even put them in /etc/rc.local or something, but I think putting it in the kernel command line is a good idea as it makes it obvious to the next sysadmin what is happening.
This table documents my current understanding of the debug values. The difference between reject_compress_fail and reject_compress_poor isn’t clear in a lot of the documentation, even reading the source didn’t make it easy to understand.
File
Meaning (LC is lifetime count)
pool_limit_hit
LC pool limit hit and pages are forced to the swap partition
pool_total_size
RAM used for zswap data
reject_alloc_fail
LC can’t allocate memory because max_pool_percent has been reached
reject_compress_fail
LC of pages with a compression algorithm failure so go straight to swap partition
reject_compress_poor
LC of pages that can’t compress so go straight to swap partition
reject_kmemcache_fail
LC kernel malloc failure (serious problem?)
reject_reclaim_fail
LC failure to move a page from compressed RAM to disk – serious problem!
stored_pages
Swapped pages stored by zswap
written_back_pages
LC of pages written back to swap partition from zswap
All of this is not nearly as easy to understand as the following command for zram:
# zramctl
NAME ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT
/dev/zram0 zstd 7.7G 2.1G 375M 386M 4 [SWAP]
Debian Wiki
The Debian Wiki page about Zswap is very brief [4] and needs more description about this, I think a lot of Debian users will use zram instead of zswap because setting up zram is just a single apt command. I’m not planning to immediately add to that wiki page because I’m not an expert on this, I would appreciate comments on this blog post from others who have got zswap working. I will update the wiki if others report matching experiences to mine.
Conclusion
I’m now using zswap on a few systems including my main home workstation which had performed poorly with zram and a swap device in the past. If that goes well I’ll put it on other systems.
I wrote the following shell script to display zswap stats, consider it GPL if you want to use it:
#!/bin/bash
if [ ! -f /sys/kernel/debug/zswap/stored_pages ]; then
echo "ZSwap not enabled"
exit 0
fi
PAGES=$(</sys/kernel/debug/zswap/stored_pages)
PAGESIZE=$(getconf PAGESIZE)
RAM=$(echo "$PAGESIZE * " $(getconf _PHYS_PAGES) | bc)
POOL=$(</sys/kernel/debug/zswap/pool_total_size)
if [ "$POOL" == "0" ]; then
echo "ZSwap not used yet"
exit 0
fi
COMP=$(</sys/module/zswap/parameters/compressor)
echo -n "$COMP compression ratio: "
echo "scale=2; $PAGES * $PAGESIZE / $POOL" | bc
echo -n "RAM%: "
echo "100 * $POOL / $RAM" | bc
In January 2025,
as a pre-requisite for something else, I published a minimal neovim
plugin called nvim-µwiki. It's essentially just the features from
vimwiki that I regularly use, which is a small fraction them.
I forgot to blog about it. I recently dusted it off and cleaned it up.
You can find it here, along with a longer list of its features and
how to configure it: https://github.com/jmtd/nvim-microwiki
I had a couple of design goals. I didn't want to define a new filetype,
so this is designed to work with the existing markdown one. I'm
using neovim, so I wanted to leverage some of its features: this plugin
is written in Lua, rather than vimscript. I use the parse trees
provided by TreeSitter to navigate the structure of a document.
I also decided to "plug into" the existing tag stack navigation, rather
than define another dimension of navigation (along with buffers, etc.)
to track: Following a wiki-link pushes onto the tag stack, just as if
you followed a tag.
This was my first serious bit of Lua programming, as well as my first
dive into neovim (or even vim) internals.
Lua is quite reasonable. Most
of the vim and neovim architecture is reasonable. The emerging conventions
about structuring neovim plugins are mostly reasonable. TreeSitter is, well,
interesting, but the devil is very much in the details. Somehow all
together the experience for me was largely just frustrating, and I didn't
really enjoy writing it.
Review: The Keeper of Magical Things, by Julie Leong
Publisher:
Ace
Copyright:
2025
ISBN:
0-593-81593-9
Format:
Kindle
Pages:
353
The Keeper of Magical Things is a cozy fantasy novel. It is set in
the same universe as The Teller of Small
Fortunes, but it doesn't share any characters or plot, they're not
marketed as a series, and so far as I can remember neither book would
spoil the other. It is Julie Leong's second novel.
Certainty Bulrush is a novice mage with one reliable magical ability: She
can talk to objects and occasionally convince them to do small things.
This ability is clearly magical, which means Certainty is indeed a mage,
but this appears to be all that her magic can do. The Guild has
requirements for the level of magical ability required to become a full
mage that go beyond talking stained quilts into unstaining themselves,
which is why Certainty has been a novice for six years.
This by itself is a problem, since Certainty's cohort keeps passing her
by. Worse, though, is that she was counting on the wages of a full mage to
pay for her brother's training to become an apothecary. The thought of
failing him is extremely upsetting. Certainty therefore jumps at an
offered mission to take a cartload of excess magical objects that are
causing a dangerous build-up of energies in the Guildtower to safe storage
in the small and very unmagical village of Shpelling. Successful
completion of that mission will earn Certainty a promotion to Deputy
Keeper and therefore to a full mage.
This is the opportunity she didn't know to hope for. The only drawback is
that she will have to work with Mage Aurelia, the famously off-putting
farspeaker and magical scholar the other novices refer to as the ice
witch.
Aurelia is every bit as icy, formal, and condescending as Certainty was
afraid she would be, Shpelling grows nothing but garlic, and the
inhabitants are suspicious and hostile. The mission could be a disaster if
it weren't for Certainty's stubborn good nature.
It's arguably a spoiler to say that there's an enemies to lovers romance,
but it's hinted at on the cover, mentioned in the publisher's blurb and,
honestly, if you aren't expecting an enemies to lovers romance by a few
chapters in, you probably haven't read many books of this sort.
I found The Keeper of Magical Things quietly enjoyable but
extremely predictable. If you're in the mood for what it's offering, the
predictability may not be a problem, but it was the kind of book where the
direction the plot was headed was so obvious that I got a bit bored
waiting for it to arrive. Certainty has a good heart, humble origins,
limited but specialized magical ability, and a self-esteem problem, and if
you've read much fantasy, you've probably read two or three or a dozen
other books with variations of this protagonist. You know how they
generally turn out, and that is indeed what you're going to get after the
obligatory setbacks and tragedies and looming catastrophes.
Aurelia, similarly, is a variation on a character you've probably met
before. Certainty discovers, not long into the book, that the brilliant
over-achieving mage wears a necklace (supposedly to help her focus) that
constantly whispers to her how inadequate she is and how much harder she
needs to work. The necklace was given to her by her parents. This book is
not exactly subtle.
That said, there's nothing wrong with the characterization. Both Certainty
and Aurelia are interesting characters with rounded-out personalities,
although it takes a while before Certainty (or the reader) is allowed to
see Aurelia's. Their interactions with the inhabitants of Shpelling are
fun to watch in the same way that it can be fun to watch people play
PowerWash
Simulator. You're not in overwhelming suspense about what's going to
happen, but the details are amusing and it is satisfying to watch people
with good intentions slowly fix things. There is a plot, and a villain,
and a not-subtle message about how everyone deserves acknowledgment and
respect, and the hours I spent reading about these characters were
enjoyable.
The problem with this book isn't that there's anything wrong with it, but
that it may not give you more enjoyment than another book you could have
been reading. I quite liked The Teller of Small Fortunes in part
because it surprised me in a few places and the main character felt a bit
different than the typical fantasy protagonist. The Keeper of
Magical Things felt less original and a bit more obvious and predictable.
It was still quietly good-hearted and occasionally charming, and I think
I'll still remember Certainty in a few months, but I'm not feeling the
urge to push it into anyone's hands.
If you're in the mood for a gentle fantasy about finding solutions to
people's problems and waiting out the prickliness of people who
desperately need a friend, you may enjoy this a great deal. Just don't
expect unpredictable twists and turns or a surprising plot structure.
An apparent third book in this loose series, The Isle of Lonely
Monsters, is currently scheduled for publication in 2027.