/* * Copyright (C) 2008 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. */ import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; /** * A loaded class. */ class LoadedClass implements Serializable, Comparable<LoadedClass> { private static final long serialVersionUID = 0; /** Class name. */ final String name; /** Load operations. */ final List<Operation> loads = new ArrayList<Operation>(); /** Static initialization operations. */ final List<Operation> initializations = new ArrayList<Operation>(); /** Memory usage gathered by loading only this class in its own VM. */ MemoryUsage memoryUsage = MemoryUsage.NOT_AVAILABLE; /** * Whether or not this class was loaded in the system class loader. */ final boolean systemClass; /** Whether or not this class will be preloaded. */ boolean preloaded; /** Constructs a new class. */ LoadedClass(String name, boolean systemClass) { this.name = name; this.systemClass = systemClass; } /** * Returns true if this class was loaded by more than one proc. */ boolean isSharable() { Set<String> procNames = new HashSet<String>(); for (Operation load : loads) { if (load.process.fromZygote()) { procNames.add(load.process.name); if (procNames.size() > 1) { return true; } } } for (Operation init : initializations) { if (init.process.fromZygote()) { procNames.add(init.process.name); if (procNames.size() > 1) { return true; } } } return false; } void measureMemoryUsage() { this.memoryUsage = MemoryUsage.forClass(name); } int mlt = -1; /** Median time to load this class. */ int medianLoadTimeMicros() { if (mlt != -1) { return mlt; } return mlt = calculateMedian(loads); } int mit = -1; /** Median time to initialize this class. */ int medianInitTimeMicros() { if (mit != -1) { return mit; } return mit = calculateMedian(initializations); } int medianTimeMicros() { return medianInitTimeMicros() + medianLoadTimeMicros(); } /** Calculates the median duration for a list of operations. */ private static int calculateMedian(List<Operation> operations) { int size = operations.size(); if (size == 0) { return 0; } int[] times = new int[size]; for (int i = 0; i < size; i++) { times[i] = operations.get(i).exclusiveTimeMicros(); } Arrays.sort(times); int middle = size / 2; if (size % 2 == 1) { // Odd return times[middle]; } else { // Even -- average the two. return (times[middle - 1] + times[middle]) / 2; } } /** Returns names of processes that loaded this class. */ Set<String> processNames() { Set<String> names = new HashSet<String>(); addProcessNames(loads, names); addProcessNames(initializations, names); return names; } private void addProcessNames(List<Operation> ops, Set<String> names) { for (Operation operation : ops) { if (operation.process.fromZygote()) { names.add(operation.process.name); } } } public int compareTo(LoadedClass o) { return name.compareTo(o.name); } @Override public String toString() { return name; } }