/******************************************************************************* * Copyright (c) 2014, 2015 É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: * Geneviève Bastien - Initial API and implementation *******************************************************************************/ package org.eclipse.tracecompass.analysis.os.linux.core.kernel; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.TreeSet; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; 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; import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval; import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue; import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue.Type; /** * Information provider utility class that retrieves thread-related information * from a Linux Kernel Analysis * * @author Geneviève Bastien * @since 2.0 */ public final class KernelThreadInformationProvider { private KernelThreadInformationProvider() { } /** * Get the ID of the thread running on the CPU at time ts * * TODO: This method may later be replaced by an aspect, when the aspect can * resolve to something that is not an event * * @param module * The kernel analysis instance to run this method on * @param cpuId * The CPU number the process is running on * @param ts * The timestamp at which we want the running process * @return The TID of the thread running on CPU cpuId at time ts or * {@code null} if either no thread is running or we do not know. */ public static @Nullable Integer getThreadOnCpu(KernelAnalysisModule module, long cpuId, long ts) { ITmfStateSystem ss = module.getStateSystem(); if (ss == null) { return null; } try { int cpuQuark = ss.getQuarkAbsolute(Attributes.CPUS, Long.toString(cpuId), Attributes.CURRENT_THREAD); ITmfStateInterval interval = ss.querySingleState(ts, cpuQuark); ITmfStateValue val = interval.getStateValue(); if (val.getType().equals(Type.INTEGER)) { return val.unboxInt(); } } catch (AttributeNotFoundException | StateSystemDisposedException | TimeRangeException e) { } return null; } /** * Get the TIDs of the threads from an analysis * * @param module * The kernel analysis instance to run this method on * @return The set of TIDs corresponding to the threads */ public static Collection<Integer> getThreadIds(KernelAnalysisModule module) { ITmfStateSystem ss = module.getStateSystem(); if (ss == null) { return Collections.EMPTY_SET; } int threadQuark; try { threadQuark = ss.getQuarkAbsolute(Attributes.THREADS); Set<@NonNull Integer> tids = new TreeSet<>(); for (Integer quark : ss.getSubAttributes(threadQuark, false)) { final @NonNull String attributeName = ss.getAttributeName(quark); tids.add(attributeName.startsWith(Attributes.THREAD_0_PREFIX) ? 0 : Integer.parseInt(attributeName)); } return tids; } catch (AttributeNotFoundException e) { } return Collections.EMPTY_SET; } /** * Get the parent process ID of a thread * * @param module * The kernel analysis instance to run this method on * @param threadId * The thread ID of the process for which to get the parent * @param ts * The timestamp at which to get the parent * @return The parent PID or {@code null} if the PPID is not found. */ public static @Nullable Integer getParentPid(KernelAnalysisModule module, Integer threadId, long ts) { ITmfStateSystem ss = module.getStateSystem(); if (ss == null) { return null; } Integer ppidNode; try { ppidNode = ss.getQuarkAbsolute(Attributes.THREADS, threadId.toString(), Attributes.PPID); ITmfStateInterval ppidInterval = ss.querySingleState(ts, ppidNode); ITmfStateValue ppidValue = ppidInterval.getStateValue(); if (ppidValue.getType().equals(Type.INTEGER)) { return Integer.valueOf(ppidValue.unboxInt()); } } catch (AttributeNotFoundException | StateSystemDisposedException | TimeRangeException e) { } return null; } /** * Get the executable name of the thread ID. If the thread ID was used * multiple time or the name changed in between, it will return the last * name the thread has taken, or {@code null} if no name is found * * @param module * The kernel analysis instance to run this method on * @param threadId * The thread ID of the process for which to get the name * @return The last executable name of this process, or {@code null} if not * found */ public static @Nullable String getExecutableName(KernelAnalysisModule module, Integer threadId) { ITmfStateSystem ss = module.getStateSystem(); if (ss == null) { return null; } 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 null; } /** * Get the priority of this thread at time ts * * @param module * The kernel analysis instance to run this method on * @param threadId * The ID of the thread to query * @param ts * The timestamp at which to query * @return The priority of the thread or <code>-1</code> if not available */ public static int getThreadPriority(KernelAnalysisModule module, int threadId, long ts) { ITmfStateSystem ss = module.getStateSystem(); if (ss == null) { return -1; } int prioQuark = ss.optQuarkAbsolute(Attributes.THREADS, String.valueOf(threadId), Attributes.PRIO); if (prioQuark == ITmfStateSystem.INVALID_ATTRIBUTE) { return -1; } try { return ss.querySingleState(ts, prioQuark).getStateValue().unboxInt(); } catch (StateSystemDisposedException e) { return -1; } } /** * Get the status intervals for a given thread with a resolution * * @param module * The kernel analysis instance to run this method on * @param threadId * The ID of the thread to get the intervals for * @param start * The start time of the requested range * @param end * The end time of the requested range * @param resolution * The resolution or the minimal time between the requested * intervals. If interval times are smaller than resolution, only * the first interval is returned, the others are ignored. * @param monitor * A progress monitor for this task * @return The list of status intervals for this thread, an empty list is * returned if either the state system is {@code null} or the quark * is not found */ public static List<ITmfStateInterval> getStatusIntervalsForThread(KernelAnalysisModule module, Integer threadId, long start, long end, long resolution, IProgressMonitor monitor) { ITmfStateSystem ss = module.getStateSystem(); if (ss == null) { return Collections.EMPTY_LIST; } try { int threadQuark = ss.getQuarkAbsolute(Attributes.THREADS, threadId.toString()); List<ITmfStateInterval> statusIntervals = StateSystemUtils.queryHistoryRange(ss, threadQuark, Math.max(start, ss.getStartTime()), Math.min(end - 1, ss.getCurrentEndTime()), resolution, monitor); return statusIntervals; } catch (AttributeNotFoundException | StateSystemDisposedException | TimeRangeException e) { } return Collections.EMPTY_LIST; } }