Skip to content

Commit 745b9ef

Browse files
committed
dpdk: Add mempool usage analysis
This analysis shows how the number of mempool objects in use changes over time, providing insights into mempool usage patterns Signed-off-by: Adel Belkhiri <adel.belkhiri@gmail.com>
1 parent bcd9af5 commit 745b9ef

File tree

11 files changed

+528
-1
lines changed

11 files changed

+528
-1
lines changed

tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/plugin.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@
7474
class="org.eclipse.tracecompass.incubator.internal.dpdk.core.mempool.analysis.DpdkMempoolAllocFreeRateDataProviderFactory"
7575
id="org.eclipse.tracecompass.incubator.internal.dpdk.core.mempool.alloc.free.dataprovider">
7676
</dataProviderFactory>
77+
<dataProviderFactory
78+
class="org.eclipse.tracecompass.incubator.internal.dpdk.core.mempool.analysis.DpdkMempoolUsageDataProviderFactory"
79+
id="org.eclipse.tracecompass.incubator.internal.dpdk.core.mempool.dataprovider">
80+
</dataProviderFactory>
7781
</extension>
7882
<extension
7983
point="org.eclipse.linuxtools.tmf.core.tracetype">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
/**********************************************************************
2+
* Copyright (c) 2025 École Polytechnique de Montréal
3+
*
4+
* All rights reserved. This program and the accompanying materials are
5+
* made available under the terms of the Eclipse Public License 2.0 which
6+
* accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
**********************************************************************/
11+
12+
package org.eclipse.tracecompass.incubator.internal.dpdk.core.mempool.analysis;
13+
14+
import java.util.ArrayList;
15+
import java.util.Arrays;
16+
import java.util.Collection;
17+
import java.util.Collections;
18+
import java.util.HashMap;
19+
import java.util.List;
20+
import java.util.Map;
21+
import java.util.Map.Entry;
22+
import java.util.Objects;
23+
import java.util.stream.Collectors;
24+
25+
import org.eclipse.core.runtime.IProgressMonitor;
26+
import org.eclipse.jdt.annotation.Nullable;
27+
import org.eclipse.tracecompass.incubator.internal.dpdk.core.Activator;
28+
import org.eclipse.tracecompass.internal.tmf.core.model.filters.FetchParametersUtils;
29+
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
30+
import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
31+
import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
32+
import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
33+
import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
34+
import org.eclipse.tracecompass.tmf.core.dataprovider.DataType;
35+
import org.eclipse.tracecompass.tmf.core.model.YModel;
36+
import org.eclipse.tracecompass.tmf.core.model.filters.SelectionTimeQueryFilter;
37+
import org.eclipse.tracecompass.tmf.core.model.tree.TmfTreeDataModel;
38+
import org.eclipse.tracecompass.tmf.core.model.tree.TmfTreeModel;
39+
import org.eclipse.tracecompass.tmf.core.model.xy.AbstractTreeCommonXDataProvider;
40+
import org.eclipse.tracecompass.tmf.core.model.xy.IYModel;
41+
import org.eclipse.tracecompass.tmf.core.model.xy.TmfXYAxisDescription;
42+
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
43+
import org.eclipse.tracecompass.tmf.core.util.Pair;
44+
45+
import com.google.common.collect.ImmutableList;
46+
47+
/**
48+
* This data provider will return a XY model, showing the variation of the
49+
* number of used mempool objects over time.
50+
*
51+
* @author Adel Belkhiri
52+
*/
53+
public class DpdkMempoolUsageDataProvider extends AbstractTreeCommonXDataProvider<DpdkMempoolAnalysisModule, TmfTreeDataModel> {
54+
55+
/**
56+
* Extension point ID.
57+
*/
58+
public static final String ID = "org.eclipse.tracecompass.incubator.internal.dpdk.core.mempool.dataprovider"; //$NON-NLS-1$
59+
60+
/**
61+
* Title of the {@link DpdkMempoolUsageDataProvider}.
62+
*/
63+
private static final String PROVIDER_TITLE = Objects.requireNonNull("DPDK Mempool Objects In Use"); //$NON-NLS-1$
64+
private static final TmfXYAxisDescription Y_AXIS_DESCRIPTION = new TmfXYAxisDescription(Objects.requireNonNull(Messages.DpdkMempoolUsage_DataProvider_YAxis), "", DataType.NUMBER); //$NON-NLS-1$
65+
66+
private class MempoolBuilder {
67+
private final long fId;
68+
private final int fMempoolQuark;
69+
private final String fName;
70+
private final double[] fValues;
71+
72+
/**
73+
* Constructor
74+
*
75+
* @param id
76+
* The series Id
77+
* @param quark
78+
* Mempool quark
79+
* @param name
80+
* The name of this series
81+
* @param length
82+
* The length of the series
83+
*/
84+
public MempoolBuilder(long id, int quark, String name, int length) {
85+
fId = id;
86+
fMempoolQuark = quark;
87+
fName = name;
88+
fValues = new double[length];
89+
}
90+
91+
/**
92+
* Build a data series
93+
*
94+
* @param yAxisDescription
95+
* Description for the Y axis
96+
* @return an IYModel
97+
*/
98+
public IYModel build(TmfXYAxisDescription yAxisDescription) {
99+
return new YModel(fId, fName, fValues, yAxisDescription);
100+
}
101+
102+
}
103+
104+
/**
105+
* Constructor
106+
*
107+
* @param trace
108+
* Source trace for the analysis
109+
* @param module
110+
* Analysis module
111+
*/
112+
public DpdkMempoolUsageDataProvider(ITmfTrace trace, DpdkMempoolAnalysisModule module) {
113+
super(trace, module);
114+
}
115+
116+
@Override
117+
public String getId() {
118+
return ID;
119+
}
120+
121+
private static String getMempoolName(ITmfStateSystem ss, Integer mempoolNameQuark) {
122+
ITmfStateInterval interval = StateSystemUtils.queryUntilNonNullValue(
123+
ss, mempoolNameQuark, ss.getStartTime(), ss.getCurrentEndTime());
124+
return (interval != null) ? String.valueOf(interval.getValue()) : "no_name"; //$NON-NLS-1$
125+
}
126+
127+
@Override
128+
protected TmfTreeModel<TmfTreeDataModel> getTree(ITmfStateSystem ss, Map<String, Object> parameters, @Nullable IProgressMonitor monitor) {
129+
List<TmfTreeDataModel> nodes = new ArrayList<>();
130+
long rootId = getId(ITmfStateSystem.ROOT_ATTRIBUTE);
131+
nodes.add(new TmfTreeDataModel(rootId, -1, Collections.singletonList(Objects.requireNonNull(getTrace().getName())), false, null));
132+
133+
try {
134+
for (int mempoolQuark : ss.getSubAttributes(ss.getQuarkAbsolute(DpdkMempoolAttributes.MEMPOOLS), false)) {
135+
long mempoolId = getId(mempoolQuark);
136+
int nameQuark = ss.getQuarkRelative(mempoolQuark, DpdkMempoolAttributes.MEMPOOL_NAME);
137+
String mempoolName = getMempoolName(ss, nameQuark);
138+
139+
nodes.add(new TmfTreeDataModel(mempoolId, rootId, Collections.singletonList(mempoolName), false, null));
140+
}
141+
} catch (AttributeNotFoundException e) {
142+
Activator.getInstance().logError(e.getMessage());
143+
}
144+
return new TmfTreeModel<>(Collections.emptyList(), nodes);
145+
}
146+
147+
@Override
148+
protected @Nullable Collection<IYModel> getYSeriesModels(ITmfStateSystem ss, Map<String, Object> fetchParameters, @Nullable IProgressMonitor monitor) throws StateSystemDisposedException {
149+
SelectionTimeQueryFilter filter = FetchParametersUtils.createSelectionTimeQuery(fetchParameters);
150+
if (filter == null) {
151+
return null;
152+
}
153+
154+
Map<Integer, MempoolBuilder> builderByQuark = initBuilders(ss, filter);
155+
if (builderByQuark.isEmpty()) {
156+
return Collections.emptyList();
157+
}
158+
159+
Collection<Integer> totalMetricQuarks = new ArrayList<>();
160+
Map<Integer, Pair<Integer, String>> metricToDataMap = new HashMap<>();
161+
for (MempoolBuilder builder : builderByQuark.values()) {
162+
final Collection<Integer> allocQuarks = getMetricQuarks(ss, builder.fMempoolQuark, DpdkMempoolAttributes.THREAD_OBJ_ALLOC);
163+
allocQuarks.forEach(metricQuark -> metricToDataMap.put(metricQuark, new Pair<>(builder.fMempoolQuark, DpdkMempoolAttributes.THREAD_OBJ_ALLOC)));
164+
totalMetricQuarks.addAll(allocQuarks);
165+
166+
final Collection<Integer> freeQuarks = getMetricQuarks(ss, builder.fMempoolQuark, DpdkMempoolAttributes.THREAD_OBJ_FREE);
167+
freeQuarks.forEach(metricQuark -> metricToDataMap.put(metricQuark, new Pair<>(builder.fMempoolQuark, DpdkMempoolAttributes.THREAD_OBJ_FREE)));
168+
totalMetricQuarks.addAll(freeQuarks);
169+
}
170+
171+
long[] xValues = filter.getTimesRequested();
172+
Collection<Long> times = getTimes(filter, ss.getStartTime(), ss.getCurrentEndTime());
173+
174+
for (ITmfStateInterval interval : ss.query2D(totalMetricQuarks, times)) {
175+
if (monitor != null && monitor.isCanceled()) {
176+
return null;
177+
}
178+
179+
Object value = interval.getValue();
180+
long nbObjCount = value instanceof Number ? ((Number) value).longValue() : 0L;
181+
182+
if (nbObjCount == 0) {
183+
continue;
184+
}
185+
186+
int from = Arrays.binarySearch(xValues, interval.getStartTime());
187+
from = (from >= 0) ? from : -1 - from;
188+
189+
int to = Arrays.binarySearch(xValues, interval.getEndTime());
190+
to = (to >= 0) ? to + 1 : -1 - to;
191+
192+
if (from < to) {
193+
Pair<Integer, String> metricData = Objects.requireNonNull(metricToDataMap.get(interval.getAttribute()));
194+
int sign = DpdkMempoolAttributes.THREAD_OBJ_ALLOC.equals(metricData.getSecond()) ? 1 : -1;
195+
196+
MempoolBuilder builder = Objects.requireNonNull(builderByQuark.get(metricData.getFirst()));
197+
198+
for (int i = from; i < to; i++) {
199+
builder.fValues[i] += sign * nbObjCount;
200+
}
201+
}
202+
}
203+
return ImmutableList.copyOf(
204+
builderByQuark.values().stream()
205+
.map(builder -> builder.build(Y_AXIS_DESCRIPTION))
206+
.collect(Collectors.toList()));
207+
}
208+
209+
/**
210+
* Retrieves the metric quarks associated with a given mempool and metric
211+
* label
212+
*
213+
* @param ss
214+
* State system
215+
* @param mempoolQuark
216+
* Mempool quark
217+
* @param metricLabel
218+
* The label used to filter metric attributes
219+
* @return A collection of sub-attribute quarks for the mempool quark that
220+
* match the specified metric label
221+
*/
222+
private static Collection<Integer> getMetricQuarks(ITmfStateSystem ss, Integer mempoolQuark, String metricLabel) {
223+
Collection<Integer> metricQuarks = new ArrayList<>();
224+
try {
225+
int threadsQuark = ss.optQuarkRelative(mempoolQuark, DpdkMempoolAttributes.THREADS);
226+
if (threadsQuark != ITmfStateSystem.INVALID_ATTRIBUTE) {
227+
for (int quark : ss.getSubAttributes(threadsQuark, true)) {
228+
if (quark != ITmfStateSystem.INVALID_ATTRIBUTE && metricLabel.equals(ss.getAttributeName(quark))) {
229+
metricQuarks.add(quark);
230+
}
231+
}
232+
}
233+
234+
} catch (IndexOutOfBoundsException e) {
235+
Activator.getInstance().logError(e.getMessage());
236+
}
237+
return metricQuarks;
238+
}
239+
240+
@Override
241+
protected boolean isCacheable() {
242+
return true;
243+
}
244+
245+
@Override
246+
protected String getTitle() {
247+
return PROVIDER_TITLE;
248+
}
249+
250+
private Map<Integer, MempoolBuilder> initBuilders(ITmfStateSystem ss, SelectionTimeQueryFilter filter) {
251+
int length = filter.getTimesRequested().length;
252+
Map<Integer, MempoolBuilder> builderMap = new HashMap<>();
253+
254+
for (Entry<Long, Integer> entry : getSelectedEntries(filter).entrySet()) {
255+
int quark = Objects.requireNonNull(entry.getValue());
256+
if (quark == ITmfStateSystem.ROOT_ATTRIBUTE || ss.getParentAttributeQuark(quark) == ITmfStateSystem.ROOT_ATTRIBUTE) {
257+
continue;
258+
}
259+
260+
int parentQuark = ss.getParentAttributeQuark(quark);
261+
if (parentQuark != ITmfStateSystem.INVALID_ATTRIBUTE &&
262+
(DpdkMempoolAttributes.MEMPOOLS.equals(ss.getAttributeName(parentQuark)))) {
263+
264+
String name = getTrace().getName() + '/' + ss.getAttributeName(quark);
265+
builderMap.put(quark, new MempoolBuilder(entry.getKey(), quark, name, length));
266+
}
267+
}
268+
return builderMap;
269+
}
270+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**********************************************************************
2+
* Copyright (c) 2025 École Polytechnique de Montréal
3+
*
4+
* All rights reserved. This program and the accompanying materials are
5+
* made available under the terms of the Eclipse Public License 2.0 which
6+
* accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
**********************************************************************/
11+
package org.eclipse.tracecompass.incubator.internal.dpdk.core.mempool.analysis;
12+
13+
import java.util.Collection;
14+
import java.util.Collections;
15+
16+
import org.eclipse.jdt.annotation.Nullable;
17+
import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderDescriptor;
18+
import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderDescriptor.ProviderType;
19+
import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderFactory;
20+
import org.eclipse.tracecompass.tmf.core.model.DataProviderDescriptor;
21+
import org.eclipse.tracecompass.tmf.core.model.tree.ITmfTreeDataModel;
22+
import org.eclipse.tracecompass.tmf.core.model.xy.ITmfTreeXYDataProvider;
23+
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
24+
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
25+
26+
/**
27+
* Factory to create instances of the {@link DpdkMempoolUsageDataProvider}.
28+
*
29+
* @author Adel Belkhiri
30+
*/
31+
public class DpdkMempoolUsageDataProviderFactory implements IDataProviderFactory {
32+
private static final IDataProviderDescriptor DESCRIPTOR = new DataProviderDescriptor.Builder()
33+
.setId(DpdkMempoolUsageDataProvider.ID)
34+
.setName("DPDK Mempool Objects In Use") //$NON-NLS-1$
35+
.setDescription("XY chart showing the variation of the number of mempool objects over time") //$NON-NLS-1$
36+
.setProviderType(ProviderType.TREE_TIME_XY)
37+
.build();
38+
39+
@Override
40+
public @Nullable ITmfTreeXYDataProvider<? extends ITmfTreeDataModel> createProvider(ITmfTrace trace) {
41+
DpdkMempoolAnalysisModule module = TmfTraceUtils.getAnalysisModuleOfClass(trace, DpdkMempoolAnalysisModule.class, DpdkMempoolAnalysisModule.ID);
42+
if (module == null) {
43+
return null;
44+
}
45+
module.schedule();
46+
return new DpdkMempoolUsageDataProvider(trace, module);
47+
}
48+
49+
@Override
50+
public Collection<IDataProviderDescriptor> getDescriptors(ITmfTrace trace) {
51+
DpdkMempoolAnalysisModule module = TmfTraceUtils.getAnalysisModuleOfClass(trace, DpdkMempoolAnalysisModule.class, DpdkMempoolAnalysisModule.ID);
52+
return module != null ? Collections.singletonList(DESCRIPTOR) : Collections.emptyList();
53+
}
54+
}

tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/mempool/analysis/Messages.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public class Messages extends NLS {
2424
private static final String BUNDLE_NAME = "org.eclipse.tracecompass.incubator.internal.dpdk.core.mempool.analysis.messages"; //$NON-NLS-1$
2525

2626
public static @Nullable String DpdkMempoolAllocFreeRate_DataProvider_YAxis;
27+
public static @Nullable String DpdkMempoolUsage_DataProvider_YAxis;
2728
static {
2829
// initialize resource bundle
2930
NLS.initializeMessages(BUNDLE_NAME, Messages.class);

tracetypes/org.eclipse.tracecompass.incubator.dpdk.core/src/org/eclipse/tracecompass/incubator/internal/dpdk/core/mempool/analysis/messages.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@
99
# SPDX-License-Identifier: EPL-2.0
1010
###############################################################################
1111

12-
DpdkMempoolAllocFreeRate_DataProvider_YAxis=Rate
12+
DpdkMempoolAllocFreeRate_DataProvider_YAxis=Rate
13+
DpdkMempoolUsage_DataProvider_YAxis=Count

tracetypes/org.eclipse.tracecompass.incubator.dpdk.ui/plugin.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@
3939
id="org.eclipse.tracecompass.incubator.dpdk.mempool.analysis">
4040
</analysisId>
4141
</output>
42+
<output
43+
class="org.eclipse.tracecompass.tmf.ui.analysis.TmfAnalysisViewOutput"
44+
id="org.eclipse.tracecompass.incubator.internal.dpdk.ui.mempool.usage.view">
45+
<analysisId
46+
id="org.eclipse.tracecompass.incubator.dpdk.mempool.analysis">
47+
</analysisId>
48+
</output>
4249
</extension>
4350
<extension
4451
point="org.eclipse.ui.views">
@@ -82,6 +89,13 @@
8289
name="Mempool Objects Alloc/Free Rate"
8390
restorable="true">
8491
</view>
92+
<view
93+
category="org.eclipse.tracecompass.incubator.internal.dpdk.ui.views.category"
94+
class="org.eclipse.tracecompass.incubator.internal.dpdk.ui.mempool.usage.MempoolUsageView"
95+
id="org.eclipse.tracecompass.incubator.internal.dpdk.ui.mempool.usage.view"
96+
name="Mempool Objects In Use"
97+
restorable="true">
98+
</view>
8599
</extension>
86100

87101
</plugin>

0 commit comments

Comments
 (0)