blob: 1a353ae706bdafc1739ea9ff52581595c3f812ae [file] [log] [blame]
/**********************************************************************
* Copyright (c) 2017, 2018 Ericsson
*
* 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.lttng2.ust.core.analysis.memory;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.analysis.os.linux.core.memory.MemoryUsageTreeModel;
import org.eclipse.tracecompass.internal.tmf.core.model.filters.FetchParametersUtils;
import org.eclipse.tracecompass.internal.tmf.core.model.xy.AbstractTreeCommonXDataProvider;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
import org.eclipse.tracecompass.tmf.core.dataprovider.DataProviderParameterUtils;
import org.eclipse.tracecompass.tmf.core.model.YModel;
import org.eclipse.tracecompass.tmf.core.model.filters.SelectionTimeQueryFilter;
import org.eclipse.tracecompass.tmf.core.model.filters.TimeQueryFilter;
import org.eclipse.tracecompass.tmf.core.model.tree.TmfTreeModel;
import org.eclipse.tracecompass.tmf.core.model.xy.IYModel;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
import com.google.common.collect.ImmutableList;
/**
* This data provider will return a XY model based on a query filter. The model
* is used afterwards by any viewer to draw charts. Model returned is for Memory
* Usage views
*
* @author Yonni Chen
* @since 3.1
*/
@NonNullByDefault
public class UstMemoryUsageDataProvider extends AbstractTreeCommonXDataProvider<UstMemoryAnalysisModule, MemoryUsageTreeModel> {
/**
* Entry point ID.
* @since 3.2
*/
public static final String ID = "org.eclipse.tracecompass.lttng2.ust.core.analysis.memory.UstMemoryUsageDataProvider"; //$NON-NLS-1$
/**
* Create an instance of {@link UstMemoryUsageDataProvider}. Returns a null
* instance if the analysis module is not found.
*
* @param trace
* A trace on which we are interested to fetch a model
* @return A MemoryUsageDataProvider. If analysis module is not found, it
* returns null
*/
public static @Nullable UstMemoryUsageDataProvider create(ITmfTrace trace) {
UstMemoryAnalysisModule module = TmfTraceUtils.getAnalysisModuleOfClass(trace, UstMemoryAnalysisModule.class, UstMemoryAnalysisModule.ID);
if (module != null) {
module.schedule();
return new UstMemoryUsageDataProvider(trace, module);
}
return null;
}
/**
* Constructor
*/
private UstMemoryUsageDataProvider(ITmfTrace trace, UstMemoryAnalysisModule module) {
super(trace, module);
}
/**
* @since 3.3
*/
@Override
protected @Nullable Collection<IYModel> getYSeriesModels(ITmfStateSystem ss, Map<String, Object> fetchParameters, @Nullable IProgressMonitor monitor) throws StateSystemDisposedException {
SelectionTimeQueryFilter filter = FetchParametersUtils.createSelectionTimeQuery(fetchParameters);
if (filter == null) {
return null;
}
long[] xValues = filter.getTimesRequested();
long currentEnd = ss.getCurrentEndTime();
Map<Integer, IYModel> models = initYModels(ss, filter);
for (ITmfStateInterval interval : ss.query2D(models.keySet(), getTimes(filter, ss.getStartTime(), currentEnd))) {
if (monitor != null && monitor.isCanceled()) {
return null;
}
IYModel model = models.get(interval.getAttribute());
Object value = interval.getValue();
if (model != null && value instanceof Number) {
int from = Arrays.binarySearch(xValues, interval.getStartTime());
from = (from >= 0) ? from : -1 - from;
int to = Arrays.binarySearch(xValues, interval.getEndTime());
to = (to >= 0) ? to + 1 : -1 - to;
Arrays.fill(model.getData(), from, to, ((Number) value).doubleValue());
}
}
return models.values();
}
/**
* Get map of UST_MEMORY_MEMORY_ATTRIBUTE to relevant model
*
* @param ss
* the queried {@link ITmfStateSystem}
* @param filter
* the {@link TimeQueryFilter}
* @return a map of the UST_MEMORY_MEMORY_ATTRIBUTE attributes to the
* initialized model
*/
private Map<Integer, IYModel> initYModels(ITmfStateSystem ss, SelectionTimeQueryFilter filter) {
Map<Integer, IYModel> selectedSeries = new HashMap<>();
int length = filter.getTimesRequested().length;
for (Entry<Long, Integer> entry : getSelectedEntries(filter).entrySet()) {
int tidQuark = entry.getValue();
int memoryAttribute = ss.optQuarkRelative(tidQuark, UstMemoryStrings.UST_MEMORY_MEMORY_ATTRIBUTE);
if (memoryAttribute != ITmfStateSystem.INVALID_ATTRIBUTE) {
String name = getTrace().getName() + ':' + ss.getAttributeName(tidQuark);
selectedSeries.put(memoryAttribute, new YModel(entry.getKey(), name, new double[length]));
}
}
return selectedSeries;
}
/**
* @since 3.3
*/
@Override
protected TmfTreeModel<MemoryUsageTreeModel> getTree(ITmfStateSystem ss, Map<String, Object> parameters, @Nullable IProgressMonitor monitor)
throws StateSystemDisposedException {
TimeQueryFilter filter = FetchParametersUtils.createTimeQuery(parameters);
if (filter == null) {
return new TmfTreeModel<>(Collections.emptyList(), Collections.emptyList());
}
long start = filter.getStart();
long end = filter.getEnd();
// Let the list of active states be null if we aren't filtering
List<ITmfStateInterval> active = null;
Boolean isFiltered = DataProviderParameterUtils.extractIsFiltered(parameters);
if (isFiltered != null && isFiltered) {
if (start == end || start > ss.getCurrentEndTime() || end < ss.getStartTime()) {
/*
* return an empty list if the filter is empty or does not intersect the state
* system
*/
return new TmfTreeModel<>(Collections.emptyList(), Collections.emptyList());
}
active = ss.queryFullState(Long.max(start, ss.getStartTime()));
}
List<ITmfStateInterval> nameFullState = ss.queryFullState(ss.getCurrentEndTime());
List<Integer> tidQuarks = ss.getSubAttributes(-1, false);
ImmutableList.Builder<MemoryUsageTreeModel> builder = ImmutableList.builder();
long rootId = getId(ITmfStateSystem.ROOT_ATTRIBUTE);
builder.add(new MemoryUsageTreeModel(rootId, -1L, -1, Collections.singletonList(getTrace().getName())));
for (int quark : tidQuarks) {
int memoryAttribute = ss.optQuarkRelative(quark, UstMemoryStrings.UST_MEMORY_MEMORY_ATTRIBUTE);
int procNameQuark = ss.optQuarkRelative(quark, UstMemoryStrings.UST_MEMORY_PROCNAME_ATTRIBUTE);
String name = ss.getAttributeName(quark);
if (procNameQuark != ITmfStateSystem.INVALID_ATTRIBUTE && procNameQuark < nameFullState.size()) {
name = String.valueOf(nameFullState.get(procNameQuark).getValue());
}
if (memoryAttribute != ITmfStateSystem.INVALID_ATTRIBUTE
&& (active == null || (memoryAttribute < active.size() && active.get(memoryAttribute).getEndTime() < end))) {
int tid = Integer.parseInt(ss.getAttributeName(quark));
builder.add(new MemoryUsageTreeModel(getId(quark), rootId, tid, Collections.singletonList(name)));
}
}
return new TmfTreeModel<>(Collections.emptyList(), builder.build());
}
/**
* @since 3.2
*/
@Override
public String getId() {
return ID;
}
/**
* @since 3.3
*/
@Override
protected boolean isCacheable() {
return false;
}
/**
* @since 3.3
*/
@Override
protected String getTitle() {
return Objects.requireNonNull(Messages.MemoryUsageDataProvider_Title);
}
}