<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Performance on KDE Blogs</title><link>https://blogs.kde.org/tags/performance/</link><description>Recent content in Performance on KDE Blogs</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Wed, 26 Aug 2026 14:06:45 +0200</lastBuildDate><atom:link href="https://blogs.kde.org/tags/performance/index.xml" rel="self" type="application/rss+xml"/><item><title>Dolphin 26.08 and KIO, part two: what got faster and smaller</title><link>https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/</link><pubDate>Thu, 27 Aug 2026 00:00:01 +0000</pubDate><author>Méven Car</author><guid>https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/</guid><description>&lt;p&gt;This is the second half of &lt;a href="https://blogs.kde.org/2026/08/26/dolphin-26.08-and-kio-perf-improvements/"&gt;what changed in Dolphin
26.08&lt;/a&gt;. The first half is what you can see: the
features, the behaviour changes, the bugs. This one is what you can measure.&lt;/p&gt;
&lt;p&gt;Dolphin does very little file work itself. It asks KIO, so the numbers below are mostly
KIO numbers: 6.25 is the version that shipped alongside Dolphin 26.04, 6.29 is the one
that ships alongside 26.08, four framework releases and 294 commits apart. The last
section is 6.30, the release still to come, since several of its changes are large enough to
be worth showing early.&lt;/p&gt;
&lt;p&gt;Every figure here was measured on the same machine, with the two versions built the same
way and run one after another, round by round. Where a number is not solid I say so
rather than rounding it up.&lt;/p&gt;
&lt;h2 id="memory-and-object-lifetimes"&gt;Memory and object lifetimes&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://blogs.kde.org/2026/05/03/dolphin-26.04-release/"&gt;26.04 post&lt;/a&gt; ended by saying the next thing was
to point LeakSanitizer at Dolphin. It turned into a lot of fixes, and into a CI job: KIO now
&lt;a href="https://invent.kde.org/frameworks/kio/-/commit/9bd177bb40ab66114d812b1c7a05638a68807f4e"&gt;runs its tests under LeakSanitizer&lt;/a&gt;
on every merge request, which is what stops the list below from growing back.&lt;/p&gt;
&lt;p&gt;Sebastian Englbrecht was the busiest contributor to Dolphin this cycle by commit count, and
most of that work was lifetime and ownership: &lt;a href="https://invent.kde.org/system/dolphin/-/commit/714830f8dda873fbefa6de9704c90220e16a6133"&gt;killing in-flight KIO
jobs&lt;/a&gt;
in destructors, &lt;a href="https://invent.kde.org/system/dolphin/-/commit/0d6302ef9be3387d3a62093ae18c92ec84e5a2e1"&gt;deleting the Konsole
part&lt;/a&gt;,
&lt;a href="https://invent.kde.org/system/dolphin/-/commit/8f7ab9d4b7ecc71083e2d7e03863857b1cfdea54"&gt;destroying owned objects before the KIO cache tears
down&lt;/a&gt;
and &lt;a href="https://invent.kde.org/system/dolphin/-/commit/680ccee08cfac2b53bb7bf7d35b780889efa4b51"&gt;fixing unowned
allocations&lt;/a&gt;.
He also added a &lt;a href="https://invent.kde.org/system/dolphin/-/commit/1330df1053a9ee9927dc27e1f333a67965dbf02e"&gt;smoke
test&lt;/a&gt;,
&lt;a href="https://invent.kde.org/system/dolphin/-/commit/d56feb8151871065505c83eeaa8bd3d53750af10"&gt;eight places-panel unit
tests&lt;/a&gt;,
and a &lt;a href="https://invent.kde.org/system/dolphin/-/commit/a33d65a418bf5bdb13d83281ce665d630a95668e"&gt;rule forbidding bare
&lt;code&gt;QTest::qWait()&lt;/code&gt;&lt;/a&gt;
with &lt;a href="https://invent.kde.org/system/dolphin/-/commit/22d65e047ac75fc3527ddac2401e90a2805a6f04"&gt;the existing waits replaced by signal-based
ones&lt;/a&gt;,
which is the sort of thing that makes the rest of the CI trustworthy. Wendi Gan fixed an
&lt;a href="https://invent.kde.org/system/dolphin/-/commit/2dce7352c1edfb13c90a8a3b858d113e3a9300b2"&gt;occasional use-after-free crash&lt;/a&gt;
in &lt;code&gt;KConfig::sync()&lt;/code&gt; during exit, closing two reports,
&lt;a href="https://bugs.kde.org/show_bug.cgi?id=516481"&gt;516481&lt;/a&gt; and
&lt;a href="https://bugs.kde.org/show_bug.cgi?id=518433"&gt;518433&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My own share was in both projects. In Dolphin: &lt;a href="https://invent.kde.org/system/dolphin/-/commit/5b21e7c3105258f90745ff12e6877e7a8e8cb366"&gt;aborting the folder stat job when the
Information Panel is destroyed&lt;/a&gt;,
&lt;a href="https://invent.kde.org/system/dolphin/-/commit/99c87fe4314d392ae8d3e4cf9c05e3f014322608"&gt;a use-after-free of the current version-control plugin&lt;/a&gt;,
&lt;a href="https://invent.kde.org/system/dolphin/-/commit/cc806587766d09f916de712b0b5e248ba0c5383c"&gt;a leaked submenu in the folder-icon action&lt;/a&gt;
and &lt;a href="https://invent.kde.org/system/dolphin/-/commit/ddfc69105a8e8975a517210116de625c621a6757"&gt;a leak in the trash settings page on exit&lt;/a&gt;.
In KIO, besides turning the sanitiser on in CI and &lt;a href="https://invent.kde.org/frameworks/kio/-/commit/abfe4b4a5fca5d554f957f9e55d73365effe99f4"&gt;teaching the tests to wait for what they
allocate to be deleted&lt;/a&gt;,
three fixes are ones a user could have met: the &amp;quot;Move Into New Folder&amp;quot; drop action had done
nothing at all since 6.25, because &lt;a href="https://invent.kde.org/frameworks/kio/-/commit/0a47ba93999eb5e91459aca8c7aface2aabee809"&gt;the menu was parented to a plugin destroyed the moment the
action fires&lt;/a&gt;
while the folder creation it starts runs asynchronously; &lt;a href="https://invent.kde.org/frameworks/kio/-/commit/ad1eb8c809c2a88e6e344df15cb9e43666976dc6"&gt;&lt;code&gt;FilePreviewJob&lt;/code&gt; armed a repeating
timeout timer it never stopped&lt;/a&gt;,
so with a context menu held open the orphaned timer could fire on a finished job and re-enter
&lt;code&gt;emitResult()&lt;/code&gt;; and &lt;a href="https://invent.kde.org/frameworks/kio/-/commit/182fc462ab396b823137a82eee36e2ef483a7ae1"&gt;&lt;code&gt;KDirModel&lt;/code&gt; dereferenced the node of a directory that had already left the
model&lt;/a&gt;
when an earlier listing completed late.&lt;/p&gt;
&lt;h2 id="performance-improvements-in-kio-between-625-and-629"&gt;Performance improvements in KIO between 6.25 and 6.29&lt;/h2&gt;
&lt;p&gt;The big one is the &lt;strong&gt;in-process worker transport&lt;/strong&gt;. For local files KIO has for some time run the
&lt;code&gt;file&lt;/code&gt; worker in a thread of the application rather than a separate process. Even in
that thread it still talked to the application over a socket, serialising every command and every
block of file content through a &lt;code&gt;QLocalSocket&lt;/code&gt; pair. In 6.29 that channel is a new
&lt;a href="https://invent.kde.org/frameworks/kio/-/commit/0bce28d5d9626afba27f8eeb48dc4c7ae3574b2d"&gt;&lt;code&gt;ThreadConnectionBackend&lt;/code&gt;&lt;/a&gt;, an in-memory queue, and &lt;code&gt;kio_file&lt;/code&gt; &lt;a href="https://invent.kde.org/frameworks/kio/-/commit/c3f5ec3bb42eda4ab41dc66e52331730d1d8d72a"&gt;hands over owned byte arrays instead of copying them&lt;/a&gt;, which makes in-process reads zero-copy. This is the
first half of the improvements described in
&lt;a href="https://blogs.kde.org/2026/07/28/making-kio-copy-many-files-fast/"&gt;the copy post from July&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Second, &lt;strong&gt;&lt;code&gt;CopyJob&lt;/code&gt; &lt;a href="https://invent.kde.org/frameworks/kio/-/commit/19ed9a036160b4f7298d1ffc04b5249e98af99ed"&gt;no longer re-probes the destination filesystem type for every file&lt;/a&gt;&lt;/strong&gt;. It called &lt;code&gt;KFileSystemType::fileSystemType()&lt;/code&gt; per file for the FAT and NTFS checks, and on libmount builds each of those calls parses
the entire mount table. Copying N files parsed &lt;code&gt;/proc/self/mountinfo&lt;/code&gt; N times. It is
determined once now. Each parse is about 57 microseconds on a host with 39 mounts,
and it scales with the number of mounts.&lt;/p&gt;
&lt;p&gt;Third, and this is the memory one, &lt;strong&gt;the directory lister cache &lt;a href="https://invent.kde.org/frameworks/kio/-/commit/5e36acccb3ec5ed5e1d049e697c6639a7f54bc65"&gt;got much smaller&lt;/a&gt;&lt;/strong&gt;.
A directory that no lister was showing any more went into a cache of ten and stayed
there until nine others had displaced it. For a picture folder of 50000 files that
is a lot of &lt;code&gt;KFileItem&lt;/code&gt; and &lt;code&gt;UDSEntry&lt;/code&gt; retained for nothing. The cache now holds
three directories, which is what going back a level or two actually needs, and drops
anything no lister has asked for in three minutes.&lt;/p&gt;
&lt;p&gt;Fourth, &lt;strong&gt;&lt;a href="https://api.kde.org/kio-udsentry.html"&gt;&lt;code&gt;UDSEntry&lt;/code&gt;&lt;/a&gt; got smaller&lt;/strong&gt;, which saves memory. An
entry now keeps its numbers and its strings in &lt;a href="https://invent.kde.org/frameworks/kio/-/commit/a7b7e249eded900d92aa2240793b40d7e1a65b8d"&gt;two separate vectors&lt;/a&gt;,
which buys a byte for every field an entry holds. And &lt;a href="https://invent.kde.org/frameworks/kio/-/commit/cbf2013c5a51d6e78bf0491170373067417004c3"&gt;loading now sizes each
vector from what the entry actually
holds&lt;/a&gt;:
both vectors used to be sized from the count of fields alone, a third of it for the
strings and two thirds for the numbers. A stat of a local file gives one string, the name,
and eight numbers, so the numbers grew past their room while the strings kept more than
they needed. That sizing change on its own takes a listing of 200000 local files from 528 bytes
an entry to 400, which is 105.6 MB down to 80 MB, 25.6 MB saved. Loading also &lt;a href="https://invent.kde.org/frameworks/kio/-/commit/6015c53d52f77081fda1e43e44c8d1fe3061d324"&gt;stopped hunting for a shared
value&lt;/a&gt; on
the fields where values cannot repeat: no two entries of a listing carry the same name, url or
local path, so comparing them with the entry before never found anything to share. Reading one
entry of a local folder off the wire went from 530 to 488 nanoseconds.&lt;/p&gt;
&lt;p&gt;Smaller ones worth naming: &lt;code&gt;KFileItem&lt;/code&gt; &lt;a href="https://invent.kde.org/frameworks/kio/-/commit/786803f7f32a36293cfa0fed821323c5fa8be7bf"&gt;no longer reads &lt;code&gt;.directory&lt;/code&gt; on slow filesystems when working out an icon name&lt;/a&gt;
(6.28, closing &lt;a href="https://bugs.kde.org/show_bug.cgi?id=519189"&gt;bug 519189&lt;/a&gt;), Sebastian
Englbrecht fixed &lt;a href="https://invent.kde.org/frameworks/kio/-/commit/086ffb96777a949792b40d652b578fe2d2f23321"&gt;&lt;code&gt;QPluginLoader&lt;/code&gt;, &lt;code&gt;QLibraryPrivate&lt;/code&gt; and thread lifecycle leaks&lt;/a&gt; in the worker machinery (6.28).&lt;/p&gt;
&lt;p&gt;&lt;a href="https://bugs.kde.org/buglist.cgi?bug_id=424545%2C459986%2C483297%2C489288%2C494704%2C503976%2C505197%2C506177%2C509461%2C515511%2C517067%2C517607%2C518012%2C518481%2C519189%2C519614%2C519773%2C520249%2C520659&amp;amp;bug_id_type=anyexact&amp;amp;order=bug_id"&gt;Nineteen reports&lt;/a&gt; were closed by fixes in KIO across those four releases. Most of
them are filed against the applications rather than against KIO, since that is where a user
meets the problem: Dolphin, Plasma, Konsole, KWin.&lt;/p&gt;
&lt;h2 id="benchmarks"&gt;Benchmarks&lt;/h2&gt;
&lt;h3 id="methodology"&gt;Methodology&lt;/h3&gt;
&lt;p&gt;I built KIO 6.25.0 and 6.29.0 from their tags, Release on gcc 16.2.1 and Qt 6.11.1, and ran
the same harness against each. The arms are interleaved one round at a time, so a CPU
frequency or load excursion hits both equally, and the best of N rounds is reported.&lt;/p&gt;
&lt;p&gt;Everything ran on one 13th Gen Core i7-1365U with 30 GB of RAM, kernel 7.1.4, on ext4, with
the benchmark processes pinned to the same two cores.&lt;/p&gt;
&lt;h3 id="copying"&gt;Copying&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;KIO::copy()&lt;/code&gt; of N files into an empty directory, timed from job start to the
&lt;code&gt;result&lt;/code&gt; signal. Source files are created untimed, the destination is cleared
untimed. &lt;code&gt;cp -r&lt;/code&gt; is there as a raw-tool floor, not as a target.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/copy.svg"&gt;&lt;figure&gt;
 &lt;img class="img-fluid" alt="Copying files into an empty directory. 1000 x 256 B: 421 ms in 6.25, 189 ms in 6.29, 34 ms for cp. 5000 x 256 B: 2279, 942, 176. 5000 x 4 KB: 2536, 1024, 188. 500 x 1 MB: 538, 327, 230." src="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/copy.svg"
 style="max-width: 100%; height: auto"
 /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Copying many small files is more than twice as fast as it was in April. The gain
