Add JNI globals tracing
Add separate tracing for global and weak global JNI references.
We only add an entry for every Nth addition or removal of a reference.
Currently N = 17 to minimize danger of getting in sync with some
application code pattern.
Bug: 189738006
Bug: 192318532
Test: Build boot and look at trace in S build.
Change-Id: I2f223c2a07932f97f89ff87d57f4379c1396ef9e
diff --git a/runtime/indirect_reference_table.h b/runtime/indirect_reference_table.h
index 884e8d1..65e384d 100644
--- a/runtime/indirect_reference_table.h
+++ b/runtime/indirect_reference_table.h
@@ -295,6 +295,12 @@
return segment_state_.top_index;
}
+ // Return the number of non-null entries in the table. Only reliable for a
+ // single segment table.
+ int32_t NEntriesForGlobal() {
+ return segment_state_.top_index - current_num_holes_;
+ }
+
// Ensure that at least free_capacity elements are available, or return false.
bool EnsureFreeCapacity(size_t free_capacity, std::string* error_msg)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -418,7 +424,7 @@
// Some values to retain old behavior with holes. Description of the algorithm is in the .cc
// file.
// TODO: Consider other data structures for compact tables, e.g., free lists.
- size_t current_num_holes_;
+ size_t current_num_holes_; // Number of holes in the current / top segment.
IRTSegmentState last_known_previous_state_;
// Whether the table's capacity may be resized. As there are no locks used, it is the caller's
diff --git a/runtime/jni/java_vm_ext.cc b/runtime/jni/java_vm_ext.cc
index b96c358..e6e341a 100644
--- a/runtime/jni/java_vm_ext.cc
+++ b/runtime/jni/java_vm_ext.cc
@@ -660,6 +660,20 @@
}
}
+void JavaVMExt::MaybeTraceGlobals() {
+ if (global_ref_report_counter_++ == kGlobalRefReportInterval) {
+ global_ref_report_counter_ = 1;
+ ATraceIntegerValue("JNI Global Refs", globals_.NEntriesForGlobal());
+ }
+}
+
+void JavaVMExt::MaybeTraceWeakGlobals() {
+ if (weak_global_ref_report_counter_++ == kGlobalRefReportInterval) {
+ weak_global_ref_report_counter_ = 1;
+ ATraceIntegerValue("JNI Weak Global Refs", weak_globals_.NEntriesForGlobal());
+ }
+}
+
jobject JavaVMExt::AddGlobalRef(Thread* self, ObjPtr<mirror::Object> obj) {
// Check for null after decoding the object to handle cleared weak globals.
if (obj == nullptr) {
@@ -670,6 +684,7 @@
{
WriterMutexLock mu(self, *Locks::jni_globals_lock_);
ref = globals_.Add(kIRTFirstSegment, obj, &error_msg);
+ MaybeTraceGlobals();
}
if (UNLIKELY(ref == nullptr)) {
LOG(FATAL) << error_msg;
@@ -705,6 +720,7 @@
}
std::string error_msg;
IndirectRef ref = weak_globals_.Add(kIRTFirstSegment, obj, &error_msg);
+ MaybeTraceWeakGlobals();
if (UNLIKELY(ref == nullptr)) {
LOG(FATAL) << error_msg;
UNREACHABLE();
@@ -722,6 +738,7 @@
LOG(WARNING) << "JNI WARNING: DeleteGlobalRef(" << obj << ") "
<< "failed to find entry";
}
+ MaybeTraceGlobals();
}
CheckGlobalRefAllocationTracking();
}
@@ -735,6 +752,7 @@
LOG(WARNING) << "JNI WARNING: DeleteWeakGlobalRef(" << obj << ") "
<< "failed to find entry";
}
+ MaybeTraceWeakGlobals();
}
static void ThreadEnableCheckJni(Thread* thread, void* arg) {
diff --git a/runtime/jni/java_vm_ext.h b/runtime/jni/java_vm_ext.h
index ef283aa..a842efa 100644
--- a/runtime/jni/java_vm_ext.h
+++ b/runtime/jni/java_vm_ext.h
@@ -228,6 +228,9 @@
void CheckGlobalRefAllocationTracking();
+ inline void MaybeTraceGlobals() REQUIRES(Locks::jni_globals_lock_);
+ inline void MaybeTraceWeakGlobals() REQUIRES(Locks::jni_weak_globals_lock_);
+
Runtime* const runtime_;
// Used for testing. By default, we'll LOG(FATAL) the reason.
@@ -268,6 +271,14 @@
std::atomic<bool> allocation_tracking_enabled_;
std::atomic<bool> old_allocation_tracking_state_;
+ // We report the number of global references after every kGlobalRefReportInterval changes.
+ static constexpr uint32_t kGlobalRefReportInterval = 17;
+ uint32_t weak_global_ref_report_counter_ GUARDED_BY(Locks::jni_weak_globals_lock_)
+ = kGlobalRefReportInterval;
+ uint32_t global_ref_report_counter_ GUARDED_BY(Locks::jni_globals_lock_)
+ = kGlobalRefReportInterval;
+
+
friend IndirectReferenceTable* GetIndirectReferenceTable(ScopedObjectAccess& soa,
IndirectRefKind kind);