Re: RFR: 8266936: Add a finalization JFR event [v10]

2021-10-18 Thread Markus Grönlund
On Tue, 31 Aug 2021 08:45:54 GMT, Erik Gahlin  wrote:

>> Markus Grönlund has updated the pull request incrementally with three 
>> additional commits since the last revision:
>> 
>>  - localize
>>  - cleanup
>>  - FinalizerStatistics
>
> src/java.base/share/classes/java/lang/ref/Finalizer.java line 71:
> 
>> 69: }
>> 70: 
>> 71: 
> 
> extraneous whitespace?

I think this version is outdated, and the extra whitespace was removed in later 
versions.

-

PR: https://git.openjdk.java.net/jdk/pull/4731


Re: RFR: 8266936: Add a finalization JFR event [v10]

2021-10-18 Thread Markus Grönlund
On Tue, 31 Aug 2021 08:42:58 GMT, Erik Gahlin  wrote:

>> Markus Grönlund has updated the pull request incrementally with three 
>> additional commits since the last revision:
>> 
>>  - localize
>>  - cleanup
>>  - FinalizerStatistics
>
> test/jdk/jdk/jfr/event/runtime/TestFinalizerStatisticsEvent.java line 98:
> 
>> 96:   case TEST_CLASS_NAME: {
>> 97:   
>> Asserts.assertTrue(event.getString("codeSource").startsWith("file://"));
>> 98:   foundTestClassName = true;
> 
> Could we (sanity) check "objects" and "totalFinalzersRun" fields as well?

It's risky to do because of the non-deterministic nature of when the Finalizer 
thread runs (if at all). The best I could think of is to check if either field 
is 0 or more, but that becomes so weak it's not much of a sanity check.

-

PR: https://git.openjdk.java.net/jdk/pull/4731


Re: RFR: 8266936: Add a finalization JFR event [v10]

2021-10-18 Thread Erik Gahlin
On Fri, 27 Aug 2021 15:23:35 GMT, Markus Grönlund  wrote:

>> Greetings,
>> 
>> Object.finalize() was deprecated in JDK9. There is an ongoing effort to 
>> replace and mitigate Object.finalize() uses in the JDK libraries; please see 
>> https://bugs.openjdk.java.net/browse/JDK-8253568 for more information. 
>> 
>> We also like to assist users in replacing and mitigating uses in non-JDK 
>> code.
>> 
>> Hence, this changeset adds a periodic JFR event to help identify which 
>> classes are overriding Object.finalize().
>> 
>> Thanks
>> Markus
>
> Markus Grönlund has updated the pull request incrementally with three 
> additional commits since the last revision:
> 
>  - localize
>  - cleanup
>  - FinalizerStatistics

Marked as reviewed by egahlin (Reviewer).

src/java.base/share/classes/java/lang/ref/Finalizer.java line 71:

> 69: }
> 70: 
> 71: 

extraneous whitespace?

test/jdk/jdk/jfr/event/runtime/TestFinalizerStatisticsEvent.java line 98:

