utils.py: Wrap calls to os.path.realpath() in an LRU cache
The os.path.realpath() function is expensive and we call it many times, to the point that os.path.realpath() calls make up around 40% of the total time spent in Element.stage_artifact().
The cleanest way to fix this is with a functools.lru_cache() wrapper
that caches recently used values. None of the code in question can be
removed (as the tests added in the previous commit will demonstrate).
I tested this by running bst shell base/base-system.bst true in
the GNOME modulesets project.
o Without this patch there are 240,019 calls os.path.realpath()
o With this patch there are 10,379 calls to os.path.realpath()
o If we increase the cache size to 128 items, there are 10,359 calls to os.path.realpath().
o If we reduce the cache size to 32 items, there are 10,426 calls.
o In all cases the number of unique calls is 10,327.
This fixes issue #174 (closed).