Array Allocation Scalability





  • Wasn't this (or something very similar) an article on the main page a little while back?



  • Okay, I had to join just because of this.

    Have you actually read the comment at the top of the class?

    /**

    • This is a generated class used internally during the writing of bytecode within the CallSiteWriter logic.
    • This is not a class exposed to users, as is the case with almost all classes in the org.codehaus.groovy packages.

    • The purpose is the reduction of the size of the bytecode.

      [SNIP]


    • The number of needed instructions is thus reduced from 15 to 4. For every entry we save 3 bytecode instructions.
    • This allows better readable bytecode and it allows the JIT to see less bytecode to optimize, helping under the
    • inlining threshold here or there.

      *
    • So even though the class is ugly, there are good reason to have this in Groovy, even if the class makes
    • absolutely no sense in normal Java. But it is not used in normal Java, but from the bytecode.

      */


  • [quote user="Renan "C#" Sousa"]For when you really need to make sure everything will fit into it:

    http://svn.codehaus.org/groovy/trunk/groovy/groovy-core/src/main/org/codehaus/groovy/runtime/ArrayUtil.java[/quote]

    Noticed the comment that it's a class used internally by the compiler (groovy is a programming language compiling to JVM)? It probably has some syntax that is either easiest or most efficient to translate this way. The comment seems to indicate the byte-code to call the function is shorter than the byte-code to assign the elements.


  • Discourse touched me in a no-no place

    Is this premature optimisation or something that's actually been tested and found to have significant impact under some/all circumstances?


    I've insufficient experience in the languages concerned to tell.



  • @PJH said:

    Is this premature optimisation or something that's actually been tested and found to have significant impact under some/all circumstances?.

    Well, the comment actually explains how the bytecode would have to look if the array was constructed and filled by item on the spot and how it looks using the helper function. It is a size optimization though; what is the effect on speed is not clear.



  • @Bulb said:

    @PJH said:
    Is this premature optimisation or something that's actually been tested and found to have significant impact under some/all circumstances?.

    Well, the comment actually explains how the bytecode would have to look if the array was constructed and filled by item on the spot and how it looks using the helper function. It is a size optimization though; what is the effect on speed is not clear.

    His question wasn't "Is this optimisation?', it was "Is this premature optimisation?".  Whether it's a size or speed optimisation, it's still worthwhile to ask if this has been benchmarked and if it makes a measureable difference in a typical groovy program.

  • Discourse touched me in a no-no place

    @Jaime said:

    Whether it's a size or speed optimisation,
    Unusually, the comments to the code indicate that it's both. 3.75-fold increase in speed and a 3 byte saving on each array created. As you alluded to, I'm wondering if

    a) Such arrays are created so frequently (compared to other code.) that the speedup is noticeable and

    b) The arrays contain so few items that the 3 bytes constitute a significant amount of memory used.



    Which, if so, leads me to subsequently wonder why these are problems, and why arrays are being used to begin with.



    Is it not on a par with, say, fiddling around trying to make the for-loops in a bubble-sort as efficient as possible for occasional large sets of data, instead of just changing the sorting algorithm being used?



  • @ggy said:

    Okay, I had to join just because of this.
    Have you actually read the comment at the top of the class?
    /**
    * This is a generated class used internally during the writing of bytecode within the CallSiteWriter logic.
    * This is not a class exposed to users, as is the case with almost all classes in the org.codehaus.groovy packages.
    *
    * The purpose is the reduction of the size of the bytecode.
    [SNIP]

    * The number of needed instructions is thus reduced from 15 to 4. For every entry we save 3 bytecode instructions.
    * This allows better readable bytecode and it allows the JIT to see less bytecode to optimize, helping under the
    * inlining threshold here or there.
    *
    * So even though the class is ugly, there are good reason to have this in Groovy, even if the class makes
    * absolutely no sense in normal Java. But it is not used in normal Java, but from the bytecode.

    */

     

    Good catch.  I read comments about as often as I write them.



  • But what if you need an array of length greater than 250?


  • Discourse touched me in a no-no place

    @toth said:

    But what if you need an array of length greater than 250?
    Well for 250, could you not create two arrays of 125 objects. Then create an array using those two arrays as objects?



  • @PJH said:

    @toth said:
    But what if you need an array of length greater than 250?
    Well for 250, could you not create two arrays of 125 objects. Then create an array using those two arrays as objects?

    A 250-array != an array of(a 125-array, a 125 array)

    Come on! I need teh codez



  • As the comments explain, the reduction in bytecode size can make the VM use inlining where it wouldn't have before. That seems to be the real justification.



  • @PJH said:

    @toth said:
    But what if you need an array of length greater than 250?
    Well for 250, could you not create two arrays of 125 objects. Then create an array using those two arrays as objects?

    It's not like I actually know anything about the Groove language or the way it works, but I guess they have a normal general way to do this and an optimized way for "specific" cases (in this case almost every normal usage case)


  • Discourse touched me in a no-no place

    @moog said:

    the reduction in bytecode size can make the VM use inlining where it wouldn't have before.

    * This allows better readable bytecode and it allows the JIT to see less bytecode to optimize, helping under the
    * inlining threshold here or there.

    That appears to be scant justification to me.



  • If you care about three instructions and as many bytes, why are you using Java?



  • @hoodaticus said:

    If you care about three instructions and as many bytes, why are you using Java?

    Groovy uses the same VM, but isn't Java.


  • Discourse touched me in a no-no place

    @dtech said:

    @PJH said:
    @toth said:
    But what if you need an array of length greater than 250?
    Well for 250, could you not create two arrays of 125 objects. Then create an array using those two arrays as objects?
    It's not like I actually know anything about the Groove language or the way it works, but I guess they have a normal general way to do this and an optimized way for "specific" cases (in this case almost every normal usage case)
    .. I wasn't entirely serious about that suggestion...



  • @powerlord said:

    @hoodaticus said:

    If you care about three instructions and as many bytes, why are you using Java?

    Groovy uses the same VM, but isn't Java.

    Groovy is like the retarded bastard child of Perl and Java, with the hideous syntax of the former and the abject slowness of the latter, hence I can see why they need to write code that saves instructions. That said, optimising interpreted/non-native languages is the very definition of "waste of time".



  • @The_Assimilator said:

    http://shootout.alioth.debian.org/u64/which-programming-languages-are-fastest.phpGroovy is like the retarded bastard child of Perl and Java, with the hideous syntax of the former and the abject slowness of the latter,
    [Citation needed]@The_Assimilator said:
    hence I can see why they need to write code that saves instructions. That said, optimising interpreted/non-native languages is the very definition of "waste of time".
    But... that's how they get to be fast.  Or are you talking about client code?  Yes, client code should avoid clever optimizations, but this is not client code (per se).  This is for the implementation of a language.  Did you even read the comments in that class?



  • @Xyro said:

    @The_Assimilator said:

    Groovy is like the retarded bastard child of Perl and Java, with the hideous syntax of the former and the abject slowness of the latter,
    [Citation needed]

    That link is obviously totally represeantative because everyone develops their Java and C# apps for Linux, right? OH WAIT. And comparing Mono, an unofficial implementation of C#, to the official JRE on Linux? Really?

    Anyway, my comment was more directed at how Java's GUI is still an abomination. Sun's desire for platform agnosticism was admirable, but ultimately foolish. Instead of wasting thousands of coding hours inventing their own version of the XP UI that nobody except XP users will be familiar with, why didn't they spend the time improving the core libraries and adding features? Fuck, Java has been around for 14 years, C# has only been around for 8, and already Java is filching "new" language features from C# (annotations anyone).

    @Xyro said:

    @The_Assimilator said:
    hence I can see why they need to write code that saves instructions. That said, optimising interpreted/non-native languages is the very definition of "waste of time".
    But... that's how they get to be fast.  Or are you talking about client code?  Yes, client code should avoid clever optimizations, but this is not client code (per se).  This is for the implementation of a language.  Did you even read the comments in that class?

    The best way to optimise software performance is to run it on faster hardware.
    If you're using an interpreted language, the next best way is to compile your bytecode to machine code.
    Optimising by writing "clever" code should be the absolute last straw, regardless of what language you're dealing with.

    Seeing this kind of "optimisation" in what's allegedly a modern language distresses me, because I thought (hoped) we'd left such arcane bullshit behind when we moved away from native compilers that had a bajillion different command-line switches to do a bajillion different possible optimisations like unrolling loops. And then maybe the optimisations didn't work for your particular case, or there was a bug in the compiler that caused an off-by-one error when that particular optimisation flag was used, or...



  • @The_Assimilator said:

    The best way to optimise software performance is to run it on faster hardware.


    If you use algorithm with too high complexity, usually no amount of hardware can help you. Nor can it help if your goal is to run on particular hardware.
    @The_Assimilator said:

    ...

    Optimising by writing "clever" code should be the absolute last straw, regardless of what language you're dealing with.


    I agree—in an application. But I can only agree because I know the compiler will produce clever code and that the libraries are written so that compiler will know how to produce clever code, so I don't have to. This is a compiler. It has to generate "clever" code.
    @The_Assimilator said:

    Seeing this kind of "optimisation" in what's allegedly a modern language distresses me, because I thought (hoped) we'd left such arcane bullshit behind when we moved away from native compilers that had a bajillion different command-line switches to do a bajillion different possible optimisations like unrolling loops. And then maybe the optimisations didn't work for your particular case, or there was a bug in the compiler that caused an off-by-one error when that particular optimisation flag was used, or...

    Have you ever read anything about how the Java compiler works and how the Java Virtual Machine works? There are all the optimizations like in a C compiler and than a couple even more scary ones in the "just-in-time" that modifies the code at runtime depending on the number of times it ran and the actual parameters it had. Not mentioning all the extremely clever code in the garbage collector that saves time by copying stuff around. So you don't need to know about them now, but they are still there and are even more arcane.



  • @The_Assimilator said:

    @Xyro said:
    Did you even read the comments in that class?
    The best way to optimise software performance is to run it on faster hardware.
    If you're using an interpreted language, the next best way is to compile your bytecode to machine code.
    Optimising by writing "clever" code should be the absolute last straw, regardless of what language you're dealing with.
    @TFC said:
    The purpose is the reduction of the size of the bytecode.
    @TFC said:
    This allows better readable bytecode
    @TFC said:
    the class makes absolutely no sense in normal Java. But it is not used in normal Java, but from the bytecode.
    Are you being obtuse on purpose?

    Groovy is a language that uses the JVM.  As such, it uses certain bytecode constructs directly.  Rather than writing these constructs by hand, which would be stupid, it uses an ugly Java class.  I don't know about you, but if I was using the language, I'd want it to use properly constructed idioms internally and not have to throw better hardware at it just because some coder believed that reducing the bytecode was impure and barbaric.

    And just because you shouldn't use clever code in higher level languages doesn't mean you can feel free to ignore how the system actually behaves. 


Log in to reply