> 96:   case TEST_CLASS_NAME: {
> 97:   
> Asserts.assertTrue(event.getString("codeSource").startsWith("file://"));
> 98:   foundTestClassName = true;

Could we (sanity) check "objects" and "totalFinalzersRun" fields as well?

-

PR: https://git.openjdk.java.net/jdk/pull/4731


Re: RFR: 8266936: Add a finalization JFR event [v10]

2021-10-14 Thread Markus Grönlund
On Thu, 14 Oct 2021 22:02:43 GMT, Coleen Phillimore  wrote:

>> Ok, I see - grow the table.
>> 
>> I'm not sure if you need to ask ik->is_loader_alive() or not, but I think 
>> you do.  The InstanceKlass is removed from your table during class unloading 
>> but before that during concurrent class unloading, the class might not be 
>> alive while you look at it and concurrent class unloading hasn't gotten 
>> around to removing it yet.  Since you save classes regardless of CLD, you 
>> have to check if it's alive.  See classLoaderDataGraph.cpp 
>> ClassLoaderDataGraphIterator for example.  The CLDG_lock only keeps the 
>> graph from not getting modified, but the classes in it might be dead.
>
> That said, I don't see where you return an InstanceKlass in the table, which 
> would need this check.  Not in class_unloading_do because this follows the 
> _unloading list.

So there is already support for concurrent class unloading today in JFR, and 
the protocol is built around the CLDG_lock. If JFR holds it, concurrent class 
unloading cannot run. If GC holds it, JFR cannot inspect classes. That's why 
the table inspection is guarded via the CLDG_lock, for mutual exclusion to 
avoid this problem. I.e. if concurrent class unloading is in progress, JFR will 
not inspect the table.

-

PR: https://git.openjdk.java.net/jdk/pull/4731


Re: RFR: 8266936: Add a finalization JFR event [v10]

2021-10-14 Thread Coleen Phillimore
On Thu, 14 Oct 2021 21:58:42 GMT, Coleen Phillimore  wrote:

>> "Since you remove entries on unloading, I don't see any reason to have any 
>> concurrent cleanup."
>> Thank you, that is true. The only concurrent work required will be to grow 
>> the table.
>> 
>> "You do however need in the lookup code, some code that doesn't find the 
>> InstanceKlass if !ik->is_loader_alive()"
>> 
>> A precondition is that the code doing the lookup hold the 
>> ClassLoaderDataGraph_lock or is at a safepoint. Is that still the case? 
>> Would not purge_unloaded() take out the InstanceKlass from the table, as 
>> part of unloading, before !ik->is_loader_alive() is published to the outside 
>> world?
>
> Ok, I see - grow the table.
> 
> I'm not sure if you need to ask ik->is_loader_alive() or not, but I think you 
> do.  The InstanceKlass is removed from your table during class unloading but 
> before that during concurrent class unloading, the class might not be alive 
> while you look at it and concurrent class unloading hasn't gotten around to 
> removing it yet.  Since you save classes regardless of CLD, you have to check 
> if it's alive.  See classLoaderDataGraph.cpp ClassLoaderDataGraphIterator for 
> example.  The CLDG_lock only keeps the graph from not getting modified, but 
> the classes in it might be dead.

That said, I don't see where you return an InstanceKlass in the table, which 
would need this check.  Not in class_unloading_do because this follows the 
_unloading list.

-

PR: https://git.openjdk.java.net/jdk/pull/4731


Re: RFR: 8266936: Add a finalization JFR event [v10]

2021-10-14 Thread Coleen Phillimore
On Mon, 13 Sep 2021 10:54:18 GMT, Markus Grönlund  wrote:

>> src/hotspot/share/services/finalizerService.cpp line 44:
>> 
>>> 42: _ik(ik),
>>> 43: _objects_on_heap(0),
>>> 44: _total_finalizers_run(0) {}
>> 
>> Is this hashtable for every InstanceKlass that defines a finalizer?  How 
>> many are there generally?  Why couldn't this be a simple hashtable like 
>> ResourceHashtable (soon to be renamed) which you can write in only a few 
>> lines of code?
>
> This hashtable holds a FinalizerEntry for every InstanceKlass that provides a 
> non-empty finalizer method and have allocated at least one object. How many 
> there are in general depends on the application. A ResourceHashtable does not 
> have the concurrency property required, as lookups and inserts will happen as 
> part of object allocation.

ok.

>> src/hotspot/share/services/finalizerService.cpp line 331:
>> 
>>> 329:   }
>>> 330:   Thread* const thread = Thread::current();
>>> 331:   // We use current size
>> 
>> Since you remove entries on unloading, I don't see any reason to have any 
>> concurrent cleanup.
>> You do however need in the lookup code, some code that doesn't find the 
>> InstanceKlass if !ik->is_loader_alive()
>
> "Since you remove entries on unloading, I don't see any reason to have any 
> concurrent cleanup."
> Thank you, that is true. The only concurrent work required will be to grow 
> the table.
> 
> "You do however need in the lookup code, some code that doesn't find the 
> InstanceKlass if !ik->is_loader_alive()"
> 
> A precondition is that the code doing the lookup hold the 
> ClassLoaderDataGraph_lock or is at a safepoint. Is that still the case? Would 
> not purge_unloaded() take out the InstanceKlass from the table, as part of 
> unloading, before !ik->is_loader_alive() is published to the outside world?

Ok, I see - grow the table.

