On Tue, 13 Aug 2024 16:30:12 GMT, Axel Boldt-Christmas <abold...@openjdk.org> 
wrote:

>> When inflating a monitor the `ObjectMonitor*` is written directly over the 
>> `markWord` and any overwritten data is displaced into a displaced 
>> `markWord`. This is problematic for concurrent GCs which needs extra care or 
>> looser semantics to use this displaced data. In Lilliput this data also 
>> contains the klass forcing this to be something that the GC has to take into 
>> account everywhere.
>> 
>> This patch introduces an alternative solution where locking only uses the 
>> lock bits of the `markWord` and inflation does not override and displace the 
>> `markWord`. This is done by keeping associations between objects and 
>> `ObjectMonitor*` in an external hash table. Different caching techniques are 
>> used to speedup lookups from compiled code.
>> 
>> A diagnostic VM option is introduced called `UseObjectMonitorTable`. It is 
>> only supported in combination with the LM_LIGHTWEIGHT locking mode (the 
>> default). 
>> 
>> This patch has been evaluated to be performance neutral when 
>> `UseObjectMonitorTable` is turned off (the default). 
>> 
>> Below is a more detailed explanation of this change and how `LM_LIGHTWEIGHT` 
>> and `UseObjectMonitorTable` works.
>> 
>> # Cleanups
>> 
>> Cleaned up displaced header usage for:
>>   * BasicLock
>>     * Contains some Zero changes
>>     * Renames one exported JVMCI field
>>   * ObjectMonitor
>>     * Updates comments and tests consistencies
>> 
>> # Refactoring
>> 
>> `ObjectMonitor::enter` has been refactored an a 
>> `ObjectMonitorContentionMark` witness object has been introduced to the 
>> signatures. Which signals that the contentions reference counter is being 
>> held. More details are given below in the section about deflation.
>> 
>> The initial purpose of this was to allow `UseObjectMonitorTable` to interact 
>> more seamlessly with the `ObjectMonitor::enter` code. 
>> 
>> _There is even more `ObjectMonitor` refactoring which can be done here to 
>> create a more understandable and enforceable API. There are a handful of 
>> invariants / assumptions which are not always explicitly asserted which 
>> could be trivially abstracted and verified by the type system by using 
>> similar witness objects._
>> 
>> # LightweightSynchronizer
>> 
>> Working on adapting and incorporating the following section as a comment in 
>> the source code
>> 
>> ## Fast Locking
>> 
>>   CAS on locking bits in markWord. 
>>   0b00 (Fast Locked) <--> 0b01 (Unlocked)
>> 
>>   When locking and 0b00 (Fast Locked) is observed, it may be beneficial to 
>> avoid inflating by spinning a bit.
>> 
>>   If 0b10 (Inflated) is observed or there is to...
>
> Axel Boldt-Christmas has updated the pull request incrementally with one 
> additional commit since the last revision:
> 
>   Whitespace and nits

I finished my first pass crawl thru on these changes. I need to mull
on these changes a bit before I make another pass. I think there's
only one real bug buried in all of my comments.

src/hotspot/share/runtime/objectMonitor.cpp line 377:

