/******************************************************************************* * Copyright (c) 2016 É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 *******************************************************************************/ package org.eclipse.tracecompass.internal.lttng2.kernel.ui.views.vm.vcpuview; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Display; import org.eclipse.tracecompass.analysis.os.linux.core.kernel.StateValues; import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.VcpuStateValues; import org.eclipse.tracecompass.internal.lttng2.kernel.ui.views.vm.vcpuview.VirtualMachineCommon.Type; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.StateItem; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphPresentationProvider; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.NullTimeEvent; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeEvent; /** * Presentation provider for the Virtual Machine view, based on the generic TMF * presentation provider. * * @author Mohamad Gebai */ public class VirtualMachinePresentationProvider extends TimeGraphPresentationProvider { private static final int ALPHA = 70; /* * TODO: Some of it is copy-pasted from the control flow presentation * provider because it actually is the same data as from the control flow * view. Ideally, we should reuse what is there instead of rewriting it here */ private enum State { UNKNOWN(new RGB(100, 100, 100)), IDLE(new RGB(200, 200, 200)), USERMODE(new RGB(0, 200, 0)), WAIT_VMM(new RGB(200, 0, 0)), VCPU_PREEMPTED(new RGB(120, 40, 90)), THREAD_UNKNOWN(new RGB(100, 100, 100)), THREAD_WAIT_BLOCKED(new RGB(200, 200, 0)), THREAD_WAIT_FOR_CPU(new RGB(200, 100, 0)), THREAD_USERMODE(new RGB(0, 200, 0)), THREAD_SYSCALL(new RGB(0, 0, 200)), THREAD_INTERRUPTED(new RGB(200, 0, 100)); private final RGB fRgb; private State(RGB rgb) { fRgb = rgb; } } /** * Default constructor */ public VirtualMachinePresentationProvider() { super(); } private static State[] getStateValues() { return State.values(); } private static State getStateForVcpu(int value) { if ((value & VcpuStateValues.VCPU_PREEMPT) > 0) { return State.VCPU_PREEMPTED; } else if ((value & VcpuStateValues.VCPU_VMM) > 0) { return State.WAIT_VMM; } else if (value == 2) { return State.USERMODE; } else if (value == 1) { return State.IDLE; } else { return State.UNKNOWN; } } private static @Nullable State getStateForThread(int value) { if (value == VcpuStateValues.VCPU_PREEMPT) { return null; } switch (value) { case StateValues.PROCESS_STATUS_RUN_USERMODE: return State.THREAD_USERMODE; case StateValues.PROCESS_STATUS_RUN_SYSCALL: return State.THREAD_SYSCALL; case StateValues.PROCESS_STATUS_WAIT_FOR_CPU: return State.THREAD_WAIT_FOR_CPU; case StateValues.PROCESS_STATUS_WAIT_BLOCKED: return State.THREAD_WAIT_BLOCKED; case StateValues.PROCESS_STATUS_INTERRUPTED: return State.THREAD_INTERRUPTED; case StateValues.PROCESS_STATUS_UNKNOWN: case StateValues.PROCESS_STATUS_WAIT_UNKNOWN: return State.THREAD_UNKNOWN; default: return null; } } private static @Nullable State getEventState(TimeEvent event) { if (event.hasValue()) { VirtualMachineViewEntry entry = (VirtualMachineViewEntry) event.getEntry(); int value = event.getValue(); if (entry.getType() == Type.VCPU) { return getStateForVcpu(value); } else if (entry.getType() == Type.THREAD) { return getStateForThread(value); } } return null; } @Override public int getStateTableIndex(@Nullable ITimeEvent event) { if (event == null) { return TRANSPARENT; } State state = getEventState((TimeEvent) event); if (state != null) { return state.ordinal(); } if (event instanceof NullTimeEvent) { return INVISIBLE; } return TRANSPARENT; } @Override public StateItem[] getStateTable() { State[] states = getStateValues(); StateItem[] stateTable = new StateItem[states.length]; for (int i = 0; i < stateTable.length; i++) { State state = states[i]; stateTable[i] = new StateItem(state.fRgb, state.toString()); } return stateTable; } @Override public @Nullable String getEventName(@Nullable ITimeEvent event) { if (event == null) { return null; } State state = getEventState((TimeEvent) event); if (state != null) { return state.toString(); } if (event instanceof NullTimeEvent) { return null; } return Messages.VmView_multipleStates; } @Override public void postDrawEvent(@Nullable ITimeEvent event, @Nullable Rectangle bounds, @Nullable GC gc) { if (bounds == null || gc == null || !(event instanceof TimeEvent)) { return; } boolean visible = bounds.width == 0 ? false : true; if (!visible) { return; } TimeEvent ev = (TimeEvent) event; /* * FIXME: There seems to be a bug when multiple events should be drawn * under a alpha event. See FIXME comment in * VirtualMachineView#getEventList */ if (ev.hasValue()) { VirtualMachineViewEntry entry = (VirtualMachineViewEntry) event.getEntry(); if (entry.getType() == Type.THREAD) { int value = ev.getValue(); if ((value & VcpuStateValues.VCPU_PREEMPT) != 0) { /* * If the status was preempted at this time, draw an alpha * over this state */ Color alphaColor = Display.getDefault().getSystemColor(SWT.COLOR_RED); int alpha = gc.getAlpha(); Color background = gc.getBackground(); // fill all rect area gc.setBackground(alphaColor); gc.setAlpha(ALPHA); gc.fillRectangle(bounds); gc.setBackground(background); gc.setAlpha(alpha); } } } } }