from Hacker News

Try-catch speeding up my code?

by vishal0123 on 5/20/14, 7:08 AM with 59 comments

  • by gorhill on 5/20/14, 11:39 AM

    I actually have a similar question re. js since a while now [with Chromium 34]... Consider these two pieces of code which do exactly the same thing, one is a standalone function:

        var makeKeyCodepoint = function(word) {
            var len = word.length;
            if ( len > 255 ) { return undefined; }
            var i = len >> 2;
            return String.fromCharCode(
                (word.charCodeAt(    0) & 0x03) << 14 |
                (word.charCodeAt(    i) & 0x03) << 12 |
                (word.charCodeAt(  i+i) & 0x03) << 10 |
                (word.charCodeAt(i+i+i) & 0x03) <<  8 |
                len
            );
        };
        
    The other a method:

        var MakeKeyCodepoint = function() {};
        MakeKeyCodepoint.prototype.makeKey = function(word) {
            var len = word.length;
            if ( len > 255 ) { return undefined; }
            var i = len >> 2;
            return String.fromCharCode(
                (word.charCodeAt(    0) & 0x03) << 14 |
                (word.charCodeAt(    i) & 0x03) << 12 |
                (word.charCodeAt(  i+i) & 0x03) << 10 |
                (word.charCodeAt(i+i+i) & 0x03) <<  8 |
                len
            );
        };
        var makeKeyCodepointObj = new MakeKeyCodepoint();
    
    Now why the standalone function runs at over 6.3M op/sec, while the method runs at 710M op/sec (on my computer)?

    Try it: http://jsperf.com/makekey-concat-vs-join/3

  • by userbinator on 5/20/14, 9:03 AM

    I wasn't surprised to see it had to do with register allocation, since I've encountered some extremely odd compiler output with similar issues before. "Why would it ever decide this was a good idea?" is the thought that often comes to mind when looking through the generated code.

    Register allocation is one of those areas where I think compilers are pretty horrible compared to a good or even mid-level Asm programmer, and I've never understood why graph colouring is often the only way that is taught because it's clearly not the way that an Asm programmer does it, and is also completely unintuitive to me. It seems to assume that variables are allocated in a fixed fashion and a load-store architecture, which is overly restrictive for real architectures like x86. There's also no interaction between RA and instruction selection, despite them both influencing each other, whereas a human programmer will essentially combine those two steps together. The bulk of research appears to be stuck on "how do we improve graph colouring", when IMHO a completely new, more intuitive approach would make more sense. At least it would make odd behaviour like this one less of a problem, I think.

  • by stinos on 5/20/14, 11:29 AM

    One of the nice things about this question (apart from the serious in-depth answers) is that Eric Lippert himself comes with an answer after discussing it directly with the people that can actually provide the proper fix. Q&A at it's best!

    edit same goes for Jon Skeet of course, and looking for info about him I came across this http://meta.stackexchange.com/questions/9134/jon-skeet-facts... which has some hilarious ones like

    Jon Skeet's SO reputation is only as modest as it is because of integer overflow (SQL Server does not have a datatype large enough) and When Jon Skeet points to null, null quakes in fear.

  • by driax on 5/20/14, 8:10 AM

    Notice that this question is 2 years old. I would imagine that several lots of things have happened for Roslyn. (They even talk about some of what they were working on). Nevertheless quite interesting.
  • by nutjob2 on 5/20/14, 8:31 AM

    It's a compiler bug.
  • by logn on 5/20/14, 1:02 PM

    I don't code in C# but it would be interesting to surround the code in just a block instead of a try-catch block and see if the same behavior is evident. If a plain block is still slow, then maybe branch prediction gets overwhelmed with considering having to unwind the stack all the way to main and dealing with open streams and objects on the stack.

    edit: I don't know byte code or machine code well so my description of what happens unwinding the stack is probably wrong, but my point is just that it's simpler for the CPU not having the possibility of unwinding the stack beyond the code section OP called out.

  • by batmansbelt on 5/20/14, 2:24 PM

    It's literally the best feeling in the world when Eric Lippert answers your c# question.

    It's like if you cried out "dear God, why?" about your troubles but actually got a response.

  • by fulafel on 5/20/14, 8:59 AM

    Puzzling that so many people still run in i386 mode. I haven't used a 32-bit system since shortly after x86 hardware went 64-bit, 10+ years ago. I guess in the Windows world it's because of XP?