From 454e2a5c47859ca5eefe6db80cf41edd44edde2a Mon Sep 17 00:00:00 2001 From: Adel Belkhiri Date: Tue, 15 Oct 2024 17:56:39 -0400 Subject: [PATCH] dpdk: add busyness analysis for ethdev PMD threads PMD threads continuously poll NIC queues, leading to constant 100% CPU usage. This analysis provides a rough estimation of how busy PMD threads are with actual work, by comparing the times they successfully retrieve packets from the NIC queue versus the times they are merely spinning without processing any packets. Signed-off-by: Adel Belkhiri --- .../META-INF/MANIFEST.MF | 1 + .../plugin.xml | 13 + .../DpdkEthdevSpinAnalysisModule.java | 198 ++++++++++++++ .../analysis/DpdkEthdevSpinAttributes.java | 28 ++ .../analysis/DpdkEthdevSpinDataProvider.java | 247 ++++++++++++++++++ .../DpdkEthdevSpinDataProviderFactory.java | 55 ++++ .../analysis/DpdkEthdevSpinEventHandler.java | 79 ++++++ .../analysis/DpdkEthdevSpinStateProvider.java | 83 ++++++ .../core/ethdev/spin/analysis/Messages.java | 36 +++ .../ethdev/spin/analysis/messages.properties | 13 + .../ethdev/spin/analysis/package-info.java | 13 + .../plugin.xml | 14 + .../dpdk/ui/ethdev/spin/Messages.java | 44 ++++ .../ethdev/spin/ThreadSpinStatisticsView.java | 67 +++++ .../spin/ThreadSpinStatisticsViewer.java | 49 ++++ .../dpdk/ui/ethdev/spin/messages.properties | 16 ++ .../dpdk/ui/ethdev/spin/package-info.java | 11 + 17 files changed, 967 insertions(+) create mode 100644 tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinAnalysisModule.java create mode 100644 tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinAttributes.java create mode 100644 tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinDataProvider.java create mode 100644 tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinDataProviderFactory.java create mode 100644 tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinEventHandler.java create mode 100644 tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinStateProvider.java create mode 100644 tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/Messages.java create mode 100644 tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/messages.properties create mode 100644 tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/package-info.java create mode 100644 tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/Messages.java create mode 100644 tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/ThreadSpinStatisticsView.java create mode 100644 tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/ThreadSpinStatisticsViewer.java create mode 100644 tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/messages.properties create mode 100644 tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/package-info.java diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/META-INF/MANIFEST.MF b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/META-INF/MANIFEST.MF index 7eef4387c..21c661002 100644 --- a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/META-INF/MANIFEST.MF +++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/META-INF/MANIFEST.MF @@ -17,6 +17,7 @@ Require-Bundle: org.eclipse.ui, org.eclipse.tracecompass.analysis.os.linux.core, org.eclipse.jdt.annotation;bundle-version="2.2.400" Export-Package: org.eclipse.tracecompass.incubator.dpdk.core.trace, + org.eclipse.tracecompass.incubator.internal.dpdk.core.ethdev.spin.analysis, org.eclipse.tracecompass.incubator.internal.dpdk.core.ethdev.throughput.analysis, org.eclipse.tracecompass.incubator.internal.dpdk.core.lcore.analysis;x-friends:="org.eclipse.tracecompass.incubator.dpdk.core.tests" Automatic-Module-Name: org.eclipse.tracecompass.incubator.dpdk.core diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/plugin.xml b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/plugin.xml index 28d16bc68..e28a4faa3 100644 --- a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/plugin.xml +++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/plugin.xml @@ -21,6 +21,15 @@ class="org.eclipse.tracecompass.incubator.dpdk.core.trace.DpdkTrace"> + + + + @@ -36,6 +45,10 @@ class="org.eclipse.tracecompass.incubator.internal.dpdk.core.ethdev.throughput.analysis.DpdkEthdevThroughputPpsDataProviderFactory" id="org.eclipse.tracecompass.incubator.dpdk.ethdev.throughput.pps.dataprovider"> + + diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinAnalysisModule.java b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinAnalysisModule.java new file mode 100644 index 000000000..670596862 --- /dev/null +++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinAnalysisModule.java @@ -0,0 +1,198 @@ +/********************************************************************** + * Copyright (c) 2024 É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 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.incubator.internal.dpdk.core.ethdev.spin.analysis; + +import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.eclipse.tracecompass.incubator.dpdk.core.trace.DpdkTrace; +import org.eclipse.tracecompass.incubator.internal.dpdk.core.Activator; +import org.eclipse.tracecompass.incubator.internal.dpdk.core.ethdev.analysis.DpdkEthdevEventLayout; +import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; +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.tmf.core.analysis.requirements.TmfAbstractAnalysisRequirement; +import org.eclipse.tracecompass.tmf.core.analysis.requirements.TmfAbstractAnalysisRequirement.PriorityLevel; +import org.eclipse.tracecompass.tmf.core.analysis.requirements.TmfAnalysisEventRequirement; +import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider; +import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.util.Pair; + +import com.google.common.collect.ImmutableList; + +/** + * This analysis module estimates the percentage of time a PMD thread spends + * performing actual work (e.g., fetching and processing packets). The obtained + * results can be used to evaluate PMD thread efficiency. The analysis is based + * on two events: + * + * 1- the "lib.ethdev.rx.burst.empty" event indicates an empty poll where no + * packets were fetched. + * + * 2- the "lib.ethdev.rx.burst.nonempty" event indicates a successful poll where + * one or more packets were fetched + * + * @author Adel Belkhiri + */ +public class DpdkEthdevSpinAnalysisModule extends TmfStateSystemAnalysisModule { + + /** The ID of this analysis module */ + public static final String ID = "org.eclipse.tracecompass.incubator.internal.dpdk.core.ethdev.spin.analysis"; //$NON-NLS-1$ + private final DpdkEthdevEventLayout fLayout = new DpdkEthdevEventLayout(); + + private final TmfAbstractAnalysisRequirement REQUIREMENT = new TmfAnalysisEventRequirement(ImmutableList.of( + fLayout.eventEthdevRxBurstEmpty(), fLayout.eventEthdevRxBurstNonEmpty()), PriorityLevel.AT_LEAST_ONE); + + @Override + protected ITmfStateProvider createStateProvider() { + ITmfTrace trace = checkNotNull(getTrace()); + + if (trace instanceof DpdkTrace) { + return new DpdkEthdevSpinStateProvider(trace, fLayout, ID); + } + + throw new IllegalStateException(); + } + + @Override + public Iterable getAnalysisRequirements() { + return Collections.singleton(REQUIREMENT); + } + + /** + * Computes the time spent in active and spin states for specified threads + * within a given time range. + * + * @param threads + * A set of thread identifiers to analyze + * @param start + * Start timestamp of the analysis interval + * @param end + * End timestamp + * @return A map where each key is a thread name, and the value is a pair + * containing time spent in active and spin states, respectively + */ + public Map> calculateThreadStateDurations(Set threads, long start, long end) { + Map> map = new HashMap<>(); + + ITmfTrace trace = getTrace(); + ITmfStateSystem threadSs = getStateSystem(); + if (trace == null || threadSs == null) { + return map; + } + + long startTime = Math.max(start, threadSs.getStartTime()); + long endTime = Math.min(end, threadSs.getCurrentEndTime()); + if (endTime < startTime) { + return map; + } + + try { + int threadsQuark = threadSs.getQuarkAbsolute(DpdkEthdevSpinAttributes.POLL_THREADS); + for (int threadQuark : threadSs.getSubAttributes(threadsQuark, false)) { + if (!threads.contains(threadQuark)) { + continue; + } + + String threadName = threadSs.getAttributeName(threadQuark); + long countActive = 0; + long countSpin = 0; + for (int queueQuark : threadSs.getSubAttributes(threadQuark, false)) { + countActive += calculateStateCount(threadSs, queueQuark, startTime, endTime, DpdkEthdevSpinAttributes.ACTIVE_STATUS); + countSpin += calculateStateCount(threadSs, queueQuark, startTime, endTime, DpdkEthdevSpinAttributes.SPIN_STATUS); + } + + map.put(threadName, new Pair<>(countActive, countSpin)); + } + + } catch (TimeRangeException | AttributeNotFoundException e) { + Activator.getInstance().logError(e.getMessage()); + } + + return map; + } + + /** + * Computes the time a thread spent in a specific state within the given + * time range. + * + * @param stateSystem + * State system + * @param attributeNode + * The node representing the thread state. + * @param startTime + * Start timestamp + * @param endTime + * End timestamp + * @param targetState + * The state to analyze (e.g., active or spin) + * @return The total time spent in the target state + */ + private static long calculateStateCount(ITmfStateSystem stateSystem, int attributeNode, long startTime, long endTime, String targetState) { + long count = 0; + long ts = startTime; + + try { + while (ts < endTime) { + ITmfStateInterval stateInterval = stateSystem.querySingleState(ts, attributeNode); + Object stateValue = stateInterval.getStateValue().unboxValue(); + long stateStart = stateInterval.getStartTime(); + long stateEnd = stateInterval.getEndTime(); + + if (stateValue != null && targetState.equals(stateValue)) { + count += interpolateCount(startTime, endTime, stateStart, stateEnd); + } + ts = Math.min(stateEnd, endTime) + 1; + } + } catch (TimeRangeException | StateSystemDisposedException e) { + Activator.getInstance().logError(e.getMessage()); + } + + return count; + } + + /** + * Adjusts the time interval to ensure it fits within the specified range. + * + * @param startTime + * Start timestamp of the analysis interval + * @param endTime + * End timestamp of the analysis interval + * @param startInterval + * Start timestamp of the state interval + * @param endInterval + * End timestamp of the state interval + * @return + */ + private static long interpolateCount(long startTime, long endTime, long startInterval, long endInterval) { + + long count = endInterval - startInterval; + + /* Sanity check */ + if (count > 0) { + if (startTime > startInterval) { + count -= (startTime - startInterval); + } + + if (endTime < endInterval) { + count -= (endInterval - endTime); + } + } + return count; + } +} diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinAttributes.java b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinAttributes.java new file mode 100644 index 000000000..7da1d92b4 --- /dev/null +++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinAttributes.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2024 É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 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.incubator.internal.dpdk.core.ethdev.spin.analysis; + +/** + * This interface defines all the attribute names used in the state system. + * + * @author Adel Belkhiri + */ +@SuppressWarnings({ "nls" }) +public interface DpdkEthdevSpinAttributes { + + /** Root attribute for DPDK PMD threads */ + String POLL_THREADS = "Threads"; + /** Thread is polling with no packets retrieved */ + String SPIN_STATUS = "Spin"; + /** Thread is polling and retrieving at least one packet */ + String ACTIVE_STATUS = "Active"; +} diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinDataProvider.java b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinDataProvider.java new file mode 100644 index 000000000..138692eea --- /dev/null +++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinDataProvider.java @@ -0,0 +1,247 @@ +/********************************************************************** + * Copyright (c) 2024 É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 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.incubator.internal.dpdk.core.ethdev.spin.analysis; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.incubator.internal.dpdk.core.Activator; +import org.eclipse.tracecompass.internal.tmf.core.model.filters.FetchParametersUtils; +import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; +import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; +import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException; +import org.eclipse.tracecompass.tmf.core.model.CommonStatusMessage; +import org.eclipse.tracecompass.tmf.core.model.IOutputStyleProvider; +import org.eclipse.tracecompass.tmf.core.model.OutputElementStyle; +import org.eclipse.tracecompass.tmf.core.model.OutputStyleModel; +import org.eclipse.tracecompass.tmf.core.model.StyleProperties; +import org.eclipse.tracecompass.tmf.core.model.YModel; +import org.eclipse.tracecompass.tmf.core.model.filters.SelectionTimeQueryFilter; +import org.eclipse.tracecompass.tmf.core.model.tree.TmfTreeDataModel; +import org.eclipse.tracecompass.tmf.core.model.tree.TmfTreeModel; +import org.eclipse.tracecompass.tmf.core.model.xy.AbstractTreeCommonXDataProvider; +import org.eclipse.tracecompass.tmf.core.model.xy.IYModel; +import org.eclipse.tracecompass.tmf.core.response.ITmfResponse; +import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; +import org.eclipse.tracecompass.tmf.core.util.Pair; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +/** + * This data provider will return a XY model, showing the percentage of + * occupancy of a PMD thread. The model also shows how much time the thread + * spends processing packets versus being idle over a period. + * + * @author Adel Belkhiri + */ +public class DpdkEthdevSpinDataProvider extends AbstractTreeCommonXDataProvider + implements IOutputStyleProvider { + + /** + * Extension point ID. + */ + public static final String ID = "org.eclipse.tracecompass.incubator.internal.dpdk.core.ethdev.spin.dataprovider"; //$NON-NLS-1$ + + /** + * Title used to create XY models for the + * {@link DpdkEthdevSpinDataProvider}. + */ + private static final String PROVIDER_TITLE = Objects.requireNonNull("DPDK Threads Effective CPU Usage"); //$NON-NLS-1$ + + private static final String BASE_STYLE = "base"; //$NON-NLS-1$ + + private static final String THREADS_LABEL = Objects.requireNonNull(Messages.DpdkEthdevSpin_DataProvider_Threads); + + private static final Map STATE_MAP; + + static { + // Create the base style + ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); + builder.put(BASE_STYLE, new OutputElementStyle(null, ImmutableMap.of(StyleProperties.SERIES_TYPE, StyleProperties.SeriesType.SCATTER, StyleProperties.WIDTH, 1.0f))); + STATE_MAP = builder.build(); + } + + /** + * Create an instance of {@link DpdkEthdevSpinDataProvider}. Returns a null + * instance if the analysis module is not found. + * + * @param trace + * A trace on which we are interested to fetch a model + * @return a {@link DpdkEthdevSpinDataProvider} instance. If analysis module + * is not found, it returns null + */ + public static @Nullable DpdkEthdevSpinDataProvider create(ITmfTrace trace) { + DpdkEthdevSpinAnalysisModule module = TmfTraceUtils.getAnalysisModuleOfClass(trace, DpdkEthdevSpinAnalysisModule.class, DpdkEthdevSpinAnalysisModule.ID); + if (module != null) { + module.schedule(); + return new DpdkEthdevSpinDataProvider(trace, module); + } + return null; + } + + /** + * Constructor + */ + private DpdkEthdevSpinDataProvider(ITmfTrace trace, DpdkEthdevSpinAnalysisModule module) { + super(trace, module); + } + + @Override + public String getId() { + return ID; + } + + @Override + protected TmfTreeModel getTree(ITmfStateSystem ss, Map parameters, @Nullable IProgressMonitor monitor) { + List nodes = new ArrayList<>(); + long rootId = getId(ITmfStateSystem.ROOT_ATTRIBUTE); + nodes.add(new TmfTreeDataModel(rootId, -1, Collections.singletonList(Objects.requireNonNull(getTrace().getName())), false, null)); + + try { + int threadsQuark = ss.getQuarkAbsolute(DpdkEthdevSpinAttributes.POLL_THREADS); + long threadsId = getId(threadsQuark); + nodes.add(new TmfTreeDataModel(threadsId, rootId, Collections.singletonList(THREADS_LABEL), false, null)); + + for (Integer threadQuark : ss.getQuarks(DpdkEthdevSpinAttributes.POLL_THREADS, "*")) { //$NON-NLS-1$ + String threadName = ss.getAttributeName(threadQuark); + long threadId = getId(threadQuark); + nodes.add(new TmfTreeDataModel(threadId, threadsId, Collections.singletonList(threadName), false, null)); + } + } catch (AttributeNotFoundException e) { + Activator.getInstance().logError("Error getting the root attribute of " + DpdkEthdevSpinAttributes.POLL_THREADS); //$NON-NLS-1$ + } + return new TmfTreeModel<>(Collections.emptyList(), nodes); + } + + /** + * Subtract from start time the same interval as the interval from start + * time to next time, ignoring duplicates in the times requested. + */ + private static long getInitialPrevTime(SelectionTimeQueryFilter filter) { + long startTime = filter.getStart(); + for (long time : filter.getTimesRequested()) { + if (time > startTime) { + return startTime - (time - startTime); + } + } + return startTime; + } + + @Override + protected @Nullable Collection getYSeriesModels(ITmfStateSystem ss, Map fetchParameters, @Nullable IProgressMonitor monitor) throws StateSystemDisposedException { + SelectionTimeQueryFilter filter = FetchParametersUtils.createSelectionTimeQuery(fetchParameters); + if (filter == null || getSelectedEntries(filter).isEmpty()) { + return null; + } + + Set threadQuarks = new HashSet<>(); + Map threadYModels = new HashMap<>(); + + // Fetch the quarks of PMD threads for analysis + for (Entry entry : getSelectedEntries(filter).entrySet()) { + int quark = Objects.requireNonNull(entry.getValue()); + if ((quark == ITmfStateSystem.ROOT_ATTRIBUTE) || + (ss.getParentAttributeQuark(quark) == ITmfStateSystem.ROOT_ATTRIBUTE)) { + continue; + } + threadQuarks.add(quark); + String name = ss.getAttributeName(quark); + threadYModels.put(name, new YModel(entry.getKey(), getTrace().getName() + '/' + name, new double[filter.getTimesRequested().length])); + } + + calculateThreadStatePercentages(ss, filter, monitor, threadQuarks, threadYModels); + return ImmutableList.copyOf(threadYModels.values()); + } + + /** + * Updates the thread YSeries models with the percentage of time each thread spent in active and spinning states + * + * @param ss + * State System + * @param filter + * Query Filter + * @param monitor + * Monitor + * @param threadQuarks + * Set of quarks representing the threads to be analyzed + * @param threadYModels + * A map of thread names to their corresponding Y-axis data models + */ + private void calculateThreadStatePercentages(ITmfStateSystem ss, SelectionTimeQueryFilter filter, @Nullable IProgressMonitor monitor, Set threadQuarks, Map threadYModels) { + long[] xValues = filter.getTimesRequested(); + long prevTime = Math.max(getInitialPrevTime(filter), ss.getStartTime()); + long currentEnd = ss.getCurrentEndTime(); + + for (int i = 0; i < xValues.length; i++) { + long currentTime = xValues[i]; + if (currentTime < ss.getStartTime() || currentTime > currentEnd) { + prevTime = currentTime; + continue; + } + + if (prevTime < currentTime) { + Map> threadUsageMap = getAnalysisModule().calculateThreadStateDurations( + threadQuarks, prevTime, currentTime); + + final int index = i; + threadUsageMap.forEach((key, durations) -> { + IYModel values = threadYModels.get(key); + if (values != null) { + values.getData()[index] = getPercentageValue(durations.getFirst(), durations.getSecond()); + } + }); + } else if (i > 0) { + for (IYModel values : threadYModels.values()) { + values.getData()[i] = values.getData()[i - 1]; + } + } + + prevTime = currentTime; + + if (monitor != null && monitor.isCanceled()) { + return; + } + } + } + + private static double getPercentageValue(long countActive, long countSpin) { + return (countActive + countSpin) == 0 ? 0.0 : (double) countActive * 100 / (countActive + countSpin); + } + + @Override + protected boolean isCacheable() { + return true; + } + + @Override + protected String getTitle() { + return PROVIDER_TITLE; + } + + @Override + public TmfModelResponse fetchStyle(Map fetchParameters, @Nullable IProgressMonitor monitor) { + return new TmfModelResponse<>(new OutputStyleModel(STATE_MAP), ITmfResponse.Status.COMPLETED, CommonStatusMessage.COMPLETED); + } +} diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinDataProviderFactory.java b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinDataProviderFactory.java new file mode 100644 index 000000000..2550304f7 --- /dev/null +++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinDataProviderFactory.java @@ -0,0 +1,55 @@ +/********************************************************************** + * Copyright (c) 2024 É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 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.incubator.internal.dpdk.core.ethdev.spin.analysis; + +import java.util.Collection; +import java.util.Collections; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderDescriptor; +import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderDescriptor.ProviderType; +import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderFactory; +import org.eclipse.tracecompass.tmf.core.model.DataProviderDescriptor; +import org.eclipse.tracecompass.tmf.core.model.tree.ITmfTreeDataModel; +import org.eclipse.tracecompass.tmf.core.model.xy.ITmfTreeXYDataProvider; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; + +/** + * Factory to create instances of the {@link DpdkEthdevSpinDataProvider}. + * + * @author Adel Belkhiri + */ +public class DpdkEthdevSpinDataProviderFactory implements IDataProviderFactory { + private static final IDataProviderDescriptor DESCRIPTOR = new DataProviderDescriptor.Builder() + .setId(DpdkEthdevSpinDataProvider.ID) + .setName("Dpdk Ethernet RX Spins") //$NON-NLS-1$ + .setDescription("XY chart showing a rough estimate of PMD threads busyness based on the number of empy and full Rx spins") //$NON-NLS-1$ + .setProviderType(ProviderType.TREE_TIME_XY) + .build(); + + @Override + public @Nullable ITmfTreeXYDataProvider createProvider(ITmfTrace trace) { + DpdkEthdevSpinAnalysisModule module = TmfTraceUtils.getAnalysisModuleOfClass(trace, DpdkEthdevSpinAnalysisModule.class, DpdkEthdevSpinAnalysisModule.ID); + if (module == null) { + return null; + } + module.schedule(); + return DpdkEthdevSpinDataProvider.create(trace); + } + + @Override + public Collection getDescriptors(ITmfTrace trace) { + DpdkEthdevSpinAnalysisModule module = TmfTraceUtils.getAnalysisModuleOfClass(trace, DpdkEthdevSpinAnalysisModule.class, DpdkEthdevSpinAnalysisModule.ID); + return module != null ? Collections.singletonList(DESCRIPTOR) : Collections.emptyList(); + } + +} diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinEventHandler.java b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinEventHandler.java new file mode 100644 index 000000000..4cd49595d --- /dev/null +++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinEventHandler.java @@ -0,0 +1,79 @@ +/********************************************************************** + * Copyright (c) 2024 É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 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.incubator.internal.dpdk.core.ethdev.spin.analysis; + +import java.util.Objects; + +import org.eclipse.tracecompass.incubator.internal.dpdk.core.Activator; +import org.eclipse.tracecompass.incubator.internal.dpdk.core.analysis.IDpdkEventHandler; +import org.eclipse.tracecompass.incubator.internal.dpdk.core.ethdev.analysis.DpdkEthdevEventLayout; +import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder; +import org.eclipse.tracecompass.statesystem.core.StateSystemBuilderUtils; +import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException; +import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; + +/** + * Event handler for the DPDK events required for the + * {@link DpdkEthdevSpinAnalysisModule} analysis + * + * @author Adel Belkhiri + */ +public class DpdkEthdevSpinEventHandler implements IDpdkEventHandler { + + private final DpdkEthdevEventLayout fLayout; + + DpdkEthdevSpinEventHandler(DpdkEthdevEventLayout layout) { + fLayout = layout; + } + + /** + * Update the count of received or transmitted packets on the state system + * + * @param ssb + * State system builder + * @param queueQuark + * Quark of the the Ethernet device queue + * @param nbPkts + * Number of packets received or transmitted + * @param ts + * Timestamp to use for state change + */ + public void updateCounts(ITmfStateSystemBuilder ssb, int queueQuark, Integer nbPkts, long ts) { + if (nbPkts <= 0) { + return; + } + try { + StateSystemBuilderUtils.incrementAttributeLong(ssb, ts, queueQuark, nbPkts); + } catch (StateValueTypeException e) { + Activator.getInstance().logWarning("Problem accessing the state of a NIC queue (Quark = " + queueQuark + ")", e); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + @Override + public void handleEvent(ITmfStateSystemBuilder ssb, ITmfEvent event) { + long ts = event.getTimestamp().getValue(); + String eventName = event.getName(); + + Integer portId = event.getContent().getFieldValue(Integer.class, fLayout.fieldPortId()); + Integer queueId = event.getContent().getFieldValue(Integer.class, fLayout.fieldQueueId()); + String threadName = event.getContent().getFieldValue(String.class, fLayout.fieldThreadName()); + Integer cpuId = event.getContent().getFieldValue(Integer.class, fLayout.fieldCpuId()); + + int threadQuark = ssb.getQuarkAbsoluteAndAdd(DpdkEthdevSpinAttributes.POLL_THREADS, threadName + "/" + cpuId); //$NON-NLS-1$ + int queueQark = ssb.getQuarkRelativeAndAdd(threadQuark, "P" + Objects.requireNonNull(portId).toString() + "/Q" + Objects.requireNonNull(queueId).toString()); //$NON-NLS-1$ //$NON-NLS-2$ + + if (eventName.equals(fLayout.eventEthdevRxBurstEmpty())) { + ssb.modifyAttribute(ts, DpdkEthdevSpinAttributes.SPIN_STATUS, queueQark); + } else if (eventName.equals(fLayout.eventEthdevRxBurstNonEmpty())) { + ssb.modifyAttribute(ts, DpdkEthdevSpinAttributes.ACTIVE_STATUS, queueQark); + } + } +} diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinStateProvider.java b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinStateProvider.java new file mode 100644 index 000000000..2cd17bda9 --- /dev/null +++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinStateProvider.java @@ -0,0 +1,83 @@ +/********************************************************************** + * Copyright (c) 2024 É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 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.incubator.internal.dpdk.core.ethdev.spin.analysis; + +import java.util.Map; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.incubator.internal.dpdk.core.analysis.AbstractDpdkStateProvider; +import org.eclipse.tracecompass.incubator.internal.dpdk.core.analysis.IDpdkEventHandler; +import org.eclipse.tracecompass.incubator.internal.dpdk.core.ethdev.analysis.DpdkEthdevEventLayout; +import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; + +import com.google.common.collect.ImmutableMap; + +/** + * State provider for the {@link DpdkEthdevSpinAnalysisModule} analysis + * + * @author Adel Belkhiri + */ +public class DpdkEthdevSpinStateProvider extends AbstractDpdkStateProvider { + + private static final int VERSION = 1; + + /** Map events needed for this analysis with their handler functions */ + private @Nullable Map fEventNames; + /** Events layout */ + private final DpdkEthdevEventLayout fLayout; + + /** + * Constructor + * + * @param trace + * trace + * @param layout + * layout + * @param id + * id + */ + protected DpdkEthdevSpinStateProvider(ITmfTrace trace, DpdkEthdevEventLayout layout, String id) { + super(trace, id); + fLayout = layout; + } + + /** + * Get the version of this state provider + */ + @Override + public int getVersion() { + return VERSION; + } + + /** + * Get a new instance + */ + @Override + public ITmfStateProvider getNewInstance() { + return new DpdkEthdevSpinStateProvider(this.getTrace(), fLayout, DpdkEthdevSpinAnalysisModule.ID); + } + + @Override + protected @Nullable IDpdkEventHandler getEventHandler(String eventName) { + if (fEventNames == null) { + ImmutableMap.Builder builder = ImmutableMap.builder(); + IDpdkEventHandler ethdevEventHandler = new DpdkEthdevSpinEventHandler(fLayout); + builder.put(fLayout.eventEthdevRxBurstEmpty(), ethdevEventHandler); + builder.put(fLayout.eventEthdevRxBurstNonEmpty(), ethdevEventHandler); + fEventNames = builder.build(); + } + if (fEventNames != null) { + return fEventNames.get(eventName); + } + return null; + } +} diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/Messages.java b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/Messages.java new file mode 100644 index 000000000..db4c9c690 --- /dev/null +++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/Messages.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2024 É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 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.incubator.internal.dpdk.core.ethdev.spin.analysis; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.osgi.util.NLS; + +/** + * Messages for {@link DpdkEthdevSpinDataProvider} + * + * @author Adel Belkhiri + */ +@SuppressWarnings("javadoc") +public class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.tracecompass.incubator.internal.dpdk.core.ethdev.spin.analysis.messages"; //$NON-NLS-1$ + + public static @Nullable String DpdkEthdevSpin_DataProvider_Threads; + public static @Nullable String DpdkEthdevSpin_DataProvider_YAxis; + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + // do nothing + } +} diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/messages.properties b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/messages.properties new file mode 100644 index 000000000..5e0387dc0 --- /dev/null +++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/messages.properties @@ -0,0 +1,13 @@ +############################################################################### +# Copyright (c) 2024 É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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0 +# +# SPDX-License-Identifier: EPL-2.0 +############################################################################### + +DpdkEthdevSpin_DataProvider_Threads=Threads +DpdkEthdevSpin_DataProvider_YAxis=Count diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/package-info.java b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/package-info.java new file mode 100644 index 000000000..6054bdc5f --- /dev/null +++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/package-info.java @@ -0,0 +1,13 @@ +/********************************************************************** + * Copyright (c) 2024 É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 2.0 which + * accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +@org.eclipse.jdt.annotation.NonNullByDefault +package org.eclipse.tracecompass.incubator.internal.dpdk.core.ethdev.spin.analysis; + diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/plugin.xml b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/plugin.xml index 535db5d2f..ea45828e4 100644 --- a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/plugin.xml +++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/plugin.xml @@ -25,6 +25,13 @@ class="org.eclipse.tracecompass.incubator.internal.dpdk.core.ethdev.throughput.analysis.DpdkEthdevThroughputAnalysisModule"> + + + + @@ -54,6 +61,13 @@ name="Ethernet Throughput View (BPS)" restorable="true"> + + diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/Messages.java b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/Messages.java new file mode 100644 index 000000000..87e787605 --- /dev/null +++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/Messages.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2024 É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 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.incubator.internal.dpdk.ui.ethdev.spin; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.osgi.util.NLS; + +/** + * Messages for the {@link ThreadSpinStatisticsViewer} view + * + * @author Adel Belkhiri + */ +public class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.tracecompass.incubator.internal.dpdk.ui.ethdev.spin.messages"; //$NON-NLS-1$ + /** Title of the view */ + public static @Nullable String EthdevThreadSpinStatsView_Title; + /** Title of the viewer */ + public static @Nullable String EthdevThreadSpinStatsViewer_Title; + /** X axis caption */ + public static @Nullable String EthdevThreadSpinStatsViewer_XAxis; + /** Y axis caption */ + public static @Nullable String EthdevThreadSpinStatsViewer_YAxis; + /** Thread name column */ + public static @Nullable String EthdevThreadSpinStatsTreeViewer_ThreadName; + /** Legend column*/ + public static @Nullable String EthdevThreadSpinStatsTreeViewer_Legend; + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + // do nothing + } +} diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/ThreadSpinStatisticsView.java b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/ThreadSpinStatisticsView.java new file mode 100644 index 000000000..336d5d617 --- /dev/null +++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/ThreadSpinStatisticsView.java @@ -0,0 +1,67 @@ +/********************************************************************** + * Copyright (c) 2024 É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 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.incubator.internal.dpdk.ui.ethdev.spin; + +import java.util.Comparator; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tracecompass.incubator.internal.dpdk.core.ethdev.spin.analysis.DpdkEthdevSpinDataProvider; +import org.eclipse.tracecompass.tmf.ui.viewers.TmfViewer; +import org.eclipse.tracecompass.tmf.ui.viewers.tree.AbstractSelectTreeViewer2; +import org.eclipse.tracecompass.tmf.ui.viewers.tree.ITmfTreeColumnDataProvider; +import org.eclipse.tracecompass.tmf.ui.viewers.tree.TmfGenericTreeEntry; +import org.eclipse.tracecompass.tmf.ui.viewers.tree.TmfTreeColumnData; +import org.eclipse.tracecompass.tmf.ui.viewers.xychart.TmfXYChartViewer; +import org.eclipse.tracecompass.tmf.ui.viewers.xychart.linechart.TmfXYChartSettings; +import org.eclipse.tracecompass.tmf.ui.views.xychart.TmfChartView; + +import com.google.common.collect.ImmutableList; + +/** + * Showing the PMD thread real occupancy across the trace duration + * + * @author Adel Belkhiri + */ +public class ThreadSpinStatisticsView extends TmfChartView { + + /** + * Identifier of this view + */ + public static final String ID = "org.eclipse.tracecompass.incubator.internal.dpdk.ui.ethdev.spin.statistics.view"; //$NON-NLS-1$ + private static final double RESOLUTION = 0.4; + + /** + * Default constructor + */ + public ThreadSpinStatisticsView() { + super(Messages.EthdevThreadSpinStatsView_Title); + } + + @Override + protected TmfXYChartViewer createChartViewer(Composite parent) { + TmfXYChartSettings settings = new TmfXYChartSettings(Messages.EthdevThreadSpinStatsViewer_Title, Messages.EthdevThreadSpinStatsViewer_XAxis, Messages.EthdevThreadSpinStatsViewer_YAxis, RESOLUTION); + return new ThreadSpinStatisticsViewer(parent, settings, DpdkEthdevSpinDataProvider.ID); + } + + @Override + protected @NonNull TmfViewer createLeftChildViewer(@Nullable Composite parent) { + return new AbstractSelectTreeViewer2(parent, 1, DpdkEthdevSpinDataProvider.ID) { + @Override + protected ITmfTreeColumnDataProvider getColumnDataProvider() { + return () -> ImmutableList.of( + createColumn(Messages.EthdevThreadSpinStatsTreeViewer_ThreadName, Comparator.comparing(TmfGenericTreeEntry::getName)), + new TmfTreeColumnData(Messages.EthdevThreadSpinStatsTreeViewer_Legend)); + } + }; + } +} diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/ThreadSpinStatisticsViewer.java b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/ThreadSpinStatisticsViewer.java new file mode 100644 index 000000000..493373f0e --- /dev/null +++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/ThreadSpinStatisticsViewer.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2024 É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 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.incubator.internal.dpdk.ui.ethdev.spin; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tracecompass.tmf.core.model.OutputElementStyle; +import org.eclipse.tracecompass.tmf.core.model.StyleProperties; +import org.eclipse.tracecompass.tmf.ui.viewers.xychart.linechart.TmfFilteredXYChartViewer; +import org.eclipse.tracecompass.tmf.ui.viewers.xychart.linechart.TmfXYChartSettings; + +/** + * Viewer for the {@link ThreadSpinStatisticsView} view + * + * @author Adel Belkhiri + */ +public class ThreadSpinStatisticsViewer extends TmfFilteredXYChartViewer { + + private static final int DEFAULT_SERIES_WIDTH = 1; + + /** + * Constructor + * + * @param parent + * Parent composite + * @param settings + * Chart settings + * @param providerId + * Data provider ID + */ + public ThreadSpinStatisticsViewer(Composite parent, TmfXYChartSettings settings, String providerId) { + super(parent, settings, providerId); + } + + @Override + public @NonNull OutputElementStyle getSeriesStyle(@NonNull Long seriesId) { + return getPresentationProvider().getSeriesStyle(seriesId, StyleProperties.SeriesType.LINE, DEFAULT_SERIES_WIDTH); + } + +} diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/messages.properties b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/messages.properties new file mode 100644 index 000000000..b5e4a0336 --- /dev/null +++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/messages.properties @@ -0,0 +1,16 @@ +############################################################################### +# Copyright (c) 2024 É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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +############################################################################### +EthdevThreadSpinStatsView_Title=PMD Effective Busyness View +EthdevThreadSpinStatsViewer_Title=PMD Effective Busyness View +EthdevThreadSpinStatsViewer_XAxis=Time +EthdevThreadSpinStatsViewer_YAxis=% BUSY +EthdevThreadSpinStatsTreeViewer_ThreadName=Threads +EthdevThreadSpinStatsTreeViewer_Legend=Legend diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/package-info.java b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/package-info.java new file mode 100644 index 000000000..79b47420f --- /dev/null +++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/package-info.java @@ -0,0 +1,11 @@ +/********************************************************************** + * Copyright (c) 2024 É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 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.incubator.internal.dpdk.ui.ethdev.spin;