/**********************************************************************
* Copyright (c) 2014 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 v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bernd Hufmann - Initial API and implementation
* Geneviève Bastien - Create and use base class for XY plots
**********************************************************************/
package org.eclipse.tracecompass.internal.lttng2.ust.ui.views.memusage;
import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.tracecompass.common.core.format.DataSizeWithUnitFormat;
import org.eclipse.tracecompass.internal.lttng2.ust.core.analysis.memory.UstMemoryStrings;
import org.eclipse.tracecompass.internal.lttng2.ust.ui.Activator;
import org.eclipse.tracecompass.lttng2.ust.core.analysis.memory.UstMemoryAnalysisModule;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
import org.eclipse.tracecompass.tmf.ui.viewers.xycharts.linecharts.TmfCommonXLineChartViewer;
import org.swtchart.Chart;
/**
* Memory usage view
*
* @author Matthew Khouzam
*/
public class MemoryUsageViewer extends TmfCommonXLineChartViewer {
private TmfStateSystemAnalysisModule fModule = null;
private final Map<Integer, double[]> fYValues = new HashMap<>();
private final Map<Integer, Integer> fMemoryQuarks = new HashMap<>();
private final Map<Integer, String> fSeriesName = new HashMap<>();
// Timeout between updates in the updateData thread
private static final long BUILD_UPDATE_TIMEOUT = 500;
/**
* Constructor
*
* @param parent
* parent view
*/
public MemoryUsageViewer(Composite parent) {
super(parent, Messages.MemoryUsageViewer_Title, Messages.MemoryUsageViewer_XAxis, Messages.MemoryUsageViewer_YAxis);
Chart chart = getSwtChart();
chart.getLegend().setPosition(SWT.LEFT);
chart.getAxisSet().getYAxis(0).getTick().setFormat(DataSizeWithUnitFormat.getInstance());
}
@Override
protected void initializeDataSource() {
ITmfTrace trace = getTrace();
if (trace != null) {
fModule = TmfTraceUtils.getAnalysisModuleOfClass(trace, TmfStateSystemAnalysisModule.class, UstMemoryAnalysisModule.ID);
if (fModule == null) {
return;
}
fModule.schedule();
}
}
@Override
protected void updateData(long start, long end, int nb, IProgressMonitor monitor) {
try {
if (getTrace() == null || fModule == null) {
return;
}
if (!fModule.waitForInitialization()) {
return;
}
ITmfStateSystem ss = fModule.getStateSystem();
/* Don't wait for the module completion, when it's ready, we'll know */
if (ss == null) {
return;
}
double[] xvalues = getXAxis(start, end, nb);
setXAxis(xvalues);
boolean complete = false;
long currentEnd = start;
while (!complete && currentEnd < end) {
if (monitor.isCanceled()) {
return;
}
complete = ss.waitUntilBuilt(BUILD_UPDATE_TIMEOUT);
currentEnd = ss.getCurrentEndTime();
List<Integer> tidQuarks = ss.getSubAttributes(-1, false);
long traceStart = getStartTime();
long traceEnd = getEndTime();
long offset = this.getTimeOffset();
/* Initialize quarks and series names */
List<ITmfStateInterval> fullState = ss.queryFullState(start);
for (int quark : tidQuarks) {
fYValues.put(quark, new double[xvalues.length]);
fMemoryQuarks.put(quark, ss.getQuarkRelative(quark, UstMemoryStrings.UST_MEMORY_MEMORY_ATTRIBUTE));
int procNameQuark = ss.getQuarkRelative(quark, UstMemoryStrings.UST_MEMORY_PROCNAME_ATTRIBUTE);
String oldSeriesName = fSeriesName.get(quark);
String seriesName = null;
try {
ITmfStateValue procnameValue = fullState.get(procNameQuark).getStateValue();
String procname = ""; //$NON-NLS-1$
if (!procnameValue.isNull()) {
procname = procnameValue.unboxStr();
}
seriesName = (procname + ' ' + '(' + ss.getAttributeName(quark) + ')').trim();
} catch (TimeRangeException e) {
seriesName = '(' + ss.getAttributeName(quark) + ')';
}
if (oldSeriesName != null && !oldSeriesName.equals(seriesName)) {
deleteSeries(oldSeriesName);
}
fSeriesName.put(quark, seriesName);
}
/*
* TODO: It should only show active threads in the time range.
* If a tid does not have any memory value (only 1 interval in
* the time range with value null or 0), then its series should
* not be displayed.
*/
double yvalue = 0.0;
for (int i = 0; i < xvalues.length; i++) {
if (monitor.isCanceled()) {
return;
}
double x = xvalues[i];
long time = (long) x + offset;
// make sure that time is in the trace range after double to
// long conversion
time = time < traceStart ? traceStart : time;
time = time > traceEnd ? traceEnd : time;
try {
fullState = ss.queryFullState(time);
for (int quark : tidQuarks) {
double[] values = checkNotNull(fYValues.get(quark));
Integer memQuark = checkNotNull(fMemoryQuarks.get(quark));
yvalue = fullState.get(memQuark.intValue()).getStateValue().unboxLong();
values[i] = yvalue;
}
} catch (TimeRangeException e) {
for (int quark : tidQuarks) {
double[] values = checkNotNull(fYValues.get(quark));
values[i] = 0;
}
}
}
for (int quark : tidQuarks) {
setSeries(fSeriesName.get(quark), fYValues.get(quark));
}
updateDisplay();
}
} catch (AttributeNotFoundException | StateValueTypeException e) {
Activator.getDefault().logError("Error updating the data of the Memory usage view", e); //$NON-NLS-1$
} catch (StateSystemDisposedException e) {
/* State system is closing down, no point continuing */
}
}
}