diff options
author | Phil Nguyen <philnguyen@google.com> | 2021-12-08 13:12:39 -0800 |
---|---|---|
committer | TreeHugger Robot <treehugger-gerrit@google.com> | 2022-02-02 17:58:27 +0000 |
commit | 9e16253491d7dd7300d2e376347db14475db0e13 (patch) | |
tree | 6d62b800b30d8fc400a6ab64c016b79f74b1bc4e /profilers | |
parent | 810db14bfb62956fc87cf33cbd3f9a31a2defbfd (diff) | |
download | idea-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.java | 192 | ||||
-rw-r--r-- | profilers/src/com/android/tools/profilers/memory/adapters/classifiers/MethodSet.kt | 85 |
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 |