Re: RFR: 8322149: ConcurrentHashMap copy constructor should not transfer from old table on presizing [v2]

2024-01-17 Thread Joshua Cao
On Fri, 12 Jan 2024 08:51:16 GMT, Volker Simonis  wrote:

>>> tryPresize(int size) is doing and if its size argument is supposed to 
>>> contain the additional number of elements which will be inserted into the 
>>> hash map or if it is a hint for the new total size of the hash map
>> 
>> Argument `size` for `tryPresize()` is a hint for the **new total size** of 
>> the hash map. If the size is too small compared to the current size of the 
>> map, there will be no resizing.
>
> Thanks. In that case, calling `tryPresize()` with `size < this.size()` 
> doesn't make sense and we should call it with `this.size() + m.size()`.

Thanks. Just committed this change. Also added a new benchmark for `putAll()` 
and the results in the top post.

-

PR Review Comment: https://git.openjdk.org/jdk/pull/17116#discussion_r1456490539


Re: RFR: 8322149: ConcurrentHashMap copy constructor should not transfer from old table on presizing [v3]

2024-01-17 Thread Joshua Cao
> ConcurrentHashMap's copy constructor calls `putAll()` -> `tryPresize()` -> 
> `transfer()`. When coming from the copy constructor, the Map is empty, so 
> there is nothing to transfer. But `transfer()` will still copy all the empty 
> nodes from the old table to the new table.
> 
> This patch avoids this work by only calling `tryPresize()` if the table is 
> already initialized. If `table` is null, the initialization is deferred to 
> `putVal()`, which calls `initTable()`.
> 
> ---
> 
> ### JMH results for testCopyConstructor
> 
> before patch:
> 
> 
> Result "org.openjdk.bench.java.util.concurrent.Maps.testCopyConstructor":
>   937395.686 ±(99.9%) 99074.324 ns/op [Average]
>   (min, avg, max) = (825732.550, 937395.686, 1072024.041), stdev = 92674.184
>   CI (99.9%): [838321.362, 1036470.010] (assumes normal distribution)
> 
> 
> after patch:
> 
> 
> Result "org.openjdk.bench.java.util.concurrent.Maps.testCopyConstructor":
>   620871.469 ±(99.9%) 59195.406 ns/op [Average]
>   (min, avg, max) = (545304.633, 620871.469, 689013.573), stdev = 55371.419
>   CI (99.9%): [561676.063, 680066.875] (assumes normal distribution)
> 
> 
> Average time is decreased by about 33%.
> 
> ### JMH results for testPutAll (size = 1)
> 
> before patch:
> 
> 
> Result 
> "org.openjdk.bench.java.util.concurrent.Maps.testConcurrentHashMapPutAll":
>   4315291.542 ±(99.9%) 336034.190 ns/op [Average]
>   (min, avg, max) = (3974688.194, 4315291.542, 4871772.209), stdev = 
> 314326.589
>   CI (99.9%): [3979257.352, 4651325.731] (assumes normal distribution)
> 
> 
> after patch:
> 
> 
> Result 
> "org.openjdk.bench.java.util.concurrent.Maps.testConcurrentHashMapPutAll":
>   3006955.723 ±(99.9%) 271757.969 ns/op [Average]
>   (min, avg, max) = (2801264.198, 3006955.723, 3553084.135), stdev = 
> 254202.573
>   CI (99.9%): [2735197.754, 3278713.692] (assumes normal distribution)
> 
> 
> Average time is decreased about 30%.

Joshua Cao has updated the pull request incrementally with one additional 
commit since the last revision:

  putAll presize based on sum on both map sizes

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/17116/files
  - new: https://git.openjdk.org/jdk/pull/17116/files/3632649c..3efa593d

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk&pr=17116&range=02
 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=17116&range=01-02

  Stats: 11 lines in 2 files changed: 10 ins; 0 del; 1 mod
  Patch: https://git.openjdk.org/jdk/pull/17116.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/17116/head:pull/17116

PR: https://git.openjdk.org/jdk/pull/17116


Re: RFR: 8322149: ConcurrentHashMap copy constructor should not transfer from old table on presizing [v2]

2024-01-12 Thread Volker Simonis
On Thu, 11 Jan 2024 19:21:00 GMT, Joshua Cao  wrote:

