blob: b59f64232118eb22a1638bb41ba8e6c1255c4738 [file] [log] [blame]
// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.errors;
import com.android.tools.r8.Diagnostic;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.keepanno.annotations.KeepForApi;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.Position;
import com.android.tools.r8.profile.startup.profile.StartupProfile;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import java.util.List;
@KeepForApi
public class StartupClassesNonStartupFractionDiagnostic implements Diagnostic {
private final int numberOfStartupClasses;
private final int numberOfStartupMethods;
private final int numberOfNonStartupMethods;
private final Int2IntMap numberOfStartupClassesByNumberOfStartupMethods;
StartupClassesNonStartupFractionDiagnostic(
int numberOfStartupClasses,
int numberOfStartupMethods,
int numberOfNonStartupMethods,
Int2IntMap numberOfStartupClassesByNumberOfStartupMethods) {
this.numberOfStartupClasses = numberOfStartupClasses;
this.numberOfStartupMethods = numberOfStartupMethods;
this.numberOfNonStartupMethods = numberOfNonStartupMethods;
this.numberOfStartupClassesByNumberOfStartupMethods =
numberOfStartupClassesByNumberOfStartupMethods;
}
@Override
public Origin getOrigin() {
return Origin.unknown();
}
@Override
public Position getPosition() {
return Position.UNKNOWN;
}
@Override
public String getDiagnosticMessage() {
return String.format(
"Startup DEX files contains %d classes and %d methods of which %d (%d%%) are non-startup "
+ "methods. Distribution of classes by their number of startup methods:\n"
+ "0: %d classes\n"
+ "1: %d classes\n"
+ "2-3: %d classes\n"
+ "4-5: %d classes\n"
+ "6-10: %d classes\n"
+ "11+: %d classes\n",
numberOfStartupClasses,
numberOfStartupMethods + numberOfNonStartupMethods,
numberOfNonStartupMethods,
Math.round(
(((double) numberOfNonStartupMethods)
/ (numberOfStartupMethods + numberOfNonStartupMethods))
* 100.0),
numberOfStartupClassesByNumberOfStartupMethods.get(0),
numberOfStartupClassesByNumberOfStartupMethods.get(1),
numberOfStartupClassesByNumberOfStartupMethods.get(2)
+ numberOfStartupClassesByNumberOfStartupMethods.get(3),
numberOfStartupClassesByNumberOfStartupMethods.get(4)
+ numberOfStartupClassesByNumberOfStartupMethods.get(5),
numberOfStartupClassesByNumberOfStartupMethods.get(6)
+ numberOfStartupClassesByNumberOfStartupMethods.get(7)
+ numberOfStartupClassesByNumberOfStartupMethods.get(8)
+ numberOfStartupClassesByNumberOfStartupMethods.get(9)
+ numberOfStartupClassesByNumberOfStartupMethods.get(10),
numberOfStartupClassesByNumberOfStartupMethods.int2IntEntrySet().stream()
.map(entry -> entry.getIntKey() > 10 ? entry.getIntValue() : 0)
.reduce(0, Integer::sum));
}
// Public factory to keep the constructor of the diagnostic out of the public API.
public static class Factory {
public static StartupClassesNonStartupFractionDiagnostic
createStartupClassesNonStartupFractionDiagnostic(
List<DexProgramClass> startupClasses, StartupProfile startupProfile) {
assert !startupClasses.isEmpty();
assert !startupProfile.isEmpty();
int numberOfStartupClasses = startupClasses.size();
int numberOfStartupMethods = 0;
int numberOfNonStartupMethods = 0;
Int2IntMap numberOfStartupClassesByNumberOfStartupMethods = new Int2IntOpenHashMap();
numberOfStartupClassesByNumberOfStartupMethods.defaultReturnValue(0);
for (DexProgramClass clazz : startupClasses) {
assert startupProfile.isStartupClass(clazz.getType());
int numberOfStartupMethodsInClass = 0;
for (DexEncodedMethod method : clazz.methods()) {
if (startupProfile.containsMethodRule(method.getReference())) {
numberOfStartupMethodsInClass++;
} else {
numberOfNonStartupMethods++;
}
}
numberOfStartupMethods += numberOfStartupMethodsInClass;
numberOfStartupClassesByNumberOfStartupMethods.put(
numberOfStartupMethodsInClass,
numberOfStartupClassesByNumberOfStartupMethods.get(numberOfStartupMethodsInClass) + 1);
}
return createStartupClassesNonStartupFractionDiagnostic(
numberOfStartupClasses,
numberOfStartupMethods,
numberOfNonStartupMethods,
numberOfStartupClassesByNumberOfStartupMethods);
}
public static StartupClassesNonStartupFractionDiagnostic
createStartupClassesNonStartupFractionDiagnostic(
int numberOfStartupClasses,
int numberOfStartupMethods,
int numberOfNonStartupMethods,
Int2IntMap numberOfStartupClassesByNumberOfStartupMethods) {
return new StartupClassesNonStartupFractionDiagnostic(
numberOfStartupClasses,
numberOfStartupMethods,
numberOfNonStartupMethods,
numberOfStartupClassesByNumberOfStartupMethods);
}
}
}