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