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 21c66100..f1c62347 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
@@ -15,6 +15,7 @@ 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.tracecompass.analysis.lami.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,
diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/plugin.xml b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/plugin.xml
index e28a4faa..276c5b45 100644
--- a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/plugin.xml
+++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/plugin.xml
@@ -31,6 +31,13 @@
+
+
+
+
true, Collections.emptyList());
+ }
+
+ @Override
+ protected synchronized void initialize() {
+ // do nothing
+ }
+
+ @Override
+ public boolean canExecute(ITmfTrace trace) {
+ if (trace instanceof DpdkTrace) {
+ return ((DpdkTrace) trace).validate(null, trace.getPath()).isOK();
+ }
+ return false;
+ }
+
+ private static int workRemaining(ITmfTrace trace) {
+ return (int) Math.min(trace.getNbEvents() / (PROGRESS_INTERVAL + 1), Integer.MAX_VALUE);
+ }
+
+ @Override
+ public List execute(ITmfTrace trace, @Nullable TmfTimeRange timeRange, String extraParamsString, IProgressMonitor monitor) throws CoreException {
+ AtomicLong done = new AtomicLong();
+ Map> pollCountPerQueue = new TreeMap<>();
+ TmfTimeRange adjustedTimeRange = timeRange == null ? TmfTimeRange.ETERNITY : timeRange;
+ SubMonitor subMonitor = SubMonitor.convert(monitor, Objects.requireNonNull(Messages.EthdevPollDistribution_AnalysisName), workRemaining(trace));
+
+ /*
+ * Handle the filter in case the user indicates a specific port to
+ * process its events
+ */
+ TmfFilterMatchesNode filter = new TmfFilterMatchesNode(null);
+ filter.setEventAspect(new TmfContentFieldAspect(Objects.requireNonNull(Messages.EthdevPollDistribution_CountLabel), fLayout.fieldPortId()));
+ filter.setRegex(extraParamsString);
+ Predicate filterPred = (event -> extraParamsString.isEmpty() || filter.matches(event));
+
+ // Create and send the event request
+ TmfEventRequest eventRequest = createEventRequest(trace, adjustedTimeRange, filterPred,
+ pollCountPerQueue, subMonitor, done);
+ trace.sendRequest(eventRequest);
+
+ try {
+ eventRequest.waitForCompletion();
+ return convertToLamiTables(adjustedTimeRange, pollCountPerQueue);
+
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return Collections.emptyList();
+ }
+ }
+
+ private TmfEventRequest createEventRequest(ITmfTrace trace, TmfTimeRange timeRange, Predicate filterPredicate, Map> pollAspectCounts, SubMonitor monitor, AtomicLong nbProcessevents) {
+ return new TmfEventRequest(ITmfEvent.class, timeRange, 0, Integer.MAX_VALUE, ExecutionType.BACKGROUND) {
+ @Override
+ public void handleData(ITmfEvent event) {
+ if (monitor.isCanceled()) {
+ cancel();
+ return;
+ }
+
+ // Process events to compute RX polls distribution
+ processEvent(event, filterPredicate, pollAspectCounts);
+
+ if ((nbProcessevents.incrementAndGet() & PROGRESS_INTERVAL) == 0) {
+ monitor.setWorkRemaining(workRemaining(trace));
+ monitor.worked(1);
+ monitor.setTaskName(String.format("DPDK Polls Distribution Analysis (%s events processed)", //$NON-NLS-1$
+ NumberFormat.getInstance().format(nbProcessevents.get())));
+ }
+ }
+ };
+ }
+
+ private void processEvent(ITmfEvent event, Predicate filterPredicate,
+ Map> pollAspectCounts) {
+
+ if (event.getName().equals(fLayout.eventEthdevRxBurstNonEmpty())
+ && filterPredicate.test(event)) {
+ Integer nbRxPkts = event.getContent().getFieldValue(Integer.class, fLayout.fieldNbRxPkts());
+ Integer portId = event.getContent().getFieldValue(Integer.class, fLayout.fieldPortId());
+ Integer queueId = event.getContent().getFieldValue(Integer.class, fLayout.fieldQueueId());
+
+ if (nbRxPkts != null && portId != null && queueId != null) {
+ String queueName = "P" + portId + "/Q" + queueId; //$NON-NLS-1$ //$NON-NLS-2$
+ Map dataSet = pollAspectCounts.computeIfAbsent(queueName, k -> new HashMap<>());
+ if (dataSet.size() < MEMORY_SANITY_LIMIT) {
+ dataSet.merge(nbRxPkts, 1L, (v1, v2) -> v1 + v2);
+ }
+ }
+ }
+ }
+
+ private List convertToLamiTables(TmfTimeRange timeRange,
+ Map> pollCountPerQueue) {
+ List results = new ArrayList<>();
+ for (Map.Entry> entry : pollCountPerQueue.entrySet()) {
+ String queueName = Objects.requireNonNull(entry.getKey());
+ Map dataSet = Objects.requireNonNull(entry.getValue());
+
+ List tableEntries = dataSet.entrySet().stream()
+ .map(e -> new LamiTableEntry(Arrays.asList(
+ new LamiString(Objects.requireNonNull(e.getKey()).toString()),
+ new LamiLongNumber(Objects.requireNonNull(e.getValue())))))
+ .collect(Collectors.toList());
+
+ List tableAspects = Arrays.asList(
+ new LamiCategoryAspect(Objects.requireNonNull(Messages.EthdevPollDistribution_NumberOfPacketsLabel), 0),
+ new LamiCountAspect(Objects.requireNonNull(Messages.EthdevPollDistribution_CountLabel), 1));
+
+ LamiTableClass tableClass = new LamiTableClass(queueName, queueName, tableAspects, Collections.emptySet());
+ results.add(new LamiResultTable(createTimeRange(timeRange), tableClass, tableEntries));
+ }
+ return results;
+ }
+
+ /**
+ * Count aspect, generic
+ *
+ */
+ private final class LamiCountAspect extends LamiGenericAspect {
+ private LamiCountAspect(String name, int column) {
+ super(name, null, column, true, false);
+ }
+ }
+
+ /**
+ * Category aspect, generic
+ *
+ */
+ private final class LamiCategoryAspect extends LamiGenericAspect {
+ private LamiCategoryAspect(String name, int column) {
+ super(name, null, column, false, false);
+ }
+ }
+
+ /**
+ * TODO: move to LAMI
+ */
+ private static LamiTimeRange createTimeRange(TmfTimeRange timeRange) {
+ return new LamiTimeRange(new LamiTimestamp(timeRange.getStartTime().toNanos()), new LamiTimestamp(timeRange.getEndTime().toNanos()));
+ }
+
+ /**
+ * TODO: LamiString in LAMI is private
+ */
+ private final class LamiString extends LamiData {
+ private final String fElement;
+
+ private LamiString(String element) {
+ fElement = element;
+ }
+
+ @Override
+ public @Nullable String toString() {
+ return fElement;
+ }
+ }
+}
diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/poll/distribution/analysis/Messages.java b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/poll/distribution/analysis/Messages.java
new file mode 100644
index 00000000..73125a8c
--- /dev/null
+++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/poll/distribution/analysis/Messages.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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.poll.distribution.analysis;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Messages for the {@link DpdkPollDistributionAnalysis} on-demand analysis
+ *
+ * @author Adel Belkhiri
+ */
+@SuppressWarnings("javadoc")
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.tracecompass.incubator.internal.dpdk.core.ethdev.poll.distribution.analysis.messages"; //$NON-NLS-1$
+
+ public static @Nullable String EthdevPollDistribution_AnalysisName;
+ public static @Nullable String EthdevPollDistribution_NumberOfPacketsLabel;
+ public static @Nullable String EthdevPollDistribution_CountLabel;
+
+ 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/poll/distribution/analysis/messages.properties b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/poll/distribution/analysis/messages.properties
new file mode 100644
index 00000000..a9f707ec
--- /dev/null
+++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/poll/distribution/analysis/messages.properties
@@ -0,0 +1,14 @@
+###############################################################################
+# 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
+###############################################################################
+
+EthdevPollDistribution_AnalysisName=DPDK Polls Distribution (ethdev)
+EthdevPollDistribution_NumberOfPacketsLabel=Number of retrieved packets
+EthdevPollDistribution_CountLabel=Count
diff --git a/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/poll/distribution/analysis/package-info.java b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/poll/distribution/analysis/package-info.java
new file mode 100644
index 00000000..7d99fdad
--- /dev/null
+++ b/tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/ethdev/poll/distribution/analysis/package-info.java
@@ -0,0 +1,12 @@
+/**********************************************************************
+ * 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.poll.distribution.analysis;