On Wed, 6 May 2026 15:56:21 GMT, Daniel Gredler <[email protected]> wrote:

>> While profiling some code which uses `LineBreakMeasurer`, I noticed that a 
>> non-trivial amount of time was being spent in `AttributedString`, because 
>> iterating through an `AttributedString` and getting a specific attribute for 
>> each character ends up calling `Vector.indexOf` inside of 
>> `AttributedString.getAttribute`. This boils down to the data structure 
>> choice of storing run attribute data in two arrays of `Vector`s, rather than 
>> in a single array of `Map`s. Based on testing, it looks like a single array 
>> of `Map`s would be simpler, faster, and require slightly less memory in some 
>> cases.
>> 
>> A JMH benchmark is included in this PR. With the updated code I'm seeing a 
>> 35% to 40% reduction in runtime for the iteration benchmark tests with one 
>> or more attributes. I checked memory usage by enabling GC profiling and 
>> looking at the three creation benchmark tests; it seems like there is no 
>> difference when the string has no attributes, a 20% reduction in memory use 
>> when the string has a single attribute, and a very small 1% reduction in 
>> memory use when we set four attributes. Full JMH results below (I focused on 
>> the `us/op` and `B/op` results specifically).
>> 
>> Tests run:
>> - make test TEST="jtreg:test/jdk/java/text"
>> - make test TEST="jtreg:test/jdk/java/awt/font"
>> - make test TEST="jtreg:test/jdk/java/awt/Graphics2D/DrawString"
>> - make test TEST="micro:java.text.AttributedStringBench" 
>> MICRO="OPTIONS=-prof gc"
>> 
>> I've assumed that the existing tests provide adequate regression test 
>> coverage, but there may be other Oracle-internal tests that should also be 
>> run to verify correctness.
>> 
>> JMH results **before** PR:
>> 
>> 
>> Benchmark                                                             Mode  
>> Cnt      Score     Error   Units
>> AttributedStringBench.creationWithFourAttributes                      avgt   
>> 15      0.182 ±   0.004   us/op
>> AttributedStringBench.creationWithFourAttributes:gc.alloc.rate        avgt   
>> 15   3989.259 ±  85.345  MB/sec
>> AttributedStringBench.creationWithFourAttributes:gc.alloc.rate.norm   avgt   
>> 15    760.001 ±   0.001    B/op
>> AttributedStringBench.creationWithFourAttributes:gc.count             avgt   
>> 15    151.000            counts
>> AttributedStringBench.creationWithFourAttributes:gc.time              avgt   
>> 15    116.000                ms
>> AttributedStringBench.creationWithNoAttributes                        avgt   
>> 15      0.003 ±   0.001   us/op
>> AttributedStringBench.creationWithNoAttributes:gc.alloc.rate          avgt   
>> ...
>
> Daniel Gredler has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   Update three comments which mention vectors

src/java.base/share/classes/java/text/AttributedString.java line 354:

> 352:      * empty Map.
> 353:      */
> 354:     public void addAttributes(Map<? extends Attribute, ?> attributes,

Since we moved from `Vector` to `Map`, I think this is now susceptible to 
`ConcurrentModificationException` when called at the same time that the 
`AttributedCharacterIterator` is iterated. I don't think it matters though 
since this method isn't specified to be thread safe and 
`AttributedCharacterIterator` does not define a concurrent modification policy, 
so I think it's OK.

test/micro/org/openjdk/bench/java/text/AttributedStringBench.java line 29:

> 27: import java.text.AttributedCharacterIterator;
> 28: import java.text.AttributedString;
> 29: import java.util.Map;

Looks unused.

test/micro/org/openjdk/bench/java/text/AttributedStringBench.java line 72:

> 70: 
> 71:     @Benchmark
> 72:     public void iterationWithNoAttributes(Blackhole blackhole) {

All the `iteration` tests are measuring missing key lookups, which is good to 
measure but is also worst-case. Might be worth adding present key lookups for 
transparency, so both cases are measured.

test/micro/org/openjdk/bench/java/text/AttributedStringBench.java line 90:

> 88: 
> 89:     @Benchmark
> 90:     public void iterationWithFourAttributes(Blackhole blackhole) {

This might be better renamed, since `string3` is technically three attribute 
_keys_.

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/30402#discussion_r3210832561
PR Review Comment: https://git.openjdk.org/jdk/pull/30402#discussion_r3210716797
PR Review Comment: https://git.openjdk.org/jdk/pull/30402#discussion_r3210712996
PR Review Comment: https://git.openjdk.org/jdk/pull/30402#discussion_r3210645781

Reply via email to