StringBuilder buffer allocation support in compiler

Vitaly Davidovich vitalyd at gmail.com
Fri Jun 6 16:20:49 UTC 2014


I don't see how it's in sync; you're testing appending in a loop (with
non-constant trip count, at least unless JIT completely devirtualizes and
inlines everything).  I thought the topic of this thread was difference in
performance between effectively:

public static String sayHello(String name, int age) {
        //return "Hello " + name + ", this is your " + age + "th birthday";
StringBuilder sb = new StringBuilder(<proper_size>);

        return sb.append("Hello ").append(name).append(...) ... .toString();

    }
vs
public static String sayHello(String name, int age) {
        StringBuilder sb = new StringBuilder(<proper_size>);
        return sb.append("Hello ").append(name).append(...) ... .toString();
    }

There's no loop here and each invocation of this is a separate
StringBuilder instance, so even if you were to call sayHello() from a loop,
the semantics are different from your benchmark.




On Fri, Jun 6, 2014 at 12:07 PM, Laszlo Hornyak <laszlo.hornyak at gmail.com>
wrote:

> I think that is in sync with the subject of this email thread.
>
>
> On Thu, Jun 5, 2014 at 11:01 PM, Vitaly Davidovich <vitalyd at gmail.com>
> wrote:
>
>> I think your benchmark is testing something else though, which is cost of
>> resizing during appends.
>>
>> To test the issue at hand, try writing two methods, one which does string
>> appends manually to a pre allocated SB of the right size (which is what you
>> want javac to do) and one that does the string concat.
>>
>> Sent from my phone
>> On Jun 5, 2014 4:39 PM, "Laszlo Hornyak" <laszlo.hornyak at gmail.com>
>> wrote:
>>
>>> Hi Vitaly,
>>>
>>> I tested with server VM and the test code has some warmup so that the
>>> JIT should have enough time to kick in, but I will check stringopts if it
>>> should do some relevant optimization.
>>>
>>>
>>>
>>> On Thu, Jun 5, 2014 at 9:43 PM, Vitaly Davidovich <vitalyd at gmail.com>
>>> wrote:
>>>
>>>> Hi Laszlo,
>>>>
>>>> I believe server jit compiler has an optimization pass that will
>>>> attempt at fusing this type of pattern into one string allocation -- see
>>>> src/share/vm/opto/stringopts.[h|c]pp in the sources.  Have you tried
>>>> benchmarking this after jit compiler gets a crack at it?
>>>>
>>>>
>>>> On Thu, Jun 5, 2014 at 3:27 PM, Laszlo Hornyak <
>>>> laszlo.hornyak at gmail.com> wrote:
>>>>
>>>>> Hi,
>>>>>
>>>>> Given this sample code
>>>>>
>>>>>     public static String sayHello(String name, int age) {
>>>>>         return "Hello " + name + ", this is your " + age + "th
>>>>> birthday";
>>>>>     }
>>>>>
>>>>> The compiler will generate this bytecode:
>>>>>        0: new           #11                 // class
>>>>> java/lang/StringBuilder
>>>>>        3: dup
>>>>>        4: invokespecial #12                 // Method
>>>>> java/lang/StringBuilder."<init>":()V
>>>>>        7: ldc           #19                 // String Hello
>>>>>        9: invokevirtual #15                 // Method
>>>>> java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
>>>>>       12: aload_0
>>>>>       13: invokevirtual #15                 // Method
>>>>> java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
>>>>>       16: ldc           #20                 // String , this is your
>>>>>       18: invokevirtual #15                 // Method
>>>>> java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
>>>>>       21: iload_1
>>>>>       22: invokevirtual #13                 // Method
>>>>> java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
>>>>>       25: ldc           #21                 // String th birthday
>>>>>       27: invokevirtual #15                 // Method
>>>>> java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
>>>>>       30: invokevirtual #17                 // Method
>>>>> java/lang/StringBuilder.toString:()Ljava/lang/String;
>>>>>       33: areturn
>>>>>
>>>>> The most interesting line is:
>>>>>        4: invokespecial #12                 // Method
>>>>> java/lang/StringBuilder."<init>":()V
>>>>>
>>>>>
>>>>> Since all the string literals are given for the compiler, it could
>>>>> give an estimation on the required buffer size to the StringBuilder
>>>>> constructor. In this example the string literals already take 32
>>>>> characters, plus a string representation of an integer takes up to 12
>>>>> characters. The String size is 0 to Integer.MAX_VALUE, but 16 might be a
>>>>> good default. In this case a constructor call could be generated to
>>>>> allocate a buffer with 50 characters and some (possibly all) buffer
>>>>> re-allocation could be saved in the subsequent append calls.
>>>>> The performance gain seems to be significant since the subsequent
>>>>> buffer allocations can take up to 30-40 percent of the execution time.
>>>>> Is there a specific reason for the java compiler not to support
>>>>> pre-allocation of StringBuilder buffer based on string literals and
>>>>> parameters?
>>>>>
>>>>> Thank you,
>>>>> Laszlo
>>>>>
>>>>>
>>>>> --
>>>>>
>>>>> EOF
>>>>>
>>>>
>>>>
>>>
>>>
>>> --
>>>
>>> EOF
>>>
>>
>
>
> --
>
> EOF
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20140606/4b0097bf/attachment-0001.html>


More information about the compiler-dev mailing list