String concatenation tweaks

Peter Levart peter.levart at gmail.com
Mon Jun 8 06:31:16 UTC 2015



On 06/04/2015 11:21 AM, Aleksey Shipilev wrote:
> The patches, notes, benchmarks are moved under the appropriate bug ID:
>    http://cr.openjdk.java.net/~shade/8085796/
>
> The patches now have a complete support in javac (implemented the "s +=
> <string> concat part as well), passes jtreg and other smoke tests [*],
> plus newly developed regression tests. I think this gives us enough
> confidence with going forward.
>
> Thanks,
> -Aleksey
>
> [*] There are few regression tests that start to fail with the change:
> one seems Indify-specific, and another is a javac-specific regression
> test. Current patches work that around, and we will probably have to fix
> these properly before integration.
>
>

Hi Aleksey,

I played with this a bit and it's cool. I created a full-MH strategy 
called EXACT which always calculates upfront exactly what the resulting 
string length will be so that it never reallocates the building buffer. 
It doesn't use StringBuilder at all, but directly fills-in a char[] 
which it then constructs resulting String with without copying the 
array. Here's how it compares with other strategies in your quick JMH 
benchmark:

-Djava.lang.invoke.stringConcat=INNER_SIZED

Benchmark                       (size)  Mode  Cnt Score    Error  Units
ConcatBench.string_string            1  avgt   15   15.433 ±  1.430  ns/op
ConcatBench.string_string           10  avgt   15   19.479 ±  2.062  ns/op
ConcatBench.string_string          100  avgt   15   46.397 ±  2.112  ns/op
ConcatBench.string_string_int        1  avgt   15   73.743 ±  3.888  ns/op
ConcatBench.string_string_int       10  avgt   15   81.760 ±  5.398  ns/op
ConcatBench.string_string_int      100  avgt   15  204.479 ± 11.887  ns/op
ConcatBench.string_string_long       1  avgt   15   78.695 ±  6.292  ns/op
ConcatBench.string_string_long      10  avgt   15   81.722 ±  6.045  ns/op
ConcatBench.string_string_long     100  avgt   15  213.209 ± 33.311  ns/op

-Djava.lang.invoke.stringConcat=INNER

Benchmark                       (size)  Mode  Cnt Score   Error  Units
ConcatBench.string_string            1  avgt   15   13.990 ± 0.795  ns/op
ConcatBench.string_string           10  avgt   15   17.306 ± 1.348  ns/op
ConcatBench.string_string          100  avgt   15   46.452 ± 2.730  ns/op
ConcatBench.string_string_int        1  avgt   15   48.821 ± 3.855  ns/op
ConcatBench.string_string_int       10  avgt   15   70.947 ± 5.537  ns/op
ConcatBench.string_string_int      100  avgt   15  145.151 ± 9.816  ns/op
ConcatBench.string_string_long       1  avgt   15   47.395 ± 3.015  ns/op
ConcatBench.string_string_long      10  avgt   15   71.046 ± 3.842  ns/op
ConcatBench.string_string_long     100  avgt   15  144.379 ± 9.042  ns/op

-Djava.lang.invoke.stringConcat=EXACT

Benchmark                       (size)  Mode  Cnt   Score Error  Units
ConcatBench.string_string            1  avgt   15  26.940 ± 1.166  ns/op
ConcatBench.string_string           10  avgt   15  29.833 ± 2.053  ns/op
ConcatBench.string_string          100  avgt   15  54.967 ± 3.610  ns/op
ConcatBench.string_string_int        1  avgt   15  32.282 ± 1.868  ns/op
ConcatBench.string_string_int       10  avgt   15  34.342 ± 1.677  ns/op
ConcatBench.string_string_int      100  avgt   15  59.280 ± 2.661  ns/op
ConcatBench.string_string_long       1  avgt   15  35.146 ± 1.911  ns/op
ConcatBench.string_string_long      10  avgt   15  35.799 ± 1.862  ns/op
ConcatBench.string_string_long     100  avgt   15  60.160 ± 5.329  ns/op

-Djava.lang.invoke.stringConcat=FULL_MH

Benchmark                       (size)  Mode  Cnt Score   Error  Units
ConcatBench.string_string            1  avgt   15   36.820 ± 1.778  ns/op
ConcatBench.string_string           10  avgt   15   39.301 ± 1.939  ns/op
ConcatBench.string_string          100  avgt   15   96.144 ± 5.151  ns/op
ConcatBench.string_string_int        1  avgt   15   55.876 ± 2.802  ns/op
ConcatBench.string_string_int       10  avgt   15   63.166 ± 4.442  ns/op
ConcatBench.string_string_int      100  avgt   15  110.761 ± 8.146  ns/op
ConcatBench.string_string_long       1  avgt   15   57.672 ± 3.732  ns/op
ConcatBench.string_string_long      10  avgt   15   61.310 ± 4.416  ns/op
ConcatBench.string_string_long     100  avgt   15  109.464 ± 8.979  ns/op


It doesn't beat INNER strategies for small sizes, but does quite well 
with bigger sizes. It is better than Remi's FULL_MH which is also 
"full-mh". I think it is a good candidate for optimization, since it 
seems it has a constant overhead which is not caused by sub-optimal 
algorithm. Perhaps by encoding the algorithm in a spinned inner class?

Here's the implementation:

http://cr.openjdk.java.net/~plevart/misc/StringConcatenation/webrev.01/


...encapsulated in StringConcatFactory.ExactStrategy inner class...

The algorithm is very unusual as it fills the char[] backwards. It uses 
a helper package-private class java.lang.StringConcatHelper with a bunch 
of methods used for measuring the lengths and "prepending" (not 
appending) to the resulting char[]. The helper class is in java.lang 
package to have access to internal methods of j.l.Integer and j.l.Long 
classes which already contain the basic algorithms for lengthing and 
stringing the int/long values. Their algorithms for converting int/long 
to characters fill characters backwards, so this is the main reason why 
the whole strategy uses this approach. byte and short primitives are 
widened into int as well as truncated into int in the caching key. float 
and double primitives are converted to String in the strategy, since 
their basic conversion algorithm is encapsulated in a class that already 
allocates a thread-local working array and it would be hard to do it 
otherwise (i.e. the algorithm can not be split into lengthing and 
stringing part - it is fused).

Regards, Peter

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20150608/5df43f39/attachment-0001.html>


More information about the compiler-dev mailing list