summaryrefslogtreecommitdiffstats
path: root/tools/preload/Operation.java
blob: 4f1938e66ebd4da02b5c6a7a53a6c9afb0b5ad54 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
 * 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();
    }

}