-
Notifications
You must be signed in to change notification settings - Fork 10
/
VmOverheadAnalysis.java
243 lines (212 loc) · 10.5 KB
/
VmOverheadAnalysis.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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
/*******************************************************************************
* Copyright (c) 2017 École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.overhead;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.analysis.profiling.core.base.ICallStackElement;
import org.eclipse.tracecompass.analysis.profiling.core.callstack2.CallStackHostUtils;
import org.eclipse.tracecompass.analysis.profiling.core.callstack2.CallStackHostUtils.IHostIdProvider;
import org.eclipse.tracecompass.analysis.profiling.core.callstack2.CallStackHostUtils.IHostIdResolver;
import org.eclipse.tracecompass.analysis.profiling.core.callstack2.CallStackHostUtils.TraceHostIdResolver;
import org.eclipse.tracecompass.analysis.profiling.core.callstack2.CallStackSeries.IThreadIdProvider;
import org.eclipse.tracecompass.analysis.profiling.core.callstack2.CallStackSeries.IThreadIdResolver;
import org.eclipse.tracecompass.analysis.profiling.core.instrumented.InstrumentedCallStackAnalysis;
import org.eclipse.tracecompass.analysis.profiling.core.model.IHostModel;
import org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.fused.FusedVMInformationProvider;
import org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.fused.FusedVirtualMachineAnalysis;
import org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.model.analysis.VirtualMachineModelAnalysis;
import org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.virtual.resources.VirtualResourcesAnalysis;
import org.eclipse.tracecompass.internal.analysis.profiling.core.instrumented.InstrumentedCallStackElement;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule;
import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment;
import com.google.common.collect.ImmutableList;
/**
* This analysis uses a callstack to make statistics on virtual machine
* overhead. At the first level is the status of a thread from a guest
* perspective, level 2 detail when the thread is in VMM mode or its VCPU is
* preempted by the host and level 3 gives reasons or status on that preemption.
*
* @author Geneviève Bastien
*/
@SuppressWarnings("restriction")
public class VmOverheadAnalysis extends InstrumentedCallStackAnalysis {
/** The ID of this analysis module */
public static final String ID = "org.eclipse.tracecompass.incubator.virtual.machine.analysis.core.overhead.analysis"; //$NON-NLS-1$
/** The path where the vcpu is kept */
public static final String HOST_CPU_TID = "hostTid"; //$NON-NLS-1$
private static final String[] HOST_CPU_TID_PATH = { HOST_CPU_TID };
private static final String[] DEFAULT_TRACES_PATTERN = new String[] { VmOverheadStateProvider.TRACES, "*" }; //$NON-NLS-1$
private static final String[] DEFAULT_THREADS_PATTERN = new String[] { VmOverheadStateProvider.THREADS, "*" }; //$NON-NLS-1$
private static final List<String[]> PATTERNS = ImmutableList.of(DEFAULT_TRACES_PATTERN, DEFAULT_THREADS_PATTERN);
private @Nullable VirtualResourcesAnalysis getDependentAnalysis() {
ITmfTrace trace = getTrace();
if (trace == null) {
return null;
}
return TmfTraceUtils.getAnalysisModuleOfClass(trace, VirtualResourcesAnalysis.class, VirtualResourcesAnalysis.ID);
}
@Override
protected @NonNull Iterable<@NonNull IAnalysisModule> getDependentAnalyses() {
VirtualResourcesAnalysis dependentAnalysis = getDependentAnalysis();
if (dependentAnalysis == null) {
return Collections.emptySet();
}
return Collections.singleton(dependentAnalysis);
}
@Override
protected @NonNull StateSystemBackendType getBackendType() {
return StateSystemBackendType.FULL;
}
@Override
protected ITmfStateProvider createStateProvider() {
ITmfTrace trace = getTrace();
if (!(trace instanceof TmfExperiment)) {
throw new IllegalStateException();
}
VirtualMachineModelAnalysis model = TmfTraceUtils.getAnalysisModuleOfClass(trace, VirtualMachineModelAnalysis.class, VirtualMachineModelAnalysis.ID);
if (model == null) {
throw new IllegalStateException("There should be a model analysis for this class"); //$NON-NLS-1$
}
model.schedule();
if (!model.waitForInitialization()) {
throw new IllegalStateException("Problem initializing the model analysis"); //$NON-NLS-1$
}
return new VmOverheadStateProvider((TmfExperiment) trace, model.getVirtualEnvironmentModel());
}
/**
* This class will retrieve the thread ID
*/
private static final class VirtualCpuThreadProvider implements IThreadIdProvider {
private final ITmfStateSystem fSs;
private final int fCpuQuark;
public VirtualCpuThreadProvider(ITmfStateSystem ss, int quark, String[] path) {
fSs = ss;
// Get the cpu quark
List<@NonNull Integer> quarks = ss.getQuarks(quark, path);
fCpuQuark = quarks.isEmpty() ? ITmfStateSystem.INVALID_ATTRIBUTE : quarks.get(0);
}
@Override
public int getThreadId(long time) {
if (fCpuQuark == ITmfStateSystem.INVALID_ATTRIBUTE) {
return IHostModel.UNKNOWN_TID;
}
// Get the CPU
try {
ITmfStateInterval querySingleState = fSs.querySingleState(time, fCpuQuark);
if (querySingleState.getStateValue().isNull()) {
return IHostModel.UNKNOWN_TID;
}
return querySingleState.getStateValue().unboxInt();
} catch (StateSystemDisposedException e) {
}
return IHostModel.UNKNOWN_TID;
}
@Override
public boolean variesInTime() {
return true;
}
}
/**
* This class will resolve the thread ID from the CPU on which the callstack was
* running at a given time
*/
public static final class VirtualCpuTidResolver implements IThreadIdResolver {
private String[] fPath;
/**
* Constructor
*
* @param path
* The path relative to the leaf element that will contain the CPU ID
*/
public VirtualCpuTidResolver(String[] path) {
fPath = path;
}
@Override
public @Nullable IThreadIdProvider resolve(IHostIdProvider hostProvider, ICallStackElement element) {
if (!(element instanceof InstrumentedCallStackElement)) {
throw new IllegalArgumentException();
}
InstrumentedCallStackElement insElement = (InstrumentedCallStackElement) element;
return new VirtualCpuThreadProvider(insElement.getStateSystem(), insElement.getQuark(), fPath);
}
}
@Override
protected @Nullable IThreadIdResolver getCallStackTidResolver() {
return new VirtualCpuTidResolver(HOST_CPU_TID_PATH);
}
@Override
protected TraceHostIdResolver getCallStackHostResolver(ITmfTrace trace) {
// FIXME: There should be a better way to get the host ID
FusedVirtualMachineAnalysis analysisModule = TmfTraceUtils.getAnalysisModuleOfClass(trace, FusedVirtualMachineAnalysis.class, FusedVirtualMachineAnalysis.ID);
if (analysisModule == null) {
return super.getCallStackHostResolver(trace);
}
analysisModule.schedule();
analysisModule.waitForCompletion();
ITmfStateSystem stateSystem = analysisModule.getStateSystem();
if (stateSystem == null) {
return super.getCallStackHostResolver(trace);
}
Optional<ITmfTrace> hostTrace = TmfTraceManager.getTraceSet(trace).stream()
.filter(t -> FusedVMInformationProvider.getParentMachineHostId(stateSystem, t.getHostId()).isEmpty())
.findFirst();
if (hostTrace.isPresent()) {
return new CallStackHostUtils.TraceHostIdResolver(hostTrace.get());
}
return super.getCallStackHostResolver(trace);
}
@Override
public IHostIdResolver getHostIdResolver() {
// The host ID is the one from the host
ITmfTrace trace = getTrace();
if (trace == null) {
return super.getHostIdResolver();
}
// FIXME: There should be a better way to get the host ID
FusedVirtualMachineAnalysis analysisModule = TmfTraceUtils.getAnalysisModuleOfClass(trace, FusedVirtualMachineAnalysis.class, FusedVirtualMachineAnalysis.ID);
if (analysisModule == null) {
return super.getHostIdResolver();
}
analysisModule.schedule();
analysisModule.waitForCompletion();
ITmfStateSystem stateSystem = analysisModule.getStateSystem();
if (stateSystem == null) {
return super.getHostIdResolver();
}
Optional<ITmfTrace> hostTrace = TmfTraceManager.getTraceSet(trace).stream()
.filter(t -> FusedVMInformationProvider.getParentMachineHostId(stateSystem, t.getHostId()).isEmpty())
.findFirst();
if (hostTrace.isPresent()) {
return new CallStackHostUtils.TraceHostIdResolver(hostTrace.get());
}
return super.getHostIdResolver();
}
/**
* Get the patterns for the process, threads and callstack levels in the state
* system
*
* @return The patterns for the different levels in the state system
*/
@Override
protected List<String[]> getPatterns() {
return PATTERNS;
}
}