Overview

test-discard is a small userspace tool for benchmarking how a block device actually handles discard. It calls the BLKDISCARD ioctl repeatedly with the parameters you give it and records how long each call takes. It was one of my first projects at Red Hat.

21 commits · 3,382 insertions(+) · 1,057 deletions(-)

What it does

You tell it how much data to discard in total, where on the device to start, and what record size to use. It then issues discards until it has covered that amount, measuring the minimum, maximum, average and total ioctl time and computing throughput from them. There are three modes: sequential, random, and discarding blocks that have already been discarded once.

It can also sweep a range of record sizes on its own, with -R start:end:step, which is the mode that produces the interesting curves. -b makes the output script friendly, and there is a test-discard.sh wrapper that runs a reasonable default sweep and plots the result, provided you have gnuplot installed.

The tool itself is not sophisticated. It calls one ioctl in a loop and times it.

Why it mattered

At the time there were very few numbers on how real drives handled TRIM. The specification says what the command means. It says nothing about what it costs, and that turned out to vary enormously between devices:

  • Support varies by drive and controller, even among devices that all advertise it.
  • Some devices handle small, frequent discards very slowly, which makes discarding on every file delete expensive.
  • Others show a benefit only once the discards are coalesced into large ranges.

That is the argument for batched discard, and it is where FITRIM and fstrim came from. Instead of discarding blocks as they are freed, which is what the realtime -o discard mount option does, collect the free space and discard it in large extents, periodically. The results also fed into wider discussions about discard across the rest of the stack, LVM and RAID included, and about how to tune it in practice.

Measuring the thing settled an argument that had been running on assumptions.