import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.Attributes;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
+import org.eclipse.tracecompass.statesystem.core.StateSystemUtils.QuarkIterator;
import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
if (ss == null) {
return null;
}
- Integer execNameNode;
- try {
- execNameNode = ss.getQuarkAbsolute(Attributes.THREADS, threadId.toString(), Attributes.EXEC_NAME);
- List<ITmfStateInterval> execNameIntervals = StateSystemUtils.queryHistoryRange(ss, execNameNode, ss.getStartTime(), ss.getCurrentEndTime());
-
- ITmfStateValue execNameValue;
- String execName = null;
- for (ITmfStateInterval interval : execNameIntervals) {
- execNameValue = interval.getStateValue();
- if (execNameValue.getType().equals(Type.STRING)) {
- execName = execNameValue.unboxStr();
- }
+ int execNameNode = ss.optQuarkAbsolute(Attributes.THREADS, threadId.toString(), Attributes.EXEC_NAME);
+ if (execNameNode == ITmfStateSystem.INVALID_ATTRIBUTE) {
+ return null;
+ }
+ QuarkIterator reversedIterator = new QuarkIterator(ss, execNameNode, ss.getCurrentEndTime());
+ while (reversedIterator.hasPrevious()) {
+ ITmfStateValue nameInterval = reversedIterator.previous().getStateValue();
+ if (nameInterval.getType() == Type.STRING) {
+ return nameInterval.unboxStr();
}
- return execName;
- } catch (AttributeNotFoundException | StateSystemDisposedException | TimeRangeException e) {
}
return null;
}
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import java.util.Iterator;
-
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
import org.eclipse.tracecompass.statesystem.core.StateSystemFactory;
import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
+import org.eclipse.tracecompass.statesystem.core.StateSystemUtils.QuarkIterator;
import org.eclipse.tracecompass.statesystem.core.backend.IStateHistoryBackend;
import org.eclipse.tracecompass.statesystem.core.backend.StateHistoryBackendFactory;
import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
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.statesystem.core.statevalue.TmfStateValue;
assertNotNull(ss);
for (int quark = 0; quark < ss.getNbAttributes(); quark++) {
- Iterator<ITmfStateInterval> iterator = StateSystemUtils.getIteratorOverQuark(ss, quark, Long.MIN_VALUE, Long.MAX_VALUE);
+ QuarkIterator iterator = new QuarkIterator(ss, quark, Long.MIN_VALUE);
ITmfStateInterval prevInterval = null;
ITmfStateInterval currInterval = null;
}
}
- /**
- * Test that the correct exception is thrown by getIteratorOverQuark when
- * the lower bound argument is strictly greater than the upper bound
- * argument
- */
- @Test(expected = TimeRangeException.class)
- public void testIteratorOverQuarkTimeRangeException() {
- ITmfStateSystem ss = fStateSystem;
- assertNotNull(ss);
- StateSystemUtils.getIteratorOverQuark(ss, 0, ss.getCurrentEndTime(), ss.getStartTime());
- }
-
/**
* Test that getIteratorOverQuark returns the correct intervals for a range
* included in the state system range
try {
quark = ss.getQuarkAbsolute(DUMMY_STRING);
- Iterator<ITmfStateInterval> iterator = StateSystemUtils.getIteratorOverQuark(ss, quark, 1200L, 1400L);
+ QuarkIterator iterator = new QuarkIterator(ss, quark, 1800L);
- /* There should be a first interval ranging from 1200L to 1499L */
+ /* There should be one interval ranging from 1500L to 2000L */
assertTrue(iterator.hasNext());
ITmfStateInterval interval = iterator.next();
assertNotNull(interval);
- assertEquals(1200L, interval.getStartTime());
- assertEquals(1499, interval.getEndTime());
+ assertEquals(1500L, interval.getStartTime());
+ assertEquals(2000L, interval.getEndTime());
/* There should not be a next interval */
assertFalse(iterator.hasNext());
ss.modifyAttribute(1500L, TmfStateValue.newValueInt(20), quark);
/* We should have 2 intervals if we iterate at this point */
- Iterator<ITmfStateInterval> iterator = StateSystemUtils.getIteratorOverQuark(ss, quark, 0, 1700L);
+ QuarkIterator iterator = new QuarkIterator(ss, quark, 0);
assertEquals(2, Iterators.size(iterator));
/* Reset the iterator */
- iterator = StateSystemUtils.getIteratorOverQuark(ss, quark, 0, 1700L);
+ iterator = new QuarkIterator(ss, quark, 0);
/* Add an interval, updating the ss.end time */
ss.closeHistory(2000L);
fail(e.getMessage());
}
}
+
+ /**
+ * Test that the reverse iterator returns the correct intervals:
+ * <ul>
+ * <li>intervals for the correct quark</li>
+ * <li>ordered intervals</li>
+ * <li>intervals covering the correct time range</li>
+ * </ul>
+ */
+ @Test
+ public void testIteratorOverQuarkReversed() {
+ ITmfStateSystem ss = fStateSystem;
+ assertNotNull(ss);
+
+ for (int quark = 0; quark < ss.getNbAttributes(); quark++) {
+ QuarkIterator iterator = new QuarkIterator(ss, quark, Long.MAX_VALUE);
+ ITmfStateInterval prevInterval = null;
+ ITmfStateInterval currInterval = null;
+
+ while (iterator.hasPrevious()) {
+ currInterval = iterator.previous();
+
+ assertEquals(quark, currInterval.getAttribute());
+ if (prevInterval == null) {
+ /* This is the first interval for this attribute */
+ assertEquals(currInterval.getEndTime(), ss.getCurrentEndTime());
+ } else {
+ assertEquals(prevInterval.getStartTime() - 1, currInterval.getEndTime());
+ }
+
+ prevInterval = currInterval;
+ }
+
+ assertNotNull("Iterator should have returned at least one interval", currInterval);
+ assertEquals(ss.getStartTime(), currInterval.getStartTime());
+ }
+ }
}
* Provide utility methods for the state system
*
* @author Geneviève Bastien
+ * @author Loïc Prieur-Drevon
*/
@NonNullByDefault
public final class StateSystemUtils {
}
/**
- * Iterator over the intervals of a given attribute. Not thread-safe.
+ * Iterator class to allow 2-way iteration over intervals of a given
+ * attribute. Not thread-safe!
*
- * @param ss
- * The state system on which to query intervals
- *
- * @param quark
- * The key to the attribute to iterate over
- * @param start
- * The begin of the range of intervals to iterate over, if start
- * is before the state system's start time, the iteration will
- * begin at the state system's start time.
- * @param end
- * The end of the range of intervals to iterate over, it can be
- * greater than the current state system's end time, iteration
- * will end at the smallest of the two.
- * @return an Iterator over the intervals of a given attribute, with
- * intervals ordered
- * @throws TimeRangeException
- * If end < start.
* @since 2.1
*/
- public static Iterator<ITmfStateInterval> getIteratorOverQuark(ITmfStateSystem ss, int quark, long start, long end) {
- if (end < start) {
- throw new TimeRangeException("iterateOverQuark: end < start !"); //$NON-NLS-1$
+ public static class QuarkIterator implements Iterator<ITmfStateInterval> {
+
+ private final ITmfStateSystem fSS;
+ private final int fQuark;
+ private final long fInitialTime;
+
+ private @Nullable ITmfStateInterval fCurrent;
+
+ /**
+ * Constructor
+ *
+ * @param ss
+ * The state system on which to query intervals
+ * @param quark
+ * The key to the attribute to iterate over
+ * @param initialTime
+ * The timestamp that the first returned interval will
+ * intersect. This timestamp can be smaller than the
+ * StateSystem's start time, in which case, iteration will
+ * start at the StateSystem's start, on bigger than the
+ * StateSystem's current end time, in which case iteration
+ * will start at the StateSystem's current end time.
+ * @throws TimeRangeException
+ * If end < start.
+ * @since 2.1
+ */
+ public QuarkIterator(ITmfStateSystem ss, int quark, long initialTime) {
+ fSS = ss;
+ fQuark = quark;
+ fInitialTime = initialTime;
}
- return new Iterator<ITmfStateInterval>() {
- private @Nullable ITmfStateInterval fCurrent;
+ private long getNextQueryTime() {
+ if (fCurrent != null) {
+ return (fCurrent.getEndTime() + 1);
+ }
+ /* Iteration has not started yet */
+ return Long.max(fInitialTime, fSS.getStartTime());
+ }
- private long getNextQueryTime() {
- if (fCurrent != null) {
- return fCurrent.getEndTime() + 1;
- }
- /* Iteration has not started yet */
- return Long.max(start, ss.getStartTime());
+ private long getPreviousQueryTime() {
+ if (fCurrent != null) {
+ return fCurrent.getStartTime() - 1;
}
+ /* Iteration has not started yet */
+ return Long.min(fInitialTime, fSS.getCurrentEndTime());
+ }
- @Override
- public boolean hasNext() {
- /*
- * Compute the query's real end time here, to update it if the
- * iterator is used during state system build
- */
- long realEnd = Long.min(end, ss.getCurrentEndTime());
-
- /*
- * Ensure that the next query time falls within state system and
- * query time range. By definition getNextQueryTime() is larger
- * than the state system's start time.
- */
- return getNextQueryTime() <= realEnd;
+ @Override
+ public boolean hasNext() {
+ /*
+ * Ensure that the next query time falls within state system and
+ * query time range. By definition getNextQueryTime() is larger than
+ * the state system's start time.
+ */
+ return (getNextQueryTime() <= fSS.getCurrentEndTime());
+ }
+
+ @Override
+ public ITmfStateInterval next() {
+ if (hasNext()) {
+ try {
+ fCurrent = fSS.querySingleState(getNextQueryTime(), fQuark);
+ return fCurrent;
+ } catch (StateSystemDisposedException e) {
+ /* GOTO throw NoSuchElementException. */
+ }
}
+ throw new NoSuchElementException();
+ }
+
+ /**
+ * Returns true if the iteration has more previous elements. (In other
+ * words, returns true if previous() would return an element rather than
+ * throwing an exception.)
+ *
+ * @return true if the iteration has more previous elements
+ */
+ public boolean hasPrevious() {
+ /*
+ * Ensure that the next query time falls within state system and
+ * query time range. By definition getPreviousQueryTime() is smaller
+ * than the state system's end time.
+ */
+ return (getPreviousQueryTime() >= fSS.getStartTime());
+ }
- @Override
- public ITmfStateInterval next() {
- if (hasNext()) {
- try {
- return fCurrent = ss.querySingleState(getNextQueryTime(), quark);
- } catch (StateSystemDisposedException e) {
- /* GOTO throw NoSuchElementException. */
- }
+ /**
+ * Returns the previous element in the iteration.
+ *
+ * @return the previous element in the iteration
+ */
+ public ITmfStateInterval previous() {
+ if (hasPrevious()) {
+ try {
+ fCurrent = fSS.querySingleState(getPreviousQueryTime(), fQuark);
+ return fCurrent;
+ } catch (StateSystemDisposedException e) {
+ /* GOTO throw NoSuchElementException. */
}
- throw new NoSuchElementException();
}
- };
+ throw new NoSuchElementException();
+ }
}
}