linux: Move SWSLatency analysis to Trace Compass core The SWSLatency computes the latency between the sched_wakeup event and the sched_switch event for each thread. It is a subclass of AbstractSegmentStoreAnalysisEventBasedModule. This commit moves the SWSLatency analysis from the incubator to Trace Compass core by copying the necessary files from org.eclipse.tracecompass.incubator.internal.kernel.core.swslatency to org.eclipse.tracecompass.analysis.os.linux.core.swslatency and making necessary changes to existing configuration files. It also moves unit tests for the analysis to Trace Compass core. To test the analysis: [1] Run the unit tests in org.eclipse.tracecompass.analysis.os.linux.core.tests.swslatency as J-unit plug-in tests. Confirm that they all pass. The goal is to test that the analysis runs and provides expected output. [2] Run the unit tests in org.eclipse.tracecompass.integration.core.tests.dataproviders as J-unit plug-in tests. Confirm that they all pass. Adding the new analysis generates new DataProviderDescriptor(s). This is to make sure that the existing test in this package is updated. [3] Open Trace Compass. Open a kernel trace. Make sure that the Scheduler Wakeup to Scheduler Switch Latency analysis is visible and not crossed out under Views in the Project Explorer. It is normal to have no output under the analysis because they are not yet included in this commit. This is required to make sure that the analysis is exposed to users in the UI of the Trace Compass application. To be done in subsequent patches: [1] Migrate outputs of the SWSLatency analysis [2] Renaming the SWSLatency analysis to SchedulerWakeupToSchedulerSwitchLatency to make the name of the analysis easier to understand [3] Add documentation [4] Deprecate the SWSLatency analysis in the incubator [Added] SWSLatency (SchedulerWakeupToSchedulerSwitchLatency) analysis Change-Id: I7e105c4bae2042fd230d43eee9e97972113b8529 Signed-off-by: Hoang Thuan Pham <hoang.pham@calian.ca> Reviewed-on: https://git.eclipse.org/r/c/tracecompass/org.eclipse.tracecompass/+/203530 Tested-by: Marco Miller <marco.miller@ericsson.com> Tested-by: Trace Compass Bot <tracecompass-bot@eclipse.org> Reviewed-by: Marco Miller <marco.miller@ericsson.com>
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/src/org/eclipse/tracecompass/analysis/os/linux/core/tests/swslatency/SWSLatencyTest.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/src/org/eclipse/tracecompass/analysis/os/linux/core/tests/swslatency/SWSLatencyTest.java new file mode 100644 index 0000000..85f16ea --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/src/org/eclipse/tracecompass/analysis/os/linux/core/tests/swslatency/SWSLatencyTest.java
@@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright (c) 2021 É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.analysis.os.linux.core.tests.swslatency; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import java.io.File; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.tracecompass.analysis.os.linux.core.swslatency.SWSLatencyAnalysis; +import org.eclipse.tracecompass.analysis.os.linux.core.swslatency.SchedWS; +import org.eclipse.tracecompass.analysis.os.linux.core.swslatency.SchedWS.InitialInfo; +import org.eclipse.tracecompass.analysis.os.linux.core.tests.Activator; +import org.eclipse.tracecompass.analysis.os.linux.core.tests.stubs.trace.TmfXmlKernelTraceStub; +import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelTrace; +import org.eclipse.tracecompass.segmentstore.core.ISegment; +import org.eclipse.tracecompass.segmentstore.core.ISegmentStore; +import org.eclipse.tracecompass.tmf.core.event.TmfEvent; +import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException; +import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.google.common.collect.ImmutableList; + +/** + * Test suite for the {@link SWSLatencyAnalysis} class + * + * @author Abdellah Rahmani + */ +public class SWSLatencyTest { + + private static final String SWS_USAGE_FILE = "testfiles/sws_analysis.xml"; + private IKernelTrace fTrace; + private SWSLatencyAnalysis fModule; + + private static void deleteSuppFiles(ITmfTrace trace) { + /* Remove supplementary files */ + if (trace != null) { + File suppDir = new File(TmfTraceManager.getSupplementaryFileDir(trace)); + for (File file : suppDir.listFiles()) { + file.delete(); + } + } + } + + /** + * Setup the trace for the tests + */ + @Before + public void setUp() { + IKernelTrace trace = new TmfXmlKernelTraceStub(); + IPath filePath = Activator.getAbsoluteFilePath(SWS_USAGE_FILE); + IStatus status = trace.validate(null, filePath.toOSString()); + if (!status.isOK()) { + fail(status.getException().getMessage()); + } + try { + trace.initTrace(null, filePath.toOSString(), TmfEvent.class); + } catch (TmfTraceException e) { + fail(e.getMessage()); + } + deleteSuppFiles(trace); + ((TmfTrace) trace).traceOpened(new TmfTraceOpenedSignal(this, trace, null)); + fModule = TmfTraceUtils.getAnalysisModuleOfClass(trace, SWSLatencyAnalysis.class, SWSLatencyAnalysis.ID); + assertNotNull(fModule); + fModule.schedule(); + fModule.waitForCompletion(); + fTrace = trace; + } + + /** + * Dispose everything + */ + @After + public void cleanup() { + ITmfTrace testTrace = fTrace; + if (testTrace != null) { + testTrace.dispose(); + } + } + + /** + * This will load the analysis and test it. as it depends on Kernel, this + * test runs the kernel trace first then the analysis + */ + @SuppressWarnings("null") + @Test + public void testSmallTraceSequential() { + SWSLatencyAnalysis swsModule = fModule; + assertNotNull(swsModule); + ISegmentStore<@NonNull ISegment> segmentStore = swsModule.getSegmentStore(); + assertNotNull(segmentStore); + assertEquals(false, segmentStore.isEmpty()); + assertEquals(5, segmentStore.size()); + + List<InitialInfo> info = ImmutableList.of(new InitialInfo(0, "proc1", 2), new InitialInfo(3, "proc3", 3), + new InitialInfo(6, "proc4", 4), new InitialInfo(10, "proc1", 1), new InitialInfo(3, "proc2", 2)); + List<SchedWS> expected = ImmutableList.of(new SchedWS(info.get(0), 1, 20), new SchedWS(info.get(1), 5, 0), + new SchedWS(info.get(2), 10, 20), new SchedWS(info.get(3), 15, 20), new SchedWS(info.get(4), 25, 20)); + + Iterator<ISegment> it = segmentStore.iterator(); + for (int i = 0; i < expected.size(); i++) { + if (it.hasNext()) { + SchedWS segment = (SchedWS) it.next(); + long startTime = expected.get(i).getStart(); + long endTime = expected.get(i).getEnd(); + long duration = expected.get(i).getLength(); + int threadID = expected.get(i).getTid(); + int priority = expected.get(i).getPriority(); + String name = expected.get(i).getName(); + + assertEquals("Start time of the segment " + i, startTime, segment.getStart()); + assertEquals("End time of the segment " + i, endTime, segment.getEnd()); + assertEquals("Duration of the segment " + i, duration, segment.getLength()); + assertEquals("TID in segment " + i, threadID, segment.getTid()); + assertEquals("Priority of the process in segment " + i, priority, segment.getPriority()); + assertEquals("Name of the process in segment " + i, name, segment.getName()); + } + } + } +} \ No newline at end of file
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/testfiles/sws_analysis.xml b/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/testfiles/sws_analysis.xml new file mode 100644 index 0000000..a48f74c --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/testfiles/sws_analysis.xml
@@ -0,0 +1,132 @@ +<!--******************************************************************************* +* Copyright (c) 2021 É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 +*******************************************************************************--> + +<trace> + <set_aspects> + <field name="cpu" value="1" type="int" /> + </set_aspects> + <event timestamp="0" name="sched_wakeup"> + <field name="cpu" value="0" type="int" /> + <field name="comm" value="proc1" type="string" /> + <field name="tid" value="2" type="long" /> + <field name="prio" value="20" type="long" /> + </event> + <event timestamp="1" name="sched_switch"> + <field name="cpu" value="0" type="int" /> + <field name="prev_comm" value="proc1" type="string" /> + <field name="prev_tid" value="1" type="long" /> + <field name="prev_prio" value="20" type="long" /> + <field name="prev_state" value="0" type="long" /> + <field name="next_comm" value="proc2" type="string" /> + <field name="next_tid" value="2" type="long" /> + <field name="next_prio" value="20" type="long" /> + </event> + <event timestamp="2" name="sched_switch"> + <field name="cpu" value="1" type="int" /> + <field name="prev_comm" value="proc3" type="string" /> + <field name="prev_tid" value="3" type="long" /> + <field name="prev_prio" value="20" type="long" /> + <field name="prev_state" value="0" type="long" /> + <field name="next_comm" value="proc4" type="string" /> + <field name="next_tid" value="4" type="long" /> + <field name="next_prio" value="20" type="long" /> + </event> + <event timestamp="3" name="sched_wakeup"> + <field name="cpu" value="0" type="int" /> + <field name="comm" value="proc3" type="string" /> + <field name="tid" value="3" type="long" /> + <field name="prio" value="0" type="long" /> + </event> + <event timestamp="3" name="sched_wakeup"> + <field name="cpu" value="0" type="int" /> + <field name="comm" value="proc2" type="string" /> + <field name="tid" value="2" type="long" /> + <field name="prio" value="20" type="long" /> + </event> + <event timestamp="5" name="sched_switch"> + <field name="cpu" value="1" type="int" /> + <field name="prev_comm" value="proc4" type="string" /> + <field name="prev_tid" value="4" type="long" /> + <field name="prev_prio" value="20" type="long" /> + <field name="prev_state" value="0" type="long" /> + <field name="next_comm" value="proc3" type="string" /> + <field name="next_tid" value="3" type="long" /> + <field name="next_prio" value="0" type="long" /> + </event> + <event timestamp="6" name="sched_wakeup"> + <field name="cpu" value="0" type="int" /> + <field name="comm" value="proc4" type="string" /> + <field name="tid" value="4" type="long" /> + <field name="prio" value="20" type="long" /> + </event> + <event timestamp="10" name="sched_wakeup"> + <field name="cpu" value="0" type="int" /> + <field name="comm" value="proc1" type="string" /> + <field name="tid" value="1" type="long" /> + <field name="prio" value="20" type="long" /> + </event> + <event timestamp="10" name="sched_switch"> + <field name="cpu" value="1" type="int" /> + <field name="prev_comm" value="proc3" type="string" /> + <field name="prev_tid" value="3" type="long" /> + <field name="prev_prio" value="20" type="long" /> + <field name="prev_state" value="0" type="long" /> + <field name="next_comm" value="proc4" type="string" /> + <field name="next_tid" value="4" type="long" /> + <field name="next_prio" value="20" type="long" /> + </event> + <event timestamp="15" name="sched_switch"> + <field name="cpu" value="1" type="int" /> + <field name="prev_comm" value="proc4" type="string" /> + <field name="prev_tid" value="4" type="long" /> + <field name="prev_prio" value="20" type="long" /> + <field name="prev_state" value="0" type="long" /> + <field name="next_comm" value="proc1" type="string" /> + <field name="next_tid" value="1" type="long" /> + <field name="next_prio" value="20" type="long" /> + </event> + <event timestamp="20" name="sched_switch"> + <field name="cpu" value="1" type="int" /> + <field name="prev_comm" value="proc1" type="string" /> + <field name="prev_tid" value="1" type="long" /> + <field name="prev_prio" value="20" type="long" /> + <field name="prev_state" value="0" type="long" /> + <field name="next_comm" value="proc4" type="string" /> + <field name="next_tid" value="4" type="long" /> + <field name="next_prio" value="20" type="long" /> + </event> + <event timestamp="20" name="sched_switch"> + <field name="cpu" value="0" type="int" /> + <field name="prev_comm" value="proc2" type="string" /> + <field name="prev_tid" value="2" type="long" /> + <field name="prev_prio" value="20" type="long" /> + <field name="prev_state" value="0" type="long" /> + <field name="next_comm" value="proc3" type="string" /> + <field name="next_tid" value="3" type="long" /> + <field name="next_prio" value="20" type="long" /> + </event> + <event timestamp="25" name="sched_switch"> + <field name="cpu" value="0" type="int" /> + <field name="prev_comm" value="proc3" type="string" /> + <field name="prev_tid" value="3" type="long" /> + <field name="prev_prio" value="20" type="long" /> + <field name="prev_state" value="0" type="long" /> + <field name="next_comm" value="proc2" type="string" /> + <field name="next_tid" value="2" type="long" /> + <field name="next_prio" value="20" type="long" /> + </event> + <event timestamp="30" name="sched_wakeup"> + <field name="cpu" value="0" type="int" /> + <field name="comm" value="proc1" type="string" /> + <field name="tid" value="1" type="long" /> + <field name="prio" value="20" type="long" /> + </event> +</trace>
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF index 3f3af4a..73b5ddc 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-Vendor: %Bundle-Vendor -Bundle-Version: 8.0.0.qualifier +Bundle-Version: 8.1.0.qualifier Bundle-Localization: plugin Bundle-SymbolicName: org.eclipse.tracecompass.analysis.os.linux.core;singleton:=true Bundle-Activator: org.eclipse.tracecompass.internal.analysis.os.linux.core.Activator @@ -36,6 +36,7 @@ org.eclipse.tracecompass.analysis.os.linux.core.memory, org.eclipse.tracecompass.analysis.os.linux.core.model, org.eclipse.tracecompass.analysis.os.linux.core.signals, + org.eclipse.tracecompass.analysis.os.linux.core.swslatency, org.eclipse.tracecompass.analysis.os.linux.core.tid, org.eclipse.tracecompass.analysis.os.linux.core.trace, org.eclipse.tracecompass.internal.analysis.os.linux.core;x-internal:=true,
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/icons/swslatency.png b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/icons/swslatency.png new file mode 100644 index 0000000..8e89336 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/icons/swslatency.png Binary files differ
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.properties b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.properties index a37714c..50f6180 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.properties +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.properties
@@ -25,5 +25,6 @@ analysis.io = Input/Output analysis.tid = Active Thread analysis.execgraph = OS Execution Graph +analysis.swsLatency.wakeupswitch = Scheduler Wakeup to Scheduler Switch Latency -extensionpoint.graphhandler.name = Operating System Graph Handler \ No newline at end of file +extensionpoint.graphhandler.name = Operating System Graph Handler
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.xml b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.xml index 9b007f9..04dae35 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.xml +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.xml
@@ -88,6 +88,18 @@ class="org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelTrace"> </tracetype> </module> + <module + analysis_module="org.eclipse.tracecompass.analysis.os.linux.core.swslatency.SWSLatencyAnalysis" + applies_experiment="false" + automatic="false" + icon="icons/swslatency.png" + id="org.eclipse.tracecompass.analysis.os.linux.core.swslatency.sws" + name="%analysis.swsLatency.wakeupswitch"> + <tracetype + applies="true" + class="org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelTrace"> + </tracetype> + </module> <tracetype applies="true" class="org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelTrace"
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/swslatency/Messages.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/swslatency/Messages.java new file mode 100644 index 0000000..8d0cab5 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/swslatency/Messages.java
@@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2021 É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.analysis.os.linux.core.swslatency; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.osgi.util.NLS; + +/** + * Messages for Sched_Wakeup Sched_switch latency analysis. + * + * @author Abdellah Rahmani + * @since 8.1 + */ +public class Messages extends NLS { + + private static final String BUNDLE_NAME = "org.eclipse.tracecompass.analysis.os.linux.core.swslatency.messages"; //$NON-NLS-1$ + + /** Sched_Wakeup/Sched_switch TID aspect help text */ + public static @Nullable String SegmentAspectHelpText_SWSTid; + + /** Sched_Wakeup/Sched_switch priority aspect help text */ + public static @Nullable String SegmentAspectHelpText_SWSPrio; + + /** Sched_Wakeup/Sched_switch priority aspect name */ + public static @Nullable String SegmentAspectName_SWSPrio; + + static { + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } + + /** + * Helper method to expose externalized strings as non-null objects. + */ + static String getMessage(@Nullable String msg) { + if (msg == null) { + return StringUtils.EMPTY; + } + return msg; + } +}
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/swslatency/SWSLatencyAnalysis.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/swslatency/SWSLatencyAnalysis.java new file mode 100644 index 0000000..cd1c83c --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/swslatency/SWSLatencyAnalysis.java
@@ -0,0 +1,296 @@ +/******************************************************************************* + * Copyright (c) 2021 É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.analysis.os.linux.core.swslatency; + +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.analysis.os.linux.core.model.OsStrings; +import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelAnalysisEventLayout; +import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelTrace; +import org.eclipse.tracecompass.analysis.timing.core.segmentstore.AbstractSegmentStoreAnalysisEventBasedModule; +import org.eclipse.tracecompass.datastore.core.interval.IHTIntervalReader; +import org.eclipse.tracecompass.segmentstore.core.ISegment; +import org.eclipse.tracecompass.segmentstore.core.ISegmentStore; +import org.eclipse.tracecompass.segmentstore.core.SegmentComparators; +import org.eclipse.tracecompass.segmentstore.core.SegmentStoreFactory.SegmentStoreType; +import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; +import org.eclipse.tracecompass.tmf.core.segment.ISegmentAspect; + +import com.google.common.collect.ImmutableList; + +/** + * This analysis module computes the latency between the sched_wakeup event and + * the sched_switch event for each thread + * + * @author Abdellah Rahmani + * @since 8.1 + */ +public class SWSLatencyAnalysis extends AbstractSegmentStoreAnalysisEventBasedModule { + + /** + * The ID of this analysis + */ + public static final String ID = "org.eclipse.tracecompass.analysis.os.linux.core.swslatency.sws"; //$NON-NLS-1$ + + private static final int VERSION = 1; + + private static final Collection<ISegmentAspect> BASE_ASPECTS = ImmutableList.of(SWSThreadAspect.INSTANCE, SWSTidAspect.INSTANCE, SWSPriorityAspect.INSTANCE); + + /** + * Constructor + */ + public SWSLatencyAnalysis() { + // do nothing + } + + @Override + public String getId() { + return ID; + } + + @Override + public Iterable<ISegmentAspect> getSegmentAspects() { + return BASE_ASPECTS; + } + + @Override + protected int getVersion() { + return VERSION; + } + + @Override + protected @NonNull SegmentStoreType getSegmentStoreType() { + return SegmentStoreType.OnDisk; + } + + @Override + protected AbstractSegmentStoreAnalysisRequest createAnalysisRequest(ISegmentStore<ISegment> swsSegment, IProgressMonitor monitor) { + return new SWSLatencyAnalysisRequest(swsSegment, monitor); + } + + @Override + protected @NonNull IHTIntervalReader<ISegment> getSegmentReader() { + return SchedWS.READER; + } + + private class SWSLatencyAnalysisRequest extends AbstractSegmentStoreAnalysisRequest { + private final Map<Integer, SchedWS.InitialInfo> fOngoingSWS = new HashMap<>(); + private @Nullable IKernelAnalysisEventLayout fLayout; + private final IProgressMonitor fMonitor; + + public SWSLatencyAnalysisRequest(ISegmentStore<ISegment> swsSegment, IProgressMonitor monitor) { + super(swsSegment); + fMonitor = monitor; + } + + @Override + public void handleData(ITmfEvent event) { + super.handleData(event); + IKernelAnalysisEventLayout layout = fLayout; + if (layout == null) { + IKernelTrace trace = (IKernelTrace) event.getTrace(); + layout = trace.getKernelEventLayout(); + fLayout = layout; + } + String eventName = event.getName(); + + if (eventName.equals(layout.eventSchedProcessWakeup()) || + eventName.equals(layout.eventSchedProcessWakeupNew()) || + eventName.equals(layout.eventSchedProcessWaking())) { + /* This is a sched_wakeup event */ + Integer tid = event.getContent().getFieldValue(Integer.class, layout.fieldTid()); + + if (tid == null) { + // no information on this event/trace ? + return; + } + + /* Record the event's data into the intial system call info */ + long startTime = event.getTimestamp().toNanos(); + String threadName = event.getContent().getFieldValue(String.class, layout.fieldComm()); + + if (threadName == null) { + threadName = ""; //$NON-NLS-1$ + } + + SchedWS.InitialInfo newSchedWS = new SchedWS.InitialInfo(startTime, threadName.intern(), tid); + fOngoingSWS.put(tid, newSchedWS); + } else if (eventName.equals(layout.eventSchedSwitch())) { + /* This is a sched_switch event */ + Integer tid = event.getContent().getFieldValue(Integer.class, layout.fieldNextTid()); + + if (tid == null) { + return; + } + SchedWS.InitialInfo info = fOngoingSWS.remove(tid); + if (info == null) { + /* + * We have not seen the sched_wakeup event corresponding to + * this thread (lost event, or before start of trace). + */ + return; + } + long endTime = event.getTimestamp().toNanos(); + Integer priority = event.getContent().getFieldValue(Integer.class, layout.fieldNextPrio()); + SchedWS swscall = new SchedWS(info, endTime, priority == null ? -1 : priority); + getSegmentStore().add(swscall); + } + } + + @Override + public void handleCompleted() { + fOngoingSWS.clear(); + super.handleCompleted(); + } + + @Override + public void handleCancel() { + fMonitor.setCanceled(true); + super.handleCancel(); + } + } + + private static final class SWSPriorityAspect implements ISegmentAspect { + public static final ISegmentAspect INSTANCE = new SWSPriorityAspect(); + + private SWSPriorityAspect() { + // Do nothing + } + + @Override + public String getHelpText() { + return Messages.getMessage(Messages.SegmentAspectHelpText_SWSPrio); + } + + @Override + public String getName() { + return Messages.getMessage(Messages.SegmentAspectName_SWSPrio); + } + + @Override + public @Nullable Object resolve(ISegment segment) { + if (segment instanceof SchedWS) { + return ((SchedWS) segment).getPriority(); + } + return EMPTY_STRING; + } + + @Override + public @Nullable Comparator<?> getComparator() { + return (ISegment segment1, ISegment segment2) -> { + if (segment1 == null) { + return 1; + } + if (segment2 == null) { + return -1; + } + if (segment1 instanceof SchedWS && segment2 instanceof SchedWS) { + int res = Integer.compare(((SchedWS) segment1).getPriority(), ((SchedWS) segment2).getPriority()); + return (res != 0 ? res : SegmentComparators.INTERVAL_START_COMPARATOR.thenComparing(SegmentComparators.INTERVAL_END_COMPARATOR).compare(segment1, segment2)); + } + return 1; + }; + } + } + + private static final class SWSTidAspect implements ISegmentAspect { + public static final ISegmentAspect INSTANCE = new SWSTidAspect(); + + private SWSTidAspect() { + // Do nothing + } + + @Override + public String getHelpText() { + return Messages.getMessage(Messages.SegmentAspectHelpText_SWSTid); + } + + @Override + public String getName() { + return OsStrings.tid(); + } + + @Override + public @Nullable Comparator<?> getComparator() { + return (ISegment segment1, ISegment segment2) -> { + if (segment1 == null) { + return 1; + } + if (segment2 == null) { + return -1; + } + if (segment1 instanceof SchedWS && segment2 instanceof SchedWS) { + int res = Integer.compare(((SchedWS) segment1).getTid(), ((SchedWS) segment2).getTid()); + return (res != 0 ? res : SegmentComparators.INTERVAL_START_COMPARATOR.thenComparing(SegmentComparators.INTERVAL_END_COMPARATOR).compare(segment1, segment2)); + } + return 0; + }; + } + + @Override + public @Nullable Integer resolve(ISegment segment) { + if (segment instanceof SchedWS) { + return ((SchedWS) segment).getTid(); + } + return -1; + } + } + + private static final class SWSThreadAspect implements ISegmentAspect { + public static final ISegmentAspect INSTANCE = new SWSThreadAspect(); + + private SWSThreadAspect() { + // Do nothing + } + + @Override + public String getHelpText() { + return Messages.getMessage(Messages.SegmentAspectHelpText_SWSTid); + } + + @Override + public String getName() { + return OsStrings.execName(); + } + + @Override + public @Nullable Comparator<?> getComparator() { + return (ISegment segment1, ISegment segment2) -> { + if (segment1 == null) { + return 1; + } + if (segment2 == null) { + return -1; + } + if (segment1 instanceof SchedWS && segment2 instanceof SchedWS) { + int res = ((SchedWS) segment1).getName().compareToIgnoreCase(((SchedWS) segment2).getName()); + return (res != 0 ? res : SegmentComparators.INTERVAL_START_COMPARATOR.thenComparing(SegmentComparators.INTERVAL_END_COMPARATOR).compare(segment1, segment2)); + } + return 1; + }; + } + + @Override + public @Nullable String resolve(ISegment segment) { + if (segment instanceof SchedWS) { + return ((SchedWS) segment).getName(); + } + return null; + } + } +}
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/swslatency/SchedWS.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/swslatency/SchedWS.java new file mode 100644 index 0000000..9ede904 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/swslatency/SchedWS.java
@@ -0,0 +1,176 @@ +/******************************************************************************* + * Copyright (c) 2021 É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.analysis.os.linux.core.swslatency; + +import org.eclipse.tracecompass.analysis.os.linux.core.model.OsStrings; +import org.eclipse.tracecompass.datastore.core.interval.IHTIntervalReader; +import org.eclipse.tracecompass.datastore.core.serialization.ISafeByteBufferWriter; +import org.eclipse.tracecompass.datastore.core.serialization.SafeByteBufferFactory; +import org.eclipse.tracecompass.segmentstore.core.ISegment; +import org.eclipse.tracecompass.segmentstore.core.segment.interfaces.INamedSegment; +import org.eclipse.tracecompass.tmf.core.model.ICoreElementResolver; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; + +/** + * A Linux kernel sched_wakeup/ sched_switch event, represented as an + * {@link ISegment}. + * + * @author Abdellah Rahmani + * @since 8.1 + */ +public final class SchedWS implements INamedSegment, ICoreElementResolver { + + private static final long serialVersionUID = 4183872871733170072L; + + /** + * The reader for this segment class + */ + public static final IHTIntervalReader<ISegment> READER = buffer -> new SchedWS(buffer.getLong(), buffer.getLong(), buffer.getString(), buffer.getInt(), buffer.getInt()); + + /** + * The subset of information that is available from the sched wakeup/switch + * entry event. + */ + public static class InitialInfo { + + private long fStartTime; + private String fName; + private int fTid; + + /** + * @param startTime + * Start time of the sched_wakeup event + * @param name + * Name of the thread to wake-up + * @param tid + * The TID of the thread to wake-up + */ + public InitialInfo( + long startTime, + String name, + int tid) { + fStartTime = startTime; + fName = name.intern(); + fTid = tid; + } + } + + private final long fStartTime; + private final long fEndTime; + private final String fName; + private final int fTid; + private final int fPriority; + + /** + * @param info + * Initial information of sched_wakeup / sched_switch event + * @param endTime + * End time of the sched_switch event + * @param priority + * The priority of the thread to wake-up + */ + public SchedWS( + InitialInfo info, + long endTime, int priority) { + fStartTime = info.fStartTime; + fName = info.fName; + fEndTime = endTime; + fTid = info.fTid; + fPriority = priority; + } + + private SchedWS(long startTime, long endTime, String name, int tid, int priority) { + fStartTime = startTime; + fEndTime = endTime; + fName = name; + fTid = tid; + fPriority = priority; + } + + @Override + public long getStart() { + return fStartTime; + } + + @Override + public long getEnd() { + return fEndTime; + } + + /** + * Get the name of the sched_wakeup / switch_event event + * + * @return Name + */ + @Override + public String getName() { + return fName; + } + + /** + * Get the thread ID for this sched_wakeup / sched_switch event + * + * @return The ID of the thread + */ + public int getTid() { + return fTid; + } + + /** + * Get the priority of the thread to wake-up + * + * @return The priority value of the thread + */ + public int getPriority() { + return fPriority; + } + + @Override + public int getSizeOnDisk() { + return 2 * Long.BYTES + SafeByteBufferFactory.getStringSizeInBuffer(fName) + 2 * Integer.BYTES; + } + + @Override + public void writeSegment(ISafeByteBufferWriter buffer) { + buffer.putLong(fStartTime); + buffer.putLong(fEndTime); + buffer.putString(fName); + buffer.putInt(fTid); + buffer.putInt(fPriority); + } + + @Override + public int compareTo(ISegment o) { + int ret = INamedSegment.super.compareTo(o); + if (ret != 0) { + return ret; + } + return toString().compareTo(o.toString()); + } + + @Override + public String toString() { + return "Start Time = " + getStart() + //$NON-NLS-1$ + "; End Time = " + getEnd() + //$NON-NLS-1$ + "; Duration = " + getLength() + //$NON-NLS-1$ + "; Name = " + getName(); //$NON-NLS-1$ + } + + @Override + public Multimap<String, Object> getMetadata() { + Multimap<String, Object> map = HashMultimap.create(); + map.put(OsStrings.tid(), fTid); + return map; + } +}
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/swslatency/messages.properties b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/swslatency/messages.properties new file mode 100644 index 0000000..49ad0a5 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/swslatency/messages.properties
@@ -0,0 +1,16 @@ +############################################################################### +# Copyright (c) 2021 Ecole Polytechnique de Montreal +# +# 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 +############################################################################### + +SegmentAspectHelpText_SWSTid=The id of the thread to wake up + +SegmentAspectHelpText_SWSPrio=Priority of the thread to wake up + +SegmentAspectName_SWSPrio=Priority
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/swslatency/package-info.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/swslatency/package-info.java new file mode 100644 index 0000000..3dc3c54 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/swslatency/package-info.java
@@ -0,0 +1,12 @@ +/******************************************************************************* + * Copyright (c) 2021 É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.analysis.os.linux.core.swslatency;
diff --git a/releng/org.eclipse.tracecompass.integration.core.tests/src/org/eclipse/tracecompass/integration/core/tests/dataproviders/DataProviderManagerTest.java b/releng/org.eclipse.tracecompass.integration.core.tests/src/org/eclipse/tracecompass/integration/core/tests/dataproviders/DataProviderManagerTest.java index 5a7a6f7..bd03506 100644 --- a/releng/org.eclipse.tracecompass.integration.core.tests/src/org/eclipse/tracecompass/integration/core/tests/dataproviders/DataProviderManagerTest.java +++ b/releng/org.eclipse.tracecompass.integration.core.tests/src/org/eclipse/tracecompass/integration/core/tests/dataproviders/DataProviderManagerTest.java
@@ -169,6 +169,21 @@ .setProviderType(ProviderType.TIME_GRAPH) .setId("org.eclipse.tracecompass.internal.analysis.os.linux.core.threadstatus.ThreadStatusDataProvider"); EXPECTED_KERNEL_DP_DESCRIPTORS.add(builder.build()); + builder.setName("Scheduler Wakeup to Scheduler Switch Latency - Latency Statistics") + .setDescription("Show latency statistics provided by Analysis module: Scheduler Wakeup to Scheduler Switch Latency") + .setProviderType(ProviderType.DATA_TREE) + .setId("org.eclipse.tracecompass.analysis.timing.core.segmentstore.SegmentStoreStatisticsDataProvider:org.eclipse.tracecompass.analysis.os.linux.core.swslatency.sws"); + EXPECTED_KERNEL_DP_DESCRIPTORS.add(builder.build()); + builder.setName("Scheduler Wakeup to Scheduler Switch Latency - Latency Table") + .setDescription("Show latency table provided by Analysis module: Scheduler Wakeup to Scheduler Switch Latency") + .setProviderType(ProviderType.TABLE) + .setId("org.eclipse.tracecompass.analysis.timing.core.segmentstore.SegmentStoreTableDataProvider:org.eclipse.tracecompass.analysis.os.linux.core.swslatency.sws"); + EXPECTED_KERNEL_DP_DESCRIPTORS.add(builder.build()); + builder.setName("Scheduler Wakeup to Scheduler Switch Latency - Latency vs Time") + .setDescription("Show latencies provided by Analysis module: Scheduler Wakeup to Scheduler Switch Latency") + .setProviderType(ProviderType.TREE_TIME_XY) + .setId("org.eclipse.tracecompass.internal.analysis.timing.core.segmentstore.scatter.dataprovider:org.eclipse.tracecompass.analysis.os.linux.core.swslatency.sws"); + EXPECTED_KERNEL_DP_DESCRIPTORS.add(builder.build()); // UST Trace builder = new DataProviderDescriptor.Builder();