summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Alex Light <allight@google.com> 2017-07-06 14:12:13 -0700
committer Alex Light <allight@google.com> 2017-07-07 08:54:58 -0700
commitc19cd2faf041a71e1b16af70109e301905aa01b8 (patch)
tree35cdb586302bbcaffbe1d37647dd5b54ced403ab
parent8ddfd9f66af232d0beb706881e1e0764c44b4a63 (diff)
Track jvmti allocations related to object tagging
Object tagging overhead can be significant. We now surface that overhead via the jvmti-extension for memory use. Test: ./test.py --host -j40 Bug: 62065509 Change-Id: Id0b98e74d66a1a99ac89186176ade39c922569cd
-rw-r--r--runtime/openjdkjvmti/jvmti_allocator.h10
-rw-r--r--runtime/openjdkjvmti/jvmti_weak_table.h7
-rw-r--r--runtime/openjdkjvmti/ti_allocator.cc17
-rw-r--r--runtime/openjdkjvmti/ti_allocator.h11
-rw-r--r--test/1900-track-alloc/src/art/Main.java32
-rw-r--r--test/1900-track-alloc/src/art/Test1900.java9
6 files changed, 78 insertions, 8 deletions
diff --git a/runtime/openjdkjvmti/jvmti_allocator.h b/runtime/openjdkjvmti/jvmti_allocator.h
index 1225c143f9..44b1cb1c20 100644
--- a/runtime/openjdkjvmti/jvmti_allocator.h
+++ b/runtime/openjdkjvmti/jvmti_allocator.h
@@ -36,6 +36,8 @@
#include "base/macros.h"
#include "jvmti.h"
+#include "ti_allocator.h"
+
namespace openjdkjvmti {
template <typename T> class JvmtiAllocator;
@@ -53,6 +55,7 @@ class JvmtiAllocator<void> {
};
explicit JvmtiAllocator(jvmtiEnv* env) : env_(env) {}
+ explicit JvmtiAllocator() : env_(nullptr) {}
template <typename U>
JvmtiAllocator(const JvmtiAllocator<U>& other) // NOLINT, implicit
@@ -89,6 +92,7 @@ class JvmtiAllocator {
};
explicit JvmtiAllocator(jvmtiEnv* env) : env_(env) {}
+ explicit JvmtiAllocator() : env_(nullptr) {}
template <typename U>
JvmtiAllocator(const JvmtiAllocator<U>& other) // NOLINT, implicit
@@ -108,8 +112,8 @@ class JvmtiAllocator {
pointer allocate(size_type n, JvmtiAllocator<void>::pointer hint ATTRIBUTE_UNUSED = nullptr) {
DCHECK_LE(n, max_size());
if (env_ == nullptr) {
- T* result = reinterpret_cast<T*>(malloc(n * sizeof(T)));
- CHECK(result != nullptr || n == 0u); // Abort if malloc() fails.
+ T* result = reinterpret_cast<T*>(AllocUtil::AllocateImpl(n * sizeof(T)));
+ CHECK(result != nullptr || n == 0u); // Abort if AllocateImpl() fails.
return result;
} else {
unsigned char* result;
@@ -120,7 +124,7 @@ class JvmtiAllocator {
}
void deallocate(pointer p, size_type n ATTRIBUTE_UNUSED) {
if (env_ == nullptr) {
- free(p);
+ AllocUtil::DeallocateImpl(reinterpret_cast<unsigned char*>(p));
} else {
jvmtiError dealloc_error = env_->Deallocate(reinterpret_cast<unsigned char*>(p));
CHECK(dealloc_error == JVMTI_ERROR_NONE);
diff --git a/runtime/openjdkjvmti/jvmti_weak_table.h b/runtime/openjdkjvmti/jvmti_weak_table.h
index 01c24b1917..a5175a42ba 100644
--- a/runtime/openjdkjvmti/jvmti_weak_table.h
+++ b/runtime/openjdkjvmti/jvmti_weak_table.h
@@ -40,6 +40,7 @@
#include "gc_root-inl.h"
#include "globals.h"
#include "jvmti.h"
+#include "jvmti_allocator.h"
#include "mirror/object.h"
#include "thread-current-inl.h"
@@ -191,7 +192,7 @@ class JvmtiWeakTable : public art::gc::SystemWeakHolder {
REQUIRES_SHARED(art::Locks::mutator_lock_)
REQUIRES(allow_disallow_lock_);
- template <typename Storage, class Allocator = std::allocator<T>>
+ template <typename Storage, class Allocator = JvmtiAllocator<T>>
struct ReleasableContainer;
struct HashGcRoot {
@@ -209,10 +210,12 @@ class JvmtiWeakTable : public art::gc::SystemWeakHolder {
}
};
+ using TagAllocator = JvmtiAllocator<std::pair<const art::GcRoot<art::mirror::Object>, T>>;
std::unordered_map<art::GcRoot<art::mirror::Object>,
T,
HashGcRoot,
- EqGcRoot> tagged_objects_
+ EqGcRoot,
+ TagAllocator> tagged_objects_
GUARDED_BY(allow_disallow_lock_)
GUARDED_BY(art::Locks::mutator_lock_);
// To avoid repeatedly scanning the whole table, remember if we did that since the last sweep.
diff --git a/runtime/openjdkjvmti/ti_allocator.cc b/runtime/openjdkjvmti/ti_allocator.cc
index b82c4f4122..8a0237d6c3 100644
--- a/runtime/openjdkjvmti/ti_allocator.cc
+++ b/runtime/openjdkjvmti/ti_allocator.cc
@@ -59,20 +59,31 @@ jvmtiError AllocUtil::Allocate(jvmtiEnv* env ATTRIBUTE_UNUSED,
*mem_ptr = nullptr;
return OK;
}
- *mem_ptr = reinterpret_cast<unsigned char*>(malloc(size));
+ *mem_ptr = AllocateImpl(size);
if (UNLIKELY(*mem_ptr == nullptr)) {
return ERR(OUT_OF_MEMORY);
}
- allocated += malloc_usable_size(*mem_ptr);
return OK;
}
+unsigned char* AllocUtil::AllocateImpl(jlong size) {
+ unsigned char* ret = size != 0 ? reinterpret_cast<unsigned char*>(malloc(size)) : nullptr;
+ if (LIKELY(ret != nullptr)) {
+ allocated += malloc_usable_size(ret);
+ }
+ return ret;
+}
+
jvmtiError AllocUtil::Deallocate(jvmtiEnv* env ATTRIBUTE_UNUSED, unsigned char* mem) {
+ DeallocateImpl(mem);
+ return OK;
+}
+
+void AllocUtil::DeallocateImpl(unsigned char* mem) {
if (mem != nullptr) {
allocated -= malloc_usable_size(mem);
free(mem);
}
- return OK;
}
} // namespace openjdkjvmti
diff --git a/runtime/openjdkjvmti/ti_allocator.h b/runtime/openjdkjvmti/ti_allocator.h
index aba77ae2fb..35575c3884 100644
--- a/runtime/openjdkjvmti/ti_allocator.h
+++ b/runtime/openjdkjvmti/ti_allocator.h
@@ -36,16 +36,27 @@
#include "jvmti.h"
#include <atomic>
+#include <memory>
namespace openjdkjvmti {
+template<typename T>
+class JvmtiAllocator;
+
class AllocUtil {
public:
static jvmtiError Allocate(jvmtiEnv* env, jlong size, unsigned char** mem_ptr);
static jvmtiError Deallocate(jvmtiEnv* env, unsigned char* mem);
static jvmtiError GetGlobalJvmtiAllocationState(jvmtiEnv* env, jlong* total_allocated);
+
private:
+ static void DeallocateImpl(unsigned char* mem);
+ static unsigned char* AllocateImpl(jlong size);
+
static std::atomic<jlong> allocated;
+
+ template <typename T>
+ friend class JvmtiAllocator;
};
} // namespace openjdkjvmti
diff --git a/test/1900-track-alloc/src/art/Main.java b/test/1900-track-alloc/src/art/Main.java
new file mode 100644
index 0000000000..aa5498bd62
--- /dev/null
+++ b/test/1900-track-alloc/src/art/Main.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+// Binder class so the agent's C code has something that can be bound and exposed to tests.
+// In a package to separate cleanly and work around CTS reference issues (though this class
+// should be replaced in the CTS version).
+public class Main {
+ // Load the given class with the given classloader, and bind all native methods to corresponding
+ // C methods in the agent. Will abort if any of the steps fail.
+ public static native void bindAgentJNI(String className, ClassLoader classLoader);
+ // Same as above, giving the class directly.
+ public static native void bindAgentJNIForClass(Class<?> klass);
+
+ // Common infrastructure.
+ public static native void setTag(Object o, long tag);
+ public static native long getTag(Object o);
+}
diff --git a/test/1900-track-alloc/src/art/Test1900.java b/test/1900-track-alloc/src/art/Test1900.java
index 717999bed5..becee1b15c 100644
--- a/test/1900-track-alloc/src/art/Test1900.java
+++ b/test/1900-track-alloc/src/art/Test1900.java
@@ -124,6 +124,15 @@ public class Test1900 {
// Back to normal after getting rid of the envs.
checkEq(base_state + 0, getAmountAllocated());
+
+ // Try adding some tags
+ Object a = new Object();
+ Object b = new Object();
+ Main.setTag(a, 100);
+ Main.setTag(b, 200);
+
+ // tags should be counted and should have some data associated with them.
+ checkLE(base_state + 1, getAmountAllocated());
}
private static native long doAllocate(long jvmtienv, long size);