diff --git a/analyses/org.eclipse.tracecompass.incubator.dpdk.core/META-INF/MANIFEST.MF b/analyses/org.eclipse.tracecompass.incubator.dpdk.core/META-INF/MANIFEST.MF index 7eef4387..c6952c0f 100644 --- a/analyses/org.eclipse.tracecompass.incubator.dpdk.core/META-INF/MANIFEST.MF +++ b/analyses/org.eclipse.tracecompass.incubator.dpdk.core/META-INF/MANIFEST.MF @@ -15,8 +15,10 @@ Require-Bundle: org.eclipse.ui, org.eclipse.tracecompass.tmf.core, org.eclipse.tracecompass.tmf.ctf.core, org.eclipse.tracecompass.analysis.os.linux.core, - org.eclipse.jdt.annotation;bundle-version="2.2.400" + org.eclipse.jdt.annotation;bundle-version="2.2.400", + com.google.guava 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/analyses/org.eclipse.tracecompass.incubator.dpdk.core/plugin.xml b/analyses/org.eclipse.tracecompass.incubator.dpdk.core/plugin.xml index 28d16bc6..694e32c5 100644 --- a/analyses/org.eclipse.tracecompass.incubator.dpdk.core/plugin.xml +++ b/analyses/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/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/Attributes.java b/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/Attributes.java new file mode 100644 index 00000000..c5352b99 --- /dev/null +++ b/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/Attributes.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * 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 Attributes { + + /* First-level attributes */ + + /** Root attribute for DPDK Ethdev Nics */ + String POLL_THREADS = "Threads"; + /** Reception Queues */ + /** */ + String SPIN_STATUS = "Spin"; + /** */ + String ACTIVE_STATUS = "Active"; +} diff --git a/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevEventHandler.java b/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevEventHandler.java new file mode 100644 index 00000000..99338162 --- /dev/null +++ b/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevEventHandler.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.DpdkEthdevEventLayout; +import org.eclipse.tracecompass.incubator.internal.dpdk.core.analysis.IDpdkEventHandler; +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 DpdkEthdevEventHandler implements IDpdkEventHandler { + + private static final String POLL_THREADS = Objects.requireNonNull(Attributes.POLL_THREADS); + + DpdkEthdevEventHandler() { + // Nothing here + } + + /** + * 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 + * time 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 = " + String.valueOf(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, DpdkEthdevEventLayout.fieldPortId()); + Integer queueId = event.getContent().getFieldValue(Integer.class, DpdkEthdevEventLayout.fieldQueueId()); + String threadName = event.getContent().getFieldValue(String.class, DpdkEthdevEventLayout.fieldThreadName()); + Integer cpuId = event.getContent().getFieldValue(Integer.class, DpdkEthdevEventLayout.fieldCpuId()); + + int threadQuark = ssb.getQuarkAbsoluteAndAdd(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(DpdkEthdevEventLayout.eventEthdevRxBurstEmpty())) { + ssb.modifyAttribute(ts, Attributes.SPIN_STATUS, queueQark); + } else if (eventName.equals(DpdkEthdevEventLayout.eventEthdevRxBurstNonEmpty())) { + ssb.modifyAttribute(ts, Attributes.ACTIVE_STATUS, queueQark); + } + } +} diff --git a/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinAnalysisModule.java b/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinAnalysisModule.java new file mode 100644 index 00000000..64828ee8 --- /dev/null +++ b/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinAnalysisModule.java @@ -0,0 +1,154 @@ +/********************************************************************** + * 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.jdt.annotation.NonNull; +import org.eclipse.tracecompass.incubator.internal.dpdk.core.Activator; +import org.eclipse.tracecompass.incubator.internal.dpdk.core.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.trace.TmfTrace; +import org.eclipse.tracecompass.tmf.core.util.Pair; + +import com.google.common.collect.ImmutableList; + +/** + * This analysis provides an estimation for the percentage of time a PMD thread + * was doing a real work (e.g., fetching and processing packets). It is based on + * two events: the "lib.ethdev.rx.burst.empty" event denotes an empty poll, and + * the "lib.ethdev.rx.burst.nonempty" event denotes a successful poll, where one + * or many packets are retrieved. + * + * @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 TmfAbstractAnalysisRequirement REQUIREMENT = new TmfAnalysisEventRequirement(ImmutableList.of( + DpdkEthdevEventLayout.eventEthdevRxBurstEmpty(), DpdkEthdevEventLayout.eventEthdevRxBurstNonEmpty()), PriorityLevel.AT_LEAST_ONE); + + @Override + protected ITmfStateProvider createStateProvider() { + ITmfTrace trace = checkNotNull(getTrace()); + + if (trace instanceof TmfTrace) { + return new DpdkEthdevSpinStateProvider(trace, ID); + } + + throw new IllegalStateException(); + } + + @Override + public Iterable getAnalysisRequirements() { + return Collections.singleton(REQUIREMENT); + } + + /** + * Calculates thread usage within a specific time interval + * + * @param threads + * Identifiers of the target threads + * @param start + * Start timestamp + * @param end + * End timestamp + * @return A map of Thread names -> time spent in empty or active iterations + */ + public Map> getThreadUsageInRange(Set<@NonNull Integer> 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 threadsNode = threadSs.getQuarkAbsolute(Attributes.POLL_THREADS); + for (int threadNode : threadSs.getSubAttributes(threadsNode, false)) { + if (!threads.contains(threadNode)) { + continue; + } + + String curThreadName = threadSs.getAttributeName(threadNode); + long countActive = 0; + long countSpin = 0; + for (int queueNode : threadSs.getSubAttributes(threadNode, false)) { + long ts = startTime; + do { + ITmfStateInterval stateInterval = threadSs.querySingleState(ts, queueNode); + Object stateValue = stateInterval.getStateValue().unboxValue(); + long stateStart = stateInterval.getStartTime(); + long stateEnd = stateInterval.getEndTime(); + + if (stateValue != null) { + String threadState = (String) stateValue; + if (threadState.equals(Attributes.ACTIVE_STATUS)) { + countActive += interpolateCount(startTime, endTime, stateEnd, stateStart); + } else if (threadState.equals(Attributes.SPIN_STATUS)) { + countSpin += interpolateCount(startTime, endTime, stateEnd, stateStart); + } + } + ts = Math.min(stateEnd, endTime) + 1; + } while (ts < endTime); + } + + map.put(curThreadName, new Pair<>(countActive, countSpin)); + } + + } catch (TimeRangeException | AttributeNotFoundException | StateSystemDisposedException e) { + Activator.getInstance().logError(e.getMessage()); + } + + return map; + } + + private static long interpolateCount(long startTime, long endTime, long spinningEnd, long spinningStart) { + + long count = spinningEnd - spinningStart; + + /* sanity check */ + if (count > 0) { + if (startTime > spinningStart) { + count -= (startTime - spinningStart); + } + + if (endTime < spinningEnd) { + count -= (spinningEnd - endTime); + } + } + return count; + } +} diff --git a/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinDataProvider.java b/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinDataProvider.java new file mode 100644 index 00000000..06e50670 --- /dev/null +++ b/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinDataProvider.java @@ -0,0 +1,240 @@ +/********************************************************************** + * 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}. + */ + protected 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(Attributes.POLL_THREADS); + long threadsId = getId(threadsQuark); + nodes.add(new TmfTreeDataModel(threadsId, rootId, Collections.singletonList(THREADS_LABEL), false, null)); + + for (Integer threadQuark : ss.getQuarks(Attributes.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 " + Attributes.POLL_THREADS); //$NON-NLS-1$ + } + return new TmfTreeModel<>(Collections.emptyList(), nodes); + } + + private static long getInitialPrevTime(SelectionTimeQueryFilter filter) { + /* + * Subtract from start time the same interval as the interval from start + * time to next time, ignoring duplicates in the times requested. + */ + 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) { + return null; + } + + if (getSelectedEntries(filter).isEmpty()) { + return null; + } + + Set selectedThreads = new HashSet<>(); + + long[] xValues = filter.getTimesRequested(); + Map selectedThreadValues = new HashMap<>(); + + for (Entry entry : getSelectedEntries(filter).entrySet()) { + int quark = Objects.requireNonNull(entry.getValue()); + + if ((quark == ITmfStateSystem.ROOT_ATTRIBUTE) || + (ss.getParentAttributeQuark(quark) == ITmfStateSystem.ROOT_ATTRIBUTE)) { + continue; + } + selectedThreads.add(quark); + String name = ss.getAttributeName(quark); + selectedThreadValues.put(name, new YModel(entry.getKey(), getTrace().getName() + '/' + name, new double[xValues.length])); + } + + long prevTime = Math.max(getInitialPrevTime(filter), ss.getStartTime()); + long currentEnd = ss.getCurrentEndTime(); + + for (int i = 0; i < xValues.length; i++) { + long time = xValues[i]; + if (time < ss.getStartTime() || time > currentEnd) { + prevTime = time; + continue; + } + if (prevTime < time) { + Map> threadUsageMap = getAnalysisModule().getThreadUsageInRange(selectedThreads, prevTime, time); + for (Entry> entry : threadUsageMap.entrySet()) { + IYModel values = selectedThreadValues.get(entry.getKey()/* + * threadName + */); + if (values != null) { + long countActive = Objects.requireNonNull(entry.getValue()).getFirst(); + long countSpin = Objects.requireNonNull(entry.getValue()).getSecond(); + values.getData()[i] = getPercentageValue(countActive, countSpin); + } + } + } else if (i > 0) { + /* In case of duplicate time xValue copy previous yValues */ + for (IYModel values : selectedThreadValues.values()) { + values.getData()[i] = values.getData()[i - 1]; + } + } + prevTime = time; + if (monitor != null && monitor.isCanceled()) { + return null; + } + } + + ImmutableList.Builder ySeries = ImmutableList.builder(); + for (IYModel entry : selectedThreadValues.values()) { + ySeries.add(entry); + } + + return ySeries.build(); + } + + private static double getPercentageValue(long countActive, long countSpin) { + double value = (countActive + countSpin == 0) ? 0.0 : (double) countActive * 100 / (countActive + countSpin); + return value; + } + + @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/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinDataProviderFactory.java b/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinDataProviderFactory.java new file mode 100644 index 00000000..2550304f --- /dev/null +++ b/analyses/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/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinStateProvider.java b/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinStateProvider.java new file mode 100644 index 00000000..6392ad6f --- /dev/null +++ b/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/DpdkEthdevSpinStateProvider.java @@ -0,0 +1,78 @@ +/********************************************************************** + * 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.DpdkEthdevEventLayout; +import org.eclipse.tracecompass.incubator.internal.dpdk.core.analysis.IDpdkEventHandler; +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; + + /** + * Constructor + * + * @param trace + * trace + * @param id + * id + */ + protected DpdkEthdevSpinStateProvider(ITmfTrace trace, String id) { + super(trace, id); + } + + /** + * 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(), DpdkEthdevSpinAnalysisModule.ID); + } + + @Override + protected @Nullable IDpdkEventHandler getEventHandler(String eventName) { + if (fEventNames == null) { + ImmutableMap.Builder builder = ImmutableMap.builder(); + IDpdkEventHandler ethdevEventHandler = new DpdkEthdevEventHandler(); + builder.put(DpdkEthdevEventLayout.eventEthdevRxBurstEmpty(), ethdevEventHandler); + builder.put(DpdkEthdevEventLayout.eventEthdevRxBurstNonEmpty(), ethdevEventHandler); + fEventNames = builder.build(); + } + if (fEventNames != null) { + return fEventNames.get(eventName); + } + return null; + } +} diff --git a/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/Messages.java b/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/Messages.java new file mode 100644 index 00000000..96d733c6 --- /dev/null +++ b/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/Messages.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * 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() { + } +} diff --git a/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/messages.properties b/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/messages.properties new file mode 100644 index 00000000..5e0387dc --- /dev/null +++ b/analyses/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/analyses/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/spin/analysis/package-info.java b/analyses/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 00000000..6054bdc5 --- /dev/null +++ b/analyses/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/analyses/org.eclipse.tracecompass.incubator.dpdk.ui/plugin.xml b/analyses/org.eclipse.tracecompass.incubator.dpdk.ui/plugin.xml index 535db5d2..bda54a8a 100644 --- a/analyses/org.eclipse.tracecompass.incubator.dpdk.ui/plugin.xml +++ b/analyses/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/analyses/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/Messages.java b/analyses/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/Messages.java new file mode 100644 index 00000000..ec3b7ec7 --- /dev/null +++ b/analyses/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/Messages.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * 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; + /** 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() { + } +} diff --git a/analyses/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/ThreadSpinStatisticsView.java b/analyses/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/ThreadSpinStatisticsView.java new file mode 100644 index 00000000..6d64ade8 --- /dev/null +++ b/analyses/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/ThreadSpinStatisticsView.java @@ -0,0 +1,69 @@ +/********************************************************************** + * 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 () -> { + return ImmutableList.of( + createColumn(Messages.EthdevThreadSpinStatsTreeViewer_ThreadName, Comparator.comparing(TmfGenericTreeEntry::getName)), + new TmfTreeColumnData(Messages.EthdevThreadSpinStatsTreeViewer_Legend)); + }; + } + }; + } +} diff --git a/analyses/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/ThreadSpinStatisticsViewer.java b/analyses/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/ThreadSpinStatisticsViewer.java new file mode 100644 index 00000000..493373f0 --- /dev/null +++ b/analyses/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/analyses/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/messages.properties b/analyses/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/messages.properties new file mode 100644 index 00000000..b5e4a033 --- /dev/null +++ b/analyses/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/analyses/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/package-info.java b/analyses/org.eclipse.tracecompass.incubator.dpdk.ui/src/org/eclipse/tracecompass/incubator/internal/dpdk/ui/ethdev/spin/package-info.java new file mode 100644 index 00000000..79b47420 --- /dev/null +++ b/analyses/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;