| /******************************************************************************* |
| * Copyright (c) 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 |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.analysis.os.linux.core.tid; |
| |
| import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; |
| |
| import java.util.Collections; |
| import java.util.Set; |
| |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule; |
| import org.eclipse.tracecompass.analysis.os.linux.core.trace.DefaultEventLayout; |
| import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelAnalysisEventLayout; |
| import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelTrace; |
| import org.eclipse.tracecompass.common.core.NonNullUtils; |
| import org.eclipse.tracecompass.internal.analysis.os.linux.core.Activator; |
| import org.eclipse.tracecompass.internal.analysis.os.linux.core.Messages; |
| 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 org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue; |
| import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue.Type; |
| import org.eclipse.tracecompass.tmf.core.analysis.requirements.TmfAbstractAnalysisRequirement; |
| import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider; |
| import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule; |
| import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; |
| |
| /** |
| * Active tid analysis module, this only does one thing: figure out the active |
| * tid on any given cpu. This analysis should be approx 10x faster than the full |
| * {@link KernelAnalysisModule}. |
| * |
| * Note: this module exists as a way to accelerate the TID aspect, but also to |
| * start splitting up the kernel analysis into smaller sections. |
| * |
| * @author Matthew Khouzam |
| * @since 2.0 |
| */ |
| public class TidAnalysisModule extends TmfStateSystemAnalysisModule { |
| |
| /** The ID of this analysis module */ |
| public static final @NonNull String ID = "org.eclipse.tracecompass.analysis.os.linux.kernel.tid"; //$NON-NLS-1$ |
| |
| /** The requirements as an immutable set */ |
| private static final @NonNull Set<@NonNull TmfAbstractAnalysisRequirement> REQUIREMENTS = Collections.emptySet(); |
| |
| @Override |
| public @NonNull Iterable<@NonNull TmfAbstractAnalysisRequirement> getAnalysisRequirements() { |
| return REQUIREMENTS; |
| } |
| |
| @Override |
| public String getHelpText() { |
| String msg = Messages.TidAnalysisModule_Description; |
| return msg != null ? msg : super.getHelpText(); |
| } |
| |
| @Override |
| public @NonNull String getHelpText(@NonNull ITmfTrace trace) { |
| return getHelpText(); |
| } |
| |
| @Override |
| protected @NonNull ITmfStateProvider createStateProvider() { |
| ITmfTrace trace = checkNotNull(getTrace()); |
| IKernelAnalysisEventLayout layout = (trace instanceof IKernelTrace) ? ((IKernelTrace) trace).getKernelEventLayout() : DefaultEventLayout.getInstance(); |
| return new ActiveTidStateProvider(trace, layout); |
| } |
| |
| /** |
| * Gets the current thread ID on a given CPU for a given time |
| * |
| * @param cpu |
| * the CPU |
| * @param time |
| * the time in nanoseconds |
| * @return the current TID at the time on the CPU or {@code null} if not |
| * known |
| */ |
| public @Nullable Integer getThreadOnCpuAtTime(int cpu, long time) { |
| ITmfStateSystem stateSystem = getStateSystem(); |
| if (stateSystem == null || time < stateSystem.getStartTime()) { |
| return null; |
| } |
| |
| Integer tid = null; |
| // Query at time - 1, because at the boundary (sched_switches), the "thread on |
| // CPU" should be the previous thread, not the next one (as LTTng contexts and |
| // perf traces show). |
| long queryTime = Math.max(time - 1, stateSystem.getStartTime()); |
| try { |
| int cpuQuark = stateSystem.optQuarkAbsolute(Integer.toString(cpu)); |
| if (cpuQuark == ITmfStateSystem.INVALID_ATTRIBUTE) { |
| return null; |
| } |
| ITmfStateValue value = stateSystem.querySingleState(queryTime, cpuQuark).getStateValue(); |
| if (value.getType().equals(Type.INTEGER)) { |
| tid = value.unboxInt(); |
| } |
| } catch (StateSystemDisposedException | TimeRangeException e) { |
| Activator.getDefault().logError(NonNullUtils.nullToEmptyString(e.getMessage()), e); |
| } |
| return tid; |
| } |
| |
| /** |
| * Gets the CPU a thread is running on for a given time <br> |
| * Note: this is not designed to be fast, only convenient |
| * |
| * @param tid |
| * the tid |
| * @param time |
| * the time in nanoseconds |
| * @return the current CPU at the time for a TID or {@code null} if not |
| * available |
| */ |
| public @Nullable Integer getCpuForTidAtTime(int tid, long time) { |
| ITmfStateSystem stateSystem = getStateSystem(); |
| if (stateSystem == null) { |
| return null; |
| } |
| |
| try { |
| for (ITmfStateInterval interval : stateSystem.queryFullState(time)) { |
| if (tid == interval.getStateValue().unboxInt()) { |
| return Integer.parseInt(stateSystem.getAttributeName(interval.getAttribute())); |
| } |
| } |
| } catch (StateSystemDisposedException e) { |
| Activator.getDefault().logError(NonNullUtils.nullToEmptyString(e.getMessage()), e); |
| } |
| return null; |
| } |
| } |