diff options
author | 2015-07-10 13:19:51 -0700 | |
---|---|---|
committer | 2015-07-10 16:31:08 -0700 | |
commit | f1820850307f7c2940c758f1232e1c40888a111a (patch) | |
tree | cb04d286428af5950f18d033ae84f8ea93f57df2 | |
parent | eaffe35038dc7b9e9e95ec997d32d19571973f54 (diff) |
Add VMDebug.countInstancesOfClasses
countInstancesOfClasses allows passing multiple classes unlike
countInstanceOfClass instead of needing to do one at a time.
This is going to be used to speed up string mode checking.
Also changed the logic to not do a GC, this was the old Dalvik
behavior. It is the job of the caller to do this.
Added test.
https://code.google.com/p/android/issues/detail?id=177552
Change-Id: Ia85684f40cf59a52aa71a8479c711a994651209b
-rw-r--r-- | runtime/gc/heap.cc | 5 | ||||
-rw-r--r-- | runtime/native/dalvik_system_VMDebug.cc | 37 | ||||
-rw-r--r-- | test/099-vmdebug/expected.txt | 6 | ||||
-rw-r--r-- | test/099-vmdebug/src/Main.java | 43 |
4 files changed, 83 insertions, 8 deletions
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 26a45d3a2b..0ae9cdf7db 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -1704,11 +1704,12 @@ class InstanceCounter { mirror::Class* instance_class = obj->GetClass(); CHECK(instance_class != nullptr); for (size_t i = 0; i < instance_counter->classes_.size(); ++i) { + mirror::Class* klass = instance_counter->classes_[i]; if (instance_counter->use_is_assignable_from_) { - if (instance_counter->classes_[i]->IsAssignableFrom(instance_class)) { + if (klass != nullptr && klass->IsAssignableFrom(instance_class)) { ++instance_counter->counts_[i]; } - } else if (instance_class == instance_counter->classes_[i]) { + } else if (instance_class == klass) { ++instance_counter->counts_[i]; } } diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc index 1078492d08..8febb62a5f 100644 --- a/runtime/native/dalvik_system_VMDebug.cc +++ b/runtime/native/dalvik_system_VMDebug.cc @@ -257,21 +257,45 @@ static void VMDebug_infopoint(JNIEnv*, jclass, jint id) { static jlong VMDebug_countInstancesOfClass(JNIEnv* env, jclass, jclass javaClass, jboolean countAssignable) { ScopedObjectAccess soa(env); - gc::Heap* heap = Runtime::Current()->GetHeap(); - // We only want reachable instances, so do a GC. Heap::VisitObjects visits all of the heap - // objects in the all spaces and the allocation stack. - heap->CollectGarbage(false); + gc::Heap* const heap = Runtime::Current()->GetHeap(); + // Caller's responsibility to do GC if desired. mirror::Class* c = soa.Decode<mirror::Class*>(javaClass); if (c == nullptr) { return 0; } - std::vector<mirror::Class*> classes; - classes.push_back(c); + std::vector<mirror::Class*> classes {c}; uint64_t count = 0; heap->CountInstances(classes, countAssignable, &count); return count; } +static jlongArray VMDebug_countInstancesOfClasses(JNIEnv* env, jclass, jobjectArray javaClasses, + jboolean countAssignable) { + ScopedObjectAccess soa(env); + gc::Heap* const heap = Runtime::Current()->GetHeap(); + // Caller's responsibility to do GC if desired. + auto* decoded_classes = soa.Decode<mirror::ObjectArray<mirror::Class>*>(javaClasses); + if (decoded_classes == nullptr) { + return nullptr; + } + std::vector<mirror::Class*> classes; + for (size_t i = 0, count = decoded_classes->GetLength(); i < count; ++i) { + classes.push_back(decoded_classes->Get(i)); + } + std::vector<uint64_t> counts(classes.size(), 0u); + // Heap::CountInstances can handle null and will put 0 for these classes. + heap->CountInstances(classes, countAssignable, &counts[0]); + auto* long_counts = mirror::LongArray::Alloc(soa.Self(), counts.size()); + if (long_counts == nullptr) { + soa.Self()->AssertPendingOOMException(); + return nullptr; + } + for (size_t i = 0; i < counts.size(); ++i) { + long_counts->Set(i, counts[i]); + } + return soa.AddLocalReference<jlongArray>(long_counts); +} + // We export the VM internal per-heap-space size/alloc/free metrics // for the zygote space, alloc space (application heap), and the large // object space for dumpsys meminfo. The other memory region data such @@ -452,6 +476,7 @@ static jobjectArray VMDebug_getRuntimeStatsInternal(JNIEnv* env, jclass) { static JNINativeMethod gMethods[] = { NATIVE_METHOD(VMDebug, countInstancesOfClass, "(Ljava/lang/Class;Z)J"), + NATIVE_METHOD(VMDebug, countInstancesOfClasses, "([Ljava/lang/Class;Z)[J"), NATIVE_METHOD(VMDebug, crash, "()V"), NATIVE_METHOD(VMDebug, dumpHprofData, "(Ljava/lang/String;Ljava/io/FileDescriptor;)V"), NATIVE_METHOD(VMDebug, dumpHprofDataDdms, "()V"), diff --git a/test/099-vmdebug/expected.txt b/test/099-vmdebug/expected.txt index 579f98fe7c..b8d72f66f8 100644 --- a/test/099-vmdebug/expected.txt +++ b/test/099-vmdebug/expected.txt @@ -17,3 +17,9 @@ Test tracing with bogus (< 1024 && != 0) filesize Got expected exception Test sampling with bogus (<= 0) interval Got expected exception +Instances of ClassA 2 +Instances of ClassB 1 +Instances of null 0 +Instances of ClassA assignable 3 +Array counts [2, 1, 0] +Array counts assignable [3, 1, 0] diff --git a/test/099-vmdebug/src/Main.java b/test/099-vmdebug/src/Main.java index add2ff6fb6..1be5765155 100644 --- a/test/099-vmdebug/src/Main.java +++ b/test/099-vmdebug/src/Main.java @@ -17,6 +17,8 @@ import java.io.File; import java.io.IOException; import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.ArrayList; import java.util.Map; public class Main { @@ -30,7 +32,9 @@ public class Main { return; } testMethodTracing(); + testCountInstances(); testRuntimeStat(); + testRuntimeStats(); } private static File createTempFile() throws Exception { @@ -220,12 +224,39 @@ public class Main { checkHistogram(blocking_gc_count_rate_histogram); } + static class ClassA { } + static class ClassB { } + static class ClassC extends ClassA { } + + private static void testCountInstances() throws Exception { + ArrayList<Object> l = new ArrayList<Object>(); + l.add(new ClassA()); + l.add(new ClassB()); + l.add(new ClassA()); + l.add(new ClassC()); + Runtime.getRuntime().gc(); + System.out.println("Instances of ClassA " + + VMDebug.countInstancesofClass(ClassA.class, false)); + System.out.println("Instances of ClassB " + + VMDebug.countInstancesofClass(ClassB.class, false)); + System.out.println("Instances of null " + VMDebug.countInstancesofClass(null, false)); + System.out.println("Instances of ClassA assignable " + + VMDebug.countInstancesofClass(ClassA.class, true)); + Class[] classes = new Class[]{ClassA.class, ClassB.class, null}; + long[] counts = VMDebug.countInstancesofClasses(classes, false); + System.out.println("Array counts " + Arrays.toString(counts)); + counts = VMDebug.countInstancesofClasses(classes, true); + System.out.println("Array counts assignable " + Arrays.toString(counts)); + } + private static class VMDebug { private static final Method startMethodTracingMethod; private static final Method stopMethodTracingMethod; private static final Method getMethodTracingModeMethod; private static final Method getRuntimeStatMethod; private static final Method getRuntimeStatsMethod; + private static final Method countInstancesOfClassMethod; + private static final Method countInstancesOfClassesMethod; static { try { Class c = Class.forName("dalvik.system.VMDebug"); @@ -235,6 +266,10 @@ public class Main { getMethodTracingModeMethod = c.getDeclaredMethod("getMethodTracingMode"); getRuntimeStatMethod = c.getDeclaredMethod("getRuntimeStat", String.class); getRuntimeStatsMethod = c.getDeclaredMethod("getRuntimeStats"); + countInstancesOfClassMethod = c.getDeclaredMethod("countInstancesOfClass", + Class.class, Boolean.TYPE); + countInstancesOfClassesMethod = c.getDeclaredMethod("countInstancesOfClasses", + Class[].class, Boolean.TYPE); } catch (Exception e) { throw new RuntimeException(e); } @@ -257,5 +292,13 @@ public class Main { public static Map<String, String> getRuntimeStats() throws Exception { return (Map<String, String>) getRuntimeStatsMethod.invoke(null); } + public static long countInstancesofClass(Class c, boolean assignable) throws Exception { + return (long) countInstancesOfClassMethod.invoke(null, new Object[]{c, assignable}); + } + public static long[] countInstancesofClasses(Class[] classes, boolean assignable) + throws Exception { + return (long[]) countInstancesOfClassesMethod.invoke( + null, new Object[]{classes, assignable}); + } } } |