>>> We don't need to compute max() here. 
>>> [tryPresize()](https://github.com/openjdk/jdk/blob/8a4dc79e1a40e7115e2971af81623b6b0368f41c/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java#L2397)
>>>  does that already.
>> 
>> The code you reference is only executed if `table == null` but in this case 
>> we know it is not `null` because we only call `tryPresize()` if `table != 
>> null`.
>> 
>> In general, it's hard fro me to understand what `tryPresize(int size)` is 
>> doing and if its `size` argument is supposed to contain the additional 
>> number of elements which will be inserted into the hash map or if it is a 
>> hint for the new total size of the hash map. Can you explain?
>
>> tryPresize(int size) is doing and if its size argument is supposed to 
>> contain the additional number of elements which will be inserted into the 
>> hash map or if it is a hint for the new total size of the hash map
> 
> Argument `size` for `tryPresize()` is a hint for the **new total size** of 
> the hash map. If the size is too small compared to the current size of the 
> map, there will be no resizing.

Thanks. In that case, calling `tryPresize()` with `size < this.size()` doesn't 
make sense and we should call it with `this.size() + m.size()`.

-

PR Review Comment: https://git.openjdk.org/jdk/pull/17116#discussion_r1450063503


Re: RFR: 8322149: ConcurrentHashMap copy constructor should not transfer from old table on presizing [v2]

2024-01-11 Thread Joshua Cao
On Thu, 11 Jan 2024 09:40:07 GMT, Volker Simonis  wrote:

> tryPresize(int size) is doing and if its size argument is supposed to contain 
> the additional number of elements which will be inserted into the hash map or 
> if it is a hint for the new total size of the hash map

Argument `size` for `tryPresize()` is a hint for the **new total size** of the 
hash map. If the size is too small compared to the current size of the map, 
there will be no resizing.

-

PR Review Comment: https://git.openjdk.org/jdk/pull/17116#discussion_r1449296202


Re: RFR: 8322149: ConcurrentHashMap copy constructor should not transfer from old table on presizing [v2]

2024-01-11 Thread Volker Simonis
On Mon, 8 Jan 2024 20:27:59 GMT, Joshua Cao  wrote:

> We don't need to compute max() here. 
> [tryPresize()](https://github.com/openjdk/jdk/blob/8a4dc79e1a40e7115e2971af81623b6b0368f41c/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java#L2397)
>  does that already.

The code you reference is only executed if `table == null` but in this case we 
know it is not `null` because we only call `tryPresize()` if `table != null`.

In general, it's hard fro me to understand what `tryPresize(int size)` is doing 
and if its `size` argument is supposed to contain the additional number of 
elements which will be inserted into the hash map or if it is a hint for the 
new total size of the hash map. Can you explain?

-

PR Review Comment: https://git.openjdk.org/jdk/pull/17116#discussion_r1448566797


Re: RFR: 8322149: ConcurrentHashMap copy constructor should not transfer from old table on presizing [v2]

2024-01-08 Thread Joshua Cao
On Mon, 8 Jan 2024 15:59:17 GMT, Volker Simonis  wrote:

> Shouldn't this be something like tryPresize(this.size() + m.size()) to 
> accommodate for the worst case where there are no common keys in this map and 
> m?

Its a good callout. Not sure if it is a miss, or intentionally conservative.

> But then shouldn't we use at least max(this.size(), m.size)?

We don't need to compute `max()` here. 
[tryPresize()](https://github.com/openjdk/jdk/blob/8a4dc79e1a40e7115e2971af81623b6b0368f41c/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java#L2397)
 does that already. Although this does bring to my attention that maybe there 
is the same symptom of "extra unnecessary work" when merging in a smaller map. 
If the new size is smaller, we should just be able to exit out of 
`tryPresize()` without having to call the expensive `transfer()`. We would need 
to run a separate experiment for it.

-

PR Review Comment: https://git.openjdk.org/jdk/pull/17116#discussion_r1445292956


Re: RFR: 8322149: ConcurrentHashMap copy constructor should not transfer from old table on presizing [v2]

2024-01-08 Thread Volker Simonis
On Wed, 3 Jan 2024 21:29:57 GMT, Joshua Cao  wrote:

>> ConcurrentHashMap's copy constructor calls `putAll()` -> `tryPresize()` -> 
>> `transfer()`. When coming from the copy constructor, the Map is empty, so 
>> there is nothing to transfer. But `transfer()` will still copy all the empty 
>> nodes from the old table to the new table.
>> 
>> This patch avoids this work by only calling `tryPresize()` if the table is 
>> already initialized. If `table` is null, the initialization is deferred to 
>> `putVal()`, which calls `initTable()`.
>> 
>> ---
>> 
>> ### JMH results for testCopyConstructor
>> 
>> before patch:
>> 
>> 
>> Result "org.openjdk.bench.java.util.concurrent.Maps.testCopyConstructor":
>>   937395.686 ±(99.9%) 99074.324 ns/op [Average]
>>   (min, avg, max) = (825732.550, 937395.686, 1072024.041), stdev = 92674.184
>>   CI (99.9%): [838321.362, 1036470.010] (assumes normal distribution)
>> 
>> 
>> after patch:
>> 
>> 
>> Result "org.openjdk.bench.java.util.concurrent.Maps.testCopyConstructor":
>>   620871.469 ±(99.9%) 59195.406 ns/op [Average]
>>   (min, avg, max) = (545304.633, 620871.469, 689013.573), stdev = 55371.419
>>   CI (99.9%): [561676.063, 680066.875] (assumes normal distribution)
>> 
>> 
>> Average time is decreased by about 33%.
>
> Joshua Cao has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   Cleanup benchmark

src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java line 
1088:

> 1086: public void putAll(Map m) {
> 1087: if (table != null) {
> 1088: tryPresize(m.size());

Shouldn't this be something like `tryPresize(this.size() + m.size())` to 
accommodate for the worst case where there are no common keys in `this` map and 
`m`?

Or do we intentionally try to be  conservative with memory usage? But then 
shouldn't we use at least `max(this.size(), m.size)`?

-

PR Review Comment: https://git.openjdk.org/jdk/pull/17116#discussion_r1444898430


Re: RFR: 8322149: ConcurrentHashMap copy constructor should not transfer from old table on presizing [v2]

2024-01-04 Thread Aleksey Shipilev
On Wed, 3 Jan 2024 21:29:57 GMT, Joshua Cao  wrote:

>> ConcurrentHashMap's copy constructor calls `putAll()` -> `tryPresize()` -> 
>> `transfer()`. When coming from the copy constructor, the Map is empty, so 
>> there is nothing to transfer. But `transfer()` will still copy all the empty 
>> nodes from the old table to the new table.
>> 
>> This patch avoids this work by only calling `tryPresize()` if the table is 
>> already initialized. If `table` is null, the initialization is deferred to 
>> `putVal()`, which calls `initTable()`.
>> 
>> ---
>> 
>> ### JMH results for testCopyConstructor
>> 
>> before patch:
>> 
>> 
>> Result "org.openjdk.bench.java.util.concurrent.Maps.testCopyConstructor":
>>   937395.686 ±(99.9%) 99074.324 ns/op [Average]
>>   (min, avg, max) = (825732.550, 937395.686, 1072024.041), stdev = 92674.184
>>   CI (99.9%): [838321.362, 1036470.010] (assumes normal distribution)
>> 
>> 
>> after patch:
>> 
>> 
>> Result "org.openjdk.bench.java.util.concurrent.Maps.testCopyConstructor":
>>   620871.469 ±(99.9%) 59195.406 ns/op [Average]
>>   (min, avg, max) = (545304.633, 620871.469, 689013.573), stdev = 55371.419
>>   CI (99.9%): [561676.063, 680066.875] (assumes normal distribution)
>> 
>> 
>> Average time is decreased by about 33%.
>
> Joshua Cao has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   Cleanup benchmark

I am good this this version. I would like a second Reviewer to ack this too.

-

Marked as reviewed by shade (Reviewer).

PR Review: https://git.openjdk.org/jdk/pull/17116#pullrequestreview-1803734314


Re: RFR: 8322149: ConcurrentHashMap copy constructor should not transfer from old table on presizing [v2]

2024-01-03 Thread Joshua Cao
On Wed, 3 Jan 2024 19:52:34 GMT, Joshua Cao  wrote:

>> test/micro/org/openjdk/bench/java/util/concurrent/Maps.java line 122:
>> 
>>> 120: public void testCopyConstructor() {
>>> 121: ConcurrentHashMap clone = new 
>>> ConcurrentHashMap<>(staticMap);
>>> 122: dummy = clone;
>> 
>> Is this for preventing dead-code elimination? If so, just do:
>> 
>> 
>>   return new ConcurrentHashMap<>(staticMap);
>
> I tried this. I don't think its working. When I just return the map, we lose 
> the improvements in performance, and the benchmark overall just runs much 
> faster. I'm guessing the map got DCE'ed

Scratch that. Was my mistake. Was running the wrong test.

I'm renaming `testCopyConstructor` to `testConcurrentHashMapCopyConstructor`, 
since the file name + test don't actually explicitly say its for 
ConcurrentHashMap.

-

PR Review Comment: https://git.openjdk.org/jdk/pull/17116#discussion_r1440968465


Re: RFR: 8322149: ConcurrentHashMap copy constructor should not transfer from old table on presizing [v2]

2024-01-03 Thread Joshua Cao
> ConcurrentHashMap's copy constructor calls `putAll()` -> `tryPresize()` -> 
> `transfer()`. When coming from the copy constructor, the Map is empty, so 
> there is nothing to transfer. But `transfer()` will still copy all the empty 
> nodes from the old table to the new table.
> 
> This patch avoids this work by only calling `tryPresize()` if the table is 
> already initialized. If `table` is null, the initialization is deferred to 
> `putVal()`, which calls `initTable()`.
> 
> ---
> 
> ### JMH results for testCopyConstructor
> 
> before patch:
> 
> 
> Result "org.openjdk.bench.java.util.concurrent.Maps.testCopyConstructor":
>   937395.686 ±(99.9%) 99074.324 ns/op [Average]
>   (min, avg, max) = (825732.550, 937395.686, 1072024.041), stdev = 92674.184
>   CI (99.9%): [838321.362, 1036470.010] (assumes normal distribution)
> 
> 
> after patch:
> 
> 
> Result "org.openjdk.bench.java.util.concurrent.Maps.testCopyConstructor":
>   620871.469 ±(99.9%) 59195.406 ns/op [Average]
>   (min, avg, max) = (545304.633, 620871.469, 689013.573), stdev = 55371.419
>   CI (99.9%): [561676.063, 680066.875] (assumes normal distribution)
> 
> 
> Average time is decreased by about 33%.

Joshua Cao has updated the pull request incrementally with one additional 
commit since the last revision:

  Cleanup benchmark

-

Changes:
  - all: https://git.openjdk.org/jdk/pull/17116/files
  - new: https://git.openjdk.org/jdk/pull/17116/files/93b9072d..3632649c

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk&pr=17116&range=01
 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=17116&range=00-01

  Stats: 12 lines in 2 files changed: 2 ins; 7 del; 3 mod
  Patch: https://git.openjdk.org/jdk/pull/17116.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/17116/head:pull/17116

PR: https://git.openjdk.org/jdk/pull/17116


Re: RFR: 8322149: ConcurrentHashMap copy constructor should not transfer from old table on presizing

2024-01-03 Thread Joshua Cao
On Wed, 3 Jan 2024 14:34:50 GMT, Aleksey Shipilev  wrote:

>> ConcurrentHashMap's copy constructor calls `putAll()` -> `tryPresize()` -> 
>> `transfer()`. When coming from the copy constructor, the Map is empty, so 
>> there is nothing to transfer. But `transfer()` will still copy all the empty 
>> nodes from the old table to the new table.
>> 
>> This patch avoids this work by only calling `tryPresize()` if the table is 
>> already initialized. If `table` is null, the initialization is deferred to 
>> `putVal()`, which calls `initTable()`.
>> 
>> ---
>> 
>> ### JMH results for testCopyConstructor
>> 
>> before patch:
>> 
>> 
>> Result "org.openjdk.bench.java.util.concurrent.Maps.testCopyConstructor":
>>   937395.686 ±(99.9%) 99074.324 ns/op [Average]
>>   (min, avg, max) = (825732.550, 937395.686, 1072024.041), stdev = 92674.184
>>   CI (99.9%): [838321.362, 1036470.010] (assumes normal distribution)
>> 
>> 
>> after patch:
>> 
>> 
>> Result "org.openjdk.bench.java.util.concurrent.Maps.testCopyConstructor":
>>   620871.469 ±(99.9%) 59195.406 ns/op [Average]
>>   (min, avg, max) = (545304.633, 620871.469, 689013.573), stdev = 55371.419
>>   CI (99.9%): [561676.063, 680066.875] (assumes normal distribution)
>> 
>> 
>> Average time is decreased by about 33%.
>
> src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java line 
> 851:
> 
>> 849:  */
>> 850: public ConcurrentHashMap(Map m) {
>> 851: this(m.size(), LOAD_FACTOR, 1);
> 
> This looks like just `this(m.size())`, right? Not sure if we want to save an 
> additional chained constructor call, though.

Yep, same thing. I'll change it.

> test/micro/org/openjdk/bench/java/util/concurrent/Maps.java line 122:
> 
>> 120: public void testCopyConstructor() {
>> 121: ConcurrentHashMap clone = new 
>> ConcurrentHashMap<>(staticMap);
>> 122: dummy = clone;
> 
> Is this for preventing dead-code elimination? If so, just do:
> 
> 
>   return new ConcurrentHashMap<>(staticMap);

I tried this. I don't think its working. When I just return the map, we lose 
the improvements in performance, and the benchmark overall just runs much 
faster. I'm guessing the map got DCE'ed

-

PR Review Comment: https://git.openjdk.org/jdk/pull/17116#discussion_r1440798729
PR Review Comment: https://git.openjdk.org/jdk/pull/17116#discussion_r1440875149


Re: RFR: 8322149: ConcurrentHashMap copy constructor should not transfer from old table on presizing

2024-01-03 Thread Aleksey Shipilev
On Fri, 15 Dec 2023 01:16:55 GMT, Joshua Cao  wrote:

> ConcurrentHashMap's copy constructor calls `putAll()` -> `tryPresize()` -> 
> `transfer()`. When coming from the copy constructor, the Map is empty, so 
> there is nothing to transfer. But `transfer()` will still copy all the empty 
> nodes from the old table to the new table.
> 
> This patch avoids this work by only calling `tryPresize()` if the table is 
> already initialized. If `table` is null, the initialization is deferred to 
> `putVal()`, which calls `initTable()`.
> 
> ---
> 
> ### JMH results for testCopyConstructor
> 
> before patch:
> 
> 
> Result "org.openjdk.bench.java.util.concurrent.Maps.testCopyConstructor":
>   937395.686 ±(99.9%) 99074.324 ns/op [Average]
>   (min, avg, max) = (825732.550, 937395.686, 1072024.041), stdev = 92674.184
>   CI (99.9%): [838321.362, 1036470.010] (assumes normal distribution)
> 
> 
> after patch:
> 
> 
> Result "org.openjdk.bench.java.util.concurrent.Maps.testCopyConstructor":
>   620871.469 ±(99.9%) 59195.406 ns/op [Average]
>   (min, avg, max) = (545304.633, 620871.469, 689013.573), stdev = 55371.419
>   CI (99.9%): [561676.063, 680066.875] (assumes normal distribution)
> 
> 
> Average time is decreased by about 33%.

All right, good! I have comments about the benchmark:

src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java line 
851:

> 849:  */
> 850: public ConcurrentHashMap(Map m) {
> 851: this(m.size(), LOAD_FACTOR, 1);

This looks like just `this(m.size())`, right? Not sure if we want to save an 
additional chained constructor call, though.

test/micro/org/openjdk/bench/java/util/concurrent/Maps.java line 83:

> 81: for (int i = 0; i < nkeys; ++i) {
> 82: staticMap.put(rng.next(), rng.next());
> 83: }

Can just merge this loop with the one above, reusing `rng.next()` for both key 
and values for `staticMap`.

test/micro/org/openjdk/bench/java/util/concurrent/Maps.java line 122:

> 120: public void testCopyConstructor() {
> 121: ConcurrentHashMap clone = new 
> ConcurrentHashMap<>(staticMap);
> 122: dummy = clone;

Is this for preventing dead-code elimination? If so, just do:


  return new ConcurrentHashMap<>(staticMap);

-

PR Review: https://git.openjdk.org/jdk/pull/17116#pullrequestreview-1802240545
PR Review Comment: https://git.openjdk.org/jdk/pull/17116#discussion_r1440523638
PR Review Comment: https://git.openjdk.org/jdk/pull/17116#discussion_r1440517305
PR Review Comment: https://git.openjdk.org/jdk/pull/17116#discussion_r1440515260


Re: RFR: 8322149: ConcurrentHashMap copy constructor should not transfer from old table on presizing

2024-01-03 Thread Doug Lea
On Fri, 15 Dec 2023 01:16:55 GMT, Joshua Cao  wrote:

> ConcurrentHashMap's copy constructor calls `putAll()` -> `tryPresize()` -> 
> `transfer()`. When coming from the copy constructor, the Map is empty, so 
> there is nothing to transfer. But `transfer()` will still copy all the empty 
> nodes from the old table to the new table.
> 
> This patch avoids this work by only calling `tryPresize()` if the table is 
> already initialized. If `table` is null, the initialization is deferred to 
> `putVal()`, which calls `initTable()`.
> 
> ---
> 
> ### JMH results for testCopyConstructor
> 
> before patch:
> 
> 
> Result "org.openjdk.bench.java.util.concurrent.Maps.testCopyConstructor":
>   937395.686 ±(99.9%) 99074.324 ns/op [Average]
>   (min, avg, max) = (825732.550, 937395.686, 1072024.041), stdev = 92674.184
>   CI (99.9%): [838321.362, 1036470.010] (assumes normal distribution)
> 
> 
> after patch:
> 
> 
> Result "org.openjdk.bench.java.util.concurrent.Maps.testCopyConstructor":
>   620871.469 ±(99.9%) 59195.406 ns/op [Average]
>   (min, avg, max) = (545304.633, 620871.469, 689013.573), stdev = 55371.419
>   CI (99.9%): [561676.063, 680066.875] (assumes normal distribution)
> 
> 
> Average time is decreased by about 33%.

Looks OK. It was just an oversight not to check for presizing here. Thanks for 
doing this.

-

PR Comment: https://git.openjdk.org/jdk/pull/17116#issuecomment-1875403205


Re: RFR: 8322149: ConcurrentHashMap copy constructor should not transfer from old table on presizing

2024-01-03 Thread Aleksey Shipilev
On Fri, 15 Dec 2023 01:16:55 GMT, Joshua Cao  wrote:

> ConcurrentHashMap's copy constructor calls `putAll()` -> `tryPresize()` -> 
> `transfer()`. When coming from the copy constructor, the Map is empty, so 
> there is nothing to transfer. But `transfer()` will still copy all the empty 
> nodes from the old table to the new table.
> 
> This patch avoids this work by only calling `tryPresize()` if the table is 
> already initialized. If `table` is null, the initialization is deferred to 
> `putVal()`, which calls `initTable()`.
> 
> ---
> 
> ### JMH results for testCopyConstructor
> 
> before patch:
> 
> 
> Result "org.openjdk.bench.java.util.concurrent.Maps.testCopyConstructor":
>   937395.686 ±(99.9%) 99074.324 ns/op [Average]
>   (min, avg, max) = (825732.550, 937395.686, 1072024.041), stdev = 92674.184
>   CI (99.9%): [838321.362, 1036470.010] (assumes normal distribution)
> 
> 
> after patch:
> 
> 
> Result "org.openjdk.bench.java.util.concurrent.Maps.testCopyConstructor":
>   620871.469 ±(99.9%) 59195.406 ns/op [Average]
>   (min, avg, max) = (545304.633, 620871.469, 689013.573), stdev = 55371.419
>   CI (99.9%): [561676.063, 680066.875] (assumes normal distribution)
> 
> 
> Average time is decreased by about 33%.

We need @DougLea to take a look :)

-

PR Comment: https://git.openjdk.org/jdk/pull/17116#issuecomment-1875046493


RFR: 8322149: ConcurrentHashMap copy constructor should not transfer from old table on presizing

2023-12-14 Thread Joshua Cao
ConcurrentHashMap's copy constructor calls `putAll()` -> `tryPresize()` -> 
`transfer()`. When coming from the copy constructor, the Map is empty, so there 
is nothing to transfer. But `transfer()` will still copy all the empty nodes 
from the old table to the new table.

This patch avoids this work by only calling `tryPresize()` if the table is 
already initialized. If `table` is null, the initialization is deferred to 
`putVal()`, which calls `initTable()`.

---

### JMH results for testCopyConstructor

before patch:


Result "org.openjdk.bench.java.util.concurrent.Maps.testCopyConstructor":
  937395.686 ±(99.9%) 99074.324 ns/op [Average]
  (min, avg, max) = (825732.550, 937395.686, 1072024.041), stdev = 92674.184
  CI (99.9%): [838321.362, 1036470.010] (assumes normal distribution)


after patch:


Result "org.openjdk.bench.java.util.concurrent.Maps.testCopyConstructor":
  620871.469 ±(99.9%) 59195.406 ns/op [Average]
  (min, avg, max) = (545304.633, 620871.469, 689013.573), stdev = 55371.419
  CI (99.9%): [561676.063, 680066.875] (assumes normal distribution)


Average time is decreased by about 33%.

-

Commit messages:
 - 8322149: ConcurrentHashMap copy constructor should not transfer from old 
table on presizing

Changes: https://git.openjdk.org/jdk/pull/17116/files
 Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=17116&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8322149
  Stats: 22 lines in 2 files changed: 19 ins; 1 del; 2 mod
  Patch: https://git.openjdk.org/jdk/pull/17116.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/17116/head:pull/17116

PR: https://git.openjdk.org/jdk/pull/17116