Blog post about CFexpress card and disk speeds.

Also updates hermit-v2 theme...
This commit is contained in:
2026-04-19 13:36:37 +02:00
parent b8ae27e102
commit d9d9c4a749
3 changed files with 248 additions and 1 deletions
+110
View File
@@ -0,0 +1,110 @@
---
title: "Testing CFexpress Type B card readers"
description: >
Is there a true, relevant difference in the performance of current CFexpress
Type B card readers, or is it all just marketing?
date: 2026-04-19T12:26:06+02:00
draft: false
# ShowLastmod: true
toc: false
scrolltotop: true
images: []
tags:
- linux
- photography
---
I've been looking for a card reader for my CFexpress Type B cards that I use in
my camera. There are not very many devices on the market, but they have a large
price span: around 10x.
Since I was wondering whether the price correlates with speed, I decided to
perform some simple tests using my existing hardware:
- a UGREEN CFexpress Type B card reader
- a PGYTECH CreateMate CFE-B/SD card reader
- a Nextorage B1 Pro CFexpress Type B card with 165 GB capacity
- the built-in NVMe SSD of my Thinkpad laptop, a Samsung SSD 990 PRO with 2 TB
storage capacity.
The two external card readers are attached via USB-C/USB 3.2 Gen 2 to my
Thinkpad Thunderbolt 3 dock. I am generally happy with both of them, I think
they have good quality.
By the way, why should I even look for a new card reader in the first place?
Well, the CreateMate card reader is a bit bulky and heavy and I once forgot to
take it with me on vacation. So I was looking for something smaller and lighter.
## Sequential read and write tests
I did not want to overcomplicate things, just get an impression if there are any
differences between card readers or not. Therefore I decided to perform
sequential read and write tests using `dd` as described at [Baeldung.com][].
The graph below shows the means and standard deviations of 5 tests for each
device. The "direct" label denotes tests with the card reader attached directly
to a USB-C/USB 3.2 Gen 2 port of my [Thinkpad P14s][] laptop, rather than via
the Thunderbolt 3 dock.
{{< figure src = "speed_tests.svg" >}}
When attached to the Thunderbolt dock, the PGYTECH CreateMate reads from the
CFexpress card much faster than the UGREEN reader. It does also write a bit
faster than the UGREEN reader.
Attaching the card readers directly to the laptop results in increased speeds
overall, and the differences between the UGREEN and the PGYTECH readers seems
negligible.
**However, regardless of how the readers are connected to the laptop, both are
left in the dust by the internal SSD!**
Is the observed difference in read speeds between the UGREEN and the PGYTECH
card readers "clinically relevant"? Does it justify spending a lot more money
for the PGYTECH reader? Given the very large difference of both of these card
readers to the internal SSD, I don't really think so.
## What to expect from a "USB-C" or rather, USB 3.2 Gen 2 connection
It should be noted that the USB 3.2 Gen 2 standard has a nominal transfer speed
of 10 GBit/s or 1.25 GB/s. As stated in the [Wikipedia article on USB 3.2][],
actual transfer rates are round 0.8-1.0 GB/s. Still higher than what I measured.
My Thinkpad's USB-C ports a really Thunderbolt 4/USB 4 ports that should be
capable of transferring up to 40 Gbit/s or 5 GB/s. This would be in the internal
SSD's ballpark. However, the card readers have "only" USB 3.2 Gen 2. PGYTECH
claims 1000 MB/s for the CreateMate and UGREEN 1250 MB/s for their device. The
card itself claims read speeds of up to 1950 MB/s and write speeds of up to 1900
MB/s, which roughly corresponds to 1.86 and 1.90 GB/s. Obviously, the 0.3 to 0.6
GB/s that I measured are nowhere near any of these numbers.
## Using Darktable's local copies feature
Evidently, nothing is faster than the internal NVMe SSD.
This reminds me that [Darktable][] has a feature to copy image files to the
built-in SSD. This not only allows for faster read and write speeds, but also
makes it possible to work on the images without having the card reader attached
to the laptop: [Darktable's user manual on local copies][local-copies].
Local copies (or rather, the XMP sidecar files) are synchronized whenever the
external storage is attached when Darktable is starting up. I don't know if
Darktable will automatically remove synchronized local copies in case disk
space gets low.
## Conclusion
In practice, I am going to create local copies of my images and select and work
on the local copies. Yes, the initial process of copying the files will take a
few seconds less with the PGYTECH reader than with the UGREEN reader, but that
is negligible given the amount of time that I spend on selecting the images and
working on the RAW file development in total.
Therefore, if I decide to purchase a new reader, I will focus on the size and
build, and the UGREEN reader is a strong contender when it comes to small size.
[baeldung.com]: https://www.baeldung.com/linux/disk-performance-test
[darktable]: https://darktable.org
[local-copies]: https://docs.darktable.org/usermanual/development/en/overview/sidecar-files/local-copies/
[Thinkpad P14s]: {{< relref "p14s" >}}
[Wikipedia article on USB 3.2]: https://en.wikipedia.org/wiki/USB_3.0#3.2
@@ -0,0 +1,137 @@
<?xml version='1.0' encoding='UTF-8' ?>
<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='576.00pt' height='432.00pt' viewBox='0 0 576.00 432.00'>
<g class='svglite'>
<defs>
<style type='text/css'><![CDATA[
.svglite line, .svglite polyline, .svglite polygon, .svglite path, .svglite rect, .svglite circle {
fill: none;
stroke: #000000;
stroke-linecap: round;
stroke-linejoin: round;
stroke-miterlimit: 10.00;
}
.svglite text {
white-space: pre;
}
.svglite g.glyphgroup path {
fill: inherit;
stroke: none;
}
]]></style>
</defs>
<rect width='100%' height='100%' style='stroke: none; fill: #303030;'/>
<defs>
<clipPath id='cpMC4wMHw1NzYuMDB8MC4wMHw0MzIuMDA='>
<rect x='0.00' y='0.00' width='576.00' height='432.00' />
</clipPath>
</defs>
<g clip-path='url(#cpMC4wMHw1NzYuMDB8MC4wMHw0MzIuMDA=)'>
<rect x='0.00' y='0.000000000000057' width='576.00' height='432.00' style='stroke-width: 1.07; stroke: none; fill: #303030;' />
</g>
<defs>
<clipPath id='cpMTQ2LjQ2fDU3MC41Mnw2MC43N3wyMTYuMDE='>
<rect x='146.46' y='60.77' width='424.06' height='155.24' />
</clipPath>
</defs>
<g clip-path='url(#cpMTQ2LjQ2fDU3MC41Mnw2MC43N3wyMTYuMDE=)'>
<polyline points='164.20,113.01 164.20,104.06 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='164.20,108.53 163.34,108.53 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='163.34,113.01 163.34,104.06 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='177.29,172.72 177.29,163.76 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='177.29,168.24 176.73,168.24 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='176.73,172.72 176.73,163.76 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='457.85,202.57 457.85,193.62 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='457.85,198.10 372.76,198.10 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='372.76,202.57 372.76,193.62 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='183.93,142.87 183.93,133.91 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='183.93,138.39 183.76,138.39 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='183.76,142.87 183.76,133.91 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='183.86,83.16 183.86,74.20 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='183.86,78.68 183.54,78.68 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='183.54,83.16 183.54,74.20 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<rect x='146.46' y='95.10' width='17.31' height='26.87' style='stroke-width: 1.07; stroke: none; stroke-linecap: butt; stroke-linejoin: miter; fill: #505090;' />
<rect x='146.46' y='154.81' width='30.56' height='26.87' style='stroke-width: 1.07; stroke: none; stroke-linecap: butt; stroke-linejoin: miter; fill: #505090;' />
<rect x='146.46' y='184.66' width='268.85' height='26.87' style='stroke-width: 1.07; stroke: none; stroke-linecap: butt; stroke-linejoin: miter; fill: #505090;' />
<rect x='146.46' y='124.95' width='37.39' height='26.87' style='stroke-width: 1.07; stroke: none; stroke-linecap: butt; stroke-linejoin: miter; fill: #505090;' />
<rect x='146.46' y='65.24' width='37.25' height='26.87' style='stroke-width: 1.07; stroke: none; stroke-linecap: butt; stroke-linejoin: miter; fill: #505090;' />
<text x='176.24' y='112.84' style='font-size: 12.04px;fill: #C0C0C0; font-family: "Arial";' textLength='60.19px' lengthAdjust='spacingAndGlyphs'>0.307 GB/s</text>
<text x='189.33' y='172.55' style='font-size: 12.04px;fill: #C0C0C0; font-family: "Arial";' textLength='60.19px' lengthAdjust='spacingAndGlyphs'>0.542 GB/s</text>
<text x='469.89' y='202.40' style='font-size: 12.04px;fill: #C0C0C0; font-family: "Arial";' textLength='60.19px' lengthAdjust='spacingAndGlyphs'>4.772 GB/s</text>
<text x='195.97' y='142.69' style='font-size: 12.04px;fill: #C0C0C0; font-family: "Arial";' textLength='60.19px' lengthAdjust='spacingAndGlyphs'>0.664 GB/s</text>
<text x='195.90' y='82.98' style='font-size: 12.04px;fill: #C0C0C0; font-family: "Arial";' textLength='60.19px' lengthAdjust='spacingAndGlyphs'>0.661 GB/s</text>
</g>
<g clip-path='url(#cpMC4wMHw1NzYuMDB8MC4wMHw0MzIuMDA=)'>
</g>
<defs>
<clipPath id='cpMTQ2LjQ2fDU3MC41MnwyNDEuMzd8Mzk2LjYy'>
<rect x='146.46' y='241.37' width='424.06' height='155.24' />
</clipPath>
</defs>
<g clip-path='url(#cpMTQ2LjQ2fDU3MC41MnwyNDEuMzd8Mzk2LjYy)'>
<polyline points='164.66,293.62 164.66,284.66 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='164.66,289.14 163.26,289.14 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='163.26,293.62 163.26,284.66 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='167.26,353.33 167.26,344.37 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='167.26,348.85 164.30,348.85 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='164.30,353.33 164.30,344.37 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='317.66,383.18 317.66,374.22 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='317.66,378.70 312.46,378.70 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='312.46,383.18 312.46,374.22 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='178.59,323.47 178.59,314.52 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='178.59,318.99 168.97,318.99 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='168.97,323.47 168.97,314.52 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='175.23,263.76 175.23,254.81 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='175.23,259.29 163.48,259.29 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<polyline points='163.48,263.76 163.48,254.81 ' style='stroke-width: 1.07; stroke: #505090; stroke-linecap: butt;' />
<rect x='146.46' y='275.71' width='17.51' height='26.87' style='stroke-width: 1.07; stroke: none; stroke-linecap: butt; stroke-linejoin: miter; fill: #505090;' />
<rect x='146.46' y='335.41' width='19.32' height='26.87' style='stroke-width: 1.07; stroke: none; stroke-linecap: butt; stroke-linejoin: miter; fill: #505090;' />
<rect x='146.46' y='365.27' width='168.60' height='26.87' style='stroke-width: 1.07; stroke: none; stroke-linecap: butt; stroke-linejoin: miter; fill: #505090;' />
<rect x='146.46' y='305.56' width='27.32' height='26.87' style='stroke-width: 1.07; stroke: none; stroke-linecap: butt; stroke-linejoin: miter; fill: #505090;' />
<rect x='146.46' y='245.85' width='22.89' height='26.87' style='stroke-width: 1.07; stroke: none; stroke-linecap: butt; stroke-linejoin: miter; fill: #505090;' />
<text x='176.52' y='293.45' style='font-size: 12.04px;fill: #C0C0C0; font-family: "Arial";' textLength='59.30px' lengthAdjust='spacingAndGlyphs'>0.311 GB/s</text>
<text x='179.30' y='353.15' style='font-size: 12.04px;fill: #C0C0C0; font-family: "Arial";' textLength='60.19px' lengthAdjust='spacingAndGlyphs'>0.343 GB/s</text>
<text x='329.70' y='383.01' style='font-size: 12.04px;fill: #C0C0C0; font-family: "Arial";' textLength='60.19px' lengthAdjust='spacingAndGlyphs'>2.993 GB/s</text>
<text x='190.63' y='323.30' style='font-size: 12.04px;fill: #C0C0C0; font-family: "Arial";' textLength='60.19px' lengthAdjust='spacingAndGlyphs'>0.485 GB/s</text>
<text x='187.26' y='263.59' style='font-size: 12.04px;fill: #C0C0C0; font-family: "Arial";' textLength='60.19px' lengthAdjust='spacingAndGlyphs'>0.406 GB/s</text>
</g>
<g clip-path='url(#cpMC4wMHw1NzYuMDB8MC4wMHw0MzIuMDA=)'>
</g>
<defs>
<clipPath id='cpMTQ2LjQ2fDU3MC41MnwyMjEuNDl8MjQxLjM3'>
<rect x='146.46' y='221.49' width='424.06' height='19.88' />
</clipPath>
</defs>
<g clip-path='url(#cpMTQ2LjQ2fDU3MC41MnwyMjEuNDl8MjQxLjM3)'>
<text x='358.49' y='235.73' text-anchor='middle' style='font-size: 12.00px;fill: #C0C0C0; font-family: "Arial";' textLength='25.34px' lengthAdjust='spacingAndGlyphs'>write</text>
</g>
<g clip-path='url(#cpMC4wMHw1NzYuMDB8MC4wMHw0MzIuMDA=)'>
</g>
<defs>
<clipPath id='cpMTQ2LjQ2fDU3MC41Mnw0MC44OHw2MC43Nw=='>
<rect x='146.46' y='40.88' width='424.06' height='19.88' />
</clipPath>
</defs>
<g clip-path='url(#cpMTQ2LjQ2fDU3MC41Mnw0MC44OHw2MC43Nw==)'>
<text x='358.49' y='55.12' text-anchor='middle' style='font-size: 12.00px;fill: #C0C0C0; font-family: "Arial";' textLength='24.02px' lengthAdjust='spacingAndGlyphs'>read</text>
</g>
<g clip-path='url(#cpMC4wMHw1NzYuMDB8MC4wMHw0MzIuMDA=)'>
<text x='146.46' y='410.14' text-anchor='middle' style='font-size: 12.00px;fill: #C0C0C0; font-family: "Arial";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>0</text>
<text x='259.13' y='410.14' text-anchor='middle' style='font-size: 12.00px;fill: #C0C0C0; font-family: "Arial";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>2</text>
<text x='371.80' y='410.14' text-anchor='middle' style='font-size: 12.00px;fill: #C0C0C0; font-family: "Arial";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>4</text>
<text x='484.47' y='410.14' text-anchor='middle' style='font-size: 12.00px;fill: #C0C0C0; font-family: "Arial";' textLength='6.67px' lengthAdjust='spacingAndGlyphs'>6</text>
<text x='141.53' y='202.40' text-anchor='end' style='font-size: 12.00px;fill: #C0C0C0; font-family: "Arial";' textLength='64.70px' lengthAdjust='spacingAndGlyphs'>internal_ssd</text>
<text x='141.53' y='172.54' text-anchor='end' style='font-size: 12.00px;fill: #C0C0C0; font-family: "Arial";' textLength='100.03px' lengthAdjust='spacingAndGlyphs'>pgytech_cfexpress</text>
<text x='141.53' y='142.69' text-anchor='end' style='font-size: 12.00px;fill: #C0C0C0; font-family: "Arial";' textLength='136.05px' lengthAdjust='spacingAndGlyphs'>pgytech_cfexpress_direct</text>
<text x='141.53' y='112.83' text-anchor='end' style='font-size: 12.00px;fill: #C0C0C0; font-family: "Arial";' textLength='95.38px' lengthAdjust='spacingAndGlyphs'>ugreen_cfexpress</text>
<text x='141.53' y='82.98' text-anchor='end' style='font-size: 12.00px;fill: #C0C0C0; font-family: "Arial";' textLength='131.39px' lengthAdjust='spacingAndGlyphs'>ugreen_cfexpress_direct</text>
<text x='141.53' y='383.00' text-anchor='end' style='font-size: 12.00px;fill: #C0C0C0; font-family: "Arial";' textLength='64.70px' lengthAdjust='spacingAndGlyphs'>internal_ssd</text>
<text x='141.53' y='353.15' text-anchor='end' style='font-size: 12.00px;fill: #C0C0C0; font-family: "Arial";' textLength='100.03px' lengthAdjust='spacingAndGlyphs'>pgytech_cfexpress</text>
<text x='141.53' y='323.29' text-anchor='end' style='font-size: 12.00px;fill: #C0C0C0; font-family: "Arial";' textLength='136.05px' lengthAdjust='spacingAndGlyphs'>pgytech_cfexpress_direct</text>
<text x='141.53' y='293.44' text-anchor='end' style='font-size: 12.00px;fill: #C0C0C0; font-family: "Arial";' textLength='95.38px' lengthAdjust='spacingAndGlyphs'>ugreen_cfexpress</text>
<text x='141.53' y='263.58' text-anchor='end' style='font-size: 12.00px;fill: #C0C0C0; font-family: "Arial";' textLength='131.39px' lengthAdjust='spacingAndGlyphs'>ugreen_cfexpress_direct</text>
<text x='358.49' y='424.00' text-anchor='middle' style='font-size: 12.00px;fill: #C0C0C0; font-family: "Arial";' textLength='72.67px' lengthAdjust='spacingAndGlyphs'>Speed (GB/s)</text>
<text x='146.46' y='32.88' style='font-size: 12.00px;fill: #C0C0C0; font-family: "Arial";' textLength='78.00px' lengthAdjust='spacingAndGlyphs'>File size: 1 GB</text>
<text x='146.46' y='15.78' style='font-size: 14.40px;fill: #C0C0C0; font-family: "Arial";' textLength='213.59px' lengthAdjust='spacingAndGlyphs'>Sequential read and write speeds</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB