V8 Function Optimization


  • Patron

    Hey guys!

    As you may or may not know, I’m currently working on a NES emulator.
    Everything was fine, until I started trying to run my 6502 emulation at the actual clock speed of the NES’s CPU. It’s just too damn slow!

    I then proceeded to profile the freaking thing, and found out that my cpu.execute function can’t be optimized because it makes a “Call to a Javascript runtime function”, whatever the heck that means.

    After spending way too much time to figure out what’s wrong with just that cryptic clue from the profiler, I still have no idea what’s the problem.

    So, I decided to plead for your help.

    Any ideas?


  • LDG

    My best guess is that your massive switch statement is causing problems. Specifically, switch statements with more than 128 “cases” cannot be optimized. Looks like your switch has 147 cases. There are a lot of other helpful optimization gotchas on that page as well.

    I’d work on splitting up that big function into a bunch of smaller ones if possible. There are a number of reasons that V8 might refuse to optimize a certain function and if one of those scenarios affects your execute function the entire thing will not be optimized.


  • Patron

    @geoffb said:

    My best guess is that your massive switch statement is causing problems. Specifically, [switch statements with more than 128 “cases” cannot be optimized][1]. Looks like your switch has 147 cases.

    Yeah, I read that page and tried removing some cases, but that doesn’t seems to be the exact problem. It worked when I removed the last 19 cases, but not the first 19.

    I’d work on splitting up that big function into a bunch of smaller ones if possible. There are a number of reasons that V8 might refuse to optimize a certain function and if one of those scenarios affects your execute function the entire thing will not be optimized.

    Oh… right. That sure does make a lot of sense!
    Even if I don’t discover the exact cause of the de-optimization, at least it won’t affect all the instructions.

    Thanks Geoff!


  • Patron

    Thank you sooooo much @geoffb!!


  • Patron

    Now not only my code performs waaaay better and looks way nicer, but now it will also be easier to find what was preventing that function from being optimized!


  • LDG

    Nice, glad that helped!


  • Jammer

    Interesting find. I just avoid switch cases in games with JS. I’ve known them to be slow. Other things I try to avoid with html5 games:

    • image scaling. This is really inefficient with the canvas especially
    • object deletion, be green and re-use, aka object pooling. This goes for any language with garbage collection
    • heavy use of draw/shape calls instead of using images
    • Avoid static functions & singletons. While you don’t want to release things liberally, you also don’t want to keep things around that you don’t really need.

  • Patron

    @agmcleod said:

    Interesting find. I just avoid switch cases in games with JS. I’ve known them to be slow.

    Yeah, this special case was kinda weird. The problem definetely wasn’t the switch statement itself but something in some of it’s 147 cases, as removing some of them sometimes allowed the function to be optimized again.
    I also tried to replace the switch statement with a ridiculously long if/else if chain, but it also didn’t work, confirming my theory.

    I just separated each instruction into a separate function and then the cpu.execute function just calls the appropriate function based on the current OP code.

    @agmcleod said:

    Other things I try to avoid with html5 games:

    • image scaling. This is really inefficient with the canvas especially
    • heavy use of draw/shape calls instead of using images

    I think rendering won’t be much of a hurdle with this project specifically. The real NES PPU draws pixels at a frequency of aproximatelly 21 MHZ and it has to be emulated that way, otherwise graphics in games that change image data while rendering will be broken.
    So, what most emulators do is write the values the PPU is outputing to a buffer and then render that buffer once a frame, which sounds just perfect for my project.

    But yeah, inneficient canvas calls can really consume your performance.

    • object deletion, be green and re-use, aka object pooling. This goes for any language with garbage collection

    Also not that much relevant for this project, I think. After the emulator boots up, no more objects are created.

    But also very important for general game devery.

    • Avoid static functions & singletons. While you don’t want to release things liberally, you also don’t want to keep things around that you don’t really need.

    Hmmmm… This one is a bit insteresting…

    I have the impression I read somewhere that static functions are faster/more easily optimized than runtime functions.
    Can anyone confirm/deny that?


  • Jammer

    @Josue said:

    Hmmmm… This one is a bit insteresting…

    I have the impression I read somewhere that static functions are faster/more easily optimized than runtime functions.
    Can anyone confirm/deny that?

    It’s definitely a lower priority of things to fix, but it being there consumes memory. We don’t really have statics in javascript, just singletons. Which you can delete manually, but obviously you must be careful if you do. It becomes an issue if your static class holds a texture for example, and you never release the texture. What if it’s an image holding 500kb? Or a large sound file at 5 MBs? Feel free to use singletons, but keep it simple. This line of thought tends to come from C++ where you use constructors & destructors to create & destroy other objects.

    I typically use global singletons like that for configuration only. In libgdx for example, my game class has two static variables for box 2d to world pixel ratios.


Log in to reply