blob: ee76ebcf648631f4f0d1184652aa2d2d139214b2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 É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 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.virtual.resources.handlers;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.tracecompass.analysis.os.linux.core.model.HostThread;
import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelAnalysisEventLayout;
import org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.IVirtualMachineEventHandler;
import org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.data.VcpuStateValues;
import org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.model.IVirtualEnvironmentModel;
import org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.model.VirtualCPU;
import org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.model.VirtualMachine;
import org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.virtual.resources.VmAttributes;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
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.trace.TmfTraceUtils;
/**
* Handle sched switches
*
* @author Geneviève Bastien
*/
public class SchedSwitchEventHandler implements IVirtualMachineEventHandler {
private Map<IKernelAnalysisEventLayout, Set<String>> fRequiredEvents = new HashMap<>();
/**
* Constructor
*/
public SchedSwitchEventHandler() {
// Nothing to do
}
@Override
public Set<String> getRequiredEvents(IKernelAnalysisEventLayout layout) {
Set<String> events = fRequiredEvents.get(layout);
if (events == null) {
events = new HashSet<>();
events.add(layout.eventSchedSwitch());
fRequiredEvents.put(layout, events);
}
return events;
}
@Override
public void handleEvent(ITmfStateSystemBuilder ss, ITmfEvent event, IVirtualEnvironmentModel virtEnv, IKernelAnalysisEventLayout eventLayout) {
ITmfEventField content = event.getContent();
long ts = event.getTimestamp().toNanos();
Long prevTid = content.getFieldValue(Long.class, eventLayout.fieldPrevTid());
Long nextTid = content.getFieldValue(Long.class, eventLayout.fieldNextTid());
VirtualMachine currentMachine = virtEnv.getCurrentMachine(event);
/*
* If sched switch is from a guest, just update the status of the virtual CPU to
* either idle or running
*/
if (currentMachine.isGuest() && nextTid != null) {
updateGuestStatus(ss, event, ts, currentMachine, nextTid);
}
/*
* If previous thread is virtual CPU, update status of the virtual CPU to
* preempted
*/
if (currentMachine.isHost() && prevTid != null) {
updatePreviousHostStatus(ss, event, ts, currentMachine, prevTid, virtEnv);
}
/*
* If next thread is virtual CPU, update status of the virtual CPU the previous
* status
*/
if (currentMachine.isHost() && nextTid != null) {
updateNextHostStatus(ss, event, ts, currentMachine, nextTid, virtEnv);
}
}
private static void updateNextHostStatus(ITmfStateSystemBuilder ss, ITmfEvent event, long ts, VirtualMachine currentMachine, Long nextTid, IVirtualEnvironmentModel virtEnv) {
HostThread ht = new HostThread(currentMachine.getHostId(), nextTid.intValue());
VirtualCPU vcpu = virtEnv.getVirtualCpu(event, ht);
if (vcpu == null) {
return;
}
VirtualMachine vm = vcpu.getVm();
int curStatusQuark = ss.getQuarkAbsoluteAndAdd(VmAttributes.VIRTUAL_MACHINES, vm.getHostId(),
vcpu.getCpuId().toString(), VmAttributes.STATUS);
/* Remove the preempted flag from the status */
int prevStatus = Math.max(VcpuStateValues.VCPU_UNKNOWN, ss.queryOngoingState(curStatusQuark).unboxInt());
int value = prevStatus & ~VcpuStateValues.VCPU_PREEMPT;
ss.modifyAttribute(ts, value, curStatusQuark);
}
private static void updatePreviousHostStatus(ITmfStateSystemBuilder ss, ITmfEvent event, long ts, VirtualMachine currentMachine, Long prevTid, IVirtualEnvironmentModel virtEnv) {
HostThread ht = new HostThread(currentMachine.getHostId(), prevTid.intValue());
VirtualCPU vcpu = virtEnv.getVirtualCpu(event, ht);
if (vcpu == null) {
return;
}
VirtualMachine vm = vcpu.getVm();
int curStatusQuark = ss.getQuarkAbsoluteAndAdd(VmAttributes.VIRTUAL_MACHINES, vm.getHostId(),
vcpu.getCpuId().toString(), VmAttributes.STATUS);
/* Add the preempted flag to the status */
int prevStatus = Math.max(VcpuStateValues.VCPU_UNKNOWN, ss.queryOngoingState(curStatusQuark).unboxInt());
int value = prevStatus | VcpuStateValues.VCPU_PREEMPT;
ss.modifyAttribute(ts, value, curStatusQuark);
}
private static void updateGuestStatus(ITmfStateSystemBuilder ss, ITmfEvent event, long ts, VirtualMachine currentMachine, Long nextTid) {
Integer cpu = TmfTraceUtils.resolveIntEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event);
if (cpu == null) {
/* We couldn't find any CPU information, ignore */
return;
}
int curStatusQuark = ss.getQuarkAbsoluteAndAdd(VmAttributes.VIRTUAL_MACHINES, currentMachine.getHostId(),
cpu.toString(), VmAttributes.STATUS);
// In theory, sched switches should not happen when vcpu is preempted or in vmm,
// but in practice, synchronization is not perfect and it may.
int currentStatus = ss.queryOngoingState(curStatusQuark).unboxInt();
int curVmStatus = currentStatus & (VcpuStateValues.VCPU_PREEMPT | VcpuStateValues.VCPU_VMM);
int value = (nextTid > 0) ? VcpuStateValues.VCPU_RUNNING | curVmStatus : VcpuStateValues.VCPU_IDLE | curVmStatus;
ss.modifyAttribute(ts, value, curStatusQuark);
}
}