ctf: Move plugins to their own sub-directory
[deliverable/tracecompass.git] / org.eclipse.tracecompass.lttng2.kernel.core / src / org / eclipse / tracecompass / internal / lttng2 / kernel / core / analysis / vm / model / qemukvm / QemuKvmVmModel.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 * Geneviève Bastien - Initial API and implementation
12 *******************************************************************************/
13
14package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.qemukvm;
15
16import java.util.HashMap;
17import java.util.Map;
18import java.util.Map.Entry;
19import java.util.Set;
20
21import org.eclipse.jdt.annotation.Nullable;
6d16f5a9 22import org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis.KernelAnalysisModule;
e363eae1 23import org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis.KernelThreadInformationProvider;
a6145763 24import org.eclipse.tracecompass.analysis.os.linux.core.model.HostThread;
4a74f111 25import org.eclipse.tracecompass.common.core.NonNullUtils;
4a74f111
MG
26import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.IVirtualMachineModel;
27import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.VirtualCPU;
28import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.VirtualMachine;
4a74f111
MG
29import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
30import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
31import org.eclipse.tracecompass.tmf.core.event.TmfEventField;
32import org.eclipse.tracecompass.tmf.core.event.aspect.TmfCpuAspect;
33import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
34import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment;
35import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperimentUtils;
36
37import com.google.common.collect.ImmutableSet;
38
39/**
40 * The virtual machine model corresponding to the Qemu/KVM hypervisor. It uses
41 * the kvm_exit/kvm_entry events to identify entry to and exit from the
42 * hypervisor. It also requires vmsync_* events from both guests and hosts to
43 * identify which thread from a host belongs to which machine.
44 *
45 * @author Mohamad Gebai
46 */
47public class QemuKvmVmModel implements IVirtualMachineModel {
48
49 private static final String KVM = "kvm_"; //$NON-NLS-1$
50
51 /* Associate a host's thread to a virtual CPU */
52 private final Map<HostThread, VirtualCPU> fTidToVcpu = new HashMap<>();
53 /* Associate a host's thread to a virtual machine */
54 private final Map<HostThread, VirtualMachine> fTidToVm = new HashMap<>();
55 /* Maps a virtual machine name to a virtual machine */
56 private final Map<String, VirtualMachine> fKnownMachines = new HashMap<>();
57
58 private final TmfExperiment fExperiment;
59
60 static final ImmutableSet<String> REQUIRED_EVENTS = NonNullUtils.checkNotNull(ImmutableSet.of(
61 QemuKvmStrings.KVM_ENTRY,
62 QemuKvmStrings.KVM_EXIT,
63 QemuKvmStrings.VMSYNC_GH_GUEST,
64 QemuKvmStrings.VMSYNC_GH_HOST,
65 QemuKvmStrings.VMSYNC_HG_GUEST,
66 QemuKvmStrings.VMSYNC_HG_HOST
67 ));
68
69 /**
70 * Constructor
71 *
72 * @param exp
73 * The experiment this model applies to
74 */
75 public QemuKvmVmModel(TmfExperiment exp) {
76 fExperiment = exp;
77 }
78
79 @Override
80 public @Nullable VirtualMachine getCurrentMachine(ITmfEvent event) {
81 final String hostId = event.getTrace().getHostId();
82 VirtualMachine machine = fKnownMachines.get(hostId);
83 if (machine != null) {
84 return machine;
85 }
86
87 /*
88 * TODO: This model wouldn't support a machine (same hostId) being both
89 * a guest and a host
90 */
91
92 /*
93 * This code path would be used only at the beginning of the analysis.
94 * Once all the hostIds have been associated with a virtual machine, the
95 * machines are all cached and the method returns earlier
96 */
97 /* Try to get the virtual machine from the event */
578716e6 98 String eventName = event.getName();
4a74f111
MG
99 if (eventName.startsWith(KVM)) {
100 /* Only the host machine has kvm_* events, so this is a host */
101 machine = VirtualMachine.newHostMachine(hostId);
102 } else if (eventName.equals(QemuKvmStrings.VMSYNC_GH_GUEST) || eventName.equals(QemuKvmStrings.VMSYNC_HG_GUEST)) {
103 /* Those events are only present in the guests */
104 TmfEventField field = (TmfEventField) event.getContent();
105 ITmfEventField data = field.getField(QemuKvmStrings.VM_UID_PAYLOAD);
106 if (data != null) {
107 machine = VirtualMachine.newGuestMachine((Long) data.getValue(), hostId);
108 }
109 }
110 if (machine != null) {
111 /* Associate the machine to the hostID here, for cached access later */
112 fKnownMachines.put(hostId, machine);
113 }
114 return machine;
115 }
116
117 @Override
118 public Set<String> getRequiredEvents() {
119 return REQUIRED_EVENTS;
120 }
121
122 private @Nullable VirtualMachine findVmFromParent(ITmfEvent event, HostThread ht) {
123 /*
124 * Maybe the parent of the current thread has a VM associated, see if we
125 * can infer the VM for this thread
126 */
6d16f5a9 127 KernelAnalysisModule module = getLttngKernelModuleFor(ht.getHost());
4a74f111
MG
128 if (module == null) {
129 return null;
130 }
131
e363eae1 132 Integer ppid = KernelThreadInformationProvider.getParentPid(module, ht.getTid(), event.getTimestamp().getValue());
4a74f111
MG
133 if (ppid == null) {
134 return null;
135 }
136
137 HostThread parentHt = new HostThread(ht.getHost(), ppid);
138 VirtualMachine vm = fTidToVm.get(parentHt);
139 if (vm == null) {
140 return null;
141 }
142 fTidToVm.put(ht, vm);
143
144 return vm;
145 }
146
147 @Override
148 public @Nullable VirtualCPU getVCpuExitingHypervisorMode(ITmfEvent event, HostThread ht) {
578716e6 149 final String eventName = event.getName();
4a74f111
MG
150
151 /* TODO: Use event layouts for this part also */
152 /*
153 * The KVM_ENTRY event means we are entering a virtual CPU, so exiting
154 * hypervisor mode
155 */
156 if (!eventName.equals(QemuKvmStrings.KVM_ENTRY)) {
157 return null;
158 }
159
160 /*
161 * Are we entering the hypervisor and if so, which virtual CPU is
162 * concerned?
163 */
164 VirtualMachine vm = fTidToVm.get(ht);
165 if (vm == null) {
166 vm = findVmFromParent(event, ht);
167 if (vm == null) {
168 return null;
169 }
170 }
171 /* Associate this thread with the virtual CPU that is going to be run */
172 final ITmfEventField content = event.getContent();
173 long vcpu_id = (Long) content.getField(QemuKvmStrings.VCPU_ID).getValue();
174
175 VirtualCPU virtualCPU = VirtualCPU.getVirtualCPU(vm, vcpu_id);
176 fTidToVcpu.put(ht, virtualCPU);
177
178 return virtualCPU;
179 }
180
181 @Override
182 public @Nullable VirtualCPU getVCpuEnteringHypervisorMode(ITmfEvent event, HostThread ht) {
578716e6 183 final String eventName = event.getName();
4a74f111
MG
184 /*
185 * The KVM_EXIT event means we are exiting a virtual CPU, so entering
186 * hypervisor mode
187 */
188 if (!eventName.equals(QemuKvmStrings.KVM_EXIT)) {
189 return null;
190 }
191
192 return getVirtualCpu(ht);
193 }
194
195 @Override
196 public @Nullable VirtualCPU getVirtualCpu(HostThread ht) {
197 return fTidToVcpu.get(ht);
198 }
199
200 @Override
201 public void handleEvent(ITmfEvent event) {
202 /* Is the event handled by this model */
578716e6 203 final String eventName = event.getName();
4a74f111
MG
204 if (!eventName.equals(QemuKvmStrings.VMSYNC_GH_HOST)) {
205 return;
206 }
207
208 final ITmfEventField content = event.getContent();
209 final long ts = event.getTimestamp().getValue();
210 final String hostId = event.getTrace().getHostId();
211
b1aad44e
GB
212 Object cpuObj = TmfTraceUtils.resolveEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event);
213 if (cpuObj == null) {
4a74f111
MG
214 /* We couldn't find any CPU information, ignore this event */
215 return;
216 }
b1aad44e 217 Integer cpu = (Integer) cpuObj;
4a74f111
MG
218
219 /* Find a virtual machine with the vm uid payload value */
220 ITmfEventField data = content.getField(QemuKvmStrings.VM_UID_PAYLOAD);
221 if (data == null) {
222 return;
223 }
224 long vmUid = (Long) data.getValue();
225 for (Entry<String, VirtualMachine> entry : fKnownMachines.entrySet()) {
226 if (entry.getValue().getVmUid() == vmUid) {
227 /*
228 * We found the VM being run, let's associate it with the thread
229 * ID
230 */
6d16f5a9 231 KernelAnalysisModule module = getLttngKernelModuleFor(hostId);
4a74f111
MG
232 if (module == null) {
233 break;
234 }
e363eae1 235 Integer tid = KernelThreadInformationProvider.getThreadOnCpu(module, cpu, ts);
4a74f111
MG
236 if (tid == null) {
237 /*
238 * We do not know which process is running at this point. It
239 * may happen at the beginning of the trace.
240 */
241 break;
242 }
243 HostThread ht = new HostThread(hostId, tid);
244 fTidToVm.put(ht, entry.getValue());
245
246 /*
247 * To make sure siblings are also associated with this VM, also
248 * add an entry for the parent TID
249 */
e363eae1 250 Integer ppid = KernelThreadInformationProvider.getParentPid(module, tid, ts);
4a74f111
MG
251 if (ppid != null) {
252 HostThread parentHt = new HostThread(hostId, ppid);
253 fTidToVm.put(parentHt, entry.getValue());
254 }
255 }
256 }
257 }
258
6d16f5a9
AM
259 private @Nullable KernelAnalysisModule getLttngKernelModuleFor(String hostId) {
260 return TmfExperimentUtils.getAnalysisModuleOfClassForHost(fExperiment, hostId, KernelAnalysisModule.class);
4a74f111
MG
261 }
262
263}
This page took 0.04403 seconds and 5 git commands to generate.