> 375: 
> 376:   if (cur == current) {
> 377:     // TODO-FIXME: check for integer overflow!  BUGID 6557169.

Thanks for removing this comment. JDK-6557169 was closed as
"Will Not FIx" in 2017.

src/hotspot/share/runtime/synchronizer.cpp line 970:

> 968:   if (value == 0) value = 0xBAD;
> 969:   assert(value != markWord::no_hash, "invariant");
> 970:   return value;

In the elided part above this line, we have:

  if (value == 0) value = 0xBAD;
  assert(value != markWord::no_hash, "invariant");

so my memory about zero being returnable as a hash value is wrong.

src/hotspot/share/runtime/synchronizer.cpp line 977:

> 975: 
> 976:   markWord mark = obj->mark_acquire();
> 977:   for(;;) {

nit - please insert space before `(`

src/hotspot/share/runtime/synchronizer.cpp line 997:

> 995:   // Since the monitor isn't in the object header, it can simply be 
> installed.
> 996:   if (UseObjectMonitorTable) {
> 997:     return install_hash_code(current, obj);

Perhaps:

  if (UseObjectMonitorTable) {
    // Since the monitor isn't in the object header, the hash can simply be
    // installed in the object header.
    return install_hash_code(current, obj);

src/hotspot/share/runtime/synchronizer.cpp line 1271:

> 1269:       _no_progress_cnt >= NoAsyncDeflationProgressMax) {
> 1270:     double remainder = (100.0 - MonitorUsedDeflationThreshold) / 100.0;
> 1271:     size_t new_ceiling = ceiling / remainder + 1;

Why was the `new_ceiling` calculation changed?
I think the `new_ceiling` value is going to lower than the old ceiling value.

src/hotspot/share/runtime/synchronizer.inline.hpp line 83:

> 81: 
> 82: 
> 83: #endif // SHARE_RUNTIME_SYNCHRONIZER_INLINE_HPP

nit - please delete one of the blank lines.

src/hotspot/share/runtime/vframe.cpp line 252:

> 250:           if (mark.has_monitor()) {
> 251:             ObjectMonitor* mon = 
> ObjectSynchronizer::read_monitor(current, monitor->owner(), mark);
> 252:             if (// if the monitor is null we must be in the process of 
> locking

nit - please add a space after `(`

test/hotspot/gtest/runtime/test_objectMonitor.cpp line 36:

> 34:     EXPECT_EQ(in_bytes(ObjectMonitor::metadata_offset()), 0)
> 35:          << "_metadata at a non 0 offset. metadata_offset = "
> 36:          << in_bytes(ObjectMonitor::metadata_offset());

nit - the indent should be four spaces instead of five spaces.

test/hotspot/gtest/runtime/test_objectMonitor.cpp line 40:

> 38:     EXPECT_GE((size_t) in_bytes(ObjectMonitor::owner_offset()), 
> cache_line_size)
> 39:          << "the _metadata and _owner fields are closer "
> 40:          << "than a cache line which permits false sharing.";

nit - the indent should be four spaces instead of five spaces.

test/hotspot/gtest/runtime/test_objectMonitor.cpp line 44:

> 42:     EXPECT_GE((size_t) in_bytes(ObjectMonitor::recursions_offset() - 
> ObjectMonitor::owner_offset()), cache_line_size)
> 43:          << "the _owner and _recursions fields are closer "
> 44:          << "than a cache line which permits false sharing.";

nit - the indent should be four spaces instead of five spaces.

test/hotspot/jtreg/runtime/Monitor/UseObjectMonitorTableTest.java line 148:

> 146:         static final int MAX_RECURSION_COUNT = 10;
> 147:         static final double RECURSION_CHANCE = .25;
> 148:         final Random random = new Random();

The test should output a seed value so that the user knows what
random seed value was in use if/when the test fails. Also add a way
to specify the seed value from the command line for reproducibility.

test/micro/org/openjdk/bench/vm/lang/LockUnlock.java line 201:

> 199: 
> 200:   /** Perform two synchronized after each other on the same object. */
> 201:     @Benchmark

Please align L200 with L201.

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

Changes requested by dcubed (Reviewer).

PR Review: https://git.openjdk.org/jdk/pull/20067#pullrequestreview-2234133776
PR Review Comment: https://git.openjdk.org/jdk/pull/20067#discussion_r1715917040
PR Review Comment: https://git.openjdk.org/jdk/pull/20067#discussion_r1715955877
PR Review Comment: https://git.openjdk.org/jdk/pull/20067#discussion_r1715957258
PR Review Comment: https://git.openjdk.org/jdk/pull/20067#discussion_r1715958513
PR Review Comment: https://git.openjdk.org/jdk/pull/20067#discussion_r1715965577
PR Review Comment: https://git.openjdk.org/jdk/pull/20067#discussion_r1715976433
PR Review Comment: https://git.openjdk.org/jdk/pull/20067#discussion_r1715978312
PR Review Comment: https://git.openjdk.org/jdk/pull/20067#discussion_r1715981270
PR Review Comment: https://git.openjdk.org/jdk/pull/20067#discussion_r1715981568
PR Review Comment: https://git.openjdk.org/jdk/pull/20067#discussion_r1715981881
PR Review Comment: https://git.openjdk.org/jdk/pull/20067#discussion_r1715986844
PR Review Comment: https://git.openjdk.org/jdk/pull/20067#discussion_r1715990141

Reply via email to