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;