- Home
- Projects
- Publications
- Academic
- Research Notes
- Open Source
- Miscellaneous
- SSD Linux benchmarks
- Git cheat sheet
- Home directory version control
- Austrian "Buergerkarte" under Linux
- Debian on a Thinkpad T42p
- (K)Ubuntu on a Dell Latitude XT
- Debian on a Gericom Phantom
- Encrypted home directories
- Automounting with hotplug
- Aladdin eToken under Linux
- Encrypted container under Linux and Windows
- SpeedTouch 330 ADSL USB modem with kernel 2.4
- Combining an open WLAN hotspot with private IPsec
- How to make a USB stick bootable
- Encrypted suspend-to-disk with Debian
- Import old emails into a Cyrus spool
- IPsec/L2TP gateway for Android and iPhone
- Nokia N900 synchronization with Egroupware
- Suspend and wakeup under Linux
- Android applications
- Debian Root CAs for KDE4
SSD Linux benchmarking: Comparing filesystems and encryption methods
Introduction
After (again) suffering under KMail's recent sluggishness when dealing with my email spool and general Eclipse slowness when run with many plugins (such as the excellent Android ADT or the still-to-mature Scala plugin), I decided that the best update for my Lenovo Thinkpad X201s laptop would be a solid state disk (SSD). Some preliminary web article research yielded the Crucial C300 256GB as one candidate with near top-level performance and reasonable pricing. However, just dumping my previous Ubuntu 10.10 / Windows 7 dual-boot installation onto the new disk would not have been optimal in any case:
- For SSDs it is crucially (pun intended) important to have correct partition and filesystem alignment to reach maximum speed.
- As mentioned in some tuning guides, extended MSDOS partitions are likely to have alignment problems, and therefore the 5 partitions I used previously on the standard 500GB 2.5" HDD may have been problematic.
- Going from 500GB to 256GB meant reducing the partition sizes anyways.
- And finally, my Windows 7 installation, although rarely used in production, already showed signs of decay and a fresh installation was in order.
- Fortunately, my Debian/Ubuntu installations rarely deteriorate significantly over time, so I did not opt to re-install Ubuntu. A simple tar.bz2 with correct preserve options was enough as a complete partition backup.
For reference, the test system is a Lenovo Thinkpad X201s with a dual-core Intel Core2 Duo i7 with 2GHz, which amounts to 4 virtual CPU cores when taking hyperthreading into account. The laptop has 8GB RAM and, after repartitioning the Crucial C300 SSD, now uses 4 partitions (printed with parted):
Modell: ATA C300-CTFDDAC256M (scsi)
Festplatte /dev/sda: 256060514kB
Sektorgröße (logisch/physisch): 512B/512B
Partitionstabelle: msdos
Nummer Anfang Ende Größe Typ Dateisystem Flags
1 1049kB 6292505kB 6291456kB primary ext4
2 6292505kB 42992665kB 36700160kB primary ntfs boot
3 42992665kB 200279065kB 157286400kB primary
4 200279065kB 256060162kB 55781097kB primary ntfs
The first partition /dev/sda1
is a small ext4
partition mounted as /boot and containing the kernel(s), initramfs image(s), Grub, and GRML as a rescue system in the form of an ISO image. Keeping this separate allows full-partition encryption and any file system for the root partition even if not supported directly by Grub. This partition is not performance critical at all and does not need to be encrypted. The second partition /dev/sda2
holds Windows 7 (chain loaded from Grub) and does not use any encryption at the moment, as I don't keep sensitive data on the Windows system partition (although I will play with Truecrypt system encryption at some time in the near future). The third partition /dev/sda3
is the one under test and is used for the benchmark. It is ca. 155GB large and will contain the Ubuntu root filesystem (including home directories). Finally, /dev/sda4
is a data parition shared between Windows 7 and Linux and not used for sensitive data. It currently uses NTFS, although for performance reasons I am considering to format it as ext3/4.
Options for the benchmark
On every laptop, encryption of my user home directory is a must-have for the data I carry around (including e.g. the additionally-encrypted SSH and GnuPG private keys that give me access to the Debian distribution infrastructure). There are two options in current Linux distributions that offer a decent compromise between usability and performance in this regard:
- ecryptfs with the advantages of only taking as much space for the encryption as the sum of all the files to be encrypted (i.e. no container file with a fixed size) and excellent support in Debian/Ubuntu for setting up ecryptfs-encrypted user home directories; and
- dm-crypt with LUKS for key management, which can be used either for container files mounted loopback (typically for user home directories as described in one of my earlier articles) or for the whole root partition. In this case, I chose the latter approach because my laptop is mostly a single-user system and, when turned on, my main user account will be logged in (therefore, the granularity of different encryption keys for different users is not required in this scenario) and because this additionally secures all files outside the home directory as well.
Both options are sufficient for my use case and, therefore, the decision should be made based on raw performance: I bought an SSD to improve the laptop performance, and I therefore want to maximise it while still fulfilling my requirements for encryption. The first two (three for better comparison of the overhead of encryption) options for the benchmarking therefore distinguish between encryption options:
- plain, no encryption (this is not going to be used, but I include it for reference)
- dm-crypt with LUKS for key management and aes-xts-plain mode with 128 Bit keys (hardware accelerated by the kernel crypto implementation) for the whole root partition
- ecryptfs with 128 Bit AES and enabled filename encryption (FNEK)
For usage on an SSD, ecryptfs as a stacked filesystem has the additional advantage of supporting the TRIM command when the underlying file system does (e.g. ext4 and btrfs support TRIM), while dm-crypt does not yet pass through TRIM from the inner filesystem to the outer block device. My current workaround is to use a patched wiper.sh script to manually send TRIM commands to the SSD as hints for internal optimizations, although the Crucial C300 series of SSDs is reported not to suffer from a lack of TRIM support. If it doesn't help, it definitely shouldn't hurt... (And I have not yet used my SSD for long enough to be able to repeat this benchmark after some time to see if performance deteriorates without issuing TRIM commands.)
The second set of options concerns the filesystems used below ecryptfs or within dm-crypt. Best candidates seem to be:
- ext4 with
discard
option (to issue TRIM commands) - [only for comparison] ext4 with custom stride size
- btrfs with SSD alignment
- btrfs with zlib compression and SSD alignment
- btrfs with lzo compression and SSD alignment
Other filesystems were not considered because only ext4 and btrfs support TRIM at the time of this writing (with kernel 2.6.38) and there don't seem to be any significant advantages in others for laptop use cases. Note that ext4 will issue TRIM only when mounted with the discard
option while btrfs will do so by default when it detects the capability. btrfs is however mounted with the ssd
option in all cases. All filesystems are mounted with the noatime,nodiratime
options to avoid unnecessary writes to the filesystem (which would decrease SSD lifetime).
File system setup
All benchmarks on this test system were done with a Ubuntu 11.04 live USB stick with standard Ubuntu kernel 2.6.38-8-generic in the x86_64 variant (amd64). The NOOP scheduler was selected by executing
echo noop > /sys/block/sda/queue/scheduler
For each of the combinations of filesystem and encryption method, bonnie++ and Linux kernel compilation were used as simple benchmarks, with kernel compilation done on an empty filesystem and on one filled with a zero-byte file to consume ca. 93% of the partition to find any negative effects on nearly-full partitions. The "benchmarks" were executed as:
sudo chmod 777 /mnt
time bonnie++ -d /mnt/ -c 5 -s 16G
do_kernel() {
cd /mnt
time tar xvfj /home/ubuntu/Downloads/linux-2.6.38.5.tar
cd linux-2.6.38.5
cp /boot/config-2.6.38-8-generic .config
yes n | make oldconfig
time make -j 4
cd ..
time rm -r linux-2.6.38.5/
}
do_kernel
time dd if=/dev/zero of=/mnt/filler bs=1024k count=130000 # --> partition ca. 93% full
do_kernel # --> partition ca. 99% full
Filesystem and encryption method combinations were created with an explicit step to make sure that TRIM commands were issued for the free parts on the partition immediately during creating it, giving the firmware the option to optimize internally:
- ext4-plain with standard options:
sudo mkfs.ext4 /dev/sda3
sudo /home/ubuntu/wiper.sh --commit /dev/sda3
sudo mount -o noatime,nodiratime,discard /dev/sda3 /mnt - ext4-plain with custom stride as suggested by a few SSD tuning guides (with the result that the custom stride option produces worse results than the default options, and therefore not being used for the encryption combinations):
sudo mkfs.ext4 -b 4096 -E stride=128,stripe-width=128 /dev/sda3
sudo /home/ubuntu/wiper.sh --commit /dev/sda3
sudo mount -o noatime,nodiratime,discard /dev/sda3 /mnt - ext4-dmcrypt with standard options:
sudo cryptsetup -c aes-xts-plain -s 256 luksFormat /dev/sda3
sudo cryptsetup luksOpen /dev/sda3 luksroot
sudo mkfs.ext4 /dev/mapper/luksroot
#sudo /home/ubuntu/wiper.sh --commit /dev/mapper/luksroot
sudo mount -o noatime,nodiratime,discard /dev/mapper/luksroot /mnt - ext4-ecryptfs with default options:
sudo mkfs.ext4 /dev/sda3
sudo /home/ubuntu/wiper.sh --commit /dev/sda3
sudo mount -o noatime,nodiratime,discard /dev/sda3 /mnt
sudo mkdir /mnt/encrypted; sudo mkdir /mnt/plain
sudo mount -t ecryptfs /mnt/encrypted /mnt/plain - btrfs-plain without compression:
sudo mkfs.ext4 /dev/sda3
sudo /home/ubuntu/wiper.sh --commit /dev/sda3
sudo mkfs.btrfs /dev/sda3
sudo mount -o noatime,nodiratime,ssd /dev/sda3 /mnt - btrfs-dmcrypt without compression:
sudo mkfs.ext4 /dev/sda3
sudo /home/ubuntu/wiper.sh --commit /dev/sda3
sudo cryptsetup -c aes-xts-plain -s 256 luksFormat /dev/sda3
sudo cryptsetup luksOpen /dev/sda3 luksroot
sudo mkfs.btrfs /dev/mapper/luksroot
sudo mount -o noatime,nodiratime,ssd /dev/mapper/luksroot /mnt - btrfs-ecryptfs without compression:
sudo mkfs.ext4 /dev/sda3
sudo /home/ubuntu/wiper.sh --commit /dev/sda3
sudo mkfs.btrfs /dev/sda3
sudo mount -o noatime,nodiratime,ssd /dev/sda3 /mnt
sudo mkdir /mnt/encrypted; sudo mkdir /mnt/plain
sudo mount -t ecryptfs /mnt/encrypted /mnt/plain - btrfs-zlib-plain with zlib compression for the whole partition:
sudo mkfs.ext4 /dev/sda3
sudo /home/ubuntu/wiper.sh --commit /dev/sda3
sudo mkfs.btrfs /dev/sda3
sudo mount -o noatime,nodiratime,ssd,compress=zlib /dev/sda3 /mnt - btrfs-zlib-dmcrypt with zlib compression for the whole partition:
sudo mkfs.ext4 /dev/sda3
sudo /home/ubuntu/wiper.sh --commit /dev/sda3
sudo cryptsetup -c aes-xts-plain -s 256 luksFormat /dev/sda3
sudo cryptsetup luksOpen /dev/sda3 luksroot
sudo mkfs.btrfs /dev/mapper/luksroot
sudo mount -o noatime,nodiratime,ssd,compress=zlib /dev/mapper/luksroot /mnt - btrfs-zlib-ecryptfs with zlib compression for the whole partition:
sudo mkfs.ext4 /dev/sda3
sudo /home/ubuntu/wiper.sh --commit /dev/sda3
sudo mkfs.btrfs /dev/sda3
sudo mount -o noatime,nodiratime,ssd,compress=zlib /dev/sda3 /mnt
sudo mkdir /mnt/encrypted; sudo mkdir /mnt/plain
sudo mount -t ecryptfs /mnt/encrypted /mnt/plain - btrfs-lzo-dmcrypt with lzo compression for the whole partition (plain and ecryptfs were skipped because the influence of encryption is already apparent in the uncompress vs. zlib cases):
sudo mkfs.ext4 /dev/sda3
sudo /home/ubuntu/wiper.sh --commit /dev/sda3
sudo cryptsetup -c aes-xts-plain -s 256 luksFormat /dev/sda3
sudo cryptsetup luksOpen /dev/sda3 luksroot
sudo mkfs.btrfs /dev/mapper/luksroot
sudo mount -o noatime,nodiratime,ssd,compress=lzo /dev/mapper/luksroot /mnt
Results
bonnie++ | untarbz2 (empty) |
compile (empty) |
remove (empty) |
filler file creation |
untarbz2 (filled) |
compile (filled) |
remove (filled) |
|
---|---|---|---|---|---|---|---|---|
ext4 plain |
5m31.439s 0m3.890s 1m10.010s |
0m22.293s 0m21.610s 0m2.710s |
41m49.204s 131m24.910s 12m55.250s |
0m3.698s 0m0.080s 0m3.300s |
11m6.336s 0m0.080s 2m37.820s |
0m22.924s 0m22.590s 0m2.690s |
41m54.401s 130m32.100s 13m11.580s |
0m6.672s 0m0.120s 0m4.070s |
ext4 custstride plain |
7m21.210s 0m3.250s 1m9.250s |
0m22.888s 0m22.410s 0m2.610s |
41m47.584s 131m12.230s 13m2.450s |
0m10.987s 0m0.080s 0m4.320s |
10m57.498s 0m0.220s 2m17.090s |
not tested | not tested | not tested |
ext4 dmcrypt |
6m31.526s 0m2.010s 0m56.550s |
0m24.559s 0m22.530s 0m2.880s |
41m13.000s 134m55.380s 13m22.790s |
0m5.267s 0m0.110s 0m4.090s |
11m40.738s 0m0.230s 2m41.920s |
0m25.176s 0m22.600s 0m2.730s |
41m28.321s 135m21.460s 13m48.630s |
0m5.325s 0m0.080s 0m4.280s |
ext4 ecryptfs |
14m13.130s 0m3.340s 12m10.470s |
0m26.457s 0m24.460s 0m13.690s |
43m22.883s 134m19.410s 19m37.150s |
1m25.489s 0m0.290s 0m12.490s |
23m38.278s 0m0.270s 22m29.310s |
0m28.022s 0m24.760s 0m14.170s |
43m40.194s 134m40.670s 20m4.680s |
1m27.743s 0m0.340s 0m12.250s |
btrfs plain |
5m15.177s 0m2.070s 1m46.370s |
0m27.078s 0m24.820s 0m3.860s |
41m11.315s 135m15.670s 13m30.190s |
0m6.560s 0m0.070s 0m6.360s |
10m7.359s 0m0.000s 1m49.980s |
0m23.820s 0m22.750s 0m4.120s |
41m25.578s 135m23.840s 14m4.780s |
0m6.594s 0m0.080s 0m6.380s |
btrfs dmcrypt |
5m17.016s 0m1.910s 1m38.330s |
0m26.963s 0m24.360s 0m3.950s |
41m19.414s 135m6.570s 13m41.730s |
0m6.695s 0m0.060s 0m6.480s |
10m28.800s 0m0.110s 1m51.810s |
0m25.950s 0m23.080s 0m4.190s |
41m31.437s 135m24.660s 13m48.310s |
0m6.934s 0m0.080s 0m6.710s |
btrfs ecryptfs |
15m27.150s 0m3.830s 13m24.810s |
0m30.500s 0m25.770s 0m16.490s |
43m48.347s 134m25.360s 20m41.500s |
0m32.573s 0m0.300s 0m20.850s |
27m33.130s 0m0.290s 24m43.330s |
0m29.714s 0m24.960s 0m16.870s |
44m10.248s 134m21.970s 21m31.050s |
0m33.140s 0m0.320s 0m21.270s |
btrfs zlib plain |
4m48.960s 0m2.810s 1m34.400s |
0m31.058s 0m25.780s 0m4.260s |
43m37.871s 137m28.460s 13m27.920s |
0m6.450s 0m0.100s 0m6.230s |
15m30.253s 0m0.000s 1m32.060s |
0m32.258s 0m27.110s 0m4.530s |
43m44.289s 135m29.930s 14m8.860s |
0m8.678s 0m0.100s 0m8.410s |
btrfs zlib dmcrypt |
5m9.068s 0m2.810s 1m32.840s |
0m31.279s 0m25.680s 0m4.200s |
43m8.367s 135m1.880s 13m34.570s |
0m6.411s 0m0.070s 0m6.220s |
16m3.178s 0m0.940s 1m29.700s |
0m31.341s 0m25.660s 0m4.710s |
43m51.727s 135m5.970s 14m7.070s |
0m6.860s 0m0.050s 0m6.690s |
btrfs zlib ecryptfs |
15m24.590s 0m3.580s 13m33.940s |
0m44.005s 0m28.690s 0m17.900s |
45m26.734s 134m9.170s 20m50.550s |
0m38.583s 0m0.240s 0m21.690s |
25m8.729s 0m0.390s 25m2.820s |
0m42.679s 0m27.330s 0m17.310s |
45m10.735s 134m1.000s 20m41.810s |
0m40.182s 0m0.240s 0m23.130s |
btrfs lzo dmcrypt |
4m9.260s 0m2.760s 1m29.140s |
0m27.360s 0m23.310s 0m3.930s |
41m29.109s 135m1.420s 13m35.870s |
0m7.868s 0m0.100s 0m7.320s |
4m0.141s 0m0.250s 1m34.880s |
0m27.928s 0m24.270s 0m4.250s |
41m41.290s 135m15.670s 14m4.930s |
0m7.212s 0m0.080s 0m7.010s |
"Good" values are marked green, "bad" ones red, and full logs including the detailed bonnie++ output for reference (the details are used for the recommendations/analysis below, but not reported in the summary table) are available here.
Summary
Based on these measurements, I now use dm-crypt
in aes-xts-plain
mode with 128 Bit keylength and btrfs
with ssd
alignment and compress=lzo
compression for the root partition of the Ubuntu/Debian installation on my laptop SSD. It was surprising that ecryptfs performed that poorly in comparison to dm-crypt, but it was actually the reason for starting these systematic measurements in the first place. My initial approach (without systematic evaluation) was to use ecryptfs on the SSD because of the inherent TRIM support when the underlying filesystem has that capability, hoping to give the SSD firmware all information it needs to optimize for maximum performance. However, the system felt sluggish and especially KMail was unusable for the first 10 minutes after login -- not at all what I expected when upgrading to an SSD (on the previously installed HDD, I also used dm-crypt for the whole root partition, but ext4 as the inner filesystem, as the installation was done early in 2010 when btrfs was considered really unstable). The measurements show that ecryptfs was indeed the culprit, and some mailing list posts indicate that, at the time of this writing, ecryptfs hits performance limits when used on fast backend storage (such as SSDs). dm-crypt does not have any such limitation and performs well on my system without any significant slowdown caused by encryption.
The following, more specific results of (some based on bonnie++ data not shown in the summary table above) are:
- Custom stride options for file system creation are not helpful, best is to use the mkfs.ext4 defaults.
- ext4 on top of dm-crypt causes ca. 10-50% loss in bonnie benchmark, <10% loss for file unpack and remove, and no difference for compile when compared to ext4 without encryption.
- ecryptfs on top of ext4 causes >100% overall loss in bonnie benchmark, little difference for compile, and 100% loss for filling with a huge zero-bytes file.
- btrfs is roughly equivalent to ext4, with slightly higher CPU load during benchmarks (time->sys value). File meta operations seem slightly slower, while file access is slightly faster, and filling is 10% faster (huge single file) with less CPU load.
- btrfs on top of dm-crypt incurs <5% loss in all benchmarks, which is not significant. In the bonnie benchmark, btrfs-dmcrypt performs differently from ext4-dmcrypt, but overall slightly faster than with ext4, filling is ca. 10% faster (huge single file). Therefore, btrfs on top of dm-crypt is a good option for encrypted filesystems on a (laptop) SSD.
- ecryptfs on top of btrfs produces a bonnie benchmark that is significantly slower than plain or with dmcrypt and slightly (10-20%) slower than with ext4-ecryptfs, and filling is nearly 200% slower.
- btrfs with zlib compression and without encryption causes the bonnie benchmark to be marginally faster than on plain btrfs without compression, while file creation is slower (compilation 5% slower, filling 50% slower) than on plain btrfs. This slowdown seems tolerable, given the potential space savings on (limited) SSDs.
- btrfs with zlib compression on top of dm-crypt is insignificantly slower than btrfs-zlib-plain, and we again see that dmcrypt causes virtually no overhead. The bonnie benchmark is even slightly faster than on btrfs-dmcrypt (without compression), but compile is slower and filling is ca. 50% slower (but naturally with significant space savings for zero-bytes file!).
- ecryptfs on top of btrfs with zlib compression is (currently) the slowest option, with compile being 10% slower than btrfs-plain and bonnie 200% slower. A slowdown as expected, because the files created by ecryptfs for the "lower" filesystem are encrypted and therefore can not be compressedm incurring the performance overhead of compression/decompression without any gain in I/O transfer size.
- btrfs with lzo compression on top of dm-crypt causes the bonnie benchmark to be faster than with btrfs-zlib-dmcrypt, and comparable to ext4-plain: btrfs-lzo is faster on block operations, but slower on character operations. Compilation with btrfs-lzo is marginally slower, with metadata operations (create/remove) being slightly slower, but fill with zero-byte file is significantly faster (50%). Therefore, btrfs on top of dm-crypt with lzo compression is currently the best option for my personal use case (with Ubuntu kernel 2.6.38-8-generic on x86_64 and using a Crucial C300 256GB SSD).