A (Slightly Faster) URL Resolver Module for ASP.NET MVC
Posted by Dylan Beattie on 05 November 2009 • permalinkYesterday, I posted some code I’d hacked together as part of an MVC2 demo that would resolve ASP.NET virtual path URLs on the fly as pages were written to the ASP.NET response stream.
Having run some tests on this code in isolation – it’s actually quite nasty. For running ad-hoc demos on your workstation, it’s fine, but the performance hit of decoding the byte array, doing the regex transform and re-encoding it is something like two hundred times slower than a direct stream copy. Not good. There is now a modified version online at Google Code which is quite a bit faster, but there’s still huge scope for improvement. In particular, although it’s using byte comparisons now to work out where the ~/ combination occurs, it’s still falling back to string comparisons every time it finds a tilde to decide whether that tilde needs replacing or not.
These stats were created using a loop that spins up HTML pages of various sizes – one version full of ASP.NET-style tilde paths, one containing no tildes - and then writes them 100 times to both a normal MemoryStream and a UrlResolverStream in order to calculate the average rendering time. If a page doesn’t contain any tildes at all, performance is 5-6 times slower than the equivalent direct memory copy – i.e. 21ms instead of 4ms. For pages with lots of tildes, the additional string processing hits quite hard and you’re looking at a slowdown factor of around 30-35x.
Tildes? | Page Size | MemoryStream copy (ms) | UrlResolverStream copy (ms) | Ratio |
Yes | 50Kb | 0.05 | 0.38 | 7 |
Yes | 101Kb | 0.17 | 2.51 | 14 |
Yes | 202Kb | 0.19 | 6.05 | 31 |
Yes | 405Kb | 0.37 | 13.88 | 37 |
Yes | 809Kb | 0.88 | 29.47 | 33 |
Yes | 1,619Kb | 1.62 | 60.55 | 37 |
Yes | 3,238Kb | 3.45 | 123.40 | 35 |
No | 50Kb | 0.02 | 0.34 | 17 |
No | 101Kb | 0.07 | 0.66 | 9 |
No | 202Kb | 0.15 | 1.28 | 8 |
No | 405Kb | 0.48 | 2.62 | 5 |
No | 809Kb | 0.83 | 5.26 | 6 |
No | 1,619Kb | 1.66 | 10.57 | 6 |
No | 3,237Kb | 3.53 | 21.17 | 5 |
It should be possible to make this considerably faster still; since the code basically scans byte arrays, this is one of those areas where using pointer arithmetic could make a huge difference. I’ll dig out my unsafe hat and my pointer-gloves this weekend and see what I can do to it. In the meantime – play with it, experiment with it, but it’s probably a good idea not to let it within a hundred miles of your live servers :)