Thanks for doing my digging work for me. :-) These were all quite interesting finds. Neither seems to aim for what I do.
Math::Calc::Units and Convert::Units both attempt to offer extremly generic parsing of input and to produce human readable output to the extend of taking (in Math::Calc::Units) specifications such as 10MB / 384kbps and returning a result expressed in minutes. That's far more work than I ever intend to do, and IMHO should be done in separate stages (and therefor modules) - one to calculate a straight result, on to apply a set of heuristics to convert a given value into a more human readable specification. The latter kind of module would be useful in different environments as well.
Math::Units is much closer to my goals, so I took a closer look. I found it only does one-shot conversions. To do so it expends considerable effort to deduce the shortest path between two indirectly convertible units. Trying to do broadside conversions with that module would be costly, and since it provides no querying interface, also quite an annoyance.
In contrast, even though brute force, the "flood fill" approach I used naturally takes shortest path between two indirectly related units. It also does broadside conversions at no extra cost.
My final gripe with Math::Units is that its internal data structure layout is quite complex and opaque. It doesn't look as though adding conversions is anywhere as simple as doing so in the table setup I used. Granted the module does try to be a lot more intelligent than my code, but it does lead to signficant complexity.
Makeshifts last the longest.