falls off as files get larger, which is what you would expect: the fix is to the
per-file overhead, and once each file carries a megabyte of actual I/O the overhead
stops being what you are waiting for.&lt;/p&gt;
&lt;p&gt;There is still a gap with &lt;code&gt;cp&lt;/code&gt;, discussed at length in
&lt;a href="https://blogs.kde.org/2026/07/28/making-kio-copy-many-files-fast/"&gt;the July post&lt;/a&gt;. KIO is doing more than &lt;code&gt;cp&lt;/code&gt; does, but not
five times more, and the batching work that closes most of the rest of that gap is still in
progress.&lt;/p&gt;
&lt;h3 id="deleting"&gt;Deleting&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;KIO::del()&lt;/code&gt; over a freshly created tree, best of three rounds. &lt;code&gt;rm -rf&lt;/code&gt; is the raw-tool
floor here, as &lt;code&gt;cp -r&lt;/code&gt; is above, and it is handed the same list of paths the job is given
rather than the folder that holds them.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/delete.svg"&gt;&lt;figure&gt;
 &lt;img class="img-fluid" alt="Deleting a tree. 1000 x 256 B: 100.0 ms in 6.25, 81.0 ms in 6.29, 13.6 ms for rm -rf. 5000 x 256 B: 509.3 ms, 406.8 ms and 69.4 ms." src="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/delete.svg"
 style="max-width: 100%; height: auto"
 /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Deletion improves less than copying, as expected: a delete carries no file content, so the
