/*
* 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;
}
}