blob: 45ff57990b03b1ad48dea56b6df8131e2c2b8fdf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2016 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
*
* Contributors:
* Jean-Christian Kouamé - Initial API and implementation
* Patrick Tasse - Updates to mipmap feature
*******************************************************************************/
package org.eclipse.tracecompass.internal.tmf.core.statesystem.mipmap;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.tracecompass.internal.tmf.core.Activator;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
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.interval.TmfStateInterval;
import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
/**
* The mipmap feature base implementation.
*
* @author Jean-Christian Kouamé
* @author Patrick Tasse
*
*/
public abstract class TmfMipmapFeature implements ITmfMipmapFeature {
/** The current state value */
protected @NonNull ITmfStateValue currentValue = TmfStateValue.nullValue();
/** The current start time for the state value */
protected long currentStartTime;
/** The list of ongoing state intervals per mipmap level */
protected List<List<ITmfStateInterval>> intervals = new ArrayList<>();
/** The state system used to store the mipmap attributes */
protected ITmfStateSystemBuilder ss;
private int mipmapResolution;
private int mipmapQuark;
private List<Integer> levelQuarks = new ArrayList<>();
/**
* Constructor
*
* @param baseQuark
* The quark of the attribute we want to mipmap
* @param mipmapQuark
* The quark of the mipmap feature attribute
* @param mipmapResolution
* The resolution that will be used for the mipmap
* @param ss
* The state system in which to insert the state changes
*/
public TmfMipmapFeature(int baseQuark, int mipmapQuark, int mipmapResolution, ITmfStateSystemBuilder ss) {
this.mipmapQuark = mipmapQuark;
this.mipmapResolution = mipmapResolution;
this.ss = ss;
/* store the base attribute quark at level 0 */
this.levelQuarks.add(baseQuark);
/* create the level 0 list */
intervals.add(new ArrayList<ITmfStateInterval>(mipmapResolution));
}
@Override
public void updateMipmap(ITmfStateValue value, long ts) {
/* if the value did not change, ignore it */
if (currentValue.equals(value)) {
return;
}
/* if the ongoing state value is not null, create and store a state interval */
if (!currentValue.isNull()) {
ITmfStateInterval interval = new TmfStateInterval(currentStartTime, ts, getLevelQuark(0), currentValue.unboxValue());
intervals.get(0).add(interval);
}
/* if the new value is not null, update the mipmap levels that are full */
if (!value.isNull()) {
int level = 0;
while (intervals.get(level).size() == getMipmapResolution()) {
updateMipmapLevel(++level, ts);
}
}
/* store the new value as the ongoing state value */
currentValue = value;
currentStartTime = ts;
}
@Override
public void updateAndCloseMipmap() {
if (!currentValue.isNull()) {
ITmfStateInterval interval = new TmfStateInterval(currentStartTime, currentStartTime, getLevelQuark(0), currentValue.unboxValue());
intervals.get(0).add(interval);
}
for (int level = 1; level <= getNbLevels(); level++) {
updateMipmapLevel(level, currentStartTime);
}
}
/**
* Compute and update the mipmap level attribute from the lower-level
* state interval list
*
* @param level
* The mipmap level to update
* @param endTime
* The end timestamp to use for the mipmap interval
*/
protected void updateMipmapLevel(int level, long endTime) {
try {
/* get the lower-level interval list */
List<ITmfStateInterval> lowerIntervals = intervals.get(level - 1);
if (lowerIntervals.isEmpty()) {
return;
}
/* get the start time from the first interval in the lower-level list */
long startTime = lowerIntervals.get(0).getStartTime();
/* compute the mipmap value */
ITmfStateValue value = computeMipmapValue(lowerIntervals, startTime, endTime);
/* clear the lower-level list */
lowerIntervals.clear();
/* get or create the current-level quark */
int levelQuark = ss.getQuarkRelativeAndAdd(mipmapQuark, String.valueOf(level));
if (!checkLevelExists(level)) {
addLevelQuark(levelQuark);
ss.updateOngoingState(TmfStateValue.newValueInt(level), mipmapQuark);
intervals.add(new ArrayList<ITmfStateInterval>(getMipmapResolution()));
}
/* add new interval to current-level list */
ITmfStateInterval interval = new TmfStateInterval(startTime, endTime, levelQuark, value.unboxValue());
intervals.get(level).add(interval);
/* update the current-level attribute */
ss.modifyAttribute(startTime, value.unboxValue(), levelQuark);
} catch (StateValueTypeException e) {
Activator.logError("TmfMipmapFeature : Bad state value type", e); //$NON-NLS-1$
} catch (TimeRangeException e) {
Activator.logError("TmfMipmapFeature : Time stamp is out of range", e); //$NON-NLS-1$
}
}
/**
* Compute the mipmap value from a list of lower-level state intervals
*
* @param lowerIntervals
* The list of lower-level state intervals
* @param startTime
* The start time of the mipmap interval
* @param endTime
* The end time of the mipmap interval
* @return A state value to be stored in the mipmap level attribute
*/
protected abstract @NonNull ITmfStateValue computeMipmapValue(List<ITmfStateInterval> lowerIntervals, long startTime, long endTime);
/**
* Get the mipmap resolution
*
* @return The mipmap resolution for this feature
*/
protected int getMipmapResolution() {
return mipmapResolution;
}
/**
* Get the mipmap feature quark. The state value
* of this attribute is the mipmap number of levels.
* This is the parent attribute of the mipmap level quarks.
*
* @return The attribute quark for this mipmap feature
*/
protected int getMipmapQuark() {
return mipmapQuark;
}
/**
* Get the mipmap quark for the specified level.
* For level 0 the base attribute quark is returned.
*
* @param level
* The mipmap level (0 for the base attribute)
* @return The attribute quark for this mipmap level
*/
protected int getLevelQuark(int level) {
return levelQuarks.get(level);
}
/**
* Add a new mipmap level quark.
*
* @param quark
* The attribute quark for the new mipmap level
*/
protected void addLevelQuark(int quark) {
levelQuarks.add(quark);
}
/**
* Get the mipmap number of levels.
*
* @return The current number of mipmap levels for this feature
* (excluding the base attribute)
*/
protected int getNbLevels() {
return levelQuarks.size() - 1;
}
/**
* Checks if a mipmap level exists.
*
* @param level
* The mipmap level to check
* @return true if this level exists, false otherwise
*/
protected boolean checkLevelExists(int level) {
return !(level >= levelQuarks.size() || level < 0);
}
}