-
Notifications
You must be signed in to change notification settings - Fork 0
/
MethodProfileData.java
204 lines (199 loc) · 9.9 KB
/
MethodProfileData.java
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
package com.mmt.travel.app.NFR.Latency;
/**
* Created by mmt6054 on 09/10/18.
*/
import android.support.annotation.Nullable;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Maps;
import com.google.common.collect.Table;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/** Statistics per method. */
public class MethodProfileData {
/*TimeUnit for all time values stored in this model. */
private static final TimeUnit DATA_TIME_UNITS = TimeUnit.NANOSECONDS;
/* Stats maintained per thread. Key is thread id. */
private final Map<Integer, MethodStats> mPerThreadCumulativeStats;
/** Stats maintained per thread and per callee. */
private final Table<Integer, Long, MethodStats> mPerThreadStatsByCallee;
/** Stats maintained per thread and per caller. */
private final Table<Integer, Long, MethodStats> mPerThreadStatsByCaller;
/** Indicates whether this method was ever used recursively. */
private final boolean mIsRecursive;
private MethodProfileData(Builder b) {
mPerThreadCumulativeStats = ImmutableMap.copyOf(b.mPerThreadCumulativeStats);
mPerThreadStatsByCallee = ImmutableTable.copyOf(b.mPerThreadStatsByCallee);
mPerThreadStatsByCaller = ImmutableTable.copyOf(b.mPerThreadStatsByCaller);
mIsRecursive = b.mRecursive;
}
/** Returns the number of invocations of this method in a given thread. */
public long getInvocationCount(ThreadInfo thread) {
MethodStats stats = mPerThreadCumulativeStats.get(thread.getId());
return getInvocationCount(stats);
}
public long getInvocationCountFromCaller(ThreadInfo thread, Long callerId) {
MethodStats stats = mPerThreadStatsByCaller.get(thread.getId(), callerId);
return getInvocationCount(stats);
}
/** Returns whether this method was ever called recursively. */
public boolean isRecursive() {
return mIsRecursive;
}
/** Returns the exclusive time of this method in a particular thread in the given time units. */
public long getExclusiveTime(ThreadInfo thread, ClockType clockType, TimeUnit unit) {
MethodStats stats = mPerThreadCumulativeStats.get(thread.getId());
return getExclusiveTime(stats, clockType, unit);
}
/** Returns the inclusive time of this method in a particular thread in the given time units. */
public long getInclusiveTime(ThreadInfo thread, ClockType clockType, TimeUnit unit) {
MethodStats stats = mPerThreadCumulativeStats.get(thread.getId());
return getInclusiveTime(stats, clockType, unit);
}
/** Returns the callers for this method in a given thread. (across all its invocations). */
public Set<Long> getCallers(ThreadInfo thread) {
Map<Long, MethodStats> perCallerStats = mPerThreadStatsByCaller.row(thread.getId());
return perCallerStats.keySet();
}
/** Returns the callees from this method in a given thread. (across all its invocations). */
public Set<Long> getCallees(ThreadInfo thread) {
Map<Long, MethodStats> perCalleeStats = mPerThreadStatsByCallee.row(thread.getId());
return perCalleeStats.keySet();
}
/** Returns the exclusive time of this method when called from the given caller method. */
public long getExclusiveTimeByCaller(ThreadInfo thread, Long callerId,
ClockType clockType, TimeUnit unit) {
MethodStats stats = mPerThreadStatsByCaller.get(thread.getId(), callerId);
return getExclusiveTime(stats, clockType, unit);
}
/** Returns the inclusive time of this method when called from the given caller method. */
public long getInclusiveTimeByCaller(ThreadInfo thread, Long callerId,
ClockType clockType, TimeUnit unit) {
MethodStats stats = mPerThreadStatsByCaller.get(thread.getId(), callerId);
return getInclusiveTime(stats, clockType, unit);
}
/** Returns the inclusive time of the callee when called from this method. */
public long getInclusiveTimeByCallee(ThreadInfo thread, Long calleeId,
ClockType clockType, TimeUnit unit) {
MethodStats stats = mPerThreadStatsByCallee.get(thread.getId(), calleeId);
return getInclusiveTime(stats, clockType, unit);
}
private long getExclusiveTime(@Nullable MethodStats stats, ClockType clockType, TimeUnit unit) {
return stats != null ? stats.getExclusiveTime(clockType, unit) : 0;
}
private long getInclusiveTime(@Nullable MethodStats stats, ClockType clockType,
TimeUnit unit) {
return stats != null ? stats.getInclusiveTime(clockType, unit) : 0;
}
private long getInvocationCount(MethodStats stats) {
return stats != null ? stats.getInvocationCount() : 0;
}
private static class MethodStats {
private long mInclusiveThreadTime;
private long mExclusiveThreadTime;
private long mInclusiveGlobalTime;
private long mExclusiveGlobalTime;
private long mInvocationCount;
public long getInclusiveTime(ClockType clockType, TimeUnit unit) {
long time = clockType == ClockType.THREAD ? mInclusiveThreadTime : mInclusiveGlobalTime;
return unit.convert(time, DATA_TIME_UNITS);
}
public long getExclusiveTime(ClockType clockType, TimeUnit unit) {
long time = clockType == ClockType.THREAD ? mExclusiveThreadTime : mExclusiveGlobalTime;
return unit.convert(time, DATA_TIME_UNITS);
}
private long getInvocationCount() {
return mInvocationCount;
}
}
public static class Builder {
private final Map<Integer, MethodStats> mPerThreadCumulativeStats = Maps.newHashMap();
private final Table<Integer, Long, MethodStats> mPerThreadStatsByCaller =
HashBasedTable.create();
private final Table<Integer, Long, MethodStats> mPerThreadStatsByCallee =
HashBasedTable.create();
private boolean mRecursive;
public void addCallTime(Call call, Call parent, ThreadInfo thread) {
for (ClockType type: ClockType.values()) {
addExclusiveTime(call, parent, thread, type);
if (!call.isRecursive()) {
addInclusiveTime(call, parent, thread, type);
}
}
}
private void addExclusiveTime(Call call, Call parent, ThreadInfo thread, ClockType type) {
long time = call.getExclusiveTime(type, DATA_TIME_UNITS);
addExclusiveTime(getPerThreadStats(thread), time, type);
if (parent != null) {
addExclusiveTime(getPerCallerStats(thread, parent), time, type);
}
}
private void addInclusiveTime(Call call, Call parent, ThreadInfo thread, ClockType type) {
long time = call.getInclusiveTime(type, DATA_TIME_UNITS);
addInclusiveTime(getPerThreadStats(thread), time, type);
if (parent != null) {
addInclusiveTime(getPerCallerStats(thread, parent), time, type);
}
for (Call callee: call.getCallees()) {
addInclusiveTime(getPerCalleeStats(thread, callee),
callee.getInclusiveTime(type, DATA_TIME_UNITS), type);
}
}
private void addInclusiveTime(MethodStats stats, long time, ClockType type) {
if (type == ClockType.THREAD) {
stats.mInclusiveThreadTime += time;
} else {
stats.mInclusiveGlobalTime += time;
}
}
private void addExclusiveTime(MethodStats stats, long time, ClockType type) {
if (type == ClockType.THREAD) {
stats.mExclusiveThreadTime += time;
} else {
stats.mExclusiveGlobalTime += time;
}
}
private MethodStats getPerThreadStats(ThreadInfo thread) {
MethodStats stats = mPerThreadCumulativeStats.get(thread.getId());
if (stats == null) {
stats = new MethodStats();
mPerThreadCumulativeStats.put(thread.getId(), stats);
}
return stats;
}
private MethodStats getPerCallerStats(ThreadInfo thread, Call parent) {
return getMethodStatsFromTable(thread.getId(), parent.getMethodId(),
mPerThreadStatsByCaller);
}
private MethodStats getPerCalleeStats(ThreadInfo thread, Call callee) {
return getMethodStatsFromTable(thread.getId(), callee.getMethodId(),
mPerThreadStatsByCallee);
}
private MethodStats getMethodStatsFromTable(Integer threadId, Long methodId,
Table<Integer, Long, MethodStats> statsTable) {
MethodStats stats = statsTable.get(threadId, methodId);
if (stats == null) {
stats = new MethodStats();
statsTable.put(threadId, methodId, stats);
}
return stats;
}
public void incrementInvocationCount(Call c, Call parent, ThreadInfo thread) {
getPerThreadStats(thread).mInvocationCount++;
if (parent != null) {
getPerCallerStats(thread, parent).mInvocationCount++;
}
for (Call callee: c.getCallees()) {
getPerCalleeStats(thread, callee).mInvocationCount++;
}
}
public MethodProfileData build() {
return new MethodProfileData(this);
}
public void setRecursive() {
mRecursive = true;
}
}
}