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