1 2 Previous Next 22 Replies Latest reply: Mar 31, 2010 9:36 PM by 807580 RSS

    Switch performance is awful

    807580
      Poor performance from switch statements has been bugging me ever since I started programming in Java, but I kinda thought I was imagining it or that there were much more complex issues at work because I didn't believe Java could possibly be as stupid as it seemed.

      But in an app I've got 900 inner classes whose purpose is solely to act as function pointers (which Java also lacks) in an array so I can avoid switch statements. It should never have been faster, since instead of simply jumping twice to get to the target (once to the switch case and once to the function, once possibly inlineable, though not completely due to HotSpot's retarded size limit for functions it will compile), now it would have to do null and bounds checks on the array, a null check on the object in the array, goodness knows how many jumps, and more indirect references and null checks just so that the 900 classes could access the members of the outer class where the switch statement was in the first place. But it is faster, significantly.

      Today I finally decided to create a test to see if HotSpot was really as bullet-in-the-head-stupid as I'd always thought and never dared to believe.

      I am absolutely flabbergasted at the results.

      Here is the test program.
      public class Test {
                
           public static volatile int tmpVal;
                
           public Test() {
                
                for (int j = 0; j < 2; j++) { // extra looping to ensure compilation
                     for (int x = 0; x < 32; x++) {
                          long t = System.nanoTime();
                          for (int i = 0; i < 4000000; i++) {
                               switchTest(x);
                          }
                          t = System.nanoTime() - t;
                          System.out.println(x + ": " + ((float)t / 1000000000) + " seconds.");
                     }
                }
                
           }
           
           
           void switchTest(int i) {
                switch (i) {
                case 0x00: doSomething(429); break;
                case 0x01: doSomething(330); break;
                case 0x02: doSomething(010); break;
                case 0x03: doSomething(425); break;
                case 0x04: doSomething(411); break;
                case 0x05: doSomething(565); break;
                case 0x06: doSomething(728); break;
                case 0x07: doSomething(821); break;
                case 0x08: doSomething(642); break;
                case 0x09: doSomething(689); break;
                case 0x0A: doSomething(435); break;
                case 0x0B: doSomething(429); break;
                case 0x0C: doSomething(352); break;
                case 0x0D: doSomething(414); break;
                case 0x0E: doSomething(023); break;
                case 0x0F: doSomething(240); break;
                case 0x10: doSomething(429); break;
                case 0x11: doSomething(3306); break;
                case 0x12: doSomething(0106); break;
                case 0x13: doSomething(4256); break;
                case 0x14: doSomething(41651); break;
                case 0x15: doSomething(5565); break;
                case 0x16: doSomething(72368); break;
                case 0x17: doSomething(821231); break;
                case 0x18: doSomething(6432); break;
                case 0x19: doSomething(689); break;
                case 0x1A: doSomething(4365); break;
                case 0x1B: doSomething(429123); break;
                case 0x1C: doSomething(123352); break;
                case 0x1D: doSomething(4414); break;
                case 0x1E: doSomething(4234); break;
                case 0x1F: doSomething(3403); break;
                }
           }
           
           
           private void doSomething(int i) {
                tmpVal ^= i;
           }
           
           
           public static void main(String[] args) {
                new Test();
           }
      }
      Disassembly of this reveals it to be using the tableswitch opcode correctly. Well of course, that's why it's there!

      Here are the results on the normal HotSpot VM, using interpreted mode (-Xint) only. As expected, it's constant time.
      0: 0.44715992 seconds.
      1: 0.49910033 seconds.
      2: 0.4569958 seconds.
      3: 0.4548293 seconds.
      4: 0.44177598 seconds.
      5: 0.44461322 seconds.
      6: 0.43912956 seconds.
      7: 0.4690669 seconds.
      8: 0.44203663 seconds.
      9: 0.43905944 seconds.
      10: 0.44306076 seconds.
      11: 0.45328274 seconds.
      12: 0.45314556 seconds.
      13: 0.45325872 seconds.
      14: 0.49787447 seconds.
      15: 0.45078048 seconds.
      16: 0.44899085 seconds.
      17: 0.44926688 seconds.
      18: 0.45840967 seconds.
      19: 0.45340985 seconds.
      20: 0.4720737 seconds.
      21: 0.45432535 seconds.
      22: 0.46975163 seconds.
      23: 0.4572827 seconds.
      24: 0.45700586 seconds.
      25: 0.45119533 seconds.
      26: 0.44262666 seconds.
      27: 0.47020724 seconds.
      28: 0.45882758 seconds.
      29: 0.45334783 seconds.
      30: 0.45127246 seconds.
      31: 0.4469272 seconds.

      Now here are the results on the normal HotSpot VM with no funny VM arguments.
      0: 0.040009275 seconds.
      1: 0.035917137 seconds.
      2: 0.03428704 seconds.
      3: 0.036118 seconds.
      4: 0.037904818 seconds.
      5: 0.040123537 seconds.
      6: 0.043588225 seconds.
      7: 0.045694914 seconds.
      8: 0.047388423 seconds.
      9: 0.051255114 seconds.
      10: 0.053002268 seconds.
      11: 0.05610685 seconds.
      12: 0.06281273 seconds.
      13: 0.060808007 seconds.
      14: 0.0606348 seconds.
      15: 0.066564046 seconds.
      16: 0.0687917 seconds.
      17: 0.07066541 seconds.
      18: 0.07193065 seconds.
      19: 0.07630104 seconds.
      20: 0.07770988 seconds.
      21: 0.081588864 seconds.
      22: 0.08352347 seconds.
      23: 0.08545136 seconds.
      24: 0.089154355 seconds.
      25: 0.09111549 seconds.
      26: 0.093199834 seconds.
      27: 0.09709055 seconds.
      28: 0.10012837 seconds.
      29: 0.10189032 seconds.
      30: 0.10632999 seconds.
      31: 0.10803328 seconds.
      That isn't funny at all. It's not a lookup table, it's apparently turned it into a binary tree or something. What the HELL!? On a 32-case switch statement it's not too bad, but in my application there are 200 to 1000 cases, and I don't have a clear way to put the most used cases at the top.

      Now here are the HotSpot Server VM results:
      0: 0.049392313 seconds.
      1: 0.05905108 seconds.
      2: 0.06143099 seconds.
      3: 0.06084405 seconds.
      4: 0.058985706 seconds.
      5: 0.059628807 seconds.
      6: 0.059008617 seconds.
      7: 0.059067845 seconds.
      8: 0.059047166 seconds.
      9: 0.05905136 seconds.
      10: 0.05876697 seconds.
      11: 0.058685113 seconds.
      12: 0.058904693 seconds.
      13: 0.058829825 seconds.
      14: 0.05892788 seconds.
      15: 0.059863195 seconds.
      16: 0.059664287 seconds.
      17: 0.05940755 seconds.
      18: 0.058956657 seconds.
      19: 0.059161432 seconds.
      20: 0.058998 seconds.
      21: 0.05921535 seconds.
      22: 0.059241887 seconds.
      23: 0.059454486 seconds.
      24: 0.057057813 seconds.
      25: 0.05719833 seconds.
      26: 0.05924943 seconds.
      27: 0.059656184 seconds.
      28: 0.05783333 seconds.
      29: 0.057483565 seconds.
      30: 0.05535229 seconds.
      31: 0.059058905 seconds.
      Okay, that's constant time. Perfect, but the Sun idiots, despite releasing both VMs for free, and despite the server one being not much slower at loading applications than the client one, think it's funny to remove lots of fantastic optimizations from it, as well as deliberately and viciously cripple its switch statements and rebadge it as a totally unnecessary "client" version for 99.9% of the world to use, while leaving all the good code in the nearly unused server version. Fantastic.

      I'm so annoyed now. True, I already have the work around -- classes, but am I stuck having 900 classes in my app just to not completely make up for Java's incompetencies? Why is the client HotSpot not using a simple God-damn lookup table like any sane, decent, and far superior C compiler? Why would it even try to do it any other, obviously more complicated, way, when it's already encoded as a table op? :-(
        • 1. Re: Switch performance is awful
          796440
          Okay, so now that you've got that off your chest, do you feel better?

          I fail to see the point of your post. So Java's not sufficient for your rather weird needs. Okay, so be it. It's not intended to be everything to everybody. So you can either use something else, or you can change your code to work around this minor limitation. I don't see how venting your spleen here addresses any technical or business problem though.
          • 2. Re: Switch performance is awful
            807580
            Just having read the first couple paragraphs, my advice is: don't try to code a different language in Java. Code Java in Java. If you want to code that other language, then drop Java and code that other language. And don't complain that Java isn't the language you want it to be; nobody cares.

            And no matter what language you're using, if you're writing methods so long that the Java compiler wouldn't accept them, then the code is unmaintainable.
            • 3. Re: Switch performance is awful
              796440
              just to not completely make up for Java's incompetencies?
              How is not catering to your particular corner case an "incompetency"?
              Why is the client HotSpot not using a simple God-damn lookup table like any sane, decent, and far superior C compiler?
              A more interesting question is why you're using such an insane and far inferior language.

              "Who is the bigger fool? The fool or the fool who follows him?"
              -- Obi Wan Kenobi
              • 4. Re: Switch performance is awful
                807580
                Java is stupid, slow, stupidly lacks function pointers and is incompetent, and HotSpot is retarded. Well, that about wraps it all up, eh. What a fool you must be for using this pointless language.
                • 5. Re: Switch performance is awful
                  jschellSomeoneStoleMyAlias
                  michael483 wrote:
                  Why is the client HotSpot not using a simple God-damn lookup table like any sane, decent, and far superior C compiler?
                  Why are you profiling statements when "any sane, decent, and far superior" developer would instead profile the application?
                  • 6. Re: Switch performance is awful
                    807580
                    You know, I've been kicking around this industry for over 25 years now, and rarely have I heard or read such drivel. Each language is made for certain things, I would not dream of using LISP for hardware driver development, nor would I try to use Assembler for presentation graphics--each of these have their place as does Java. It is an exercise in masochism to continually use a product that is so horribly mismatched to your need. Why do you do it?

                    Perhaps you need to take up Assembler, where the only limitations you have are your willingness to reinvent the wheel, ingenuity, and your chosen hardware architecture.
                    • 7. Re: Switch performance is awful
                      JoachimSauer
                      michael483 wrote:
                      a totally unnecessary "client"
                      The Client VM starts up significantly faster than the Server VM. That's its main reason for existence. Almost all Desktop applications care a lot more about startup time than about raw performance.
                      version for 99.9% of the world to use while leaving all the good code in the nearly unused server version.
                      I don't believe that. A significant percentage of all Java code runs on the server and a.) most of those instances have the server VM configured explicitly and b.) even if they haven't, the JRE chooses the Server VM when it detects a "server class machine".
                      • 8. Re: Switch performance is awful
                        807580
                        Clearly I've touched a nerve. HotSpot's optimizer is all-around crap and you all know it, and the best answer you can give is "don't use Java".

                        Fine, I won't.
                        • 9. Re: Switch performance is awful
                          DarrylBurke
                          Buh-bye
                          • 10. Re: Switch performance is awful
                            796440
                            michael483 wrote:
                            Clearly I've touched a nerve.
                            Not the one you think. I'm sure you're assuming we're a bunch of Java fanboys because we didn't jump on your bitch session band wagon. On the contrary, we see Java for what it is--a decent general purpose language that has is strengths and weaknesses and is suited for some jobs and not others. The temper tantrum tone of your post is annoying, regardless of the topic.
                            HotSpot's optimizer is all-around crap and you all know it,
                            No, I don't know that. What I do know is that I've seen Java code run much faster and more smoothly since the introduction of hotspot, and that it is sufficient for the tasks we've set it on the various projects where I've used it.
                            and the best answer you can give is "don't use Java".
                            Well, duh. If a tool doesn't suit the needs of the job at hand, you don't use it, and if you have no choice, then you do what you can to work around it the best you can. This is what professionals do.

                            What did you expect as a response to your little hissy rant? Did you really think your post was a good way to try to solve whatever technical or business problem you're encountering?
                            Fine, I won't.
                            Wise choice. If nothing else, your blood pressure might come back down.
                            • 11. Re: Switch performance is awful
                              807580
                              michael483 wrote:
                              HotSpot's optimizer is all-around crap
                              I find this statement extraordinary. On the basis of one feature and test you condemn Hotspot and Java in general. I have spent many many years working with signal processing and my experience is that for my signal processing HotSpot creates code that is within 10% of the performance of my C++ equivalents and 20% of my FORTRAN equivalent. In some cases Java outperforms both C++ and FORTRAN. OK, I don't use switch statements with thousands of cases but I do use 'functors' a great deal to do the essence of what you are doing but not to your scale.
                              and you all know it,
                              This is just plain silly and immature. I know that HotSpot is not "all-around crap" so how can we all know it is!
                              and the best answer you can give is "don't use Java".
                              What other answer can we give? You don't feel that Java works for you and nobody is going to spend a lot of time making work just for you so "don't use Java" is the only sensible comment.

                              >
                              Fine, I won't.
                              • 12. Re: Switch performance is awful
                                807580
                                michael483 wrote:
                                Clearly I've touched a nerve. HotSpot's optimizer is all-around crap and you all know it, and the best answer you can give is "don't use Java".

                                Fine, I won't.
                                I am glad the forum has been able to bring you to your senses. When you choose a language please consider that you need to take an objective look at what you need it to do and what the language was designed to do--it cold be that your best language is Modula 2, though I highly doubt it, but I think you get what I'm trying to say. And please remember that no language is well suited for all applications.

                                Your OP was quite troll like and confrontational, if your intent was to get a heated debate going, then perhaps another site altogether would be more appropriate for your needs.
                                • 13. Re: Switch performance is awful
                                  masijade
                                  morgalr wrote:
                                  Your OP was quite troll like and confrontational, if your intent was to get a heated debate going, then perhaps another site altogether would be more appropriate for your needs.
                                  [This one|http://www.geekinterview.com/Interview-Questions/J2EE/Core-Java], maybe?
                                  • 14. Re: Switch performance is awful
                                    807580
                                    I love the way the OP expects me to be hurt that a total stranger who doesn't know what he's doing, isn't even going to try anymore.
                                    1 2 Previous Next