StringBuilder buffer allocation support in compiler

Vitaly Davidovich vitalyd at gmail.com
Fri Jun 6 16:21:56 UTC 2014


Sorry, hit Send too early.  The first version of sayHello in my previous
email should be:

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

    }



On Fri, Jun 6, 2014 at 12:20 PM, Vitaly Davidovich <vitalyd at gmail.com>
wrote:

> 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/4eebf6f5/attachment.html>


More information about the compiler-dev mailing list