|  | /* | 
|  | * 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.util.List; | 
|  | import java.util.ArrayList; | 
|  | import java.io.Serializable; | 
|  |  | 
|  | /** | 
|  | * An operation with a duration. Could represent a class load or initialization. | 
|  | */ | 
|  | class Operation implements Serializable { | 
|  |  | 
|  | private static final long serialVersionUID = 0; | 
|  |  | 
|  | /** | 
|  | * Type of operation. | 
|  | */ | 
|  | enum Type { | 
|  | LOAD, INIT | 
|  | } | 
|  |  | 
|  | /** Process this operation occurred in. */ | 
|  | final Proc process; | 
|  |  | 
|  | /** Start time for this operation. */ | 
|  | final long startTimeNanos; | 
|  |  | 
|  | /** Index of this operation relative to its process. */ | 
|  | final int index; | 
|  |  | 
|  | /** Type of operation. */ | 
|  | final Type type; | 
|  |  | 
|  | /** End time for this operation. */ | 
|  | long endTimeNanos = -1; | 
|  |  | 
|  | /** The class that this operation loaded or initialized. */ | 
|  | final LoadedClass loadedClass; | 
|  |  | 
|  | /** Other operations that occurred during this one. */ | 
|  | final List<Operation> subops = new ArrayList<Operation>(); | 
|  |  | 
|  | /** Constructs a new operation. */ | 
|  | Operation(Proc process, LoadedClass loadedClass, long startTimeNanos, | 
|  | int index, Type type) { | 
|  | this.process = process; | 
|  | this.loadedClass = loadedClass; | 
|  | this.startTimeNanos = startTimeNanos; | 
|  | this.index = index; | 
|  | this.type = type; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns how long this class initialization and all the nested class | 
|  | * initializations took. | 
|  | */ | 
|  | private long inclusiveTimeNanos() { | 
|  | if (endTimeNanos == -1) { | 
|  | throw new IllegalStateException("End time hasn't been set yet: " | 
|  | + loadedClass.name); | 
|  | } | 
|  |  | 
|  | return endTimeNanos - startTimeNanos; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns how long this class initialization took. | 
|  | */ | 
|  | int exclusiveTimeMicros() { | 
|  | long exclusive = inclusiveTimeNanos(); | 
|  |  | 
|  | for (Operation child : subops) { | 
|  | exclusive -= child.inclusiveTimeNanos(); | 
|  | } | 
|  |  | 
|  | if (exclusive < 0) { | 
|  | throw new AssertionError(loadedClass.name); | 
|  | } | 
|  |  | 
|  | return nanosToMicros(exclusive); | 
|  | } | 
|  |  | 
|  | /** Gets the median time that this operation took across all processes. */ | 
|  | int medianExclusiveTimeMicros() { | 
|  | switch (type) { | 
|  | case LOAD: return loadedClass.medianLoadTimeMicros(); | 
|  | case INIT: return loadedClass.medianInitTimeMicros(); | 
|  | default: throw new AssertionError(); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Converts nanoseconds to microseconds. | 
|  | * | 
|  | * @throws RuntimeException if overflow occurs | 
|  | */ | 
|  | private static int nanosToMicros(long nanos) { | 
|  | long micros = nanos / 1000; | 
|  | int microsInt = (int) micros; | 
|  | if (microsInt != micros) { | 
|  | throw new RuntimeException("Integer overflow: " + nanos); | 
|  | } | 
|  | return microsInt; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Primarily for debugger support | 
|  | */ | 
|  | @Override | 
|  | public String toString() { | 
|  | StringBuilder sb = new StringBuilder(); | 
|  | sb.append(type.toString()); | 
|  | sb.append(' '); | 
|  | sb.append(loadedClass.toString()); | 
|  | if (subops.size() > 0) { | 
|  | sb.append(" ("); | 
|  | sb.append(subops.size()); | 
|  | sb.append(" sub ops)"); | 
|  | } | 
|  | return sb.toString(); | 
|  | } | 
|  |  | 
|  | } |