zero-copy half of the transport work does nothing for it. What is left is the cheaper
per-command round trip, 1.23x on the smaller tree and 1.25x on the larger one.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;rm -rf&lt;/code&gt; is six times quicker than 6.29 on both trees, a wider gap than copying shows
against &lt;code&gt;cp&lt;/code&gt;. That fits: a copy at least spends real time moving bytes, where a delete is
almost nothing but the per-file round trip, so what KIO adds is most of what there is to
measure.&lt;/p&gt;
&lt;p&gt;How the job is asked matters as much as the count. These runs hand &lt;code&gt;KIO::del()&lt;/code&gt; the 5000
files one by one, the way a select-all in a file manager does. Handing it the one folder
instead takes about a fifth of that on the same filesystem, because the worker then walks
the tree itself instead of taking a command per file. &lt;code&gt;rm&lt;/code&gt; given the folder rather
than the 5000 paths goes from 69.4 ms to 66.8, which is the difference the filesystem
charges for the two shapes. The rest of it is KIO's. That second path is the one the 6.30
section below measures.&lt;/p&gt;
&lt;h3 id="listing"&gt;Listing&lt;/h3&gt;
&lt;p&gt;One &lt;code&gt;KCoreDirLister&lt;/code&gt; over an existing directory. The cold number is the first
listing in a fresh process. The warm number is a later listing of the same
directory, which &lt;code&gt;KCoreDirListerCache&lt;/code&gt; answers without going to disk. The second chart is the resident growth
while the lister is still showing the folder, which is what a file manager displaying that
folder actually costs.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/listing.svg"&gt;&lt;figure&gt;
 &lt;img class="img-fluid" alt="First listing of a folder. 5000 files: 136 ms in 6.25, 124 ms in 6.29. 50000 files: 4026 ms and 3443 ms." src="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/listing.svg"
 style="max-width: 100%; height: auto"
 /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/listing-held.svg"&gt;&lt;figure&gt;
 &lt;img class="img-fluid" alt="Memory held when a folder is shown. 5000 files: 10.2 MB in 6.25, 8.8 MB in 6.29. 50000 files: 58.7 MB and 50.5 MB." src="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/listing-held.svg"
 style="max-width: 100%; height: auto"
 /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Listing is about 9 percent quicker on the 5000-file folder and 15 percent on the 50000-file
one, and holds about 14 percent less memory in both cases. The memory part is the &lt;code&gt;UDSEntry&lt;/code&gt;
work described above. The warm listing is unchanged either way, 2.6 ms against 2.8 ms on the
5000-file folder and 37 ms on the 50000-file one, which is the cache answering rather than
the disk.&lt;/p&gt;
&lt;h3 id="memory-kept-for-folders-you-have-left"&gt;Memory kept for folders you have left&lt;/h3&gt;
&lt;p&gt;Of everything measured here, this is what a long-running Dolphin notices most. Walk twelve
directories one after another, the way you do going down and back up a tree, and then look at
how much memory the process is still holding. Nothing is on screen in either case, so all of
it is held for folders nobody is looking at any more.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/lister-memory.svg"&gt;&lt;figure&gt;
 &lt;img class="img-fluid" alt="Memory still held after walking twelve folders and leaving them. 12 x 5000 files: 63.5 MB in 6.25, 22.7 MB in 6.29, 2.8x less. 12 x 20000 files: 238.7 MB and 77.5 MB, 3.1x less." src="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/lister-memory.svg"
 style="max-width: 100%; height: auto"
 /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In 6.25 a directory nothing was showing any more sat in a cache of ten and stayed until nine
others displaced it. Browse through a few large folders and you are holding all of them. &lt;a href="https://invent.kde.org/frameworks/kio/-/commit/5e36acccb3ec5ed5e1d049e697c6639a7f54bc65"&gt;The
cache now keeps
three&lt;/a&gt;,
and drops anything no lister has wanted for three minutes. Repeat listings do not suffer for
it, which is what the warm listing above shows: re-opening a folder you just left still
finds it. What the eleventh slot bought was going eleven folders back, and every
user of a large folder paid for it.&lt;/p&gt;
&lt;h2 id="630-improvements"&gt;6.30 improvements&lt;/h2&gt;
&lt;p&gt;None of this has shipped, so treat it as a preview rather than a result. 6.30 has several commits that touch
exactly what this post measures, so I built it as a third arm and ran the same harness.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/kio-630-time.svg"&gt;&lt;figure&gt;
 &lt;img class="img-fluid" alt="6.30 against 6.29, the longer runs. Listing 50000 files: 1232.9 ms down to 531.5 ms, -57.0%. Copying 5000 x 256 B: 909.3 ms down to 883.8 ms, -2.8%. Deleting a 20000-file tree: 319.9 ms down to 290.9 ms, -9.1%." src="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/kio-630-time.svg"
 style="max-width: 100%; height: auto"
 /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/kio-630-time-small.svg"&gt;&lt;figure&gt;
 &lt;img class="img-fluid" alt="6.30 against 6.29, the quicker runs. Listing 5000 files: 36.0 ms down to 33.8 ms, -5.8%. Deleting a 5000-file tree: 80.9 ms down to 72.6 ms, -10.3%." src="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/kio-630-time-small.svg"
 style="max-width: 100%; height: auto"
 /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/kio-630-allocations.svg"&gt;&lt;figure&gt;
 &lt;img class="img-fluid" alt="Allocations for one listing. 5000 files: 151,809 down to 116,393, -23.3%. 50000 files: 1,292,614 down to 983,567, -23.9%." src="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/kio-630-allocations.svg"
 style="max-width: 100%; height: auto"
 /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/kio-630-memory.svg"&gt;&lt;figure&gt;
 &lt;img class="img-fluid" alt="Peak memory listing 50000 files. Peak heap: 42.45 MB down to 41.68 MB, -1.8%. Peak resident: 81.05 MB down to 78.45 MB, -3.2%." src="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/kio-630-memory.svg"
 style="max-width: 100%; height: auto"
 /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Most of what 6.30 gains comes from one change: &lt;a href="https://invent.kde.org/frameworks/kio/-/commit/94c9b2843064d7470ba785e77866196158ebc726"&gt;handing over what a message carries as it is
