blob: dfeb3d6fbb9fce8cce3dd5915d74ed1d10b4ecc9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2018 Ericsson, É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.internal.analysis.os.linux.ui.views.resources;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.tracecompass.analysis.os.linux.core.kernel.StateValues;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.registry.LinuxStyle;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.resourcesstatus.ResourcesEntryModel;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.resourcesstatus.ResourcesEntryModel.Type;
import org.eclipse.tracecompass.internal.analysis.os.linux.ui.Messages;
import org.eclipse.tracecompass.internal.provisional.tmf.core.model.timegraph.ITimeGraphEntryModelWeighted;
import org.eclipse.tracecompass.internal.tmf.core.model.filters.FetchParametersUtils;
import org.eclipse.tracecompass.tmf.core.model.StyleProperties;
import org.eclipse.tracecompass.tmf.core.model.filters.SelectionTimeQueryFilter;
import org.eclipse.tracecompass.tmf.core.model.timegraph.ITimeGraphDataProvider;
import org.eclipse.tracecompass.tmf.core.model.timegraph.TimeGraphEntryModel;
import org.eclipse.tracecompass.tmf.core.model.tree.ITmfTreeDataModel;
import org.eclipse.tracecompass.tmf.core.presentation.RGBAColor;
import org.eclipse.tracecompass.tmf.core.presentation.RotatingPaletteProvider;
import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse;
import org.eclipse.tracecompass.tmf.ui.colors.ColorUtils;
import org.eclipse.tracecompass.tmf.ui.views.timegraph.BaseDataProviderTimeGraphView;
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.ITimeGraphEntry;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.NullTimeEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
/**
* Presentation provider for the Resource view, based on the generic TMF
* presentation provider.
*
* @author Patrick Tasse
*/
public class ResourcesPresentationProvider extends TimeGraphPresentationProvider {
private static final int SEPARATOR_HEIGHT = 4;
private static final int NUM_COLORS = 25;
private static final float BRIGHTNESS = 0.8f;
private static final float SATURATION = 0.8f;
private static final List<RGBAColor> PALETTE = new RotatingPaletteProvider.Builder()
.setNbColors(NUM_COLORS)
.setBrightness(BRIGHTNESS)
.setSaturation(SATURATION)
.build().get();
private static final int COLOR_DIFFERENCIATION_FACTOR = NUM_COLORS / 2 + 2;
private static final Map<Integer, StateItem> STATE_MAP;
private static final List<StateItem> STATE_LIST;
private static final StateItem[] STATE_TABLE;
private static StateItem createState(LinuxStyle style) {
return new StateItem(style.toMap());
}
static {
ImmutableMap.Builder<Integer, StateItem> builder = new ImmutableMap.Builder<>();
builder.put(StateValues.CPU_STATUS_IDLE, new StateItem(LinuxStyle.IDLE.toMap()));
builder.put(StateValues.CPU_STATUS_RUN_USERMODE, new StateItem(LinuxStyle.USERMODE.toMap()));
builder.put(StateValues.CPU_STATUS_RUN_SYSCALL, new StateItem(LinuxStyle.SYSCALL.toMap()));
builder.put(StateValues.CPU_STATUS_IRQ, createState(LinuxStyle.INTERRUPTED));
builder.put(StateValues.CPU_STATUS_SOFTIRQ, createState(LinuxStyle.SOFT_IRQ));
builder.put(StateValues.CPU_STATUS_SOFT_IRQ_RAISED, createState(LinuxStyle.SOFT_IRQ_RAISED));
STATE_MAP = builder.build();
STATE_LIST = ImmutableList.copyOf(STATE_MAP.values());
STATE_TABLE = STATE_LIST.toArray(new StateItem[STATE_LIST.size()]);
}
/**
* Default constructor
*/
public ResourcesPresentationProvider() {
super();
}
private static StateItem getEventState(TimeEvent event) {
if (event instanceof NullTimeEvent) {
return null;
}
ITimeGraphEntry entry = event.getEntry();
if (entry instanceof TimeGraphEntry
&& ((TimeGraphEntry) entry).getEntryModel() instanceof ResourcesEntryModel) {
int value = event.getValue();
ResourcesEntryModel resourcesModel = (ResourcesEntryModel) ((TimeGraphEntry) entry).getEntryModel();
Type type = resourcesModel.getType();
switch (type) {
case CPU:
return STATE_MAP.get(value);
case IRQ:
return STATE_MAP.get(StateValues.CPU_STATUS_IRQ);
case SOFT_IRQ:
if (value == StateValues.CPU_STATUS_SOFT_IRQ_RAISED) {
return STATE_MAP.get(StateValues.CPU_STATUS_SOFT_IRQ_RAISED);
}
return STATE_MAP.get(StateValues.CPU_STATUS_SOFTIRQ);
case GROUP:
return null;
case CURRENT_THREAD:
case FREQUENCY:
if (!event.hasValue()) {
return null;
}
return STATE_MAP.get(StateValues.CPU_STATUS_RUN_USERMODE);
default:
return null;
}
}
return null;
}
@Override
public int getItemHeight(ITimeGraphEntry entry) {
if (!entry.hasTimeEvents() && entry.getParent() != null) {
return SEPARATOR_HEIGHT;
}
return super.getItemHeight(entry);
}
@Override
public int getStateTableIndex(ITimeEvent event) {
StateItem state = getEventState((TimeEvent) event);
if (state != null) {
return STATE_LIST.indexOf(state);
}
if (event instanceof NullTimeEvent) {
return INVISIBLE;
}
return TRANSPARENT;
}
@Override
public StateItem[] getStateTable() {
return STATE_TABLE;
}
@Override
public String getEventName(ITimeEvent event) {
StateItem state = getEventState((TimeEvent) event);
if (state != null) {
return state.getStateString();
}
if (event instanceof NullTimeEvent || isType(event.getEntry(), Type.CURRENT_THREAD)) {
return null;
}
return Messages.ResourcesView_multipleStates;
}
@Override
public Map<String, String> getEventHoverToolTipInfo(ITimeEvent event, long hoverTime) {
ITimeGraphEntry entry = event.getEntry();
if (event instanceof TimeEvent && ((TimeEvent) event).hasValue() && entry instanceof TimeGraphEntry) {
ITmfTreeDataModel model = ((TimeGraphEntry) entry).getEntryModel();
TimeEvent tcEvent = (TimeEvent) event;
if (tcEvent.hasValue() && model instanceof ResourcesEntryModel) {
ResourcesEntryModel resourcesModel = (ResourcesEntryModel) model;
if (resourcesModel.getType().equals(Type.IRQ) || resourcesModel.getType().equals(Type.SOFT_IRQ) ||
resourcesModel.getType().equals(Type.CPU) || resourcesModel.getType().equals(Type.CURRENT_THREAD) ||
resourcesModel.getType().equals(Type.FREQUENCY)) {
ITimeGraphDataProvider<? extends TimeGraphEntryModel> provider = BaseDataProviderTimeGraphView.getProvider((TimeGraphEntry) entry);
if (provider != null) {
return getTooltip(provider, model.getId(), hoverTime);
}
}
}
}
return Collections.emptyMap();
}
private static Map<String, String> getTooltip(ITimeGraphDataProvider<? extends TimeGraphEntryModel> provider, long id, long hoverTime) {
SelectionTimeQueryFilter filter = new SelectionTimeQueryFilter(Collections.singletonList(hoverTime), Collections.singleton(id));
TmfModelResponse<Map<String, String>> response = provider.fetchTooltip(FetchParametersUtils.selectionTimeQueryToMap(filter), null);
Map<String, String> tooltip = response.getModel();
if (tooltip == null) {
return Collections.emptyMap();
}
Map<String, String> retMap = new LinkedHashMap<>();
retMap.putAll(tooltip);
return retMap;
}
@Override
public Map<String, Object> getSpecificEventStyle(ITimeEvent event) {
Map<String, Object> map = new HashMap<>(super.getSpecificEventStyle(event));
if (isType(event.getEntry(), Type.CURRENT_THREAD) && event instanceof TimeEvent) {
int threadEventValue = ((TimeEvent) event).getValue();
RGBAColor color = PALETTE.get(Math.floorMod(threadEventValue + COLOR_DIFFERENCIATION_FACTOR, NUM_COLORS));
map.put(StyleProperties.BACKGROUND_COLOR, ColorUtils.toHexColor(color.getRed(), color.getGreen(), color.getBlue()));
map.put(StyleProperties.STYLE_NAME, String.valueOf(threadEventValue));
} else if (event.getEntry() instanceof TimeGraphEntry &&
((TimeGraphEntry) event.getEntry()).getEntryModel() instanceof ITimeGraphEntryModelWeighted) {
ITimeGraphEntryModelWeighted model = (ITimeGraphEntryModelWeighted) ((TimeGraphEntry) event.getEntry()).getEntryModel();
int eventValue = ((TimeEvent) event).getValue();
map.put(StyleProperties.HEIGHT, (float) model.getWeight(eventValue));
}
return map;
}
private static boolean isType(ITimeGraphEntry entry, Type type) {
if (entry instanceof TimeGraphEntry) {
ITmfTreeDataModel model = ((TimeGraphEntry) entry).getEntryModel();
if (model instanceof ResourcesEntryModel) {
return (((ResourcesEntryModel) model).getType().equals(type));
}
}
return false;
}
}