| /******************************************************************************* |
| * Copyright (c) 2016 É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 |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.incubator.callstack.core.instrumented.statesystem; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| |
| import org.apache.commons.lang3.StringUtils; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.tracecompass.analysis.os.linux.core.model.HostThread; |
| import org.eclipse.tracecompass.incubator.analysis.core.model.IHostModel; |
| import org.eclipse.tracecompass.incubator.analysis.core.model.ModelManager; |
| import org.eclipse.tracecompass.incubator.callstack.core.base.ICallStackElement; |
| import org.eclipse.tracecompass.incubator.callstack.core.base.ICallStackGroupDescriptor; |
| import org.eclipse.tracecompass.incubator.callstack.core.flamechart.CallStack; |
| import org.eclipse.tracecompass.incubator.callstack.core.instrumented.CallStackDepth; |
| import org.eclipse.tracecompass.incubator.callstack.core.instrumented.ICalledFunction; |
| import org.eclipse.tracecompass.incubator.callstack.core.instrumented.statesystem.CallStackHostUtils.IHostIdProvider; |
| import org.eclipse.tracecompass.incubator.callstack.core.instrumented.statesystem.CallStackHostUtils.IHostIdResolver; |
| import org.eclipse.tracecompass.incubator.internal.callstack.core.Activator; |
| import org.eclipse.tracecompass.incubator.internal.callstack.core.instrumented.InstrumentedCallStackElement; |
| import org.eclipse.tracecompass.incubator.internal.callstack.core.instrumented.InstrumentedGroupDescriptor; |
| import org.eclipse.tracecompass.incubator.internal.callstack.core.instrumented.callgraph.CalledFunctionFactory; |
| import org.eclipse.tracecompass.segmentstore.core.BasicSegment; |
| import org.eclipse.tracecompass.segmentstore.core.ISegment; |
| import org.eclipse.tracecompass.segmentstore.core.ISegmentStore; |
| import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; |
| import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException; |
| import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException; |
| import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval; |
| |
| import com.google.common.base.Function; |
| import com.google.common.collect.ArrayListMultimap; |
| import com.google.common.collect.Iterables; |
| import com.google.common.collect.Iterators; |
| import com.google.common.collect.Maps; |
| import com.google.common.collect.Multimap; |
| |
| /** |
| * A callstack series contain the information necessary to build all the |
| * different callstacks from a same pattern. |
| * |
| * Example: Let's take a trace that registers function entry and exit for |
| * threads and where events also provide information on some other stackable |
| * application component: |
| * |
| * The structure of this callstack in the state system could be as follows: |
| * |
| * <pre> |
| * Per PID |
| * [pid] |
| * [tid] |
| * callstack |
| * 1 {@literal ->} function name |
| * 2 {@literal ->} function name |
| * 3 {@literal ->} function name |
| * Per component |
| * [application component] |
| * [tid] |
| * callstack |
| * 1 {@literal ->} some string |
| * 2 {@literal ->} some string |
| * </pre> |
| * |
| * There are 2 {@link CallStackSeries} in this example, one starting by "Per |
| * PID" and another "Per component". For the first series, there could be 3 |
| * {@link ICallStackGroupDescriptor}: "Per PID/*", "*", "callstack". |
| * |
| * If the function names happen to be addresses in an executable and the PID is |
| * the key to map those symbols to actual function names, then the first group |
| * "Per PID/*" would be the symbol key group. |
| * |
| * Each group descriptor can get the corresponding {@link ICallStackElement}s, |
| * ie, for the first group, it would be all the individual pids in the state |
| * system, and for the second group, it would be the application components. |
| * Each element that is not a leaf element (check with |
| * {@link ICallStackElement#isLeaf()}) will have a next group descriptor that |
| * can fetch the elements under it. The last group will resolve to leaf elements |
| * and each leaf elements has one {@link CallStack} object. |
| * |
| * @author Geneviève Bastien |
| */ |
| public class CallStackSeries implements ISegmentStore<ISegment> { |
| |
| /** |
| * Interface for classes that provide a thread ID at time t for a callstack. The |
| * thread ID can be used to calculate extra statistics per thread, for example, |
| * the CPU time of each call site. |
| */ |
| public interface IThreadIdProvider { |
| |
| /** |
| * Get the ID of callstack thread at a given time |
| * |
| * @param time |
| * The time of request |
| * @return The ID of the thread, or {@link IHostModel#UNKNOWN_TID} if |
| * unavailable |
| */ |
| int getThreadId(long time); |
| |
| /** |
| * Return whether the value returned by this provider is variable through time |
| * (ie, each function of a stack may have a different thread ID), or is fixed |
| * (ie, all functions in a stack have the same thread ID) |
| * |
| * @return If <code>true</code>, the thread ID will be identical for a stack all |
| * throughout its life, it can be therefore be used to provider other |
| * thread-related information on stack even when there are no function |
| * calls. |
| */ |
| boolean variesInTime(); |
| |
| } |
| |
| /** |
| * This class uses the value of an attribute as a thread ID. |
| */ |
| private static final class AttributeValueThreadProvider implements IThreadIdProvider { |
| |
| private final ITmfStateSystem fSs; |
| private final int fQuark; |
| private @Nullable ITmfStateInterval fInterval; |
| private int fLastThreadId = IHostModel.UNKNOWN_TID; |
| private boolean fVariesInTime = true; |
| |
| public AttributeValueThreadProvider(ITmfStateSystem ss, int quark) { |
| fSs = ss; |
| fQuark = quark; |
| } |
| |
| @Override |
| public int getThreadId(long time) { |
| ITmfStateInterval interval = fInterval; |
| int tid = fLastThreadId; |
| // If interval is not null and either the tid does not vary in time or the |
| // interval intersects the requested time |
| if (interval != null && (!fVariesInTime || interval.intersects(time))) { |
| return tid; |
| } |
| try { |
| interval = fSs.querySingleState(time, fQuark); |
| switch (interval.getStateValue().getType()) { |
| case INTEGER: |
| tid = interval.getStateValue().unboxInt(); |
| break; |
| case LONG: |
| tid = (int) interval.getStateValue().unboxLong(); |
| break; |
| case STRING: |
| try { |
| tid = Integer.valueOf(interval.getStateValue().unboxStr()); |
| } catch (NumberFormatException e) { |
| tid = IHostModel.UNKNOWN_TID; |
| } |
| break; |
| case NULL: /* Fallthrough cases */ |
| case DOUBLE: /* Fallthrough cases */ |
| case CUSTOM: /* Fallthrough cases */ |
| default: |
| break; |
| |
| } |
| // If the interval spans the whole state system, the tid does not vary in time |
| if (fSs.waitUntilBuilt(0)) { |
| if (interval.intersects(fSs.getStartTime()) && interval.intersects(fSs.getCurrentEndTime() - 1)) { |
| fVariesInTime = false; |
| } |
| } |
| } catch (StateSystemDisposedException e) { |
| interval = null; |
| tid = IHostModel.UNKNOWN_TID; |
| } |
| fInterval = interval; |
| fLastThreadId = tid; |
| return tid; |
| } |
| |
| @Override |
| public boolean variesInTime() { |
| return fVariesInTime; |
| } |
| |
| } |
| |
| /** |
| * This class uses the value of an attribute as a thread ID. |
| */ |
| private static final class AttributeNameThreadProvider implements IThreadIdProvider { |
| |
| private final int fTid; |
| |
| public AttributeNameThreadProvider(ITmfStateSystem ss, int quark) { |
| int tid = IHostModel.UNKNOWN_TID; |
| try { |
| String attributeName = ss.getAttributeName(quark); |
| tid = Integer.valueOf(attributeName); |
| } catch (IndexOutOfBoundsException | NumberFormatException e) { |
| tid = IHostModel.UNKNOWN_TID; |
| } |
| fTid = tid; |
| } |
| |
| @Override |
| public int getThreadId(long time) { |
| return fTid; |
| } |
| |
| @Override |
| public boolean variesInTime() { |
| return false; |
| } |
| |
| } |
| |
| /** |
| * This class will retrieve the thread ID |
| */ |
| private static final class CpuThreadProvider implements IThreadIdProvider { |
| |
| private final ITmfStateSystem fSs; |
| private final int fCpuQuark; |
| private final IHostIdProvider fHostProvider; |
| |
| public CpuThreadProvider(IHostIdProvider hostProvider, ITmfStateSystem ss, int quark, String[] path) { |
| fSs = ss; |
| fHostProvider = hostProvider; |
| // Get the cpu quark |
| List<@NonNull Integer> quarks = ss.getQuarks(quark, path); |
| fCpuQuark = quarks.isEmpty() ? ITmfStateSystem.INVALID_ATTRIBUTE : quarks.get(0); |
| } |
| |
| @Override |
| public int getThreadId(long time) { |
| if (fCpuQuark == ITmfStateSystem.INVALID_ATTRIBUTE) { |
| return IHostModel.UNKNOWN_TID; |
| } |
| // Get the CPU |
| try { |
| ITmfStateInterval querySingleState = fSs.querySingleState(time, fCpuQuark); |
| |
| if (querySingleState.getStateValue().isNull()) { |
| return IHostModel.UNKNOWN_TID; |
| } |
| int cpu = querySingleState.getStateValue().unboxInt(); |
| // The thread running is the one on the CPU at the beginning of this interval |
| long startTime = querySingleState.getStartTime(); |
| IHostModel model = ModelManager.getModelFor(fHostProvider.apply(startTime)); |
| return model.getThreadOnCpu(cpu, startTime); |
| } catch (StateSystemDisposedException e) { |
| |
| } |
| return IHostModel.UNKNOWN_TID; |
| } |
| |
| @Override |
| public boolean variesInTime() { |
| return true; |
| } |
| |
| } |
| |
| /** |
| * Interface for describing how a callstack will get the thread ID |
| */ |
| public interface IThreadIdResolver { |
| |
| /** |
| * Get the actual thread ID provider from this resolver |
| * |
| * @param hostProvider |
| * The provider of the host ID for the callstack |
| * @param element |
| * The leaf element of the callstack |
| * @return The thread ID provider |
| */ |
| @Nullable IThreadIdProvider resolve(IHostIdProvider hostProvider, ICallStackElement element); |
| |
| } |
| |
| /** |
| * This class will resolve the thread ID provider by the value of a attribute at |
| * a given depth |
| */ |
| public static final class AttributeValueThreadResolver implements IThreadIdResolver { |
| |
| private int fLevel; |
| |
| /** |
| * Constructor |
| * |
| * @param level |
| * The depth of the element whose value will be used to retrieve the |
| * thread ID |
| */ |
| public AttributeValueThreadResolver(int level) { |
| fLevel = level; |
| } |
| |
| @Override |
| public @Nullable IThreadIdProvider resolve(IHostIdProvider hostProvider, ICallStackElement element) { |
| if (!(element instanceof InstrumentedCallStackElement)) { |
| throw new IllegalArgumentException(); |
| } |
| InstrumentedCallStackElement insElement = (InstrumentedCallStackElement) element; |
| |
| List<InstrumentedCallStackElement> elements = new ArrayList<>(); |
| InstrumentedCallStackElement el = insElement; |
| while (el != null) { |
| elements.add(el); |
| el = el.getParentElement(); |
| } |
| Collections.reverse(elements); |
| if (elements.size() <= fLevel) { |
| return null; |
| } |
| InstrumentedCallStackElement stackElement = elements.get(fLevel); |
| return new AttributeValueThreadProvider(stackElement.getStateSystem(), stackElement.getQuark()); |
| } |
| |
| } |
| |
| /** |
| * This class will resolve the thread ID provider by the value of a attribute at |
| * a given depth |
| */ |
| public static final class AttributeNameThreadResolver implements IThreadIdResolver { |
| |
| private int fLevel; |
| |
| /** |
| * Constructor |
| * |
| * @param level |
| * The depth of the element whose value will be used to retrieve the |
| * thread ID |
| */ |
| public AttributeNameThreadResolver(int level) { |
| fLevel = level; |
| } |
| |
| @Override |
| public @Nullable IThreadIdProvider resolve(IHostIdProvider hostProvider, ICallStackElement element) { |
| if (!(element instanceof InstrumentedCallStackElement)) { |
| throw new IllegalArgumentException(); |
| } |
| InstrumentedCallStackElement insElement = (InstrumentedCallStackElement) element; |
| |
| List<InstrumentedCallStackElement> elements = new ArrayList<>(); |
| InstrumentedCallStackElement el = insElement; |
| while (el != null) { |
| elements.add(el); |
| el = el.getParentElement(); |
| } |
| Collections.reverse(elements); |
| if (elements.size() <= fLevel) { |
| return null; |
| } |
| InstrumentedCallStackElement stackElement = elements.get(fLevel); |
| return new AttributeNameThreadProvider(stackElement.getStateSystem(), stackElement.getQuark()); |
| } |
| |
| } |
| |
| /** |
| * This class will resolve the thread ID from the CPU on which the callstack was |
| * running at a given time |
| */ |
| public static final class CpuResolver implements IThreadIdResolver { |
| |
| private String[] fPath; |
| |
| /** |
| * Constructor |
| * |
| * @param path |
| * The path relative to the leaf element that will contain the CPU ID |
| */ |
| public CpuResolver(String[] path) { |
| fPath = path; |
| } |
| |
| @Override |
| public @Nullable IThreadIdProvider resolve(IHostIdProvider hostProvider, ICallStackElement element) { |
| if (!(element instanceof InstrumentedCallStackElement)) { |
| throw new IllegalArgumentException(); |
| } |
| InstrumentedCallStackElement insElement = (InstrumentedCallStackElement) element; |
| |
| return new CpuThreadProvider(hostProvider, insElement.getStateSystem(), insElement.getQuark(), fPath); |
| } |
| |
| } |
| |
| private final InstrumentedGroupDescriptor fRootGroup; |
| private final String fName; |
| private final @Nullable IThreadIdResolver fResolver; |
| private final IHostIdResolver fHostResolver; |
| private final ITmfStateSystem fStateSystem; |
| private final Map<Integer, ICallStackElement> fRootElements = new HashMap<>(); |
| |
| /** |
| * Constructor |
| * |
| * @param ss |
| * The state system containing this call stack |
| * @param patternPaths |
| * The patterns for the different levels of the callstack in the |
| * state system. Any further level path is relative to the previous |
| * one. |
| * @param symbolKeyLevelIndex |
| * The index in the list of the list to be used as a key to the |
| * symbol provider. The data at this level must be an integer, for |
| * instance a process ID |
| * @param name |
| * A name for this callstack |
| * @param hostResolver |
| * The host ID resolver for this callstack |
| * @param threadResolver |
| * The thread resolver |
| */ |
| public CallStackSeries(ITmfStateSystem ss, List<String[]> patternPaths, int symbolKeyLevelIndex, String name, IHostIdResolver hostResolver, @Nullable IThreadIdResolver threadResolver) { |
| // Build the groups from the state system and pattern paths |
| if (patternPaths.isEmpty()) { |
| throw new IllegalArgumentException("State system callstack: the list of paths should not be empty"); //$NON-NLS-1$ |
| } |
| int startIndex = patternPaths.size() - 1; |
| InstrumentedGroupDescriptor prevLevel = new InstrumentedGroupDescriptor(ss, patternPaths.get(startIndex), null, symbolKeyLevelIndex == startIndex ? true : false); |
| for (int i = startIndex - 1; i >= 0; i--) { |
| InstrumentedGroupDescriptor level = new InstrumentedGroupDescriptor(ss, patternPaths.get(i), prevLevel, symbolKeyLevelIndex == i ? true : false); |
| prevLevel = level; |
| } |
| fStateSystem = ss; |
| fRootGroup = prevLevel; |
| fName = name; |
| fResolver = threadResolver; |
| fHostResolver = hostResolver; |
| } |
| |
| /** |
| * Get the root elements of this callstack series |
| * |
| * @return The root elements of the callstack series |
| */ |
| public Collection<ICallStackElement> getRootElements() { |
| return InstrumentedCallStackElement.getRootElements(fRootGroup, fHostResolver, fResolver, fRootElements); |
| } |
| |
| /** |
| * Get the root group of the callstack series |
| * |
| * @return The root group descriptor |
| */ |
| public ICallStackGroupDescriptor getRootGroup() { |
| return fRootGroup; |
| } |
| |
| /** |
| * Get the name of this callstack series |
| * |
| * @return The name of the callstack series |
| */ |
| public String getName() { |
| return fName; |
| } |
| |
| /** |
| * Query the requested callstacks and return the segments for the sampled times. |
| * The returned segments will be simply {@link ISegment} when there is no |
| * function at a given depth, or {@link ICalledFunction} when there is an actual |
| * function. |
| * |
| * @param callstacks |
| * The callstack entries to query |
| * @param times |
| * The complete list of times to query, they may not all be within |
| * this series's range |
| * @return A map of callstack depths to a list of segments. |
| */ |
| public Multimap<CallStackDepth, ISegment> queryCallStacks(Collection<CallStackDepth> callstacks, Collection<Long> times) { |
| Map<Integer, CallStackDepth> quarks = Maps.uniqueIndex(callstacks, cs -> cs.getQuark()); |
| Multimap<CallStackDepth, ISegment> map = Objects.requireNonNull(ArrayListMultimap.create()); |
| Collection<Long> queryTimes = getTimes(fStateSystem, times); |
| try { |
| Iterable<ITmfStateInterval> query2d = fStateSystem.query2D(quarks.keySet(), queryTimes); |
| for (ITmfStateInterval callInterval : query2d) { |
| CallStackDepth callStackDepth = Objects.requireNonNull(quarks.get(callInterval.getAttribute())); |
| if (callInterval.getValue() != null) { |
| map.put(callStackDepth, callStackDepth.getCallStack().getFunctionFromInterval(callInterval)); |
| } else { |
| map.put(callStackDepth, new BasicSegment(callInterval.getStartTime(), callInterval.getEndTime() + 1)); |
| } |
| } |
| } catch (IndexOutOfBoundsException | TimeRangeException | StateSystemDisposedException e) { |
| e.printStackTrace(); |
| } |
| return map; |
| } |
| |
| private static Collection<Long> getTimes(ITmfStateSystem ss, Collection<Long> times) { |
| // Filter and deduplicate the time stamps for the statesystem |
| long start = ss.getStartTime(); |
| long end = ss.getCurrentEndTime(); |
| // use a HashSet to deduplicate time stamps |
| Collection<Long> queryTimes = new HashSet<>(); |
| for (long t : times) { |
| if (t >= start && t <= end) { |
| queryTimes.add(t); |
| } |
| } |
| return queryTimes; |
| } |
| |
| // --------------------------------------------------- |
| // Segment store methods |
| // --------------------------------------------------- |
| |
| private Collection<ICallStackElement> getLeafElements(ICallStackElement element) { |
| if (element.isLeaf()) { |
| return Collections.singleton(element); |
| } |
| List<ICallStackElement> list = new ArrayList<>(); |
| element.getChildren().forEach(e -> list.addAll(getLeafElements(e))); |
| return list; |
| } |
| |
| @Override |
| public int size() { |
| return Iterators.size(iterator()); |
| } |
| |
| @Override |
| public boolean isEmpty() { |
| return !iterator().hasNext(); |
| } |
| |
| @Override |
| public boolean contains(@Nullable Object o) { |
| // narrow down search when object is a segment |
| if (o instanceof ICalledFunction) { |
| ICalledFunction seg = (ICalledFunction) o; |
| Iterable<@NonNull ISegment> iterable = getIntersectingElements(seg.getStart()); |
| return Iterables.contains(iterable, seg); |
| } |
| return false; |
| } |
| |
| @Override |
| public Iterator<ISegment> iterator() { |
| ITmfStateSystem stateSystem = fRootGroup.getStateSystem(); |
| long start = stateSystem.getStartTime(); |
| long end = stateSystem.getCurrentEndTime(); |
| return getIntersectingElements(start, end).iterator(); |
| } |
| |
| @Override |
| public Object[] toArray() { |
| throw new UnsupportedOperationException("This segment store can potentially cause OutOfMemoryExceptions"); //$NON-NLS-1$ |
| } |
| |
| @Override |
| public <T> T[] toArray(T[] a) { |
| throw new UnsupportedOperationException("This segment store can potentially cause OutOfMemoryExceptions"); //$NON-NLS-1$ |
| } |
| |
| @Override |
| public boolean add(ISegment e) { |
| throw new UnsupportedOperationException("This segment store does not support adding new segments"); //$NON-NLS-1$ |
| } |
| |
| @Override |
| public boolean containsAll(@Nullable Collection<?> c) { |
| if (c == null) { |
| return false; |
| } |
| /* |
| * Check that all elements in the collection are indeed ISegments, and |
| * find their min end and max start time |
| */ |
| long minEnd = Long.MAX_VALUE, maxStart = Long.MIN_VALUE; |
| for (Object o : c) { |
| if (o instanceof ICalledFunction) { |
| ICalledFunction seg = (ICalledFunction) o; |
| minEnd = Math.min(minEnd, seg.getEnd()); |
| maxStart = Math.max(maxStart, seg.getStart()); |
| } else { |
| return false; |
| } |
| } |
| if (minEnd > maxStart) { |
| /* |
| * all segments intersect a common range, we just need to intersect |
| * a time stamp in that range |
| */ |
| minEnd = maxStart; |
| } |
| |
| /* Iterate through possible segments until we have found them all */ |
| Iterator<@NonNull ISegment> iterator = getIntersectingElements(minEnd, maxStart).iterator(); |
| int unFound = c.size(); |
| while (iterator.hasNext() && unFound > 0) { |
| ISegment seg = iterator.next(); |
| for (Object o : c) { |
| if (Objects.equals(o, seg)) { |
| unFound--; |
| } |
| } |
| } |
| return unFound == 0; |
| } |
| |
| @Override |
| public boolean addAll(@Nullable Collection<? extends ISegment> c) { |
| throw new UnsupportedOperationException("This segment store does not support adding new segments"); //$NON-NLS-1$ |
| } |
| |
| @Override |
| public void clear() { |
| throw new UnsupportedOperationException("This segment store does not support clearing the data"); //$NON-NLS-1$ |
| } |
| |
| private Map<Integer, CallStack> getCallStackQuarks() { |
| Map<Integer, CallStack> quarkToElement = new HashMap<>(); |
| // Get the leaf elements and their callstacks |
| getRootElements().stream().flatMap(e -> getLeafElements(e).stream()) |
| .filter(e -> e instanceof InstrumentedCallStackElement) |
| .map(e -> (InstrumentedCallStackElement) e) |
| .forEach(e -> { |
| e.getStackQuarks().forEach(c -> quarkToElement.put(c, e.getCallStack())); |
| }); |
| return quarkToElement; |
| } |
| |
| @Override |
| public Iterable<ISegment> getIntersectingElements(long start, long end) { |
| ITmfStateSystem stateSystem = fRootGroup.getStateSystem(); |
| // Start can be Long.MIN_VALUE, we need to avoid underflow |
| long startTime = Math.max(Math.max(1, start) - 1, stateSystem.getStartTime()); |
| long endTime = Math.min(end, stateSystem.getCurrentEndTime()); |
| if (startTime > endTime) { |
| return Collections.emptyList(); |
| } |
| Map<Integer, CallStack> quarksToElement = getCallStackQuarks(); |
| try { |
| Iterable<ITmfStateInterval> query2d = stateSystem.query2D(quarksToElement.keySet(), startTime, endTime); |
| query2d = Iterables.filter(query2d, interval -> !interval.getStateValue().isNull()); |
| Function<ITmfStateInterval, ICalledFunction> fct = interval -> { |
| CallStack callstack = quarksToElement.get(interval.getAttribute()); |
| if (callstack == null) { |
| throw new NullPointerException("The quark was in that map in the first place, there must be a callstack to go with it!"); //$NON-NLS-1$ |
| } |
| HostThread hostThread = callstack.getHostThread(interval.getStartTime()); |
| |
| int pid = -1 ; |
| if (hostThread == null) { |
| hostThread = new HostThread(StringUtils.EMPTY, IHostModel.UNKNOWN_TID); |
| } else { |
| pid = ModelManager.getModelFor(hostThread.getHost()).getProcessId(hostThread.getTid(), interval.getStartTime()); |
| } |
| return CalledFunctionFactory.create(interval.getStartTime(), interval.getEndTime() + 1, interval.getValue(), pid, hostThread.getTid(), |
| null, ModelManager.getModelFor(hostThread.getHost())); |
| }; |
| return Iterables.transform(query2d, fct); |
| } catch (StateSystemDisposedException e) { |
| Activator.getInstance().logError("Error getting intersecting elements: StateSystemDisposed"); //$NON-NLS-1$ |
| } |
| return Collections.emptyList(); |
| } |
| |
| @Override |
| public void dispose() { |
| // Nothing to do |
| } |
| |
| } |