when the worker runs in the application's own
process&lt;/a&gt;.
&lt;code&gt;kio_file&lt;/code&gt; runs in a thread of the application, but used to write its data down with
&lt;code&gt;QDataStream&lt;/code&gt; the way a process-based worker has to. Except it does not need to. Avoiding that
serialisation is where the fewer allocations come from, and the entries cost less memory
besides, since one no longer reserves room for fields most files never carry. Nothing changes
for a worker in another process, which still has a socket between it and the application.&lt;/p&gt;
&lt;p&gt;The other major improvement was a dormant issue. It had been there for years, and
benchmarking made it visible: 50000 files listed in 1233 ms while 5000 listed in 36, 10
times the files taking 34 times as long, where listing should be close to linear.&lt;/p&gt;
&lt;p&gt;A profile of the large case revealed 42 percent of the whole listing is &lt;code&gt;KFileItem&lt;/code&gt; copy
construction and destruction, all of it under &lt;code&gt;KCoreDirListerCache::DirItem::insertSortedItems&lt;/code&gt;
calling &lt;a href="https://doc.qt.io/qt-6/qlist.html#reserve"&gt;&lt;code&gt;QList::reserve&lt;/code&gt;&lt;/a&gt; once per batch of entries. Except &lt;code&gt;reserve&lt;/code&gt; has no relocatable
fast path: on the growth path it allocates exactly the size asked for and copy-appends
every element already there, even for a type declared &lt;code&gt;Q_RELOCATABLE_TYPE&lt;/code&gt; as &lt;code&gt;KFileItem&lt;/code&gt;. Since the
previous call had sized the buffer exactly, every batch reallocated and copied the whole
list. Heaptrack counted 239 such calls for 50000 files, so about six million copy
constructions for fifty thousand items.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://invent.kde.org/frameworks/kio/-/commit/0fbc94a14"&gt;Deleting the &lt;code&gt;reserve&lt;/code&gt; call&lt;/a&gt; and
letting the list grow geometrically takes that listing from 1233 ms to 531 ms, over 2x
quicker. What cost the time was inside those reallocations, copy-constructing every
&lt;code&gt;KFileItem&lt;/code&gt; already in the list, and a &lt;code&gt;KFileItem&lt;/code&gt; copy is a refcount bump that allocates
nothing at all. So none of it showed up in an allocation count, which is why it took a
cycles profile to find.&lt;/p&gt;
&lt;p&gt;Deleting a folder gained from
&lt;a href="https://invent.kde.org/frameworks/kio/-/commit/af3d9e0e787f0fb758c34645dc1a45da6dfd123d"&gt;&lt;code&gt;af3d9e0e7&lt;/code&gt;&lt;/a&gt;, which removes a tree with the
system's own calls instead of walking it, and how much depends on the shape of
the tree. &lt;code&gt;openat&lt;/code&gt; and &lt;code&gt;unlinkat&lt;/code&gt; work from a descriptor for the directory an entry was
read from, so they stop resolving a whole path for every entry, and the deeper the tree
the more that is worth. Fifteen thousand files on tmpfs, deleted as one folder, with
&lt;code&gt;rm -rf&lt;/code&gt; over the same tree as the floor:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/delete-depth.svg"&gt;&lt;figure&gt;
 &lt;img class="img-fluid" alt="Deleting 15000 files as one folder, by how deep the tree is. 10 deep: 103.4 ms in 6.29, 84.6 ms in 6.30, 65.3 ms for rm -rf. 100 deep: 136.2, 78.1 and 60.2 ms. 300 deep: 227.2, 77.4 and 62.8 ms. 800 deep: 418.7, 78.7 and 64.0 ms." src="https://blogs.kde.org/2026/08/27/dolphin-26.08-and-kio-part-two-what-got-faster-and-smaller/delete-depth.svg"
 style="max-width: 100%; height: auto"
 /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;6.29 costs more the deeper the tree, four times as much at 800 levels as at ten. 6.30 does
