Log StringOptimizer usage.
Bug: 118536394, 120138731
Change-Id: Ifa36fefe687149e18adf48c4332c5e080606a959
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 4e2e013..c09d73a 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -697,6 +697,9 @@
if (uninstantiatedTypeOptimization != null) {
uninstantiatedTypeOptimization.logResults();
}
+ if (stringOptimizer != null) {
+ stringOptimizer.logResult();
+ }
if (stringBuilderOptimizer != null) {
stringBuilderOptimizer.logResults();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
index 1ccf6df..f368351 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
@@ -30,7 +30,12 @@
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.code.InvokeVirtual;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.logging.Log;
import com.android.tools.r8.naming.dexitembasedstring.ClassNameComputationInfo;
+import com.android.tools.r8.naming.dexitembasedstring.ClassNameComputationInfo.ClassNameMapping;
+import com.android.tools.r8.utils.StringUtils;
+import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
import java.util.function.BiFunction;
import java.util.function.Function;
@@ -40,10 +45,60 @@
private final DexItemFactory factory;
private final ThrowingInfo throwingInfo;
+ private int numberOfSimplifiedOperations = 0;
+ private final Object2IntMap<ClassNameMapping> numberOfComputedNames;
+ private final Object2IntMap<ClassNameMapping> numberOfDeferredComputationOfNames;
+ private final Object2IntMap<Integer> histogramOfLengthOfNames;
+ private final Object2IntMap<Integer> histogramOfLengthOfDeferredNames;
+ private int numberOfSimplifiedConversions = 0;
+
public StringOptimizer(AppView<?> appView) {
this.appView = appView;
this.factory = appView.dexItemFactory();
this.throwingInfo = ThrowingInfo.defaultForConstString(appView.options());
+ if (Log.ENABLED) {
+ numberOfComputedNames = new Object2IntArrayMap<>();
+ numberOfDeferredComputationOfNames = new Object2IntArrayMap<>();
+ histogramOfLengthOfNames = new Object2IntArrayMap<>();
+ histogramOfLengthOfDeferredNames = new Object2IntArrayMap<>();
+ } else {
+ numberOfComputedNames = null;
+ numberOfDeferredComputationOfNames = null;
+ histogramOfLengthOfNames = null;
+ histogramOfLengthOfDeferredNames = null;
+ }
+ }
+
+ public void logResult() {
+ assert Log.ENABLED;
+ Log.info(getClass(),
+ "# trivial operations on const-string: %s", numberOfSimplifiedOperations);
+ Log.info(getClass(),
+ "# trivial conversions from/to const-string: %s", numberOfSimplifiedConversions);
+ assert numberOfComputedNames != null;
+ Log.info(getClass(), "------ # of get*Name() computation ------");
+ numberOfComputedNames.forEach((kind, count) -> {
+ Log.info(getClass(),
+ "%s: %s (%s)", kind, StringUtils.times("*", Math.min(count, 53)), count);
+ });
+ assert numberOfDeferredComputationOfNames != null;
+ Log.info(getClass(), "------ # of deferred get*Name() computation ------");
+ numberOfDeferredComputationOfNames.forEach((kind, count) -> {
+ Log.info(getClass(),
+ "%s: %s (%s)", kind, StringUtils.times("*", Math.min(count, 53)), count);
+ });
+ assert histogramOfLengthOfNames != null;
+ Log.info(getClass(), "------ histogram of get*Name() result lengths ------");
+ histogramOfLengthOfNames.forEach((length, count) -> {
+ Log.info(getClass(),
+ "%s: %s (%s)", length, StringUtils.times("*", Math.min(count, 53)), count);
+ });
+ assert histogramOfLengthOfDeferredNames != null;
+ Log.info(getClass(), "------ histogram of original type length for deferred get*Name() ------");
+ histogramOfLengthOfDeferredNames.forEach((length, count) -> {
+ Log.info(getClass(),
+ "%s: %s (%s)", length, StringUtils.times("*", Math.min(count, 53)), count);
+ });
}
// int String#length()
@@ -119,6 +174,7 @@
invoke.getLocalInfo());
it.replaceCurrentInstruction(
new ConstString(stringValue, factory.createString(sub), throwingInfo));
+ numberOfSimplifiedOperations++;
continue;
}
@@ -196,6 +252,7 @@
constNumber = code.createIntConstant(v);
}
+ numberOfSimplifiedOperations++;
it.replaceCurrentInstruction(constNumber);
}
}
@@ -280,8 +337,10 @@
baseType,
ClassNameComputationInfo.create(NAME, arrayDepth),
throwingInfo);
+ logDeferredNameComputation(NAME);
} else {
name = NAME.map(descriptor, holder, factory, arrayDepth);
+ logNameComputation(NAME);
}
} else if (invokedMethod == factory.classMethods.getTypeName) {
// TODO(b/119426668): desugar Type#getTypeName
@@ -305,8 +364,10 @@
baseType,
ClassNameComputationInfo.create(CANONICAL_NAME, arrayDepth),
throwingInfo);
+ logDeferredNameComputation(CANONICAL_NAME);
} else {
name = CANONICAL_NAME.map(descriptor, holder, factory, arrayDepth);
+ logNameComputation(CANONICAL_NAME);
}
}
} else if (invokedMethod == factory.classMethods.getSimpleName) {
@@ -327,8 +388,10 @@
baseType,
ClassNameComputationInfo.create(SIMPLE_NAME, arrayDepth),
throwingInfo);
+ logDeferredNameComputation(SIMPLE_NAME);
} else {
name = SIMPLE_NAME.map(descriptor, holder, factory, arrayDepth);
+ logNameComputation(SIMPLE_NAME);
}
}
}
@@ -339,9 +402,11 @@
invoke.getLocalInfo());
ConstString constString = new ConstString(stringValue, name, throwingInfo);
it.replaceCurrentInstruction(constString);
+ logHistogramOfNames(name);
} else if (deferred != null) {
it.replaceCurrentInstruction(deferred);
markUseIdentifierNameString = true;
+ logHistogramOfNames(deferred);
}
}
if (markUseIdentifierNameString) {
@@ -349,6 +414,46 @@
}
}
+ private void logNameComputation(ClassNameMapping kind) {
+ if (Log.ENABLED && Log.isLoggingEnabledFor(StringOptimizer.class)) {
+ synchronized (numberOfComputedNames) {
+ int count = numberOfComputedNames.getOrDefault(kind, 0);
+ numberOfComputedNames.put(kind, count + 1);
+ }
+ }
+ }
+
+ private void logHistogramOfNames(DexString name) {
+ if (Log.ENABLED && Log.isLoggingEnabledFor(StringOptimizer.class)) {
+ Integer length = name.size;
+ synchronized (histogramOfLengthOfNames) {
+ int count = histogramOfLengthOfNames.getOrDefault(length, 0);
+ histogramOfLengthOfNames.put(length, count + 1);
+ }
+ }
+ }
+
+ private void logDeferredNameComputation(ClassNameMapping kind) {
+ if (Log.ENABLED && Log.isLoggingEnabledFor(StringOptimizer.class)) {
+ synchronized (numberOfDeferredComputationOfNames) {
+ int count = numberOfDeferredComputationOfNames.getOrDefault(kind, 0);
+ numberOfDeferredComputationOfNames.put(kind, count + 1);
+ }
+ }
+ }
+
+ private void logHistogramOfNames(DexItemBasedConstString deferred) {
+ if (Log.ENABLED && Log.isLoggingEnabledFor(StringOptimizer.class)) {
+ assert deferred.getItem().isDexType();
+ DexType original = deferred.getItem().asDexType();
+ Integer length = original.descriptor.size;
+ synchronized (histogramOfLengthOfDeferredNames) {
+ int count = histogramOfLengthOfDeferredNames.getOrDefault(length, 0);
+ histogramOfLengthOfDeferredNames.put(length, count + 1);
+ }
+ }
+ }
+
// String#valueOf(null) -> "null"
// String#valueOf(String s) -> s
// str.toString() -> str
@@ -376,6 +481,7 @@
ConstString nullString =
new ConstString(nullStringValue, factory.createString("null"), throwingInfo);
it.replaceCurrentInstruction(nullString);
+ numberOfSimplifiedConversions++;
} else if (inType.nullability().isDefinitelyNotNull()
&& inType.isClassType()
&& inType.asClassTypeLatticeElement().getClassType().equals(factory.stringType)) {
@@ -385,6 +491,7 @@
} else {
it.removeOrReplaceByDebugLocalRead();
}
+ numberOfSimplifiedConversions++;
}
} else if (instr.isInvokeVirtual()) {
InvokeVirtual invoke = instr.asInvokeVirtual();
@@ -404,6 +511,7 @@
} else {
it.removeOrReplaceByDebugLocalRead();
}
+ numberOfSimplifiedConversions++;
}
}
}