I'm not sure if you need to ask ik->is_loader_alive() or not, but I think you 
do.  The InstanceKlass is removed from your table during class unloading but 
before that during concurrent class unloading, the class might not be alive 
while you look at it and concurrent class unloading hasn't gotten around to 
removing it yet.  Since you save classes regardless of CLD, you have to check 
if it's alive.  See classLoaderDataGraph.cpp ClassLoaderDataGraphIterator for 
example.  The CLDG_lock only keeps the graph from not getting modified, but the 
classes in it might be dead.

-

PR: https://git.openjdk.java.net/jdk/pull/4731


Re: RFR: 8266936: Add a finalization JFR event [v10]

2021-09-13 Thread Markus Grönlund
On Wed, 8 Sep 2021 17:37:20 GMT, Coleen Phillimore  wrote:

>> Markus Grönlund has updated the pull request incrementally with three 
>> additional commits since the last revision:
>> 
>>  - localize
>>  - cleanup
>>  - FinalizerStatistics
>
> src/hotspot/share/services/classLoadingService.cpp line 80:
> 
>> 78: 
>> 79: size_t ClassLoadingService::compute_class_size(InstanceKlass* k) {
>> 80:   // lifted from ClassStatistics.do_class(Klass* k)
> 
> Can you remove this line? I think that function is gone now.

Thanks Coleen for taking a look at this.

It is used internally by notify_class_loaded() and notify_class_unloaded(); 
therefore I will change it to have internal linkage.

> src/hotspot/share/services/finalizerService.cpp line 44:
> 
>> 42: _ik(ik),
>> 43: _objects_on_heap(0),
>> 44: _total_finalizers_run(0) {}
> 
> Is this hashtable for every InstanceKlass that defines a finalizer?  How many 
> are there generally?  Why couldn't this be a simple hashtable like 
> ResourceHashtable (soon to be renamed) which you can write in only a few 
> lines of code?

This hashtable holds a FinalizerEntry for every InstanceKlass that provides a 
non-empty finalizer method and have allocated at least one object. How many 
there are in general depends on the application. A ResourceHashtable does not 
have the concurrency property required, as lookups and inserts will happen as 
part of object allocation.

> src/hotspot/share/services/finalizerService.cpp line 114:
> 
>> 112: 
>> 113: static inline void added() {
>> 114:   set_atomic(&_count);
> 
> Why isn't Atomic::inc() good enough here? It's used everywhere else.

Our Atomic implementation does not support CAS of a 64-bit value on 32-bit 
platforms (compiles but does not link).

> src/hotspot/share/services/finalizerService.cpp line 123:
> 
>> 121: static inline uintx hash_function(const InstanceKlass* ik) {
>> 122:   assert(ik != nullptr, "invariant");
>> 123:   return primitive_hash(ik);
> 
> If the hash function is primitive_hash, this hash is good enough to not need 
> rehashing.  The only reason for the rehashing for symbol and string table was 
> that the char* had a dumb hash that was faster but could be hacked, so it 
> needed to become a different hashcode.  This doesn't need rehashing.

Thank you for pointing that out. I had assumed this to be a part of the 
syntactic contract for using the ConcurrentHashTable. My wrong assumption was 
because the SymbolTable (which I used as a model) seemed to pass a 
"rehash_warning" bool to the accessor APIs (get, insert). However, looking more 
closely at the signatures in ConcurrentHashTable, that bool is a "grow_hint", 
not "rehash" specifically. Thanks again; I will remove the rehash support code.

> src/hotspot/share/services/finalizerService.cpp line 485:
> 
>> 483: void FinalizerService::purge_unloaded() {
>> 484:   assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
>> 485:   ClassLoaderDataGraph::classes_unloading_do(&on_unloading);
> 
> Since you remove entries on unloading, I don't see any reason to have any 
> concurrent cleanup.
> You do however need in the lookup code, some code that doesn't find the 
> InstanceKlass if !ik->is_loader_alive()

"Since you remove entries on unloading, I don't see any reason to have any 
concurrent cleanup."
Thank you, that is true. The only concurrent work required will be to grow the 
table.

"You do however need in the lookup code, some code that doesn't find the 
InstanceKlass if !ik->is_loader_alive()"

A precondition is that the code doing the lookup hold the 
ClassLoaderDataGraph_lock or is at a safepoint. Is that still the case? Would 
not purge_unloaded() take out the InstanceKlass from the table, as part of 
unloading, before !ik->is_loader_alive() is published to the outside world?

-

PR: https://git.openjdk.java.net/jdk/pull/4731


Re: RFR: 8266936: Add a finalization JFR event [v10]

2021-09-08 Thread Coleen Phillimore
On Fri, 27 Aug 2021 15:23:35 GMT, Markus Grönlund  wrote:

>> Greetings,
>> 
>> Object.finalize() was deprecated in JDK9. There is an ongoing effort to 
>> replace and mitigate Object.finalize() uses in the JDK libraries; please see 
>> https://bugs.openjdk.java.net/browse/JDK-8253568 for more information. 
>> 
>> We also like to assist users in replacing and mitigating uses in non-JDK 
>> code.
>> 
>> Hence, this changeset adds a periodic JFR event to help identify which 
>> classes are overriding Object.finalize().
>> 
>> Thanks
>> Markus
>
> Markus Grönlund has updated the pull request incrementally with three 
> additional commits since the last revision:
> 
>  - localize
>  - cleanup
>  - FinalizerStatistics

I have some general comments and questions about this code.

src/hotspot/share/services/classLoadingService.cpp line 80:

> 78: 
> 79: size_t ClassLoadingService::compute_class_size(InstanceKlass* k) {
> 80:   // lifted from ClassStatistics.do_class(Klass* k)

Can you remove this line? I think that function is gone now.

src/hotspot/share/services/finalizerService.cpp line 44:

> 42: _ik(ik),
> 43: _objects_on_heap(0),
> 44: _total_finalizers_run(0) {}

Is this hashtable for every InstanceKlass that defines a finalizer?  How many 
are there generally?  Why couldn't this be a simple hashtable like 
ResourceHashtable (soon to be renamed) which you can write in only a few lines 
of code?

src/hotspot/share/services/finalizerService.cpp line 114:

> 112: 
> 113: static inline void added() {
> 114:   set_atomic(&_count);

Why isn't Atomic::inc() good enough here? It's used everywhere else.

src/hotspot/share/services/finalizerService.cpp line 123:

> 121: static inline uintx hash_function(const InstanceKlass* ik) {
> 122:   assert(ik != nullptr, "invariant");
> 123:   return primitive_hash(ik);

If the hash function is primitive_hash, this hash is good enough to not need 
rehashing.  The only reason for the rehashing for symbol and string table was 
that the char* had a dumb hash that was faster but could be hacked, so it 
needed to become a different hashcode.  This doesn't need rehashing.

src/hotspot/share/services/finalizerService.cpp line 485:

> 483: void FinalizerService::purge_unloaded() {
> 484:   assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
> 485:   ClassLoaderDataGraph::classes_unloading_do(&on_unloading);

Since you remove entries on unloading, I don't see any reason to have any 
concurrent cleanup.
You do however need in the lookup code, some code that doesn't find the 
InstanceKlass if !ik->is_loader_alive()

-

PR: https://git.openjdk.java.net/jdk/pull/4731


Re: RFR: 8266936: Add a finalization JFR event [v10]

2021-08-27 Thread Markus Grönlund
> Greetings,
> 
> Object.finalize() was deprecated in JDK9. There is an ongoing effort to 
> replace and mitigate Object.finalize() uses in the JDK libraries; please see 
> https://bugs.openjdk.java.net/browse/JDK-8253568 for more information. 
> 
> We also like to assist users in replacing and mitigating uses in non-JDK code.
> 
> Hence, this changeset adds a periodic JFR event to help identify which 
> classes are overriding Object.finalize().
> 
> Thanks
> Markus

Markus Grönlund has updated the pull request incrementally with three 
additional commits since the last revision:

 - localize
 - cleanup
 - FinalizerStatistics

-

Changes:
  - all: https://git.openjdk.java.net/jdk/pull/4731/files
  - new: https://git.openjdk.java.net/jdk/pull/4731/files/e6b786f1..fd86899f

Webrevs:
 - full: https://webrevs.openjdk.java.net/?repo=jdk&pr=4731&range=09
 - incr: https://webrevs.openjdk.java.net/?repo=jdk&pr=4731&range=08-09

  Stats: 457 lines in 17 files changed: 190 ins; 222 del; 45 mod
  Patch: https://git.openjdk.java.net/jdk/pull/4731.diff
  Fetch: git fetch https://git.openjdk.java.net/jdk pull/4731/head:pull/4731

PR: https://git.openjdk.java.net/jdk/pull/4731