not care how deep it is, and stays within a third of &lt;code&gt;rm -rf&lt;/code&gt; at every depth, which is about
as close as a job that reports progress and can be cancelled is going to get to a tool that
does neither.&lt;/p&gt;
&lt;h2 id="closing"&gt;Closing&lt;/h2&gt;
&lt;p&gt;The copy path still has more in it than 6.29 ships: the batching that closes most of the
remaining gap to &lt;code&gt;cp&lt;/code&gt; is written and measured in &lt;a href="https://blogs.kde.org/2026/07/28/making-kio-copy-many-files-fast/"&gt;Making KIO copy many
files fast&lt;/a&gt; and is not finished yet. The listing
path has an open question of its own, which is that an entry could carry its fields more
cheaply again; a branch that does it trades about two percent of listing time for eleven
percent of the memory an entry holds, and which of the two is the better trade depends on
how many entries you are holding.&lt;/p&gt;
&lt;p&gt;Enjoy the speed.&lt;/p&gt;</description></item><item><title>Dolphin 26.08, and KIO perf improvements</title><link>https://blogs.kde.org/2026/08/26/dolphin-26.08-and-kio-perf-improvements/</link><pubDate>Wed, 26 Aug 2026 00:00:01 +0000</pubDate><author>Méven Car</author><guid>https://blogs.kde.org/2026/08/26/dolphin-26.08-and-kio-perf-improvements/</guid><description>&lt;style&gt;
/* The site gives table cells no padding, which runs the column headings together. */
.content-width table th,
.content-width table td { padding: 0.35rem 0.35rem; }
.content-width table th { white-space: nowrap; }
&lt;/style&gt;
&lt;p&gt;Dolphin 26.08 &lt;a href="https://kde.org/announcements/gear/26.08.0/"&gt;has been released&lt;/a&gt;. Here is more of what changed in it, and in the KIO framework underneath it.&lt;/p&gt;
&lt;p&gt;The version of KIO that shipped alongside Dolphin 26.04 was 6.25. The one that ships
alongside 26.08 is 6.29, four framework releases and 294 commits later. A fair part
of this post is about that, because the largest performance change of this cycle is
not in Dolphin at all. If you only read one thing, read
&lt;a href="https://blogs.kde.org/2026/07/28/making-kio-copy-many-files-fast/"&gt;Making KIO copy many files fast&lt;/a&gt;, which is the story behind why copying a
folder of small files in 26.08 takes less than half the time it did in 26.04.&lt;/p&gt;
&lt;h2 id="new-features"&gt;New features&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Grouping is no longer tied to sorting.&lt;/strong&gt; Ramil Nurmanov
&lt;a href="https://bugs.kde.org/show_bug.cgi?id=416134"&gt;added an explicit group role&lt;/a&gt;, so
grouping by type no longer forces you to sort by type as well. The old
&amp;quot;Show in Groups&amp;quot; toggle is replaced by a &amp;quot;Group By&amp;quot; menu, which lets you turn
grouping off, keep the old &amp;quot;Same as Sort&amp;quot; behaviour, or pick a criterion outright.
Inside each group the normal sort role is still used as a secondary key.
(&lt;a href="https://invent.kde.org/system/dolphin/-/commit/989c0f4f0319f7d8e573c8a88fe8011bd3315466"&gt;989c0f4f0&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The filter bar tells you what it is doing.&lt;/strong&gt; Alessio Bonfiglio replaced the hidden
auto-detecting regex behaviour with an explicit mode selector offering Plain Text,
Glob and Regular Expression, plus a case-sensitivity toggle. The old behaviour tried
to guess: typing a name containing &lt;code&gt;*&lt;/code&gt;, &lt;code&gt;?&lt;/code&gt; or &lt;code&gt;[&lt;/code&gt; silently switched the bar to a
regular expression, which made a file genuinely named &lt;code&gt;[draft].txt&lt;/code&gt; impossible to
filter for. An invalid expression now turns the bar red instead of quietly doing
something else. (&lt;a href="https://invent.kde.org/system/dolphin/-/commit/3084a4e11e54b71065a408c7d288489bc72ea8a2"&gt;3084a4e11&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &amp;quot;Folder Name&amp;quot; column in the details view&lt;/strong&gt;, by Jussi Räsänen, closing
&lt;a href="https://bugs.kde.org/show_bug.cgi?id=433937"&gt;a request from 2021&lt;/a&gt;. It is most useful
when a search or an expanded tree puts files from several folders on screen at once.
(&lt;a href="https://invent.kde.org/system/dolphin/-/commit/4a7be9f25332942b071e7a1659a7aed67236cfb8"&gt;4a7be9f25&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Per-folder zoom&lt;/strong&gt;, by Wagner Soares. When you are not using global view properties,
the zoom level is now remembered per folder like the other view properties are.
(&lt;a href="https://invent.kde.org/system/dolphin/-/commit/0f7a9c681c4f7336362bf8a5d1c41f2bc8ed9215"&gt;0f7a9c681&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;quot;Focus Other View&amp;quot;&lt;/strong&gt;, by Felix Ernst. The &amp;quot;Switch between views with Tab key&amp;quot;
setting is gone, replaced by a real action you can bind to whatever you like. It
moves focus to the inactive split view, and opens a split if there is not one yet.
(&lt;a href="https://invent.kde.org/system/dolphin/-/commit/12b4a8a91e0b9b8dd00816b5fb84e8e09000afcd"&gt;12b4a8a91&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Close tabs to the left or right&lt;/strong&gt;, by Ramil Nurmanov. (&lt;a href="https://invent.kde.org/system/dolphin/-/commit/91e7c0c1e032b6e3e0558b8048fce6a3b68d297a"&gt;91e7c0c1e&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A button to restore view properties to their defaults&lt;/strong&gt;, which I added for the
per-folder view properties case. It enables and disables itself depending on whether
the current folder already matches the defaults. (&lt;a href="https://invent.kde.org/system/dolphin/-/commit/70f34211cb4ad1f3f6170ded062bafff85d66643"&gt;70f34211c&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Type-ahead feedback in the status bar&lt;/strong&gt;, by Felix Ernst. As you type, the status
bar shows the keys you have typed and which file name they selected, so a type-ahead
that lands somewhere unexpected is no longer silent. (&lt;a href="https://invent.kde.org/system/dolphin/-/commit/1e13c6abb6fc179fa8da32fe62df89560a801b3d"&gt;1e13c6abb&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The terminal panel can be resynchronised with F5&lt;/strong&gt;, by Antti Savolainen, closing
&lt;a href="https://bugs.kde.org/show_bug.cgi?id=510557"&gt;bug 510557&lt;/a&gt;. When a foreground program
is running in the panel, the terminal and the view can drift apart. Konsole does not
signal when that program exits, so responding to F5 is the practical answer.
(&lt;a href="https://invent.kde.org/system/dolphin/-/commit/07baa7bb68d3d3c8ed1f564ea42efa80684b3a23"&gt;07baa7bb6&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;KDE Connect integration&lt;/strong&gt;, by Kai Uwe Broulik: an &amp;quot;Open KDE Connect&amp;quot; button when
browsing the &lt;code&gt;kdeconnect&lt;/code&gt; scheme (&lt;a href="https://invent.kde.org/system/dolphin/-/commit/d5903bd810ee0447e6201a1cc36dcf186fc9c37d"&gt;d5903bd81&lt;/a&gt;), and a proper placeholder for a KDE Connect
folder (&lt;a href="https://invent.kde.org/system/dolphin/-/commit/dfef28748e4e9af8aefd969e24689e68698b74a3"&gt;dfef28748&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Session restore for the first instance&lt;/strong&gt;, by Sergey Katunin, closing
&lt;a href="https://bugs.kde.org/show_bug.cgi?id=464693"&gt;bug 464693&lt;/a&gt;. If Dolphin is not already
running and something launches it with &lt;code&gt;--new-window&lt;/code&gt;, as browsers and Kate do, the
session is restored rather than discarded. (&lt;a href="https://invent.kde.org/system/dolphin/-/commit/173794ce15620aa0c673464f532cfd67f55ab278"&gt;173794ce1&lt;/a&gt;)&lt;/p&gt;
&lt;h2 id="behaviour-changes"&gt;Behaviour changes&lt;/h2&gt;
&lt;p&gt;These are the changes most likely to surprise you, so they are worth naming
explicitly.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Create New Folder is now two actions.&lt;/strong&gt; Ctrl+Shift+N and the context menu entry
shared one action, so the menu advertised a shortcut that did something subtly
different: the shortcut creates in the viewed directory, the menu entry in the
folder you clicked. They are separate actions now, and the context menu one has no
default shortcut. (&lt;a href="https://invent.kde.org/system/dolphin/-/commit/705e366aaf6ea76c2583107c708c7bdd6dc4a08a"&gt;705e366aa&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;Empty Trash&amp;quot; moved&lt;/strong&gt; in the context menu, by Antti Savolainen, closing
&lt;a href="https://bugs.kde.org/show_bug.cgi?id=518713"&gt;bug 518713&lt;/a&gt;. It now sits with the
other destructive actions rather than next to harmless ones. The reporter had been
emptying the trash while reaching for something else. (&lt;a href="https://invent.kde.org/system/dolphin/-/commit/7d81e3092a85b77d575d2519d97c578365080e0e"&gt;7d81e3092&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;quot;Open Terminal Here&amp;quot; only appears for folders&lt;/strong&gt;, not for files, by Brijesh
krishna. (&lt;a href="https://invent.kde.org/system/dolphin/-/commit/8a9f7d9d43d38d626dd9b25b966f851b2d78caf6"&gt;8a9f7d9d4&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The play arrow over video previews in the Information Panel is gone&lt;/strong&gt;, by Ryan
Nosurname. There is already a play button and a seek bar directly beneath it.
(&lt;a href="https://invent.kde.org/system/dolphin/-/commit/71f8db089771733d89a9211750a383f48c01d427"&gt;71f8db089&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Icon overlays are drawn at a fixed size&lt;/strong&gt; rather than composited into the
thumbnail and rescaled with it
(&lt;a href="https://bugs.kde.org/show_bug.cgi?id=498211"&gt;bug 498211&lt;/a&gt;). Emblem size was
previously inconsistent from file to file, because each thumbnail was rescaled by
its own factor, and slightly cropped at fractional display scaling.
(&lt;a href="https://invent.kde.org/system/dolphin/-/commit/63f21036e7f44a6b6c8505c9cd277aabbf0bf832"&gt;63f21036e&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Special folders keep their saved view properties&lt;/strong&gt; even with global view
properties enabled, by Pan Zhang
(&lt;a href="https://bugs.kde.org/show_bug.cgi?id=520089"&gt;bug 520089&lt;/a&gt;, &lt;a href="https://invent.kde.org/system/dolphin/-/commit/2e665e1b513b3f7c082bedc8faaf47bee8008c73"&gt;2e665e1b5&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Names like &lt;code&gt;file.2.txt&lt;/code&gt; sort naturally&lt;/strong&gt;, by Pan Zhang
(&lt;a href="https://bugs.kde.org/show_bug.cgi?id=411707"&gt;bug 411707&lt;/a&gt;, &lt;a href="https://invent.kde.org/system/dolphin/-/commit/0d10eff3726e5de60298452308cc4b2b7820e10b"&gt;0d10eff37&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="who-wrote-it"&gt;Who wrote it&lt;/h2&gt;
&lt;p&gt;Counting commits that are new in 26.08 and not already in a 26.04.x release, and
leaving the translation robot out of it:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;/th&gt;
 &lt;th&gt;&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;commits&lt;/td&gt;
 &lt;td&gt;207, of which 97 code changes&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;lines&lt;/td&gt;
 &lt;td&gt;3822 added, 772 removed, net +3050&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;contributors&lt;/td&gt;
 &lt;td&gt;22&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;first time in Dolphin&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;13 of those 22&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;returning&lt;/td&gt;
 &lt;td&gt;9&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The busiest by a wide margin:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Contributor&lt;/th&gt;
 &lt;th style="text-align: right"&gt;commits&lt;/th&gt;
 &lt;th style="text-align: right"&gt;added&lt;/th&gt;
 &lt;th style="text-align: right"&gt;removed&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Sebastian Englbrecht&lt;/td&gt;
 &lt;td style="text-align: right"&gt;31&lt;/td&gt;
 &lt;td style="text-align: right"&gt;1145&lt;/td&gt;
 &lt;td style="text-align: right"&gt;87&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Méven Car&lt;/td&gt;
 &lt;td style="text-align: right"&gt;29&lt;/td&gt;
 &lt;td style="text-align: right"&gt;706&lt;/td&gt;
 &lt;td style="text-align: right"&gt;236&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Pan Zhang&lt;/td&gt;
 &lt;td style="text-align: right"&gt;6&lt;/td&gt;
 &lt;td style="text-align: right"&gt;424&lt;/td&gt;
 &lt;td style="text-align: right"&gt;58&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Felix Ernst&lt;/td&gt;
 &lt;td style="text-align: right"&gt;5&lt;/td&gt;
 &lt;td style="text-align: right"&gt;250&lt;/td&gt;
 &lt;td style="text-align: right"&gt;165&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Ramil Nurmanov&lt;/td&gt;
 &lt;td style="text-align: right"&gt;2&lt;/td&gt;
 &lt;td style="text-align: right"&gt;428&lt;/td&gt;
 &lt;td style="text-align: right"&gt;54&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Alessio Bonfiglio&lt;/td&gt;
 &lt;td style="text-align: right"&gt;2&lt;/td&gt;
 &lt;td style="text-align: right"&gt;406&lt;/td&gt;
 &lt;td style="text-align: right"&gt;22&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Kai Uwe Broulik&lt;/td&gt;
 &lt;td style="text-align: right"&gt;2&lt;/td&gt;
 &lt;td style="text-align: right"&gt;58&lt;/td&gt;
 &lt;td style="text-align: right"&gt;4&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Akseli Lahtinen&lt;/td&gt;
 &lt;td style="text-align: right"&gt;2&lt;/td&gt;
 &lt;td style="text-align: right"&gt;49&lt;/td&gt;
 &lt;td style="text-align: right"&gt;42&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Antti Savolainen&lt;/td&gt;
 &lt;td style="text-align: right"&gt;2&lt;/td&gt;
 &lt;td style="text-align: right"&gt;37&lt;/td&gt;
 &lt;td style="text-align: right"&gt;12&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Filip Fila&lt;/td&gt;
 &lt;td style="text-align: right"&gt;2&lt;/td&gt;
 &lt;td style="text-align: right"&gt;13&lt;/td&gt;
 &lt;td style="text-align: right"&gt;5&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Oleksandr Bondar&lt;/td&gt;
 &lt;td style="text-align: right"&gt;2&lt;/td&gt;
 &lt;td style="text-align: right"&gt;11&lt;/td&gt;
 &lt;td style="text-align: right"&gt;6&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Sergey Katunin&lt;/td&gt;
 &lt;td style="text-align: right"&gt;2&lt;/td&gt;
 &lt;td style="text-align: right"&gt;11&lt;/td&gt;
 &lt;td style="text-align: right"&gt;5&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Commit counts and line counts do not rank people the same way. Ramil Nurmanov and
Alessio Bonfiglio wrote two commits each and still added more lines than anyone
except the top two, because grouping by a separate criterion and the filter bar modes
each arrived whole. Ryan Nosurname's single commit is the opposite shape: removing the
video preview play arrow takes away 43 lines and adds none.&lt;/p&gt;
&lt;p&gt;Thirteen people landed their first Dolphin commit this cycle: Antti Savolainen, Areeb
Faisal, Brijesh krishna, Evgeniy Harchenko, Filip Fila, Florian RICHER, Jussi Räsänen,
Ketal Wang, Oleksandr Bondar, Ramil Nurmanov, Ryan Nosurname, Sebastian Englbrecht and
Wagner Soares. Kudos to them! Several are long-standing KDE contributors who had simply not touched
this repository before, so read it as new to Dolphin rather than new to KDE.&lt;/p&gt;
&lt;p&gt;The other 110 commits were mainly translation commits. Thank you, translators!&lt;/p&gt;
&lt;h2 id="bugs-fixed"&gt;Bugs fixed&lt;/h2&gt;
&lt;p&gt;Nineteen bugs are fixed in 26.08 that were not already fixed in a 26.04.x point
release. Ten of them are the changes described above, so here are the other nine:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Bug&lt;/th&gt;
 &lt;th&gt;What&lt;/th&gt;
 &lt;th&gt;Who&lt;/th&gt;
 &lt;th&gt;Commit&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;a href="https://bugs.kde.org/show_bug.cgi?id=492298"&gt;492298&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Menubar visibility applied after the UI has loaded&lt;/td&gt;
 &lt;td&gt;Oleksandr Bondar&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://invent.kde.org/system/dolphin/-/commit/c3ef613f29dd256e1b6065f1c744241b6f69788a"&gt;&lt;code&gt;c3ef613f&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;a href="https://bugs.kde.org/show_bug.cgi?id=506884"&gt;506884&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Inline rename preserved when the item scrolls out of view&lt;/td&gt;
 &lt;td&gt;Pan Zhang&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://invent.kde.org/system/dolphin/-/commit/5e35194b00d84db6aea3370ee8bb0ad560428c62"&gt;&lt;code&gt;5e35194b&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;a href="https://bugs.kde.org/show_bug.cgi?id=508465"&gt;508465&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Item widgets use style primitives instead of custom painting&lt;/td&gt;
 &lt;td&gt;Akseli Lahtinen&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://invent.kde.org/system/dolphin/-/commit/61b6e173f2647e885814f5c11f9861e7bb9144c2"&gt;&lt;code&gt;61b6e173&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;a href="https://bugs.kde.org/show_bug.cgi?id=509150"&gt;509150&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Wrong item count in the Size column for folders of 200+ entries&lt;/td&gt;
 &lt;td&gt;Pan Zhang&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://invent.kde.org/system/dolphin/-/commit/914cd9010b52125a01e607c0b0f08401be225106"&gt;&lt;code&gt;914cd901&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;a href="https://bugs.kde.org/show_bug.cgi?id=510469"&gt;510469&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Animated-height widgets no longer scroll the viewport&lt;/td&gt;
 &lt;td&gt;Pan Zhang&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://invent.kde.org/system/dolphin/-/commit/cde91dd71a89d1f82bc87dabe95643cc93853e50"&gt;&lt;code&gt;cde91dd7&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;a href="https://bugs.kde.org/show_bug.cgi?id=514401"&gt;514401&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Re-triggering an inline rename made robust&lt;/td&gt;
 &lt;td&gt;Méven Car&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://invent.kde.org/system/dolphin/-/commit/7ca6daea69a38c006a001bb423b9398b639d027f"&gt;&lt;code&gt;7ca6daea&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;a href="https://bugs.kde.org/show_bug.cgi?id=515236"&gt;515236&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;No spurious history entry when leaving search results&lt;/td&gt;
 &lt;td&gt;Pan Zhang&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://invent.kde.org/system/dolphin/-/commit/35b309aa3efac59b12e0c6bfc127516649f8cfa2"&gt;&lt;code&gt;35b309aa&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;a href="https://bugs.kde.org/show_bug.cgi?id=518285"&gt;518285&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Non-Breeze styles may style the non-toolbar navigation bar&lt;/td&gt;
 &lt;td&gt;Filip Fila&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://invent.kde.org/system/dolphin/-/commit/76f6eb07739290bd7e7a61946f51d7329fb75545"&gt;&lt;code&gt;76f6eb07&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;a href="https://bugs.kde.org/show_bug.cgi?id=523348"&gt;523348&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Delete action shown in selection mode in the trash&lt;/td&gt;
 &lt;td&gt;Méven Car&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://invent.kde.org/system/dolphin/-/commit/d392e6b5fae18d78233344fe9d01931fc404b045"&gt;&lt;code&gt;d392e6b5&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="two-regressions-worth-knowing-about"&gt;Two regressions worth knowing about&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Icons could be missing entirely.&lt;/strong&gt; On a freshly opened view every item drew a blank where
its icon should be, and it stayed that way until the view mode was switched or the zoom
slider moved (&lt;a href="https://bugs.kde.org/show_bug.cgi?id=523228"&gt;bug 523228&lt;/a&gt;). A regression from
&lt;a href="https://invent.kde.org/system/dolphin/-/commit/0f7a9c681"&gt;per-folder zoom&lt;/a&gt;, fixed in
&lt;a href="https://invent.kde.org/system/dolphin/-/commit/9c652faca"&gt;&lt;code&gt;9c652faca&lt;/code&gt;&lt;/a&gt;. That fix brought one
of its own, turning previews off in icons view rendering at 16 pixels rather than the 32 that
mode is set to (&lt;a href="https://bugs.kde.org/show_bug.cgi?id=524606"&gt;bug 524606&lt;/a&gt;), fixed in
&lt;a href="https://invent.kde.org/system/dolphin/-/commit/57c6b10e1"&gt;&lt;code&gt;57c6b10e1&lt;/code&gt;&lt;/a&gt;. Both are on the
&lt;code&gt;release/26.08&lt;/code&gt; branch and ship in &lt;strong&gt;Dolphin 26.08.1&lt;/strong&gt;, due in the first half of September
2026.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Service submenus disappeared from the context menu.&lt;/strong&gt; Entries that a service menu file
groups into a submenu were missing from the context menu, in any application that builds one
with &lt;code&gt;KFileItemActions&lt;/code&gt;, Dolphin included (&lt;a href="https://bugs.kde.org/show_bug.cgi?id=524239"&gt;bug
524239&lt;/a&gt;). A regression from
&lt;a href="https://invent.kde.org/frameworks/kio/-/commit/148b9253d"&gt;&lt;code&gt;148b9253d&lt;/code&gt;&lt;/a&gt; in 6.29, fixed by
Luis Bocanegra in
&lt;a href="https://invent.kde.org/frameworks/kio/-/commit/774defb94"&gt;&lt;code&gt;774defb94&lt;/code&gt;&lt;/a&gt;, which ships in &lt;strong&gt;KDE
Frameworks 6.30&lt;/strong&gt;, due in the first week of September 2026.&lt;/p&gt;
&lt;p&gt;Neither was found by a test, and both have one now: &lt;code&gt;dolphinitemlistviewtest&lt;/code&gt;, which is new,
and three cases in &lt;code&gt;dolphinviewtest&lt;/code&gt; for the per-folder cache, and
&lt;code&gt;testServiceMenuSubmenuActions&lt;/code&gt; with a &lt;code&gt;submenu.desktop&lt;/code&gt; fixture in KIO.&lt;/p&gt;
&lt;h2 id="closing"&gt;Closing&lt;/h2&gt;
&lt;p&gt;If you want to help, the leak and lifetime work above is a good way in, and so is
picking a bug from the list. The KIO copy path still has more in it than 6.29 ships:
the batching that closes most of the remaining gap to &lt;code&gt;cp&lt;/code&gt; is written and measured in
&lt;a href="https://blogs.kde.org/2026/07/28/making-kio-copy-many-files-fast/"&gt;Making KIO copy many files fast&lt;/a&gt; but not yet finished.&lt;/p&gt;
&lt;p&gt;That's all, folks.&lt;/p&gt;</description></item><item><title>Making KIO copy many files fast</title><link>https://blogs.kde.org/2026/07/28/making-kio-copy-many-files-fast/</link><pubDate>Tue, 28 Jul 2026 00:00:01 +0000</pubDate><author>Méven Car</author><guid>https://blogs.kde.org/2026/07/28/making-kio-copy-many-files-fast/</guid><description>&lt;p&gt;There is a bug in KDE's bug tracker that is almost as old as some of our
contributors: &lt;a href="https://bugs.kde.org/show_bug.cgi?id=342056"&gt;bug 342056&lt;/a&gt;,
&amp;quot;Ridiculously slow file copy (multiple small files)&amp;quot;, reported by Alexander
Nestorov back in 2014. The report is blunt: copying a 15 GB folder of roughly 3
million small files took 5 to 10 hours in KDE, versus about 20 minutes with
&lt;code&gt;rsync&lt;/code&gt;. One commenter summed up the mood:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I generally use cp and rsync instead of dolphin for anything more than a few files.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;That bug has been stuck in my head for a while, so this post is about finally
fixing it. I have been working on KIO's copy path, and I want to walk
through where the time was going, some history that explains why, and show
numbers across KIO versions including a plain &lt;code&gt;cp&lt;/code&gt; for reference.&lt;/p&gt;
&lt;p&gt;At with any optimization, let's measure first:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blogs.kde.org/2026/07/28/making-kio-copy-many-files-fast/offcpu-socket.svg"&gt;&lt;figure&gt;
 &lt;img class="img-fluid" alt="Off-CPU flame graph of a KIO 6.28 copy of 5000 small files, with the socket round-trip frames highlighted" src="https://blogs.kde.org/2026/07/28/making-kio-copy-many-files-fast/offcpu-socket.svg"
 style="max-width: 100%; height: auto"
 /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Where a KIO 6.28 copy of 5000 small files spends its blocking time, and there
is no single hotspot. Each file blocks in a burst of short syscalls: reading the
mount table (&lt;code&gt;/proc/self/mountinfo&lt;/code&gt;), opening the source and destination, and
round-tripping a command to the worker over an internal socket. The socket
round-trips, the send and receive plus the waits for each reply, are the frames
highlighted in red, about 15% of the blocking here, spread as thin slivers
across both threads because every one of the thousands of files pays them. The
frames in green are the real filesystem work the copy cannot avoid: the &lt;code&gt;statx&lt;/code&gt;
and &lt;code&gt;openat&lt;/code&gt; calls, &lt;code&gt;copy_file_range&lt;/code&gt; moving the bytes, and the &lt;code&gt;ext4&lt;/code&gt; metadata
updates beneath them. That per-file storm, not any single call, is what the rest
of this post discusses.
(Off-CPU flame graph from &lt;code&gt;sched:sched_switch&lt;/code&gt;, weighted by number of blocking
switches; click to open the full SVG.)&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="a-little-history"&gt;A little history&lt;/h2&gt;
&lt;p&gt;KIO is the layer behind almost every file operation in KDE software, from Dolphin's copy
and paste to the network transparency that lets you open &lt;code&gt;sftp://&lt;/code&gt; or &lt;code&gt;smb://&lt;/code&gt;
URLs as if they were local. Its design goes back to the KDE 2 days, around the
year 2000. Back then the answer to &amp;quot;how do I do I/O without freezing the UI&amp;quot; was
not a thread but a separate process: a &lt;em&gt;worker&lt;/em&gt; (we used to call them kioslaves)
is launched for a protocol and talks to the application over a socket. This
predates usable threading on Linux (&lt;a href="https://en.wikipedia.org/wiki/Native_POSIX_Thread_Library"&gt;Native POSIX Thread
Library&lt;/a&gt; only landed
in Linux 2.6 in 2003), so processes plus socket IPC was the portable, robust
choice, and it still is for network protocols today: if an &lt;code&gt;smb://&lt;/code&gt; worker
crashes, your file manager does not go down with it.&lt;/p&gt;
&lt;p&gt;The flip side is cost. Every request and its reply are serialized and sent over
that socket, with an event-loop hop on each side. For &lt;code&gt;file://&lt;/code&gt; that overhead
buys you nothing, because there is no untrusted network on the other end, just
the local disk.&lt;/p&gt;
&lt;p&gt;In 2022 David Faure changed that: &lt;a href="https://invent.kde.org/frameworks/kio/-/merge_requests/740"&gt; Implement running KIO workers in-process
using a thread &lt;/a&gt;
landed in Frameworks 5.95. Since then the &lt;code&gt;file&lt;/code&gt; worker runs on a thread inside
the application instead of as a separate process (other protocols stay
out-of-process for robustness). That removed process launch and context-switch
cost.&lt;/p&gt;
&lt;h2 id="no-socket-between-the-thread-and-the-app-629"&gt;No socket between the thread and the app (6.29)&lt;/h2&gt;
&lt;p&gt;There was still a catch that had been hiding in plain sight: even in-process,
the worker thread and the application talked to each other over a socketpair,
serializing every command as if they were separate processes. Once the thread
was used, that socket was pure overhead.&lt;/p&gt;
&lt;p&gt;That's the red highlight in the first flamegraph.&lt;/p&gt;
&lt;p&gt;So in-process workers now use a real in-memory transport instead of a loopback
socket. A new &lt;code&gt;ThreadConnectionBackend&lt;/code&gt; handles commands, and for reads the actual
data buffer, straight to the peer thread, with no serialization and no syscall,
which makes in-process file reads zero-copy. This is the biggest single jump in
the numbers below, and it has landed on master for 6.29
(&lt;a href="https://invent.kde.org/frameworks/kio/-/merge_requests/2279"&gt;kio!2279&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id="next-batching-the-copy-and-the-stat-under-review"&gt;Next: batching the copy and the stat (under review)&lt;/h2&gt;
&lt;p&gt;The changes above make each command cheap. The remaining cost is that there are
still so many of them: copying N files is N separate &lt;code&gt;file_copy&lt;/code&gt; jobs, each one
going through the job scheduler and taking its own round-trip to the worker. For
many small files that fixed per-file cost, not the data, is what dominates.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CopyJob&lt;/code&gt; can dispatch a whole batch of plain local-to-local files to the worker
in one command, and the worker copies them (using &lt;code&gt;copy_file_range&lt;/code&gt;,
and reflink on filesystems like Btrfs or XFS that support it). Each file still
gets its progress signal, its byte accounting, its undo entry, and anything
the worker cannot do blindly — an existing destination, an unreadable source, a
rename or skip decision — is handed back to the normal per-file path. The gate is
conservative on purpose so a hung mount can never freeze the batch
(&lt;a href="https://invent.kde.org/frameworks/kio/-/merge_requests/2282"&gt;kio!2282&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blogs.kde.org/2026/07/28/making-kio-copy-many-files-fast/offcpu-batch.svg"&gt;&lt;figure&gt;
 &lt;img class="img-fluid" alt="Off-CPU flame graph after batch-copy, with the socket round-trip frames gone" src="https://blogs.kde.org/2026/07/28/making-kio-copy-many-files-fast/offcpu-batch.svg"
 style="max-width: 100%; height: auto"
 /&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The same copy on 6.29 with batch-copy: the red socket round-trips are gone. Two
things removed them: the in-memory transport from the previous section (no
socketpair at all) and batch-copy folding a whole run of files into one command
instead of one round-trip each. What is left is real filesystem work: the green
frames are the copy itself, &lt;code&gt;copy_file_range&lt;/code&gt; moving the bytes, the &lt;code&gt;openat&lt;/code&gt; and
&lt;code&gt;statx&lt;/code&gt; calls, and the &lt;code&gt;ext4&lt;/code&gt; metadata beneath them. The wide plateau that is not
green is the benchmark loop deleting each pass's files before the next run
(&lt;code&gt;unlink&lt;/code&gt;), which is teardown rather than part of the copy.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Before copying, &lt;code&gt;CopyJob&lt;/code&gt; stats every source, which is another per-file
round-trip. The follow-up batches the stat phase over the same in-process lane.
This is the &lt;code&gt;batch-copy-stat&lt;/code&gt; column below.&lt;/p&gt;
&lt;p&gt;Both of these are under review and targeted at a release after 6.29, so treat
their columns in the table as a preview of what is coming rather than something
you can install today.&lt;/p&gt;
&lt;h2 id="numbers"&gt;Numbers&lt;/h2&gt;
&lt;p&gt;Methodology: a 13th-gen Intel Core i7-1365U laptop, everything built
&lt;code&gt;RelWithDebInfo&lt;/code&gt; without any sanitizer, copying onto a real ext4 volume (so no
reflink shortcut, &lt;code&gt;copy_file_range&lt;/code&gt; moves real bytes). Each KIO version supplies
both its own &lt;code&gt;libKIOCore&lt;/code&gt; and its own &lt;code&gt;kio_file&lt;/code&gt; worker. Times are the median of
5 runs (3 for the large set) after a discarded warm-up, so caches are warm and
equal for every version. &lt;code&gt;cp -r --preserve=mode,timestamps&lt;/code&gt; is included as the
floor, since that is what the bug reporter reached for instead of Dolphin.&lt;/p&gt;
&lt;p&gt;5000 files of 4 KB each (the many-small-files case from the bug):&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Version&lt;/th&gt;
 &lt;th&gt;Median time&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;cp -r&lt;/code&gt; (coreutils)&lt;/td&gt;
 &lt;td&gt;81 ms&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;KIO 6.28.0&lt;/td&gt;
 &lt;td&gt;1616 ms&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;KIO 6.29-dev (master)&lt;/td&gt;
 &lt;td&gt;396 ms&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;KIO 6.29-dev + batch-copy&lt;/td&gt;
 &lt;td&gt;88 ms&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;KIO 6.29-dev + batch-copy-stat&lt;/td&gt;
 &lt;td&gt;93 ms&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;1000 files of 5 MB each (bulk data, where the copy is I/O-bound):&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Version&lt;/th&gt;
 &lt;th&gt;Median time&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;cp -r&lt;/code&gt; (coreutils)&lt;/td&gt;
 &lt;td&gt;1312 ms&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;KIO 6.28.0&lt;/td&gt;
 &lt;td&gt;1997 ms&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;KIO 6.29-dev (master)&lt;/td&gt;
 &lt;td&gt;1687 ms&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;KIO 6.29-dev + batch-copy&lt;/td&gt;
 &lt;td&gt;1506 ms&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;KIO 6.29-dev + batch-copy-stat&lt;/td&gt;
 &lt;td&gt;1454 ms&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The small-files case is the story. KIO 6.28 was about 20x slower than &lt;code&gt;cp&lt;/code&gt;,
which is exactly the ratio the 2014 report complained about. Removing the socket
for in-process workers, together with no longer probing the destination
filesystem once per file, takes it from about 1.6 s to 0.4 s (roughly 4x).
Batching the copy takes it to 88 ms, essentially &lt;code&gt;cp&lt;/code&gt; speed and about 18x faster
than 6.28. That &amp;quot;I use cp instead of dolphin&amp;quot; line finally has an answer.&lt;/p&gt;
&lt;p&gt;The large-file case was already well covered before any of this work, and the
table shows it: the copy is bound by moving the bytes, so even KIO 6.28 stayed
close to &lt;code&gt;cp&lt;/code&gt; there, and the per-file optimizations barely move the number
(batch-copy lands within about 15% of &lt;code&gt;cp&lt;/code&gt;). That is the whole reason this
effort targets many small files instead, where the fixed per-file cost, not the
data, is what dominates.&lt;/p&gt;
&lt;p&gt;batch-copy and batch-copy-stat come out tied here: the benchmark copies a single
directory, so its entries arrive in one listing and batch-stat has nothing to
batch. It helps the other case, copying a large selection of individual files
that would otherwise be one stat round-trip each. Since it removes the
round-trip and not the &lt;code&gt;stat&lt;/code&gt; call, the win is largest when stats are cheap, not
when the disk is slow. Read the two as equal on this test.&lt;/p&gt;
&lt;p&gt;And &lt;code&gt;cp&lt;/code&gt; will almost certainly stay a little ahead, by design: KIO does more
than copy the bytes. It reports per-file progress, can be paused and cancelled,
keeps an undo record, preserves permissions and timestamps, resolves conflicts,
and tells any open file manager what changed so its view refreshes. That work is
not free, and the goal was never to beat &lt;code&gt;cp&lt;/code&gt;, only to make the local case fast
enough that reaching for &lt;code&gt;cp&lt;/code&gt; instead of Dolphin stops being the obvious choice.&lt;/p&gt;
&lt;h2 id="caveats-and-what-is-next"&gt;Caveats and what is next&lt;/h2&gt;
&lt;p&gt;These are laptop numbers on one ext4 disk with warm caches, meant to compare
versions, not to be absolute. On Btrfs or XFS the batch path reflinks instead of
copying, which changes the large-file picture entirely. The batch fast path only
engages for plain local-to-local copies on a responsive filesystem; anything
else (network, FAT/NTFS, conflicts needing a dialog) falls back to the existing
per-file path, unchanged.&lt;/p&gt;
&lt;p&gt;Thanks to David Faure for the in-process worker threads that made all of this
possible, to Frank Reininghaus for the earlier listing fixes, and to Alexander
Nestorov for a bug report that aged well enough to still be worth closing.&lt;/p&gt;
&lt;p&gt;That's all, folks.&lt;/p&gt;</description></item></channel></rss>