org.eclipse.tracecompass.tmf.ctf.core,
org.eclipse.tracecompass.lttng2.control.core
Export-Package: org.eclipse.tracecompass.internal.lttng2.kernel.core;x-friends:="org.eclipse.tracecompass.lttng2.kernel.ui,org.eclipse.tracecompass.lttng2.kernel.core.tests",
+ org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm;x-friends:="org.eclipse.tracecompass.lttng2.kernel.core.tests,org.eclipse.tracecompass.lttng2.kernel.ui",
+ org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model;x-friends:="org.eclipse.tracecompass.lttng2.kernel.core.tests,org.eclipse.tracecompass.lttng2.kernel.ui",
+ org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.qemukvm;x-friends:="org.eclipse.tracecompass.lttng2.kernel.core.tests,org.eclipse.tracecompass.lttng2.kernel.ui",
+ org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.module;x-friends:="org.eclipse.tracecompass.lttng2.kernel.core.tests,org.eclipse.tracecompass.lttng2.kernel.ui",
+ org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.trace;x-friends:="org.eclipse.tracecompass.lttng2.kernel.ui,org.eclipse.tracecompass.lttng2.kernel.core.tests",
org.eclipse.tracecompass.internal.lttng2.kernel.core.event.matching,
org.eclipse.tracecompass.internal.lttng2.kernel.core.trace.layout;x-friends:="org.eclipse.tracecompass.lttng2.kernel.core.tests,org.eclipse.tracecompass.lttng2.kernel.ui",
org.eclipse.tracecompass.lttng2.kernel.core.analysis.cpuusage,
org.eclipse.tracecompass.lttng2.kernel.core.analysis.kernel,
org.eclipse.tracecompass.lttng2.kernel.core.trace
-Import-Package: com.google.common.collect
+Import-Package: com.google.common.collect,
+ com.google.common.hash;version="15.0.0"
name="%tracetype.type.kernel"
trace_type="org.eclipse.tracecompass.lttng2.kernel.core.trace.LttngKernelTrace">
</type>
+ <experiment
+ experiment_type="org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.trace.VirtualMachineExperiment"
+ id="lttng2.analysis.vm.VirtualMachineExperiment"
+ name="Virtual Machine Experiment">
+ </experiment>
</extension>
<extension
point="org.eclipse.linuxtools.tmf.core.analysis">
class="org.eclipse.tracecompass.lttng2.kernel.core.trace.LttngKernelTrace">
</tracetype>
</module>
+ <module
+ analysis_module="org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.module.VirtualMachineCpuAnalysis"
+ automatic="false"
+ id="lttng2.analysis.vm.core.VirtualMachineAnalysisModule"
+ name="Virtual Machine Analysis">
+ <tracetype
+ applies="true"
+ class="org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.trace.VirtualMachineExperiment">
+ </tracetype>
+ </module>
</extension>
</plugin>
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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 v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mohamad Gebai - Initial API and implementation
+ * Geneviève Bastien - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm;
+
+/**
+ * State system values used by the VM analysis
+ *
+ * @author Mohamad Gebai
+ */
+public interface VcpuStateValues {
+
+ /* VCPU Status */
+ /** The virtual CPU state is unknown */
+ int VCPU_UNKNOWN = 0;
+ /** The virtual CPU is idle */
+ int VCPU_IDLE = 1;
+ /** The virtual CPU is running */
+ int VCPU_RUNNING = 2;
+ /** Flag for when the virtual CPU is in hypervisor mode */
+ int VCPU_VMM = 128;
+ /** Flag for when the virtual CPU is preempted */
+ int VCPU_PREEMPT = 256;
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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 v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mohamad Gebai - Initial API and implementation
+ * Geneviève Bastien - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm;
+
+/**
+ * Attributes used by the VM Analysis
+ *
+ * @author Mohamad Gebai
+ */
+@SuppressWarnings({"nls"})
+public interface VmAttributes {
+
+ /** First-level attributes */
+ String VIRTUAL_MACHINES = "Virtual Machines";
+
+ /** Sub-attributes for virtual CPUs */
+ String STATUS = "Status";
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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 v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Geneviève Bastien - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+
+import com.google.common.hash.HashFunction;
+import com.google.common.hash.Hashing;
+
+/**
+ * This class represents a thread from a specific host. Many machines in an
+ * experiment can have the same thread IDs. This class differentiates the
+ * threads by adding the host ID it belongs to.
+ *
+ * @author Geneviève Bastien
+ */
+public class HostThread {
+
+ private static final HashFunction HF = NonNullUtils.checkNotNull(Hashing.goodFastHash(32));
+
+ private final String fHost;
+ private final Integer fTid;
+
+ /**
+ * Constructor
+ *
+ * @param host
+ * The host this thread belongs to
+ * @param tid
+ * The thread ID of this thread
+ */
+ public HostThread(String host, Integer tid) {
+ fHost = host;
+ fTid = tid;
+ }
+
+ @Override
+ public int hashCode() {
+ return HF.newHasher()
+ .putUnencodedChars(fHost)
+ .putInt(fTid).hash().asInt();
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (o instanceof HostThread) {
+ HostThread hostTid = (HostThread) o;
+ if (fTid.equals(hostTid.fTid) &&
+ fHost.equals(hostTid.fHost)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "HostTid: [" + fHost + ',' + fTid + ']'; //$NON-NLS-1$
+ }
+
+ /**
+ * Get the thread ID of this thread
+ *
+ * @return The thread ID of this thread
+ */
+ public Integer getTid() {
+ return fTid;
+ }
+
+ /**
+ * Get the host ID of the machine this thread belongs to
+ *
+ * @return The host ID this thread belongs to
+ */
+ public String getHost() {
+ return fHost;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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 v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Geneviève Bastien - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model;
+
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+
+/**
+ * Interface that represents the model of an hypervisor. Each hypervisor (or
+ * tracing method for an hypervisor) should implement this.
+ *
+ * @author Geneviève Bastien
+ */
+public interface IVirtualMachineModel {
+
+ /**
+ * Get the machine that ran this event
+ *
+ * @param event
+ * The trace event
+ * @return The machine this event was run on or {@code null} if the machine
+ * is not one belonging to this model.
+ */
+ @Nullable
+ VirtualMachine getCurrentMachine(ITmfEvent event);
+
+ /**
+ * Get a the set of events required for this model to apply.
+ *
+ * TODO: This should be updated to something else to fit the event layout
+ * generic linux model
+ *
+ * @return The set of required events for this model
+ */
+ Set<String> getRequiredEvents();
+
+ /**
+ * Get the virtual CPU that is entering hypervisor mode with this event.
+ *
+ * "Hypervisor mode" means the virtual CPU of the guest is running on the
+ * host, but it is not running code from the guest, but rather other tasks
+ * from the hypervisor. When hypervisor mode is entered, the process on the
+ * host stops running guest code, so from the guest point of view, the
+ * thread running on this CPU is preempted.
+ *
+ * @param event
+ * The event being handled
+ * @param ht
+ * The current thread this event belongs to
+ * @return The virtual CPU entering hypervisor mode or {@code null} if the
+ * hypervisor is not being entered with this event.
+ */
+ @Nullable
+ VirtualCPU getVCpuEnteringHypervisorMode(ITmfEvent event, HostThread ht);
+
+ /**
+ * Get the virtual CPU that is exiting hypervisor mode with this event.
+ *
+ * "Hypervisor mode" means the virtual CPU of the guest is running on the
+ * host, but it is not running code from the guest, but rather other tasks
+ * from the hypervisor. When hypervisor mode is exited, the process on the
+ * host runs guest code, so from the guest point of view, the thread running
+ * on this CPU is actively running.
+ *
+ * @param event
+ * The event being handled
+ * @param ht
+ * The current thread this event belongs to
+ * @return The virutal CPU exiting hypervisor mode or {@code null} if the
+ * hypervisor is not exiting with this event.
+ */
+ @Nullable
+ VirtualCPU getVCpuExitingHypervisorMode(ITmfEvent event, HostThread ht);
+
+ /**
+ * Get the virtual CPU from a guest that corresponds to a specific thread
+ * from the host
+ *
+ * @param event
+ * The event being handled
+ * @param ht
+ * The current thread this event belongs to. This thread should
+ * be running on the host.
+ * @return The virtual CPU corresponding to this thread or {@code null} if
+ * no virtual CPU corresponds to the thread
+ */
+ @Nullable
+ VirtualCPU getVirtualCpu(HostThread ht);
+
+ /**
+ * Handles the event. This method will be called for each event required or
+ * optional by the analysis, before any other handling is done on this
+ * event.
+ *
+ * This is where each implementation of the model will build itself,
+ * determine which guests are running on which hosts and get the necessary
+ * information to be able to return the virtual CPUs requested by the other
+ * methods of this interface.
+ *
+ * @param event
+ * The event being handled. It can come from any trace in the
+ * experiment
+ */
+ void handleEvent(ITmfEvent event);
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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 v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Geneviève Bastien - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model;
+
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Table;
+
+/**
+ * This class represents a virtual CPU, which is a CPU running on a guest. It
+ * associates the guest CPU ID to a virtual machine of the model.
+ *
+ * @author Geneviève Bastien
+ */
+public class VirtualCPU {
+
+ private static final Table<VirtualMachine, Long, VirtualCPU> VIRTUAL_CPU_TABLE = NonNullUtils.checkNotNull(HashBasedTable.<VirtualMachine, Long, VirtualCPU> create());
+
+ private final VirtualMachine fVm;
+ private final Long fCpuId;
+
+ /**
+ * Return the virtual CPU for to the virtual machine and requested CPU ID
+ *
+ * @param vm
+ * The virtual machine
+ * @param cpu
+ * the CPU number
+ * @return the virtual CPU
+ */
+ public static synchronized VirtualCPU getVirtualCPU(VirtualMachine vm, Long cpu) {
+ VirtualCPU ht = VIRTUAL_CPU_TABLE.get(vm, cpu);
+ if (ht == null) {
+ ht = new VirtualCPU(vm, cpu);
+ VIRTUAL_CPU_TABLE.put(vm, cpu, ht);
+ }
+ return ht;
+ }
+
+ private VirtualCPU(VirtualMachine vm, Long cpu) {
+ fVm = vm;
+ fCpuId = cpu;
+ }
+
+ /**
+ * Get the CPU ID of this virtual CPU
+ *
+ * @return The zero-based CPU ID
+ */
+ public Long getCpuId() {
+ return fCpuId;
+ }
+
+ /**
+ * Get the virtual machine object this virtual CPU belongs to
+ *
+ * @return The guest Virtual Machine
+ */
+ public VirtualMachine getVm() {
+ return fVm;
+ }
+
+ @Override
+ public String toString() {
+ return "VirtualCPU: [" + fVm + ',' + fCpuId + ']'; //$NON-NLS-1$
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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 v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Geneviève Bastien - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model;
+
+/**
+ * This class represents a machine, host or guest, in a virtual machine model. A
+ * machine is identified by a trace's host ID.
+ *
+ * @author Geneviève Bastien
+ */
+public class VirtualMachine {
+
+ private static enum MachineType {
+ HOST,
+ GUEST
+ }
+
+ private final long fVmUid;
+ private final String fHostId;
+ private final MachineType fType;
+
+ /**
+ * Create a new host machine. A host is a physical machine that may contain
+ * virtual guest machines.
+ *
+ * @param hostId
+ * The host ID of the trace(s) this machine represents
+ * @return A {@link VirtualMachine} of type host
+ */
+ public static VirtualMachine newHostMachine(String hostId) {
+ return new VirtualMachine(MachineType.HOST, hostId, -1);
+ }
+
+ /**
+ * Create a new guest machine. A guest is a virtual machine with virtual
+ * CPUs running on a host.
+ *
+ * @param uid
+ * Some unique identifier of this guest machine that can be used
+ * in both the guest and the host to match both machines.
+ * @param hostId
+ * The host ID of the trace(s) this machine represents
+ * @return A {@link VirtualMachine} of type guest.
+ */
+ public static VirtualMachine newGuestMachine(long uid, String hostId) {
+ return new VirtualMachine(MachineType.GUEST, hostId, uid);
+ }
+
+ private VirtualMachine(MachineType type, String hostId, long uid) {
+ fType = type;
+ fVmUid = uid;
+ fHostId = hostId;
+ }
+
+ /**
+ * Return whether this machine is a guest or a host
+ *
+ * @return {@code true} if the machine is a guest, or {@code false} if it is
+ * a host
+ */
+ public boolean isGuest() {
+ return fType == MachineType.GUEST;
+ }
+
+ /**
+ * Get the unique identifier that is used between the host and the guest to
+ * identify this machine.
+ *
+ * @return The Virtual Machine unique ID.
+ */
+ public long getVmUid() {
+ return fVmUid;
+ }
+
+ /**
+ * Get the host ID of this machine
+ *
+ * @return The host ID of this machine
+ */
+ public String getHostId() {
+ return fHostId;
+ }
+
+ @Override
+ public String toString() {
+ return "VirtualMachine: " + fHostId; //$NON-NLS-1$
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * École Polytechnique de Montréal - Initial API and implementation
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model;
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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 v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mohamad Gebai - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.qemukvm;
+
+/**
+ * Lttng specific strings for the events used by the Qemu/KVM virtual machine
+ * model
+ *
+ * TODO: The whole model should be updated to use the linux event layout. These
+ * event names are LTTng-specific
+ *
+ * @author Mohamad Gebai
+ */
+@SuppressWarnings({ "nls" })
+public interface QemuKvmStrings {
+
+ /* vmsync events */
+
+ /**
+ * Event produced by the host, for a message sent from the guest, received
+ * by the host
+ */
+ String VMSYNC_GH_HOST = "vmsync_gh_host";
+ /**
+ * Event produced by the host, for a message sent from the host, received by
+ * the guest
+ */
+ String VMSYNC_HG_HOST = "vmsync_hg_host";
+ /**
+ * Event produced by the guest, for a message sent from the guest, received
+ * by the host
+ */
+ String VMSYNC_GH_GUEST = "vmsync_gh_guest";
+ /**
+ * Event produced by the guest, for a message sent from the host, received
+ * by the guest
+ */
+ String VMSYNC_HG_GUEST = "vmsync_hg_guest";
+ /**
+ * Event field of previous events, containing a message counter, updated at
+ * each message
+ */
+ String COUNTER_PAYLOAD = "cnt";
+ /**
+ * Event field of previous events, with a unique UID to identify a single
+ * guest on a host
+ */
+ String VM_UID_PAYLOAD = "vm_uid";
+
+ /* kvm entry/exit events */
+ /**
+ * KVM kernel event indicating that virtual machine code is being run
+ */
+ String KVM_ENTRY = "kvm_entry";
+ /**
+ * KVM kernel event indicating that virtual machine code is not run anymore,
+ * but rather hypervisor-specific code
+ */
+ String KVM_EXIT = "kvm_exit";
+ /**
+ * Field from kvm_entry event indicating which virtual CPU is being run
+ */
+ String VCPU_ID = "vcpu_id";
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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 v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mohamad Gebai - Initial API and implementation
+ * Geneviève Bastien - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.qemukvm;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.HostThread;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.IVirtualMachineModel;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.VirtualCPU;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.VirtualMachine;
+import org.eclipse.tracecompass.lttng2.kernel.core.analysis.kernel.LttngKernelAnalysis;
+import org.eclipse.tracecompass.lttng2.kernel.core.analysis.kernel.LttngKernelThreadInformationProvider;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
+import org.eclipse.tracecompass.tmf.core.event.TmfEventField;
+import org.eclipse.tracecompass.tmf.core.event.aspect.TmfCpuAspect;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
+import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment;
+import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperimentUtils;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * The virtual machine model corresponding to the Qemu/KVM hypervisor. It uses
+ * the kvm_exit/kvm_entry events to identify entry to and exit from the
+ * hypervisor. It also requires vmsync_* events from both guests and hosts to
+ * identify which thread from a host belongs to which machine.
+ *
+ * @author Mohamad Gebai
+ */
+public class QemuKvmVmModel implements IVirtualMachineModel {
+
+ private static final String KVM = "kvm_"; //$NON-NLS-1$
+
+ /* Associate a host's thread to a virtual CPU */
+ private final Map<HostThread, VirtualCPU> fTidToVcpu = new HashMap<>();
+ /* Associate a host's thread to a virtual machine */
+ private final Map<HostThread, VirtualMachine> fTidToVm = new HashMap<>();
+ /* Maps a virtual machine name to a virtual machine */
+ private final Map<String, VirtualMachine> fKnownMachines = new HashMap<>();
+
+ private final TmfExperiment fExperiment;
+
+ static final ImmutableSet<String> REQUIRED_EVENTS = NonNullUtils.checkNotNull(ImmutableSet.of(
+ QemuKvmStrings.KVM_ENTRY,
+ QemuKvmStrings.KVM_EXIT,
+ QemuKvmStrings.VMSYNC_GH_GUEST,
+ QemuKvmStrings.VMSYNC_GH_HOST,
+ QemuKvmStrings.VMSYNC_HG_GUEST,
+ QemuKvmStrings.VMSYNC_HG_HOST
+ ));
+
+ /**
+ * Constructor
+ *
+ * @param exp
+ * The experiment this model applies to
+ */
+ public QemuKvmVmModel(TmfExperiment exp) {
+ fExperiment = exp;
+ }
+
+ @Override
+ public @Nullable VirtualMachine getCurrentMachine(ITmfEvent event) {
+ final String hostId = event.getTrace().getHostId();
+ VirtualMachine machine = fKnownMachines.get(hostId);
+ if (machine != null) {
+ return machine;
+ }
+
+ /*
+ * TODO: This model wouldn't support a machine (same hostId) being both
+ * a guest and a host
+ */
+
+ /*
+ * This code path would be used only at the beginning of the analysis.
+ * Once all the hostIds have been associated with a virtual machine, the
+ * machines are all cached and the method returns earlier
+ */
+ /* Try to get the virtual machine from the event */
+ String eventName = event.getType().getName();
+ if (eventName.startsWith(KVM)) {
+ /* Only the host machine has kvm_* events, so this is a host */
+ machine = VirtualMachine.newHostMachine(hostId);
+ } else if (eventName.equals(QemuKvmStrings.VMSYNC_GH_GUEST) || eventName.equals(QemuKvmStrings.VMSYNC_HG_GUEST)) {
+ /* Those events are only present in the guests */
+ TmfEventField field = (TmfEventField) event.getContent();
+ ITmfEventField data = field.getField(QemuKvmStrings.VM_UID_PAYLOAD);
+ if (data != null) {
+ machine = VirtualMachine.newGuestMachine((Long) data.getValue(), hostId);
+ }
+ }
+ if (machine != null) {
+ /* Associate the machine to the hostID here, for cached access later */
+ fKnownMachines.put(hostId, machine);
+ }
+ return machine;
+ }
+
+ @Override
+ public Set<String> getRequiredEvents() {
+ return REQUIRED_EVENTS;
+ }
+
+ private @Nullable VirtualMachine findVmFromParent(ITmfEvent event, HostThread ht) {
+ /*
+ * Maybe the parent of the current thread has a VM associated, see if we
+ * can infer the VM for this thread
+ */
+ LttngKernelAnalysis module = getLttngKernelModuleFor(ht.getHost());
+ if (module == null) {
+ return null;
+ }
+
+ Integer ppid = LttngKernelThreadInformationProvider.getParentPid(module, ht.getTid(), event.getTimestamp().getValue());
+ if (ppid == null) {
+ return null;
+ }
+
+ HostThread parentHt = new HostThread(ht.getHost(), ppid);
+ VirtualMachine vm = fTidToVm.get(parentHt);
+ if (vm == null) {
+ return null;
+ }
+ fTidToVm.put(ht, vm);
+
+ return vm;
+ }
+
+ @Override
+ public @Nullable VirtualCPU getVCpuExitingHypervisorMode(ITmfEvent event, HostThread ht) {
+ final String eventName = event.getType().getName();
+
+ /* TODO: Use event layouts for this part also */
+ /*
+ * The KVM_ENTRY event means we are entering a virtual CPU, so exiting
+ * hypervisor mode
+ */
+ if (!eventName.equals(QemuKvmStrings.KVM_ENTRY)) {
+ return null;
+ }
+
+ /*
+ * Are we entering the hypervisor and if so, which virtual CPU is
+ * concerned?
+ */
+ VirtualMachine vm = fTidToVm.get(ht);
+ if (vm == null) {
+ vm = findVmFromParent(event, ht);
+ if (vm == null) {
+ return null;
+ }
+ }
+ /* Associate this thread with the virtual CPU that is going to be run */
+ final ITmfEventField content = event.getContent();
+ long vcpu_id = (Long) content.getField(QemuKvmStrings.VCPU_ID).getValue();
+
+ VirtualCPU virtualCPU = VirtualCPU.getVirtualCPU(vm, vcpu_id);
+ fTidToVcpu.put(ht, virtualCPU);
+
+ return virtualCPU;
+ }
+
+ @Override
+ public @Nullable VirtualCPU getVCpuEnteringHypervisorMode(ITmfEvent event, HostThread ht) {
+ final String eventName = event.getType().getName();
+ /*
+ * The KVM_EXIT event means we are exiting a virtual CPU, so entering
+ * hypervisor mode
+ */
+ if (!eventName.equals(QemuKvmStrings.KVM_EXIT)) {
+ return null;
+ }
+
+ return getVirtualCpu(ht);
+ }
+
+ @Override
+ public @Nullable VirtualCPU getVirtualCpu(HostThread ht) {
+ return fTidToVcpu.get(ht);
+ }
+
+ @Override
+ public void handleEvent(ITmfEvent event) {
+ /* Is the event handled by this model */
+ final String eventName = event.getType().getName();
+ if (!eventName.equals(QemuKvmStrings.VMSYNC_GH_HOST)) {
+ return;
+ }
+
+ final ITmfEventField content = event.getContent();
+ final long ts = event.getTimestamp().getValue();
+ final String hostId = event.getTrace().getHostId();
+
+ Integer cpu = null;
+ Iterable<TmfCpuAspect> aspects = TmfTraceUtils.getEventAspectsOfClass(event.getTrace(), TmfCpuAspect.class);
+ for (TmfCpuAspect aspect : aspects) {
+ Integer thisCpu = aspect.resolve(event);
+ if (!thisCpu.equals(TmfCpuAspect.CPU_UNAVAILABLE)) {
+ cpu = thisCpu;
+ break;
+ }
+ }
+ if (cpu == null) {
+ /* We couldn't find any CPU information, ignore this event */
+ return;
+ }
+
+ /* Find a virtual machine with the vm uid payload value */
+ ITmfEventField data = content.getField(QemuKvmStrings.VM_UID_PAYLOAD);
+ if (data == null) {
+ return;
+ }
+ long vmUid = (Long) data.getValue();
+ for (Entry<String, VirtualMachine> entry : fKnownMachines.entrySet()) {
+ if (entry.getValue().getVmUid() == vmUid) {
+ /*
+ * We found the VM being run, let's associate it with the thread
+ * ID
+ */
+ LttngKernelAnalysis module = getLttngKernelModuleFor(hostId);
+ if (module == null) {
+ break;
+ }
+ Integer tid = LttngKernelThreadInformationProvider.getThreadOnCpu(module, cpu, ts);
+ if (tid == null) {
+ /*
+ * We do not know which process is running at this point. It
+ * may happen at the beginning of the trace.
+ */
+ break;
+ }
+ HostThread ht = new HostThread(hostId, tid);
+ fTidToVm.put(ht, entry.getValue());
+
+ /*
+ * To make sure siblings are also associated with this VM, also
+ * add an entry for the parent TID
+ */
+ Integer ppid = LttngKernelThreadInformationProvider.getParentPid(module, tid, ts);
+ if (ppid != null) {
+ HostThread parentHt = new HostThread(hostId, ppid);
+ fTidToVm.put(parentHt, entry.getValue());
+ }
+ }
+ }
+ }
+
+ private @Nullable LttngKernelAnalysis getLttngKernelModuleFor(String hostId) {
+ return TmfExperimentUtils.getAnalysisModuleOfClassForHost(fExperiment, hostId, LttngKernelAnalysis.class);
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * École Polytechnique de Montréal - Initial API and implementation
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.qemukvm;
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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 v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Geneviève Bastien - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.module;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Externalized message strings from the LTTng Kernel Analysis
+ *
+ * @author Geneviève Bastien
+ */
+@SuppressWarnings("javadoc")
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.module.messages"; //$NON-NLS-1$
+
+ public static @Nullable String VirtualMachineCPUAnalysis_Help;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+
+ /**
+ * Helper method to expose externalized strings as non-null objects.
+ */
+ public static String getMessage(@Nullable String msg) {
+ if (msg == null) {
+ return ""; //$NON-NLS-1$
+ }
+ return msg;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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 v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mohamad Gebai - Initial API and implementation
+ * Geneviève Bastien - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.module;
+
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.VcpuStateValues;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.VmAttributes;
+import org.eclipse.tracecompass.lttng2.kernel.core.analysis.kernel.LttngKernelAnalysis;
+import org.eclipse.tracecompass.lttng2.kernel.core.analysis.kernel.LttngKernelThreadInformationProvider;
+import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
+import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
+import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
+import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
+import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
+import org.eclipse.tracecompass.statesystem.core.interval.TmfStateInterval;
+import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
+import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
+import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule;
+import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider;
+import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
+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 org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperimentUtils;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.TreeMultimap;
+
+/**
+ * Module for the virtual machine CPU analysis. It tracks the status of the
+ * virtual CPUs for each guest of the experiment.
+ *
+ * @author Mohamad Gebai
+ * @author Geneviève Bastien
+ */
+public class VirtualMachineCpuAnalysis extends TmfStateSystemAnalysisModule {
+
+ // TODO: Update with event layout when requirements are back */
+ static final Set<String> REQUIRED_EVENTS = NonNullUtils.checkNotNull(ImmutableSet.<String> of(
+ // LttngStrings.SCHED_SWITCH
+ ));
+
+ /* State value for a preempted virtual CPU */
+ private static final ITmfStateValue VCPU_PREEMPT_VALUE = TmfStateValue.newValueInt(VcpuStateValues.VCPU_PREEMPT);
+
+ /**
+ * Constructor
+ */
+ public VirtualMachineCpuAnalysis() {
+ super();
+ }
+
+ @Override
+ protected ITmfStateProvider createStateProvider() {
+ ITmfTrace trace = getTrace();
+ if (!(trace instanceof TmfExperiment)) {
+ throw new IllegalStateException();
+ }
+ return new VirtualMachineStateProvider((TmfExperiment) trace);
+ }
+
+ @Override
+ protected @NonNull StateSystemBackendType getBackendType() {
+ return StateSystemBackendType.FULL;
+ }
+
+ @Override
+ public String getHelpText() {
+ return Messages.getMessage(Messages.VirtualMachineCPUAnalysis_Help);
+ }
+
+ @Override
+ protected Iterable<IAnalysisModule> getDependentAnalyses() {
+ Set<IAnalysisModule> modules = new HashSet<>();
+ /* Depends on the LTTng Kernel analysis modules */
+ for (ITmfTrace trace : TmfTraceManager.getTraceSet(getTrace())) {
+ for (LttngKernelAnalysis module : TmfTraceUtils.getAnalysisModulesOfClass(trace, LttngKernelAnalysis.class)) {
+ modules.add(module);
+ }
+ }
+ return modules;
+ }
+
+ private static Multimap<Integer, ITmfStateInterval> createThreadMultimap() {
+
+ /*
+ * Create the multimap for threads with the appropriate comparator
+ * objects for keys and values
+ */
+ final Multimap<Integer, ITmfStateInterval> map = NonNullUtils.checkNotNull(TreeMultimap.<Integer, ITmfStateInterval> create(
+ new Comparator<Integer>() {
+ @Override
+ public int compare(@Nullable Integer arg0, @Nullable Integer arg1) {
+ /*
+ * Keys do not have to be sorted, just use natural
+ * sorting
+ */
+ if (arg0 == null || arg1 == null) {
+ return -1;
+ }
+ return arg0.compareTo(arg1);
+ }
+ }, new Comparator<ITmfStateInterval>() {
+ @Override
+ public int compare(@Nullable ITmfStateInterval arg0, @Nullable ITmfStateInterval arg1) {
+ if (arg0 == null || arg1 == null) {
+ return 0;
+ }
+ if (arg1.getStateValue() == VCPU_PREEMPT_VALUE && arg0.getStateValue() != VCPU_PREEMPT_VALUE) {
+ /*
+ * For VCPU_PREEMPT state values, the state has to
+ * be after any other state that it overlaps,
+ * because those intervals usually decorate the
+ * other intervals.
+ */
+ if (((Long) arg0.getEndTime()).compareTo(arg1.getStartTime()) < 0) {
+ return -1;
+ }
+ return ((Long) arg0.getStartTime()).compareTo(arg1.getEndTime());
+ }
+ /* Otherwise, we use ordering by start time */
+ return (((Long) arg0.getStartTime()).compareTo(arg1.getStartTime()));
+ }
+ }));
+ return map;
+ }
+
+ /**
+ * Get the status intervals for the threads from a virtual machine. Those
+ * intervals are correlated with the data from the virtual CPU's preemption
+ * status.
+ *
+ * This method uses the Linux Kernel Analysis data for the thread's status
+ * intervals.
+ *
+ * @param vmQuark
+ * The quark of the virtual machine
+ * @param start
+ * The start time of the period to get the intervals from
+ * @param end
+ * The end time of the period to get the intervals from
+ * @param resolution
+ * The resolution
+ * @param monitor
+ * A progress monitor for this task
+ * @return A map of status intervals for the machine's threads, including
+ * preempted intervals. Intervals from the thread status and the CPU
+ * preemption status overlap and are ordered such that CPU
+ * preemption intervals are after any interval they overlap with
+ */
+ public Multimap<Integer, ITmfStateInterval> getUpdatedThreadIntervals(int vmQuark, long start, long end, long resolution, IProgressMonitor monitor) {
+
+ final Multimap<Integer, ITmfStateInterval> map = createThreadMultimap();
+
+ ITmfStateSystem ss = getStateSystem();
+ if (ss == null) {
+ return map;
+ }
+ ITmfTrace trace = getTrace();
+ if (!(trace instanceof TmfExperiment)) {
+ return map;
+ }
+
+ String vmHostId = NonNullUtils.checkNotNull(ss.getAttributeName(vmQuark));
+ LttngKernelAnalysis kernelModule = TmfExperimentUtils.getAnalysisModuleOfClassForHost((TmfExperiment) trace, vmHostId, LttngKernelAnalysis.class);
+ if (kernelModule == null) {
+ return map;
+ }
+
+ /*
+ * Initialize the map with the original status intervals from the kernel
+ * module
+ */
+ for (Integer tid : LttngKernelThreadInformationProvider.getThreadIds(kernelModule)) {
+ if (tid == null) {
+ throw new IllegalStateException();
+ }
+ map.putAll(tid, LttngKernelThreadInformationProvider.getStatusIntervalsForThread(kernelModule, tid, start, end, resolution, monitor));
+ if (monitor.isCanceled()) {
+ return map;
+ }
+ }
+
+ try {
+ /* Correlate thread information with virtual CPU information */
+ for (Integer vcpuQuark : ss.getSubAttributes(vmQuark, false)) {
+ Long virtualCPU = Long.parseLong(ss.getAttributeName(vcpuQuark));
+ Integer statusQuark = ss.getQuarkRelative(vcpuQuark, VmAttributes.STATUS);
+
+ for (ITmfStateInterval cpuInterval : StateSystemUtils.queryHistoryRange(ss, statusQuark, start, end - 1, resolution, monitor)) {
+ ITmfStateValue stateValue = cpuInterval.getStateValue();
+ switch (stateValue.getType()) {
+ case INTEGER:
+ int value = stateValue.unboxInt();
+ /*
+ * If the current CPU is either preempted or in
+ * hypervisor mode, add preempted intervals to running
+ * processes
+ */
+ if ((value & (VcpuStateValues.VCPU_PREEMPT | VcpuStateValues.VCPU_VMM)) == 0) {
+ break;
+ }
+ Integer threadOnCpu = LttngKernelThreadInformationProvider.getThreadOnCpu(kernelModule, virtualCPU, cpuInterval.getStartTime());
+ if (threadOnCpu != null) {
+ map.put(threadOnCpu, new TmfStateInterval(cpuInterval.getStartTime(), cpuInterval.getEndTime(), threadOnCpu, VCPU_PREEMPT_VALUE));
+ }
+ break;
+ case DOUBLE:
+ case LONG:
+ case NULL:
+ case STRING:
+ default:
+ break;
+ }
+
+ }
+ }
+ } catch (AttributeNotFoundException | StateSystemDisposedException e) {
+ }
+ return NonNullUtils.checkNotNull(map);
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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 v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mohamad Gebai - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.module;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.Activator;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.VcpuStateValues;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.VmAttributes;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.HostThread;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.IVirtualMachineModel;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.VirtualCPU;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.VirtualMachine;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.model.qemukvm.QemuKvmVmModel;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.trace.layout.IKernelAnalysisEventLayout;
+import org.eclipse.tracecompass.internal.lttng2.kernel.core.trace.layout.LttngEventLayout;
+import org.eclipse.tracecompass.lttng2.kernel.core.analysis.kernel.LttngKernelAnalysis;
+import org.eclipse.tracecompass.lttng2.kernel.core.analysis.kernel.LttngKernelThreadInformationProvider;
+import org.eclipse.tracecompass.lttng2.kernel.core.trace.LttngKernelTrace;
+import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
+import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
+import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
+import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
+import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
+import org.eclipse.tracecompass.tmf.core.event.aspect.TmfCpuAspect;
+import org.eclipse.tracecompass.tmf.core.statesystem.AbstractTmfStateProvider;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
+import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment;
+import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperimentUtils;
+
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Table;
+
+/**
+ * This is the state provider which translates the virtual machine experiment
+ * events to a state system.
+ *
+ * Attribute tree:
+ *
+ * <pre>
+ * |- Virtual Machines
+ * | |- <Guest Host ID> -> Friendly name (trace name)
+ * | | |- <VCPU number>
+ * | | | |- Status -> <Status value>
+ * </pre>
+ *
+ * The status value of the VCPUs are either {@link VcpuStateValues#VCPU_IDLE},
+ * {@link VcpuStateValues#VCPU_UNKNOWN} or {@link VcpuStateValues#VCPU_RUNNING}.
+ * Those three values are ORed with flags {@link VcpuStateValues#VCPU_VMM}
+ * and/or {@link VcpuStateValues#VCPU_PREEMPT} to indicate respectively whether
+ * they are in hypervisor mode or preempted on the host.
+ *
+ * @author Mohamad Gebai
+ */
+public class VirtualMachineStateProvider extends AbstractTmfStateProvider {
+
+ /**
+ * Version number of this state provider. Please bump this if you modify the
+ * contents of the generated state history in some way.
+ */
+ private static final int VERSION = 1;
+
+ private static final int SCHED_SWITCH_INDEX = 0;
+
+ /* TODO: An analysis should support many hypervisor models */
+ private IVirtualMachineModel fModel;
+ private final Table<ITmfTrace, String, Integer> fEventNames;
+ private final Map<ITmfTrace, IKernelAnalysisEventLayout> fLayouts;
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructor
+ *
+ * @param experiment
+ * The virtual machine experiment
+ */
+ public VirtualMachineStateProvider(TmfExperiment experiment) {
+ super(experiment, ITmfEvent.class, "Virtual Machine State Provider"); //$NON-NLS-1$
+
+ fModel = new QemuKvmVmModel(experiment);
+ Table<ITmfTrace, String, Integer> table = NonNullUtils.checkNotNull(HashBasedTable.<ITmfTrace, String, Integer> create());
+ fEventNames = table;
+ fLayouts = new HashMap<>();
+ }
+
+ // ------------------------------------------------------------------------
+ // Event names management
+ // ------------------------------------------------------------------------
+
+ private void buildEventNames(ITmfTrace trace) {
+ IKernelAnalysisEventLayout layout;
+ if (trace instanceof LttngKernelTrace) {
+ layout = ((LttngKernelTrace) trace).getEventLayout();
+ } else {
+ /* Fall-back to the base LttngEventLayout */
+ layout = LttngEventLayout.getInstance();
+ }
+ fLayouts.put(trace, layout);
+ fEventNames.put(trace, layout.eventSchedSwitch(), SCHED_SWITCH_INDEX);
+ }
+
+ // ------------------------------------------------------------------------
+ // IStateChangeInput
+ // ------------------------------------------------------------------------
+
+ @Override
+ public TmfExperiment getTrace() {
+ ITmfTrace trace = super.getTrace();
+ if (trace instanceof TmfExperiment) {
+ return (TmfExperiment) trace;
+ }
+ throw new IllegalStateException("VirtualMachineStateProvider: The associated trace should be an experiment"); //$NON-NLS-1$
+ }
+
+ @Override
+ public int getVersion() {
+ return VERSION;
+ }
+
+ @Override
+ public VirtualMachineStateProvider getNewInstance() {
+ TmfExperiment trace = getTrace();
+ return new VirtualMachineStateProvider(trace);
+ }
+
+ @Override
+ protected void eventHandle(@Nullable ITmfEvent event) {
+ if (event == null) {
+ return;
+ }
+
+ /* Is the event managed by this analysis */
+ final String eventName = event.getType().getName();
+
+ /* TODO When requirements work again, don't hardcode this */
+ if (!eventName.equals("sched_switch") && //$NON-NLS-1$
+ !fModel.getRequiredEvents().contains(eventName)) {
+ return;
+ }
+
+ ITmfStateValue value;
+
+ final ITmfEventField content = event.getContent();
+ final long ts = event.getTimestamp().getValue();
+ final String hostId = event.getTrace().getHostId();
+ try {
+ /* Do we know this trace's role yet? */
+ VirtualMachine host = fModel.getCurrentMachine(event);
+ if (host == null) {
+ return;
+ }
+
+ /* Make sure guest traces are added to the state system */
+ if (host.isGuest()) {
+ /*
+ * If event from a guest OS, make sure the guest exists in the
+ * state system
+ */
+ int vmQuark = -1;
+ try {
+ vmQuark = ss.getQuarkRelative(getNodeVirtualMachines(), host.getHostId());
+ } catch (AttributeNotFoundException e) {
+ /*
+ * We should enter this catch only once per machine, so it
+ * is not so costly to do compared with adding the trace's
+ * name for each guest event
+ */
+ vmQuark = ss.getQuarkRelativeAndAdd(getNodeVirtualMachines(), host.getHostId());
+ TmfStateValue machineName = TmfStateValue.newValueString(event.getTrace().getName());
+ ss.modifyAttribute(ts, machineName, vmQuark);
+ }
+ }
+
+ /* Have the hypervisor models handle the event first */
+ fModel.handleEvent(event);
+
+ /* Handle the event here */
+ if (!fEventNames.containsRow(event.getTrace())) {
+ buildEventNames(event.getTrace());
+ }
+ Integer idx = fEventNames.get(event.getTrace(), eventName);
+ int intval = (idx == null ? -1 : idx.intValue());
+ switch (intval) {
+ case SCHED_SWITCH_INDEX: // "sched_switch":
+ /*
+ * Fields: string prev_comm, int32 prev_tid, int32 prev_prio, int64
+ * prev_state, string next_comm, int32 next_tid, int32 next_prio
+ */
+ {
+ Integer prevTid = ((Long) content.getField(fLayouts.get(event.getTrace()).fieldPrevTid()).getValue()).intValue();
+ Integer nextTid = ((Long) content.getField(fLayouts.get(event.getTrace()).fieldNextTid()).getValue()).intValue();
+
+ if (prevTid == null || nextTid == null) {
+ break;
+ }
+
+ if (host.isGuest()) {
+ /* Get the event's CPU */
+ Integer cpu = null;
+ Iterable<TmfCpuAspect> aspects = TmfTraceUtils.getEventAspectsOfClass(event.getTrace(), TmfCpuAspect.class);
+ for (TmfCpuAspect aspect : aspects) {
+ if (!aspect.resolve(event).equals(TmfCpuAspect.CPU_UNAVAILABLE)) {
+ cpu = aspect.resolve(event);
+ break;
+ }
+ }
+ if (cpu == null) {
+ /*
+ * We couldn't find any CPU information, ignore this
+ * event
+ */
+ break;
+ }
+
+ /*
+ * If sched switch is from a guest, just update the status
+ * of the virtual CPU to either idle or running
+ */
+ int curStatusQuark = ss.getQuarkRelativeAndAdd(getNodeVirtualMachines(), host.getHostId(),
+ cpu.toString(), VmAttributes.STATUS);
+ value = TmfStateValue.newValueInt(VcpuStateValues.VCPU_IDLE);
+ if (nextTid > 0) {
+ value = TmfStateValue.newValueInt(VcpuStateValues.VCPU_RUNNING);
+ }
+ ss.modifyAttribute(ts, value, curStatusQuark);
+ break;
+ }
+
+ /* Event is not from a guest */
+ /* Verify if the previous thread corresponds to a virtual CPU */
+ HostThread ht = new HostThread(hostId, prevTid);
+ VirtualCPU vcpu = fModel.getVirtualCpu(ht);
+
+ /*
+ * If previous thread is virtual CPU, update status of the
+ * virtual CPU to preempted
+ */
+ if (vcpu != null) {
+ VirtualMachine vm = vcpu.getVm();
+
+ int curStatusQuark = ss.getQuarkRelativeAndAdd(getNodeVirtualMachines(), vm.getHostId(),
+ vcpu.getCpuId().toString(), VmAttributes.STATUS);
+
+ /* Add the preempted flag to the status */
+ value = ss.queryOngoingState(curStatusQuark);
+ int newVal = Math.max(VcpuStateValues.VCPU_UNKNOWN, value.unboxInt());
+ value = TmfStateValue.newValueInt(newVal | VcpuStateValues.VCPU_PREEMPT);
+ ss.modifyAttribute(ts, value, curStatusQuark);
+ }
+
+ /* Verify if the next thread corresponds to a virtual CPU */
+ ht = new HostThread(hostId, nextTid);
+ vcpu = fModel.getVirtualCpu(ht);
+
+ /*
+ * If next thread is virtual CPU, update status of the virtual
+ * CPU the previous status
+ */
+ if (vcpu != null) {
+ VirtualMachine vm = vcpu.getVm();
+ int curStatusQuark = ss.getQuarkRelativeAndAdd(getNodeVirtualMachines(), vm.getHostId(),
+ vcpu.getCpuId().toString(), VmAttributes.STATUS);
+
+ /* Remove the preempted flag from the status */
+ value = ss.queryOngoingState(curStatusQuark);
+ int newVal = Math.max(VcpuStateValues.VCPU_UNKNOWN, value.unboxInt());
+ value = TmfStateValue.newValueInt(newVal & ~VcpuStateValues.VCPU_PREEMPT);
+ ss.modifyAttribute(ts, value, curStatusQuark);
+
+ }
+
+ }
+ break;
+
+ default:
+ /* Other events not covered by the main switch */
+ {
+ HostThread ht = getCurrentHostThread(event, ts);
+ if (ht == null) {
+ break;
+ }
+
+ /*
+ * Are we entering the hypervisor mode and if so, which virtual
+ * CPU is concerned?
+ */
+ VirtualCPU virtualCpu = fModel.getVCpuEnteringHypervisorMode(event, ht);
+ if (virtualCpu != null) {
+ /* Add the hypervisor flag to the status */
+ VirtualMachine vm = virtualCpu.getVm();
+ int curStatusQuark = ss.getQuarkRelativeAndAdd(getNodeVirtualMachines(), vm.getHostId(),
+ Long.toString(virtualCpu.getCpuId()), VmAttributes.STATUS);
+ value = ss.queryOngoingState(curStatusQuark);
+ int newVal = Math.max(VcpuStateValues.VCPU_UNKNOWN, value.unboxInt());
+ value = TmfStateValue.newValueInt(newVal | VcpuStateValues.VCPU_VMM);
+ ss.modifyAttribute(ts, value, curStatusQuark);
+ }
+
+ /*
+ * Are we exiting the hypervisor mode and if so, which virtual
+ * CPU is concerned?
+ */
+ virtualCpu = fModel.getVCpuExitingHypervisorMode(event, ht);
+ if (virtualCpu != null) {
+ /* Remove the hypervisor flag from the status */
+ VirtualMachine vm = virtualCpu.getVm();
+ int curStatusQuark = ss.getQuarkRelativeAndAdd(getNodeVirtualMachines(), vm.getHostId(),
+ Long.toString(virtualCpu.getCpuId()), VmAttributes.STATUS);
+ value = ss.queryOngoingState(curStatusQuark);
+ int newVal = Math.max(VcpuStateValues.VCPU_UNKNOWN, value.unboxInt());
+ value = TmfStateValue.newValueInt(newVal & ~VcpuStateValues.VCPU_VMM);
+ ss.modifyAttribute(ts, value, curStatusQuark);
+ }
+
+ }
+ break;
+ }
+
+ } catch (AttributeNotFoundException | TimeRangeException | StateValueTypeException e) {
+ Activator.getDefault().logError("Error handling event in VirtualMachineStateProvider", e); //$NON-NLS-1$
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Convenience methods for commonly-used attribute tree locations
+ // ------------------------------------------------------------------------
+
+ private int getNodeVirtualMachines() {
+ return ss.getQuarkAbsoluteAndAdd(VmAttributes.VIRTUAL_MACHINES);
+ }
+
+ private @Nullable HostThread getCurrentHostThread(ITmfEvent event, long ts) {
+ /* Get the LTTng kernel analysis for the host */
+ String hostId = event.getTrace().getHostId();
+ LttngKernelAnalysis module = TmfExperimentUtils.getAnalysisModuleOfClassForHost(getTrace(), hostId, LttngKernelAnalysis.class);
+ if (module == null) {
+ return null;
+ }
+
+ /* Get the CPU the event is running on */
+ Integer cpu = null;
+ Iterable<TmfCpuAspect> aspects = TmfTraceUtils.getEventAspectsOfClass(event.getTrace(), TmfCpuAspect.class);
+ for (TmfCpuAspect aspect : aspects) {
+ if (!aspect.resolve(event).equals(TmfCpuAspect.CPU_UNAVAILABLE)) {
+ cpu = aspect.resolve(event);
+ break;
+ }
+ }
+ if (cpu == null) {
+ /* We couldn't find any CPU information, ignore this event */
+ return null;
+ }
+
+ Integer currentTid = LttngKernelThreadInformationProvider.getThreadOnCpu(module, cpu, ts);
+ if (currentTid == null) {
+ return null;
+ }
+ return new HostThread(hostId, currentTid);
+ }
+
+}
\ No newline at end of file
--- /dev/null
+###############################################################################
+# Copyright (c) 2014 É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 v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Geneviève Bastien - Initial API and implementation
+###############################################################################
+
+VirtualMachineCPUAnalysis_Help=Tracks the state of the virtual CPUs of the guest virtual machine in an experiment. It also interrelate the CPU information with the information from thread status of each guest.
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * École Polytechnique de Montréal - Initial API and implementation
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.module;
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * École Polytechnique de Montréal - Initial API and implementation
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm;
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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 v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mohamad Gebai - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.trace;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment;
+import org.eclipse.tracecompass.tmf.ctf.core.event.CtfTmfEvent;
+
+/**
+ * Experiment class containing traces from physical machine and the virtual
+ * guests running on them.
+ *
+ * @author Mohamad Gebai
+ */
+public class VirtualMachineExperiment extends TmfExperiment {
+
+ /**
+ * Default constructor. Needed by the extension point.
+ */
+ @SuppressWarnings("null")
+ public VirtualMachineExperiment() {
+ this("default", Collections.EMPTY_SET); //$NON-NLS-1$
+ }
+
+ /**
+ * Constructor with traces and id
+ *
+ * @param id
+ * The ID of this experiment
+ * @param traces
+ * The set of traces that are part of this experiment
+ */
+ public VirtualMachineExperiment(String id, Set<ITmfTrace> traces) {
+ super(CtfTmfEvent.class, id, traces.toArray(new ITmfTrace[traces.size()]), TmfExperiment.DEFAULT_INDEX_PAGE_SIZE, null);
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 É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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * École Polytechnique de Montréal - Initial API and implementation
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.trace;
\ No newline at end of file
private static final ImmutableSet<String> OPTIONAL_EVENTS = ImmutableSet.of(
// FIXME These cannot be declared statically anymore, they depend on
// the OriginTracer of the kernel trace.
-// LttngStrings.EXIT_SYSCALL,
-// LttngStrings.IRQ_HANDLER_ENTRY,
-// LttngStrings.IRQ_HANDLER_EXIT,
-// LttngStrings.SOFTIRQ_ENTRY,
-// LttngStrings.SOFTIRQ_EXIT,
-// LttngStrings.SOFTIRQ_RAISE,
-// LttngStrings.SCHED_PROCESS_FORK,
-// LttngStrings.SCHED_PROCESS_EXIT,
-// LttngStrings.SCHED_PROCESS_FREE,
-// LttngStrings.SCHED_SWITCH,
-// LttngStrings.STATEDUMP_PROCESS_STATE,
-// LttngStrings.SCHED_WAKEUP,
-// LttngStrings.SCHED_WAKEUP_NEW,
-//
-// /* FIXME Add the prefix for syscalls */
-// LttngStrings.SYSCALL_PREFIX
+ // LttngStrings.EXIT_SYSCALL,
+ // LttngStrings.IRQ_HANDLER_ENTRY,
+ // LttngStrings.IRQ_HANDLER_EXIT,
+ // LttngStrings.SOFTIRQ_ENTRY,
+ // LttngStrings.SOFTIRQ_EXIT,
+ // LttngStrings.SOFTIRQ_RAISE,
+ // LttngStrings.SCHED_PROCESS_FORK,
+ // LttngStrings.SCHED_PROCESS_EXIT,
+ // LttngStrings.SCHED_PROCESS_FREE,
+ // LttngStrings.SCHED_SWITCH,
+ // LttngStrings.STATEDUMP_PROCESS_STATE,
+ // LttngStrings.SCHED_WAKEUP,
+ // LttngStrings.SCHED_WAKEUP_NEW,
+ //
+ // /* FIXME Add the prefix for syscalls */
+ // LttngStrings.SYSCALL_PREFIX
);
/** The requirements as an immutable set */