tmf: Introduce resolveIntEventAspectOfClassForEvent
[deliverable/tracecompass.git] / lttng / org.eclipse.tracecompass.lttng2.kernel.core / src / org / eclipse / tracecompass / internal / lttng2 / kernel / core / analysis / vm / module / VirtualMachineStateProvider.java
CommitLineData
4a74f111 1/*******************************************************************************
ed902a2b 2 * Copyright (c) 2014, 2015 École Polytechnique de Montréal
4a74f111
MG
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Mohamad Gebai - Initial API and implementation
11 *******************************************************************************/
12
13package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.module;
14
d0c7e4ba
AM
15import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
16
4a74f111
MG
17import java.util.HashMap;
18import java.util.Map;
19
20import org.eclipse.jdt.annotation.Nullable;
6d16f5a9 21import org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis.KernelAnalysisModule;
e363eae1 22import org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis.KernelThreadInformationProvider;
a6145763 23import org.eclipse.tracecompass.analysis.os.linux.core.model.HostThread;
e363eae1 24import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelAnalysisEventLayout;
4a74f111
MG
25import org.eclipse.tracecompass.common.core.NonNullUtils;
26import org.eclipse.tracecompass.internal.lttng2.kernel.core.Activator;
27import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.VcpuStateValues;
28import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.VmAttributes;
4a74f111
MG
29import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.IVirtualMachineModel;
30import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.VirtualCPU;
31import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.VirtualMachine;
32import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.qemukvm.QemuKvmVmModel;
4a74f111 33import org.eclipse.tracecompass.internal.lttng2.kernel.core.trace.layout.LttngEventLayout;
4a74f111 34import org.eclipse.tracecompass.lttng2.kernel.core.trace.LttngKernelTrace;
d0c7e4ba 35import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
4a74f111
MG
36import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
37import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
38import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
39import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
40import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
41import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
42import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
43import org.eclipse.tracecompass.tmf.core.event.aspect.TmfCpuAspect;
44import org.eclipse.tracecompass.tmf.core.statesystem.AbstractTmfStateProvider;
45import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
46import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
47import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment;
48import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperimentUtils;
49
50import com.google.common.collect.HashBasedTable;
51import com.google.common.collect.Table;
52
53/**
54 * This is the state provider which translates the virtual machine experiment
55 * events to a state system.
56 *
57 * Attribute tree:
58 *
59 * <pre>
60 * |- Virtual Machines
61 * | |- <Guest Host ID> -> Friendly name (trace name)
62 * | | |- <VCPU number>
63 * | | | |- Status -> <Status value>
64 * </pre>
65 *
66 * The status value of the VCPUs are either {@link VcpuStateValues#VCPU_IDLE},
67 * {@link VcpuStateValues#VCPU_UNKNOWN} or {@link VcpuStateValues#VCPU_RUNNING}.
68 * Those three values are ORed with flags {@link VcpuStateValues#VCPU_VMM}
69 * and/or {@link VcpuStateValues#VCPU_PREEMPT} to indicate respectively whether
70 * they are in hypervisor mode or preempted on the host.
71 *
72 * @author Mohamad Gebai
73 */
74public class VirtualMachineStateProvider extends AbstractTmfStateProvider {
75
76 /**
77 * Version number of this state provider. Please bump this if you modify the
78 * contents of the generated state history in some way.
79 */
80 private static final int VERSION = 1;
81
82 private static final int SCHED_SWITCH_INDEX = 0;
83
84 /* TODO: An analysis should support many hypervisor models */
85 private IVirtualMachineModel fModel;
4c4e2816 86 private final Table<ITmfTrace, String, @Nullable Integer> fEventNames;
4a74f111
MG
87 private final Map<ITmfTrace, IKernelAnalysisEventLayout> fLayouts;
88
89 // ------------------------------------------------------------------------
90 // Constructor
91 // ------------------------------------------------------------------------
92
93 /**
94 * Constructor
95 *
96 * @param experiment
97 * The virtual machine experiment
98 */
99 public VirtualMachineStateProvider(TmfExperiment experiment) {
e2bcc8a5 100 super(experiment, "Virtual Machine State Provider"); //$NON-NLS-1$
4a74f111
MG
101
102 fModel = new QemuKvmVmModel(experiment);
df2597e0 103 Table<ITmfTrace, String, @Nullable Integer> table = NonNullUtils.checkNotNull(HashBasedTable.create());
4a74f111
MG
104 fEventNames = table;
105 fLayouts = new HashMap<>();
106 }
107
108 // ------------------------------------------------------------------------
109 // Event names management
110 // ------------------------------------------------------------------------
111
112 private void buildEventNames(ITmfTrace trace) {
113 IKernelAnalysisEventLayout layout;
114 if (trace instanceof LttngKernelTrace) {
e363eae1 115 layout = ((LttngKernelTrace) trace).getKernelEventLayout();
4a74f111
MG
116 } else {
117 /* Fall-back to the base LttngEventLayout */
118 layout = LttngEventLayout.getInstance();
119 }
120 fLayouts.put(trace, layout);
121 fEventNames.put(trace, layout.eventSchedSwitch(), SCHED_SWITCH_INDEX);
122 }
123
124 // ------------------------------------------------------------------------
125 // IStateChangeInput
126 // ------------------------------------------------------------------------
127
128 @Override
129 public TmfExperiment getTrace() {
130 ITmfTrace trace = super.getTrace();
131 if (trace instanceof TmfExperiment) {
132 return (TmfExperiment) trace;
133 }
134 throw new IllegalStateException("VirtualMachineStateProvider: The associated trace should be an experiment"); //$NON-NLS-1$
135 }
136
137 @Override
138 public int getVersion() {
139 return VERSION;
140 }
141
142 @Override
143 public VirtualMachineStateProvider getNewInstance() {
144 TmfExperiment trace = getTrace();
145 return new VirtualMachineStateProvider(trace);
146 }
147
148 @Override
149 protected void eventHandle(@Nullable ITmfEvent event) {
150 if (event == null) {
151 return;
152 }
153
154 /* Is the event managed by this analysis */
578716e6 155 final String eventName = event.getName();
4a74f111
MG
156
157 /* TODO When requirements work again, don't hardcode this */
158 if (!eventName.equals("sched_switch") && //$NON-NLS-1$
159 !fModel.getRequiredEvents().contains(eventName)) {
160 return;
161 }
162
d0c7e4ba 163 ITmfStateSystemBuilder ss = checkNotNull(getStateSystemBuilder());
4a74f111
MG
164 ITmfStateValue value;
165
166 final ITmfEventField content = event.getContent();
167 final long ts = event.getTimestamp().getValue();
168 final String hostId = event.getTrace().getHostId();
169 try {
170 /* Do we know this trace's role yet? */
171 VirtualMachine host = fModel.getCurrentMachine(event);
172 if (host == null) {
173 return;
174 }
175
176 /* Make sure guest traces are added to the state system */
177 if (host.isGuest()) {
178 /*
179 * If event from a guest OS, make sure the guest exists in the
180 * state system
181 */
182 int vmQuark = -1;
183 try {
184 vmQuark = ss.getQuarkRelative(getNodeVirtualMachines(), host.getHostId());
185 } catch (AttributeNotFoundException e) {
186 /*
187 * We should enter this catch only once per machine, so it
188 * is not so costly to do compared with adding the trace's
189 * name for each guest event
190 */
191 vmQuark = ss.getQuarkRelativeAndAdd(getNodeVirtualMachines(), host.getHostId());
192 TmfStateValue machineName = TmfStateValue.newValueString(event.getTrace().getName());
193 ss.modifyAttribute(ts, machineName, vmQuark);
194 }
195 }
196
197 /* Have the hypervisor models handle the event first */
198 fModel.handleEvent(event);
199
200 /* Handle the event here */
201 if (!fEventNames.containsRow(event.getTrace())) {
202 buildEventNames(event.getTrace());
203 }
204 Integer idx = fEventNames.get(event.getTrace(), eventName);
205 int intval = (idx == null ? -1 : idx.intValue());
206 switch (intval) {
207 case SCHED_SWITCH_INDEX: // "sched_switch":
208 /*
209 * Fields: string prev_comm, int32 prev_tid, int32 prev_prio, int64
210 * prev_state, string next_comm, int32 next_tid, int32 next_prio
211 */
212 {
94411c58
AM
213 final IKernelAnalysisEventLayout eventLayout = fLayouts.get(event.getTrace());
214 if (eventLayout == null) {
215 return;
216 }
217 int prevTid = ((Long) content.getField(eventLayout.fieldPrevTid()).getValue()).intValue();
218 int nextTid = ((Long) content.getField(eventLayout.fieldNextTid()).getValue()).intValue();
4a74f111
MG
219
220 if (host.isGuest()) {
221 /* Get the event's CPU */
b3867ecc
MAL
222 Integer cpu = TmfTraceUtils.resolveIntEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event);
223 if (cpu == null) {
52efabb6
CB
224 /*
225 * We couldn't find any CPU information, ignore this
226 * event
227 */
4a74f111
MG
228 break;
229 }
230
231 /*
232 * If sched switch is from a guest, just update the status
233 * of the virtual CPU to either idle or running
234 */
235 int curStatusQuark = ss.getQuarkRelativeAndAdd(getNodeVirtualMachines(), host.getHostId(),
236 cpu.toString(), VmAttributes.STATUS);
237 value = TmfStateValue.newValueInt(VcpuStateValues.VCPU_IDLE);
238 if (nextTid > 0) {
239 value = TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING);
240 }
241 ss.modifyAttribute(ts, value, curStatusQuark);
242 break;
243 }
244
245 /* Event is not from a guest */
246 /* Verify if the previous thread corresponds to a virtual CPU */
247 HostThread ht = new HostThread(hostId, prevTid);
248 VirtualCPU vcpu = fModel.getVirtualCpu(ht);
249
250 /*
251 * If previous thread is virtual CPU, update status of the
252 * virtual CPU to preempted
253 */
254 if (vcpu != null) {
255 VirtualMachine vm = vcpu.getVm();
256
257 int curStatusQuark = ss.getQuarkRelativeAndAdd(getNodeVirtualMachines(), vm.getHostId(),
258 vcpu.getCpuId().toString(), VmAttributes.STATUS);
259
260 /* Add the preempted flag to the status */
261 value = ss.queryOngoingState(curStatusQuark);
52efabb6
CB
262 if ((value.unboxInt() & VcpuStateValues.VCPU_IDLE) == 0) {
263 int newVal = Math.max(VcpuStateValues.VCPU_UNKNOWN, value.unboxInt());
264 value = TmfStateValue.newValueInt(newVal | VcpuStateValues.VCPU_PREEMPT);
265 ss.modifyAttribute(ts, value, curStatusQuark);
266 }
4a74f111
MG
267 }
268
269 /* Verify if the next thread corresponds to a virtual CPU */
270 ht = new HostThread(hostId, nextTid);
271 vcpu = fModel.getVirtualCpu(ht);
272
273 /*
274 * If next thread is virtual CPU, update status of the virtual
275 * CPU the previous status
276 */
277 if (vcpu != null) {
278 VirtualMachine vm = vcpu.getVm();
279 int curStatusQuark = ss.getQuarkRelativeAndAdd(getNodeVirtualMachines(), vm.getHostId(),
280 vcpu.getCpuId().toString(), VmAttributes.STATUS);
281
282 /* Remove the preempted flag from the status */
283 value = ss.queryOngoingState(curStatusQuark);
284 int newVal = Math.max(VcpuStateValues.VCPU_UNKNOWN, value.unboxInt());
285 value = TmfStateValue.newValueInt(newVal & ~VcpuStateValues.VCPU_PREEMPT);
286 ss.modifyAttribute(ts, value, curStatusQuark);
287
288 }
289
290 }
291 break;
292
293 default:
294 /* Other events not covered by the main switch */
295 {
296 HostThread ht = getCurrentHostThread(event, ts);
297 if (ht == null) {
298 break;
299 }
300
301 /*
302 * Are we entering the hypervisor mode and if so, which virtual
303 * CPU is concerned?
304 */
305 VirtualCPU virtualCpu = fModel.getVCpuEnteringHypervisorMode(event, ht);
306 if (virtualCpu != null) {
307 /* Add the hypervisor flag to the status */
308 VirtualMachine vm = virtualCpu.getVm();
309 int curStatusQuark = ss.getQuarkRelativeAndAdd(getNodeVirtualMachines(), vm.getHostId(),
310 Long.toString(virtualCpu.getCpuId()), VmAttributes.STATUS);
311 value = ss.queryOngoingState(curStatusQuark);
52efabb6
CB
312 if ((value.unboxInt() & VcpuStateValues.VCPU_IDLE) == 0) {
313 int newVal = Math.max(VcpuStateValues.VCPU_UNKNOWN, value.unboxInt());
314 value = TmfStateValue.newValueInt(newVal | VcpuStateValues.VCPU_VMM);
315 ss.modifyAttribute(ts, value, curStatusQuark);
316 }
4a74f111
MG
317 }
318
319 /*
320 * Are we exiting the hypervisor mode and if so, which virtual
321 * CPU is concerned?
322 */
323 virtualCpu = fModel.getVCpuExitingHypervisorMode(event, ht);
324 if (virtualCpu != null) {
325 /* Remove the hypervisor flag from the status */
326 VirtualMachine vm = virtualCpu.getVm();
327 int curStatusQuark = ss.getQuarkRelativeAndAdd(getNodeVirtualMachines(), vm.getHostId(),
328 Long.toString(virtualCpu.getCpuId()), VmAttributes.STATUS);
329 value = ss.queryOngoingState(curStatusQuark);
330 int newVal = Math.max(VcpuStateValues.VCPU_UNKNOWN, value.unboxInt());
331 value = TmfStateValue.newValueInt(newVal & ~VcpuStateValues.VCPU_VMM);
332 ss.modifyAttribute(ts, value, curStatusQuark);
333 }
334
335 }
336 break;
337 }
338
339 } catch (AttributeNotFoundException | TimeRangeException | StateValueTypeException e) {
340 Activator.getDefault().logError("Error handling event in VirtualMachineStateProvider", e); //$NON-NLS-1$
341 }
342 }
343
344 // ------------------------------------------------------------------------
345 // Convenience methods for commonly-used attribute tree locations
346 // ------------------------------------------------------------------------
347
348 private int getNodeVirtualMachines() {
d0c7e4ba 349 return checkNotNull(getStateSystemBuilder()).getQuarkAbsoluteAndAdd(VmAttributes.VIRTUAL_MACHINES);
4a74f111
MG
350 }
351
352 private @Nullable HostThread getCurrentHostThread(ITmfEvent event, long ts) {
353 /* Get the LTTng kernel analysis for the host */
354 String hostId = event.getTrace().getHostId();
6d16f5a9 355 KernelAnalysisModule module = TmfExperimentUtils.getAnalysisModuleOfClassForHost(getTrace(), hostId, KernelAnalysisModule.class);
4a74f111
MG
356 if (module == null) {
357 return null;
358 }
359
360 /* Get the CPU the event is running on */
b3867ecc
MAL
361 Integer cpu = TmfTraceUtils.resolveIntEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event);
362 if (cpu == null) {
4a74f111
MG
363 /* We couldn't find any CPU information, ignore this event */
364 return null;
365 }
366
e363eae1 367 Integer currentTid = KernelThreadInformationProvider.getThreadOnCpu(module, cpu, ts);
4a74f111
MG
368 if (currentTid == null) {
369 return null;
370 }
371 return new HostThread(hostId, currentTid);
372 }
373
4c4e2816 374}
This page took 0.060464 seconds and 5 git commands to generate.