summaryrefslogtreecommitdiff
path: root/profilers
diff options
context:
space:
mode:
authorPhil Nguyen <philnguyen@google.com>2021-12-08 13:12:39 -0800
committerTreeHugger Robot <treehugger-gerrit@google.com>2022-02-02 17:58:27 +0000
commit9e16253491d7dd7300d2e376347db14475db0e13 (patch)
tree6d62b800b30d8fc400a6ab64c016b79f74b1bc4e /profilers
parent810db14bfb62956fc87cf33cbd3f9a31a2defbfd (diff)
downloadidea-9e16253491d7dd7300d2e376347db14475db0e13.tar.gz
Refactor `MethodSet`
This change converts `MethodSet` to Kotlin, and represents `MethodSetInfo` as a sum type of 2 cases instead of one giant class with all the fields and flags tracking how an instance was contructed and whether names have been resolved. Bug: n/a Test: existing Change-Id: I2b65716db45aef619a647c037974103db6e1deef
Diffstat (limited to 'profilers')
-rw-r--r--profilers/src/com/android/tools/profilers/memory/adapters/classifiers/MethodSet.java192
-rw-r--r--profilers/src/com/android/tools/profilers/memory/adapters/classifiers/MethodSet.kt85
2 files changed, 85 insertions, 192 deletions
diff --git a/profilers/src/com/android/tools/profilers/memory/adapters/classifiers/MethodSet.java b/profilers/src/com/android/tools/profilers/memory/adapters/classifiers/MethodSet.java
deleted file mode 100644
index aaeca283ffb..00000000000
--- a/profilers/src/com/android/tools/profilers/memory/adapters/classifiers/MethodSet.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2020 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 com.android.tools.profilers.memory.adapters.classifiers;
-
-import com.android.tools.idea.codenavigation.CodeLocation;
-import com.android.tools.profiler.proto.Memory.AllocationStack;
-import com.android.tools.profilers.memory.adapters.CaptureObject;
-import com.android.tools.profilers.memory.adapters.InstanceObject;
-import com.google.common.base.Strings;
-import com.intellij.openapi.util.text.StringUtil;
-import java.util.Arrays;
-import kotlin.jvm.functions.Function1;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Classifies {@link InstanceObject}s based on a particular stack trace line of its allocation stack. If the end of the stack is reached or
- * if there's no stack, then the instances are classified under {@link ClassSet.ClassClassifier}s.
- */
-public class MethodSet extends ClassifierSet {
- @NotNull private final MethodSetInfo myMethodInfo;
- @NotNull private final CaptureObject myCaptureObject;
- private final int myCallstackDepth;
-
- @NotNull
- public static Classifier createDefaultClassifier(@NotNull CaptureObject captureObject) {
- return methodClassifier(captureObject, 0);
- }
-
- public MethodSet(@NotNull CaptureObject captureObject, @NotNull MethodSetInfo methodInfo, int callstackDepth) {
- super(() -> methodInfo.getName());
- myCaptureObject = captureObject;
- myMethodInfo = methodInfo;
- myCallstackDepth = callstackDepth;
- }
-
- @NotNull
- @Override
- public Classifier createSubClassifier() {
- return methodClassifier(myCaptureObject, myCallstackDepth);
- }
-
- @NotNull
- public String getClassName() {
- return myMethodInfo.getClassName();
- }
-
- @NotNull
- public String getMethodName() {
- return myMethodInfo.getMethodName();
- }
-
- private static Classifier methodClassifier(CaptureObject captureObject, int depth) {
- return new Classifier.Join<>(getMethodInfo(captureObject, depth), info -> new MethodSet(captureObject, info, depth + 1),
- Classifier.of(InstanceObject::getClassEntry, ClassSet::new));
- }
-
- private static Function1<InstanceObject, MethodSetInfo> getMethodInfo(CaptureObject captureObject, int depth) {
- return inst -> {
- int stackDepth = inst.getCallStackDepth();
- if (stackDepth <= 0 || depth >= stackDepth) {
- return null;
- }
- int frameIndex = stackDepth - depth - 1;
- AllocationStack stack = inst.getAllocationCallStack();
- if (stack != null) {
- switch (stack.getFrameCase()) {
- case FULL_STACK:
- AllocationStack.StackFrameWrapper fullStack = stack.getFullStack();
- AllocationStack.StackFrame stackFrame = fullStack.getFrames(frameIndex);
- return new MethodSetInfo(captureObject, stackFrame.getClassName(), stackFrame.getMethodName());
- case ENCODED_STACK:
- AllocationStack.EncodedFrameWrapper smallStack = stack.getEncodedStack();
- AllocationStack.EncodedFrame smallFrame = smallStack.getFrames(frameIndex);
- return new MethodSetInfo(captureObject, smallFrame.getMethodId());
- default:
- throw new UnsupportedOperationException();
- }
- }
-
- assert frameIndex >= 0 && frameIndex < stackDepth;
- CodeLocation location = inst.getAllocationCodeLocations().get(frameIndex);
- return new MethodSetInfo(captureObject,
- Strings.nullToEmpty(location.getClassName()),
- Strings.nullToEmpty(location.getMethodName()));
- };
- }
-
- private static final class MethodSetInfo {
- static final long INVALID_METHOD_ID = -1;
-
- @NotNull private final CaptureObject myCaptureObject;
-
- private long myMethodId;
- @Nullable private String myClassName;
- @Nullable private String myMethodName;
-
- private boolean myResolvedNames;
- private int myHashCode;
-
- MethodSetInfo(@NotNull CaptureObject captureObject, @NotNull String className, @NotNull String methodName) {
- myCaptureObject = captureObject;
- myClassName = className;
- myMethodName = methodName;
- myMethodId = INVALID_METHOD_ID;
- myHashCode = Arrays.hashCode(new int[]{myClassName.hashCode(), myMethodName.hashCode()});
- myResolvedNames = true;
- }
-
- MethodSetInfo(@NotNull CaptureObject captureObject, long methodId) {
- myCaptureObject = captureObject;
- myMethodId = methodId;
- myHashCode = Long.hashCode(myMethodId);
- myResolvedNames = false;
- }
-
- @Override
- public int hashCode() {
- return myHashCode;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof MethodSetInfo)) {
- return false;
- }
-
- MethodSetInfo other = (MethodSetInfo)obj;
- if (myMethodId == INVALID_METHOD_ID) {
- return StringUtil.equals(myClassName, other.myClassName) && StringUtil.equals(myMethodName, other.myMethodName);
- }
- else {
- return myMethodId == other.myMethodId;
- }
- }
-
- @NotNull
- String getName() {
- resolveNames();
-
- StringBuilder builder = new StringBuilder();
- if (myMethodName != null) {
- builder.append(myMethodName).append("()");
- }
- else {
- builder.append("<unknown method>");
- }
- if (!Strings.isNullOrEmpty(myClassName)) {
- builder.append(" (").append(myClassName).append(")");
- }
- return builder.toString();
- }
-
- @NotNull
- String getClassName() {
- resolveNames();
- return myClassName;
- }
-
- @NotNull
- String getMethodName() {
- resolveNames();
- return myMethodName;
- }
-
- private void resolveNames() {
- if (myResolvedNames) {
- return;
- }
-
- assert myMethodId != INVALID_METHOD_ID;
- AllocationStack.StackFrame frameInfo = myCaptureObject.getStackFrame(myMethodId);
- assert frameInfo != null;
- myClassName = frameInfo.getClassName();
- myMethodName = frameInfo.getMethodName();
- myResolvedNames = true;
- }
- }
-}
diff --git a/profilers/src/com/android/tools/profilers/memory/adapters/classifiers/MethodSet.kt b/profilers/src/com/android/tools/profilers/memory/adapters/classifiers/MethodSet.kt
new file mode 100644
index 00000000000..16b60c2eebc
--- /dev/null
+++ b/profilers/src/com/android/tools/profilers/memory/adapters/classifiers/MethodSet.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2020 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 com.android.tools.profilers.memory.adapters.classifiers
+
+import com.android.tools.profiler.proto.Memory.AllocationStack.FrameCase
+import com.android.tools.profilers.memory.adapters.CaptureObject
+import com.android.tools.profilers.memory.adapters.InstanceObject
+import com.android.tools.profilers.memory.adapters.classifiers.Classifier.Companion.of
+import com.google.common.base.Strings
+
+/**
+ * Classifies [InstanceObject]s based on a particular stack trace line of its allocation stack. If the end of the stack is reached or
+ * if there's no stack, then the instances are classified under [ClassSet.ClassClassifier]s.
+ */
+class MethodSet(private val captureObject: CaptureObject, private val methodInfo: MethodSetInfo, private val callstackDepth: Int) :
+ ClassifierSet({ methodInfo.name }) {
+
+ val className: String get() = methodInfo.className
+ val methodName: String get() = methodInfo.methodName
+
+ public override fun createSubClassifier(): Classifier = methodClassifier(captureObject, callstackDepth)
+
+ sealed class MethodSetInfo {
+ data class ByName(override val className: String, override val methodName: String): MethodSetInfo()
+ data class ById(private val captureObject: CaptureObject, private val methodId: Long): MethodSetInfo() {
+ override val className get() = classAndMethodName.first
+ override val methodName get() = classAndMethodName.second
+ private val classAndMethodName by lazy {
+ val frameInfo = captureObject.getStackFrame(methodId)!!
+ frameInfo.className to frameInfo.methodName
+ }
+ }
+ abstract val className: String
+ abstract val methodName: String
+ val name: String get() = "$methodName()${if (Strings.isNullOrEmpty(className)) "" else " ($className)"}"
+ }
+
+ companion object {
+ @JvmStatic
+ fun createDefaultClassifier(captureObject: CaptureObject): Classifier = methodClassifier(captureObject, 0)
+
+ private fun methodClassifier(captureObject: CaptureObject, depth: Int) =
+ Classifier.Join(getMethodInfo(captureObject, depth), { MethodSet(captureObject, it, depth + 1) },
+ of(InstanceObject::getClassEntry, ::ClassSet))
+
+ private fun getMethodInfo(captureObject: CaptureObject, depth: Int): (InstanceObject) -> MethodSetInfo? = { inst ->
+ val stackDepth = inst.callStackDepth
+ when {
+ stackDepth <= 0 || depth >= stackDepth -> null
+ else -> {
+ val frameIndex = stackDepth - depth - 1
+ val stack = inst.allocationCallStack
+ when {
+ stack == null -> {
+ val location = inst.allocationCodeLocations[frameIndex]
+ MethodSetInfo.ByName(Strings.nullToEmpty(location.className), Strings.nullToEmpty(location.methodName))
+ }
+ stack.frameCase == FrameCase.FULL_STACK -> {
+ val stackFrame = stack.fullStack.getFrames(frameIndex)
+ MethodSetInfo.ByName(stackFrame.className, stackFrame.methodName)
+ }
+ stack.frameCase == FrameCase.ENCODED_STACK -> {
+ val smallFrame = stack.encodedStack.getFrames(frameIndex)
+ MethodSetInfo.ById(captureObject, smallFrame.methodId)
+ }
+ else -> throw UnsupportedOperationException()
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file