RFR: 8366122: Shenandoah: Implement efficient support for object count after gc events

pf0n duke at openjdk.org
Wed Sep 3 15:54:22 UTC 2025


### Summary

The new implementation of ObjectCountAfterGC for Shenandoah piggybacks off of the existing marking phases and records strongly marked objects in a histogram. If the event is disabled, the original marking closures are used. When enabled new mark-and-count closures are used by the worker threads. Each worker thread updates its local histogram as it marks an object. These local histograms are merged at the conclusion of the marking phase under a mutex. The event is emitted outside a safepoint. Because (most) Shenandoah's marking is done concurrently, so is the object counting work.

### Performance
The performance test were ran using the Extremem benchmark on a default and stress workload. (will edit this section to include data after average time and test for GenShen)

#### Default workload:
ObjectCountAfterGC disabled (master branch):
`[807.216s][info][gc,stats    ] Pause Init Mark (G)            =    0.003 s (a =      264 us)`
`[807.216s][info][gc,stats    ] Pause Init Mark (N)            =    0.001 s (a =       91 us)`
`[807.216s][info][gc,stats    ] Concurrent Mark Roots          =    0.041 s (a =     4099 us)`
`[807.216s][info][gc,stats    ] Concurrent Marking             =    1.660 s (a =   166035 us)`
`[807.216s][info][gc,stats    ] Pause Final Mark (G)           =    0.004 s (a =      446 us) `
`[807.216s][info][gc,stats    ] Pause Final Mark (G)           =    0.004 s (a =      446 us) `
`[807.216s][info][gc,stats    ] Pause Final Mark (N)           =    0.004 s (a =      357 us)`

ObjectCountAfterGC disabled (feature branch):
`[807.104s][info][gc,stats    ] Pause Init Mark (G)            =    0.003 s (a =      302 us)`
`[807.104s][info][gc,stats    ] Pause Init Mark (N)            =    0.001 s (a =       92 us) `
`[807.104s][info][gc,stats    ] Concurrent Mark Roots          =    0.048 s (a =     4827 us)`
`[807.104s][info][gc,stats    ] Concurrent Marking             =    1.666 s (a =   166638 us) `
`[807.104s][info][gc,stats    ] Pause Final Mark (G)           =    0.006 s (a =      603 us)`
`[807.104s][info][gc,stats    ] Pause Final Mark (N)           =    0.005 s (a =      516 us)`

ObjectCountAfterGC enabled (feature branch)
`[807.299s][info][gc,stats    ] Pause Init Mark (G)            =    0.002 s (a =      227 us)`
`[807.299s][info][gc,stats    ] Pause Init Mark (N)            =    0.001 s (a =       89 us) `
`[807.299s][info][gc,stats    ] Concurrent Mark Roots          =    0.053 s (a =     5279 us)`
`[807.299s][info][gc,stats    ] Concurrent Marking             =    1.676 s (a =   167595 us)`
`[807.299s][info][gc,stats    ] Pause Final Mark (G)           =    0.005 s (a =      537 us)`
`[807.299s][info][gc,stats    ] Pause Final Mark (N)           =    0.004 s (a =      430 us)`

#### Stress workload:
ObjectCountAfterGC disabled (master branch):
`[1213.361s][info][gc,stats    ] Pause Init Mark (G)            =    0.023 s (a =      232 us)`
`[1213.361s][info][gc,stats    ] Pause Init Mark (N)            =    0.009 s (a =       85 us)`
`[1213.361s][info][gc,stats    ] Concurrent Mark Roots          =    0.252 s (a =     2521 us)`
`[1213.361s][info][gc,stats    ] Concurrent Marking             =   17.635 s (a =   176354 us) `
`[1213.361s][info][gc,stats    ] Pause Final Mark (G)           =    0.065 s (a =      651 us)`
`[1213.361s][info][gc,stats    ] Pause Final Mark (N)           =    0.049 s (a =      493 us)`

ObjectCountAfterGC disabled (feature branch):
`[1213.626s][info][gc,stats    ] Pause Init Mark (G)            =    0.023 s (a =      234 us)`
`[1213.626s][info][gc,stats    ] Pause Init Mark (N)            =    0.009 s (a =       86 us)`
`[1213.626s][info][gc,stats    ] Concurrent Mark Roots          =    0.265 s (a =     2645 us)`
`[1213.626s][info][gc,stats    ] Concurrent Marking             =   17.747 s (a =   177468 us)`
`[1213.626s][info][gc,stats    ] Pause Final Mark (G)           =    0.043 s (a =      431 us)`
`[1213.626s][info][gc,stats    ] Pause Final Mark (N)           =    0.036 s (a =      362 us)`

ObjectCountAfterGC enabled (feature branch):
`[1213.699s][info][gc,stats    ] Pause Init Mark (G)            =    0.020 s (a =      202 us) `
`[1213.699s][info][gc,stats    ] Pause Init Mark (N)            =    0.008 s (a =       83 us)`
`[1213.699s][info][gc,stats    ] Concurrent Mark Roots          =    0.340 s (a =     3404 us)`
`[1213.699s][info][gc,stats    ] Concurrent Marking             =   17.929 s (a =   179289 us)`
`[1213.699s][info][gc,stats    ] Pause Final Mark (G)           =    0.049 s (a =      492 us)`
`[1213.699s][info][gc,stats    ] Pause Final Mark (N)           =    0.040 s (a =      405 us)`

### Testing
Tested changes with GHA, jtreg tier1 JFR, and hotspot_gc. CodePipeline internal perf and stress test succeeded.

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

Commit messages:
 - Changed comment, included another guard
 - Removing whitespace
 - Merge master
 - Merge master
 - Merge branch 'master' of https://github.com/openjdk/jdk into test/shen-aggregate-closure
 - Comment on why return value was changed to bool
 - Deleted objectCountEventSender.inline.hpp
 - Merging master
 - Reverting changes back to original state for some files
 - Merge branch '8366122/shen-object-count-after-gc' into test/shen-aggregate-closure
 - ... and 121 more: https://git.openjdk.org/jdk/compare/efb81daf...9552c62b

Changes: https://git.openjdk.org/jdk/pull/26977/files
  Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=26977&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8366122
  Stats: 307 lines in 24 files changed: 252 ins; 28 del; 27 mod
  Patch: https://git.openjdk.org/jdk/pull/26977.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/26977/head:pull/26977

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


More information about the hotspot-dev mailing list