diff --git a/features/nl.esi.pps.tmsc.cpu.ui.feature/.project b/features/nl.esi.pps.tmsc.cpu.ui.feature/.project
new file mode 100644
index 0000000..3dd511b
--- /dev/null
+++ b/features/nl.esi.pps.tmsc.cpu.ui.feature/.project
@@ -0,0 +1,17 @@
+
+
+ nl.esi.pps.tmsc.cpu.ui.feature
+
+
+
+
+
+ org.eclipse.pde.FeatureBuilder
+
+
+
+
+
+ org.eclipse.pde.FeatureNature
+
+
diff --git a/features/nl.esi.pps.tmsc.cpu.ui.feature/.settings/org.eclipse.core.resources.prefs b/features/nl.esi.pps.tmsc.cpu.ui.feature/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/features/nl.esi.pps.tmsc.cpu.ui.feature/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/features/nl.esi.pps.tmsc.cpu.ui.feature/build.properties b/features/nl.esi.pps.tmsc.cpu.ui.feature/build.properties
new file mode 100644
index 0000000..09b9d21
--- /dev/null
+++ b/features/nl.esi.pps.tmsc.cpu.ui.feature/build.properties
@@ -0,0 +1,11 @@
+#
+# Copyright (c) 2018-2025 TNO and Contributors to the GitHub community
+#
+# This program and the accompanying materials are made available
+# under the terms of the MIT License which is available at
+# https://opensource.org/licenses/MIT
+#
+# SPDX-License-Identifier: MIT
+#
+
+bin.includes = feature.xml
diff --git a/features/nl.esi.pps.tmsc.cpu.ui.feature/feature.xml b/features/nl.esi.pps.tmsc.cpu.ui.feature/feature.xml
new file mode 100644
index 0000000..2a3fa08
--- /dev/null
+++ b/features/nl.esi.pps.tmsc.cpu.ui.feature/feature.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+ [Enter Feature Description here.]
+
+
+
+ [Enter Copyright Description here.]
+
+
+
+ [Enter License Description here.]
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/nl.esi.pps.tmsc.cpu.edit/.classpath b/plugins/nl.esi.pps.tmsc.cpu.edit/.classpath
new file mode 100644
index 0000000..2b8bad5
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu.edit/.classpath
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/plugins/nl.esi.pps.tmsc.cpu.edit/.project b/plugins/nl.esi.pps.tmsc.cpu.edit/.project
new file mode 100644
index 0000000..ed22f7b
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu.edit/.project
@@ -0,0 +1,34 @@
+
+
+ nl.esi.pps.tmsc.cpu.edit
+
+
+
+
+
+ org.eclipse.xtext.ui.shared.xtextBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+ org.eclipse.xtext.ui.shared.xtextNature
+
+
diff --git a/plugins/nl.esi.pps.tmsc.cpu.edit/.settings/org.eclipse.core.resources.prefs b/plugins/nl.esi.pps.tmsc.cpu.edit/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu.edit/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/plugins/nl.esi.pps.tmsc.cpu.edit/.settings/org.eclipse.jdt.core.prefs b/plugins/nl.esi.pps.tmsc.cpu.edit/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..23fa13b
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu.edit/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,9 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=21
+org.eclipse.jdt.core.compiler.compliance=21
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=21
diff --git a/plugins/nl.esi.pps.tmsc.cpu.edit/META-INF/MANIFEST.MF b/plugins/nl.esi.pps.tmsc.cpu.edit/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..1be8648
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu.edit/META-INF/MANIFEST.MF
@@ -0,0 +1,10 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: TMSC CPU Edit
+Bundle-SymbolicName: nl.esi.pps.tmsc.cpu.edit;singleton:=true
+Bundle-Version: 0.30.0.qualifier
+Require-Bundle: nl.esi.pps.tmsc.edit,
+ nl.esi.pps.tmsc.cpu
+Bundle-Vendor: ESI (TNO)
+Automatic-Module-Name: nl.esi.pps.tmsc.cpu.edit
+Bundle-RequiredExecutionEnvironment: JavaSE-21
diff --git a/plugins/nl.esi.pps.tmsc.cpu.edit/build.properties b/plugins/nl.esi.pps.tmsc.cpu.edit/build.properties
new file mode 100644
index 0000000..f1e823f
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu.edit/build.properties
@@ -0,0 +1,16 @@
+#
+# Copyright (c) 2018-2025 TNO and Contributors to the GitHub community
+#
+# This program and the accompanying materials are made available
+# under the terms of the MIT License which is available at
+# https://opensource.org/licenses/MIT
+#
+# SPDX-License-Identifier: MIT
+#
+
+source.. = src/,\
+ xtend-gen/
+output.. = target/classes/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml
diff --git a/plugins/nl.esi.pps.tmsc.cpu.edit/plugin.xml b/plugins/nl.esi.pps.tmsc.cpu.edit/plugin.xml
new file mode 100644
index 0000000..172e296
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu.edit/plugin.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/nl.esi.pps.tmsc.cpu.edit/src/nl/esi/pps/tmsc/cpu/edit/ExecutionDataAnalysisItemContentProvider.xtend b/plugins/nl.esi.pps.tmsc.cpu.edit/src/nl/esi/pps/tmsc/cpu/edit/ExecutionDataAnalysisItemContentProvider.xtend
new file mode 100644
index 0000000..c6dfdd9
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu.edit/src/nl/esi/pps/tmsc/cpu/edit/ExecutionDataAnalysisItemContentProvider.xtend
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2018-2025 TNO and Contributors to the GitHub community
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT
+ *
+ * SPDX-License-Identifier: MIT
+ */
+package nl.esi.pps.tmsc.cpu.edit
+
+import java.util.Collections
+import nl.esi.pps.tmsc.Execution
+import nl.esi.pps.tmsc.cpu.TmscCpuInfoQueries
+import nl.esi.pps.tmsc.provider.dataanalysis.IDataAnalysisItemContentProvider
+import nl.esi.pps.tmsc.util.TmscQueries
+
+import static extension nl.esi.pps.tmsc.cpu.TmscCpuInfoQueries.*
+
+class ExecutionDataAnalysisItemContentProvider implements IDataAnalysisItemContentProvider {
+ /**
+ * Data analysis of On-CPU for all {@link Execution executions} with the same
+ * {@link Execution#getFunction() function} on the same{@link Execution#getLifeline() executor.}
+ */
+ static final String CONF_ON_CPU = "On-CPU (On same executor)"
+
+ /**
+ * Data analysis of Wait-for-CPU for all {@link Execution executions} with the same
+ * {@link Execution#getFunction() function} on the same{@link Execution#getLifeline() executor.}
+ */
+ static final String CONF_WAIT_CPU = "Wait-for-CPU (On same executor)"
+
+ override getConfigurations(Object object) {
+ val Execution execution = object as Execution
+ return execution.hasCpuInfo ? newLinkedHashSet(CONF_ON_CPU, CONF_WAIT_CPU) : Collections.emptySet()
+ }
+
+ override getTitle(Object object, String configuration) {
+ val Execution execution = object as Execution
+ return switch (configuration) {
+ case CONF_ON_CPU: '''On-CPU for «execution.function.name» on «execution.lifeline.executor.name»'''
+ case CONF_WAIT_CPU: '''Wait-for-CPU for «execution.function.name» on «execution.lifeline.executor.name»'''
+ default: '''Unsupported configuration: «configuration»'''
+ }
+ }
+
+ override getSiblings(Object object, String configuration) {
+ val Execution execution = object as Execution
+ return TmscQueries::findAllWithFunctionAndLifeline(execution)
+ }
+
+ override getDuration(Object object, Object sibling, String configuration) {
+ val Execution execution = sibling as Execution
+ return switch (configuration) {
+ case CONF_ON_CPU: TmscCpuInfoQueries::getOnCpuNanos(execution, true)
+ case CONF_WAIT_CPU: TmscCpuInfoQueries::getWaitCpuNanos(execution, true)
+ default: throw new IllegalArgumentException('''Unsupported configuration: «configuration»''')
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/nl.esi.pps.tmsc.cpu.edit/xtend-gen/nl/esi/pps/tmsc/cpu/edit/ExecutionDataAnalysisItemContentProvider.java b/plugins/nl.esi.pps.tmsc.cpu.edit/xtend-gen/nl/esi/pps/tmsc/cpu/edit/ExecutionDataAnalysisItemContentProvider.java
new file mode 100644
index 0000000..9f859d1
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu.edit/xtend-gen/nl/esi/pps/tmsc/cpu/edit/ExecutionDataAnalysisItemContentProvider.java
@@ -0,0 +1,122 @@
+/**
+ * Copyright (c) 2018-2025 TNO and Contributors to the GitHub community
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT
+ *
+ * SPDX-License-Identifier: MIT
+ */
+package nl.esi.pps.tmsc.cpu.edit;
+
+import java.util.Collections;
+import java.util.Set;
+import nl.esi.pps.tmsc.Execution;
+import nl.esi.pps.tmsc.cpu.TmscCpuInfoQueries;
+import nl.esi.pps.tmsc.provider.dataanalysis.IDataAnalysisItemContentProvider;
+import nl.esi.pps.tmsc.util.TmscQueries;
+import org.eclipse.xtend2.lib.StringConcatenation;
+import org.eclipse.xtext.xbase.lib.CollectionLiterals;
+
+@SuppressWarnings("all")
+public class ExecutionDataAnalysisItemContentProvider implements IDataAnalysisItemContentProvider {
+ /**
+ * Data analysis of On-CPU for all {@link Execution executions} with the same
+ * {@link Execution#getFunction() function} on the same{@link Execution#getLifeline() executor.}
+ */
+ private static final String CONF_ON_CPU = "On-CPU (On same executor)";
+
+ /**
+ * Data analysis of Wait-for-CPU for all {@link Execution executions} with the same
+ * {@link Execution#getFunction() function} on the same{@link Execution#getLifeline() executor.}
+ */
+ private static final String CONF_WAIT_CPU = "Wait-for-CPU (On same executor)";
+
+ @Override
+ public Set getConfigurations(final Object object) {
+ final Execution execution = ((Execution) object);
+ Set _xifexpression = null;
+ boolean _hasCpuInfo = TmscCpuInfoQueries.hasCpuInfo(execution);
+ if (_hasCpuInfo) {
+ _xifexpression = CollectionLiterals.newLinkedHashSet(ExecutionDataAnalysisItemContentProvider.CONF_ON_CPU, ExecutionDataAnalysisItemContentProvider.CONF_WAIT_CPU);
+ } else {
+ _xifexpression = Collections.emptySet();
+ }
+ return _xifexpression;
+ }
+
+ @Override
+ public String getTitle(final Object object, final String configuration) {
+ final Execution execution = ((Execution) object);
+ String _switchResult = null;
+ if (configuration != null) {
+ switch (configuration) {
+ case ExecutionDataAnalysisItemContentProvider.CONF_ON_CPU:
+ StringConcatenation _builder = new StringConcatenation();
+ _builder.append("On-CPU for ");
+ String _name = execution.getFunction().getName();
+ _builder.append(_name);
+ _builder.append(" on ");
+ String _name_1 = execution.getLifeline().getExecutor().getName();
+ _builder.append(_name_1);
+ _switchResult = _builder.toString();
+ break;
+ case ExecutionDataAnalysisItemContentProvider.CONF_WAIT_CPU:
+ StringConcatenation _builder_1 = new StringConcatenation();
+ _builder_1.append("Wait-for-CPU for ");
+ String _name_2 = execution.getFunction().getName();
+ _builder_1.append(_name_2);
+ _builder_1.append(" on ");
+ String _name_3 = execution.getLifeline().getExecutor().getName();
+ _builder_1.append(_name_3);
+ _switchResult = _builder_1.toString();
+ break;
+ default:
+ StringConcatenation _builder_2 = new StringConcatenation();
+ _builder_2.append("Unsupported configuration: ");
+ _builder_2.append(configuration);
+ _switchResult = _builder_2.toString();
+ break;
+ }
+ } else {
+ StringConcatenation _builder_2 = new StringConcatenation();
+ _builder_2.append("Unsupported configuration: ");
+ _builder_2.append(configuration);
+ _switchResult = _builder_2.toString();
+ }
+ return _switchResult;
+ }
+
+ @Override
+ public Iterable> getSiblings(final Object object, final String configuration) {
+ final Execution execution = ((Execution) object);
+ return TmscQueries.findAllWithFunctionAndLifeline(execution);
+ }
+
+ @Override
+ public Long getDuration(final Object object, final Object sibling, final String configuration) {
+ final Execution execution = ((Execution) sibling);
+ long _switchResult = (long) 0;
+ if (configuration != null) {
+ switch (configuration) {
+ case ExecutionDataAnalysisItemContentProvider.CONF_ON_CPU:
+ _switchResult = TmscCpuInfoQueries.getOnCpuNanos(execution, true);
+ break;
+ case ExecutionDataAnalysisItemContentProvider.CONF_WAIT_CPU:
+ _switchResult = TmscCpuInfoQueries.getWaitCpuNanos(execution, true);
+ break;
+ default:
+ StringConcatenation _builder = new StringConcatenation();
+ _builder.append("Unsupported configuration: ");
+ _builder.append(configuration);
+ throw new IllegalArgumentException(_builder.toString());
+ }
+ } else {
+ StringConcatenation _builder = new StringConcatenation();
+ _builder.append("Unsupported configuration: ");
+ _builder.append(configuration);
+ throw new IllegalArgumentException(_builder.toString());
+ }
+ return Long.valueOf(_switchResult);
+ }
+}
diff --git a/plugins/nl.esi.pps.tmsc.cpu.editor/.classpath b/plugins/nl.esi.pps.tmsc.cpu.editor/.classpath
new file mode 100644
index 0000000..c001577
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu.editor/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/plugins/nl.esi.pps.tmsc.cpu.editor/.project b/plugins/nl.esi.pps.tmsc.cpu.editor/.project
new file mode 100644
index 0000000..4f0d8ca
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu.editor/.project
@@ -0,0 +1,28 @@
+
+
+ nl.esi.pps.tmsc.cpu.editor
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/plugins/nl.esi.pps.tmsc.cpu.editor/.settings/org.eclipse.core.resources.prefs b/plugins/nl.esi.pps.tmsc.cpu.editor/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu.editor/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/plugins/nl.esi.pps.tmsc.cpu.editor/.settings/org.eclipse.jdt.core.prefs b/plugins/nl.esi.pps.tmsc.cpu.editor/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..23fa13b
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu.editor/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,9 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=21
+org.eclipse.jdt.core.compiler.compliance=21
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=21
diff --git a/plugins/nl.esi.pps.tmsc.cpu.editor/META-INF/MANIFEST.MF b/plugins/nl.esi.pps.tmsc.cpu.editor/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..5704106
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu.editor/META-INF/MANIFEST.MF
@@ -0,0 +1,12 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: TMSC CPU Editor
+Bundle-SymbolicName: nl.esi.pps.tmsc.cpu.editor;singleton:=true
+Bundle-Vendor: ESI (TNO)
+Bundle-Version: 0.30.0.qualifier
+Require-Bundle: nl.esi.pps.tmsc.cpu,
+ nl.esi.pps.tmsc.editor,
+ nl.esi.pps,
+ org.eclipse.lsat.common.queries
+Automatic-Module-Name: nl.esi.pps.tmsc.cpu.editor
+Bundle-RequiredExecutionEnvironment: JavaSE-21
diff --git a/plugins/nl.esi.pps.tmsc.cpu.editor/build.properties b/plugins/nl.esi.pps.tmsc.cpu.editor/build.properties
new file mode 100644
index 0000000..c0ee467
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu.editor/build.properties
@@ -0,0 +1,16 @@
+#
+# Copyright (c) 2018-2025 TNO and Contributors to the GitHub community
+#
+# This program and the accompanying materials are made available
+# under the terms of the MIT License which is available at
+# https://opensource.org/licenses/MIT
+#
+# SPDX-License-Identifier: MIT
+#
+
+source.. = src/
+output.. = target/classes/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ icons/
diff --git a/plugins/nl.esi.pps.tmsc.cpu.editor/icons/cpu.png b/plugins/nl.esi.pps.tmsc.cpu.editor/icons/cpu.png
new file mode 100644
index 0000000..716ba39
Binary files /dev/null and b/plugins/nl.esi.pps.tmsc.cpu.editor/icons/cpu.png differ
diff --git a/plugins/nl.esi.pps.tmsc.cpu.editor/plugin.xml b/plugins/nl.esi.pps.tmsc.cpu.editor/plugin.xml
new file mode 100644
index 0000000..727c374
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu.editor/plugin.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/nl.esi.pps.tmsc.cpu.editor/src/nl/esi/pps/tmsc/cpu/editor/plot/CpuInfoRenderingKey.java b/plugins/nl.esi.pps.tmsc.cpu.editor/src/nl/esi/pps/tmsc/cpu/editor/plot/CpuInfoRenderingKey.java
new file mode 100644
index 0000000..9419722
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu.editor/src/nl/esi/pps/tmsc/cpu/editor/plot/CpuInfoRenderingKey.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018-2025 TNO and Contributors to the GitHub community
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT
+ *
+ * SPDX-License-Identifier: MIT
+ */
+package nl.esi.pps.tmsc.cpu.editor.plot;
+
+import java.awt.Color;
+import java.awt.Paint;
+
+import nl.esi.pps.tmsc.rendering.plot.IRenderingSeriesConfigurator;
+import nl.esi.pps.tmsc.viewers.plot.ExecutionsRenderer;
+
+public enum CpuInfoRenderingKey implements IRenderingSeriesConfigurator {
+ ON_CPU("On-CPU", new Color(0, 183, 185)),
+ WAIT_CPU("Wait-for-CPU", new Color(234, 0, 94)),
+ WAIT_OTHER("Wait-Other", new Color(174, 182, 193));
+
+ private final String literal;
+ private final Paint paint;
+
+ private CpuInfoRenderingKey(String literal, Paint paint) {
+ this.literal = literal;
+ this.paint = paint;
+ }
+
+ @Override
+ public void configureExecutionsSeries(ExecutionsRenderer executionsRenderer, int series, boolean notify) {
+ executionsRenderer.setSeriesVisibleInLegend(series, true, notify);
+ executionsRenderer.setSeriesPaint(series, paint, notify);
+ }
+
+ @Override
+ public String toString() {
+ return literal;
+ }
+}
diff --git a/plugins/nl.esi.pps.tmsc.cpu.editor/src/nl/esi/pps/tmsc/cpu/editor/plot/CpuInfoRenderingStrategy.java b/plugins/nl.esi.pps.tmsc.cpu.editor/src/nl/esi/pps/tmsc/cpu/editor/plot/CpuInfoRenderingStrategy.java
new file mode 100644
index 0000000..cb051f8
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu.editor/src/nl/esi/pps/tmsc/cpu/editor/plot/CpuInfoRenderingStrategy.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2018-2025 TNO and Contributors to the GitHub community
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT
+ *
+ * SPDX-License-Identifier: MIT
+ */
+package nl.esi.pps.tmsc.cpu.editor.plot;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.lsat.common.queries.QueryableIterable;
+import org.eclipse.trace4cps.common.jfreechart.chart.axis.Section;
+import org.eclipse.trace4cps.common.jfreechart.chart.axis.SectionAxis;
+import org.eclipse.trace4cps.common.jfreechart.data.xy.XYEdgeSeriesCollection;
+import org.eclipse.trace4cps.common.jfreechart.ui.gantt.XYGanttDataItem;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.data.Range;
+import org.jfree.data.xy.XYIntervalSeriesCollection;
+
+import nl.esi.pps.preferences.PPSPreferences;
+import nl.esi.pps.tmsc.Dependency;
+import nl.esi.pps.tmsc.Execution;
+import nl.esi.pps.tmsc.FullScopeTMSC;
+import nl.esi.pps.tmsc.Lifeline;
+import nl.esi.pps.tmsc.LifelineSegment;
+import nl.esi.pps.tmsc.cpu.TmscCpuInfoQueries;
+import nl.esi.pps.tmsc.rendering.plot.EnumRenderingStrategy;
+import nl.esi.pps.tmsc.rendering.plot.EnumRenderingStrategy.VoidRenderingKey;
+import nl.esi.pps.tmsc.viewers.plot.DependenciesRenderer;
+import nl.esi.pps.tmsc.viewers.plot.DependencyDataItem;
+import nl.esi.pps.tmsc.viewers.plot.ExecutionDataItem;
+import nl.esi.pps.tmsc.viewers.plot.ExecutionsRenderer;
+
+public class CpuInfoRenderingStrategy extends EnumRenderingStrategy {
+ private XYIntervalSeriesCollection executionsDataset;
+ private Map lifelineRanges;
+
+ public CpuInfoRenderingStrategy() {
+ super(CpuInfoRenderingKey.class, VoidRenderingKey.class);
+ }
+
+ @Override
+ public boolean isSupported(EditingDomain editingDomain) {
+ return PPSPreferences.isAdvancedFeaturesEnabled() &&
+ QueryableIterable.from(editingDomain.getResourceSet().getResources())
+ .collect(Resource::getContents)
+ .objectsOfKind(FullScopeTMSC.class)
+ .exists(TmscCpuInfoQueries::hasCpuInfo);
+ }
+
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ if (element instanceof Lifeline lifeline) {
+ return TmscCpuInfoQueries.hasCpuInfo(lifeline);
+ } else if (element instanceof Execution execution) {
+ // Results in every lifeline getting 1 height unit
+ // Although we are not rendering executions, we need the root level executions
+ // in order for the lifeline to be rendered.
+ return execution.getParent() == null;
+ } else if (element instanceof LifelineSegment segment) {
+ return segment.getStartTime() != null && segment.getEndTime() != null;
+ } else if (element instanceof Dependency) {
+ return false;
+ }
+ return super.select(viewer, parentElement, element);
+ }
+
+ @Override
+ public void preRendering(XYEdgeSeriesCollection dependenciesDataset, DependenciesRenderer dependenciesRenderer,
+ XYIntervalSeriesCollection executionsDataset, ExecutionsRenderer executionsRenderer) {
+ this.executionsDataset = executionsDataset;
+ this.lifelineRanges = new HashMap<>();
+ super.preRendering(dependenciesDataset, dependenciesRenderer, executionsDataset, executionsRenderer);
+ }
+
+ @Override
+ public Section addLifelineSection(SectionAxis axis, Lifeline lifeline, String label, double length) {
+ Section section = super.addLifelineSection(axis, lifeline, label, 10);
+ section.setGridBandNumberRange(new Range(0, 100), true);
+ this.lifelineRanges.put(lifeline, section.getRange());
+ return section;
+ }
+
+ @Override
+ public void postRendering(XYEdgeSeriesCollection dependenciesDataset, DependenciesRenderer dependenciesRenderer,
+ XYIntervalSeriesCollection executionsDataset, ExecutionsRenderer executionsRenderer) {
+ super.postRendering(dependenciesDataset, dependenciesRenderer, executionsDataset, executionsRenderer);
+ executionsRenderer.setDefaultItemLabelsVisible(false);
+ executionsRenderer.setDrawBarOutline(false);
+ this.executionsDataset = null;
+ this.lifelineRanges = null;
+ }
+
+ @Override
+ public void add(ExecutionDataItem executionDataItem, XYIntervalSeriesCollection executionsDataset,
+ ExecutionsRenderer executionsRenderer) {
+ // We are not rendering the root executions, but we need them for the life-line to be rendered.
+ // super.add(executionDataItem, executionsDataset, executionsRenderer);
+ }
+
+ @Override
+ public void add(DependencyDataItem dataItem, XYEdgeSeriesCollection dataSet, DependenciesRenderer renderer) {
+ Dependency dependency = dataItem.getBackReference();
+ if (dependency instanceof LifelineSegment segment) {
+ Range cpuSectionRange = lifelineRanges.get(segment.getLifeline());
+ if (cpuSectionRange == null) {
+ return;
+ }
+
+ BigDecimal cpuOffset = BigDecimal.ZERO;
+ long onCpuNanos = TmscCpuInfoQueries.getOnCpuNanos(segment);
+ if (onCpuNanos > 0) {
+ BigDecimal cpuOccupation = BigDecimal.valueOf(onCpuNanos)
+ .divide(BigDecimal.valueOf(segment.getDuration()), 10, RoundingMode.HALF_UP);
+ XYGanttDataItem item = new XYGanttDataItem<>(cpuSectionRange, cpuOccupation,
+ cpuOffset, dataItem.getX0(), dataItem.getX1(), PlotOrientation.VERTICAL, segment);
+ this.executionsDataset.getSeries(getSeries(CpuInfoRenderingKey.ON_CPU)).add(item, true);
+ cpuOffset = cpuOffset.add(cpuOccupation);
+ }
+ long waitCpuNanos = TmscCpuInfoQueries.getWaitCpuNanos(segment);
+ if (waitCpuNanos > 0) {
+ BigDecimal cpuOccupation = BigDecimal.valueOf(waitCpuNanos)
+ .divide(BigDecimal.valueOf(segment.getDuration()), 10, RoundingMode.HALF_UP);
+ XYGanttDataItem item = new XYGanttDataItem<>(cpuSectionRange, cpuOccupation,
+ cpuOffset, dataItem.getX0(), dataItem.getX1(), PlotOrientation.VERTICAL, segment);
+ this.executionsDataset.getSeries(getSeries(CpuInfoRenderingKey.WAIT_CPU)).add(item, true);
+ cpuOffset = cpuOffset.add(cpuOccupation);
+ }
+ long waitOtherNanos = TmscCpuInfoQueries.getWaitOtherNanos(segment);
+ if (waitOtherNanos > 0) {
+ BigDecimal cpuOccupation = BigDecimal.valueOf(waitOtherNanos)
+ .divide(BigDecimal.valueOf(segment.getDuration()), 10, RoundingMode.HALF_UP);
+ XYGanttDataItem item = new XYGanttDataItem<>(cpuSectionRange, cpuOccupation,
+ cpuOffset, dataItem.getX0(), dataItem.getX1(), PlotOrientation.VERTICAL, segment);
+ this.executionsDataset.getSeries(getSeries(CpuInfoRenderingKey.WAIT_OTHER)).add(item, true);
+ cpuOffset = cpuOffset.add(cpuOccupation);
+ }
+ }
+ }
+
+ @Override
+ protected CpuInfoRenderingKey getRenderingKey(Execution execution) {
+ // Not used, not showing executions
+ return null;
+ }
+
+ @Override
+ protected VoidRenderingKey getRenderingKey(Dependency dependency) {
+ // Not used, not showing dependencies
+ return null;
+ }
+}
diff --git a/plugins/nl.esi.pps.tmsc.cpu/.classpath b/plugins/nl.esi.pps.tmsc.cpu/.classpath
new file mode 100644
index 0000000..2b8bad5
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu/.classpath
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/plugins/nl.esi.pps.tmsc.cpu/.project b/plugins/nl.esi.pps.tmsc.cpu/.project
new file mode 100644
index 0000000..5ab6d8d
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu/.project
@@ -0,0 +1,34 @@
+
+
+ nl.esi.pps.tmsc.cpu
+
+
+
+
+
+ org.eclipse.xtext.ui.shared.xtextBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+ org.eclipse.xtext.ui.shared.xtextNature
+
+
diff --git a/plugins/nl.esi.pps.tmsc.cpu/.settings/org.eclipse.core.resources.prefs b/plugins/nl.esi.pps.tmsc.cpu/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/plugins/nl.esi.pps.tmsc.cpu/.settings/org.eclipse.jdt.core.prefs b/plugins/nl.esi.pps.tmsc.cpu/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..23fa13b
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,9 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=21
+org.eclipse.jdt.core.compiler.compliance=21
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=21
diff --git a/plugins/nl.esi.pps.tmsc.cpu/META-INF/MANIFEST.MF b/plugins/nl.esi.pps.tmsc.cpu/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..e4c9f83
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu/META-INF/MANIFEST.MF
@@ -0,0 +1,11 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: TMSC CPU
+Bundle-SymbolicName: nl.esi.pps.tmsc.cpu
+Bundle-Version: 0.30.0.qualifier
+Export-Package: nl.esi.pps.tmsc.cpu
+Require-Bundle: nl.esi.pps.tmsc;visibility:=reexport,
+ org.eclipse.lsat.common.xtend
+Bundle-Vendor: ESI (TNO)
+Automatic-Module-Name: nl.esi.pps.tmsc.cpu
+Bundle-RequiredExecutionEnvironment: JavaSE-21
diff --git a/plugins/nl.esi.pps.tmsc.cpu/build.properties b/plugins/nl.esi.pps.tmsc.cpu/build.properties
new file mode 100644
index 0000000..3bfbd1f
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu/build.properties
@@ -0,0 +1,15 @@
+#
+# Copyright (c) 2018-2025 TNO and Contributors to the GitHub community
+#
+# This program and the accompanying materials are made available
+# under the terms of the MIT License which is available at
+# https://opensource.org/licenses/MIT
+#
+# SPDX-License-Identifier: MIT
+#
+
+source.. = src/,\
+ xtend-gen/
+output.. = target/classes/
+bin.includes = META-INF/,\
+ .
diff --git a/plugins/nl.esi.pps.tmsc.cpu/src/nl/esi/pps/tmsc/cpu/TmscCpuInfoProjection.xtend b/plugins/nl.esi.pps.tmsc.cpu/src/nl/esi/pps/tmsc/cpu/TmscCpuInfoProjection.xtend
new file mode 100644
index 0000000..784c1c2
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu/src/nl/esi/pps/tmsc/cpu/TmscCpuInfoProjection.xtend
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2018-2025 TNO and Contributors to the GitHub community
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT
+ *
+ * SPDX-License-Identifier: MIT
+ */
+package nl.esi.pps.tmsc.cpu
+
+import java.util.Map
+import nl.esi.pps.tmsc.Dependency
+import nl.esi.pps.tmsc.Event
+import nl.esi.pps.tmsc.LifelineSegment
+import nl.esi.pps.tmsc.util.DependencyFeatureProjection
+import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
+
+import static extension nl.esi.pps.tmsc.cpu.TmscCpuInfoQueries.*
+
+class TmscCpuInfoProjection {
+ public static val ON_CPU_PROJECTION = new LifelineSegmentCpuInfoProjection([onCpuNanos],[$0.onCpuNanos = $1])
+ public static val WAIT_CPU_PROJECTION = new LifelineSegmentCpuInfoProjection([waitCpuNanos],[$0.waitCpuNanos = $1])
+ public static val WAIT_OTHER_PROJECTION = new LifelineSegmentCpuInfoProjection([waitOtherNanos],[$0.waitOtherNanos = $1])
+
+ private new() {
+ // Empty for utility classes
+ }
+
+ @FinalFieldsConstructor
+ private static class LifelineSegmentCpuInfoProjection implements DependencyFeatureProjection {
+ val (LifelineSegment)=>long getter
+ val (LifelineSegment, long)=>void setter
+
+ override getInitialValue(Event projectionSource) {
+ return 0L
+ }
+
+ override calculateProjectedValue(Event projectionSource, Map projectionValues) {
+ val validProjectionValues = projectionValues.entrySet.filter[key instanceof LifelineSegment].reject[key.projection || value === null]
+ return switch (it: validProjectionValues) {
+ case isEmpty: null
+ case size == 1: head.value + getter.apply(head.key as LifelineSegment)
+ default: throw new IllegalStateException('Programming error, please contact PPS support!')
+ }
+ }
+
+ override apply(Dependency projection, Long projectedValue) {
+ if (projection instanceof LifelineSegment) {
+ if (getter.apply(projection) > 0 && getter.apply(projection) != projectedValue) {
+ // Expected the same onCpuNanos to be calculated if projection is reused
+ throw new IllegalArgumentException('Programming error, please contact PPS support!')
+ }
+ setter.apply(projection, projectedValue ?: 0L)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/nl.esi.pps.tmsc.cpu/src/nl/esi/pps/tmsc/cpu/TmscCpuInfoQueries.xtend b/plugins/nl.esi.pps.tmsc.cpu/src/nl/esi/pps/tmsc/cpu/TmscCpuInfoQueries.xtend
new file mode 100644
index 0000000..8d42946
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu/src/nl/esi/pps/tmsc/cpu/TmscCpuInfoQueries.xtend
@@ -0,0 +1,81 @@
+/**
+ * Copyright (c) 2018-2025 TNO and Contributors to the GitHub community
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT
+ *
+ * SPDX-License-Identifier: MIT
+ */
+package nl.esi.pps.tmsc.cpu
+
+import nl.esi.emf.properties.xtend.PersistedProperty
+import nl.esi.pps.tmsc.Execution
+import nl.esi.pps.tmsc.FullScopeTMSC
+import nl.esi.pps.tmsc.Lifeline
+import nl.esi.pps.tmsc.LifelineSegment
+
+import static extension nl.esi.pps.tmsc.util.TmscQueries.*
+
+class TmscCpuInfoQueries {
+ @PersistedProperty(LifelineSegment)
+ public static val long onCpuNanos = 0L
+
+ @PersistedProperty(LifelineSegment)
+ public static val long waitCpuNanos = 0L
+
+ @PersistedProperty(LifelineSegment)
+ public static val long waitOtherNanos = 0L
+
+ static def long getOnCpuNanos(Execution execution, boolean includeChildren) {
+ return execution.callStackLifelineSegments.fold(0L)[sum, segment |
+ return (includeChildren || segment.activeExecution === execution) ? sum + segment.onCpuNanos : sum
+ ]
+ }
+
+ static def long getWaitCpuNanos(Execution execution, boolean includeChildren) {
+ return execution.callStackLifelineSegments.fold(0L)[sum, segment |
+ return (includeChildren || segment.activeExecution === execution) ? sum + segment.waitCpuNanos : sum
+ ]
+ }
+
+ static def long getWaitOtherNanos(Execution execution, boolean includeChildren) {
+ return execution.callStackLifelineSegments.fold(0L)[sum, segment |
+ return (includeChildren || segment.activeExecution === execution) ? sum + segment.waitOtherNanos : sum
+ ]
+ }
+
+ static def boolean hasCpuInfo(FullScopeTMSC tmsc) {
+ return tmsc.dependencies.filter(LifelineSegment).exists[hasCpuInfo]
+ }
+
+ static def boolean hasCpuInfo(Lifeline lifeline) {
+ return lifeline.segments.exists[hasCpuInfo]
+ }
+
+ static def boolean hasCpuInfo(Execution execution) {
+ return execution.callStackLifelineSegments.exists[hasCpuInfo]
+ }
+
+ static def boolean hasCpuInfo(LifelineSegment segement) {
+ return segement.onCpuNanos > 0 || segement.waitCpuNanos > 0 || segement.waitOtherNanos > 0
+ }
+
+ static def void clearCpuInfo(FullScopeTMSC tmsc) {
+ tmsc.dependencies.filter(LifelineSegment).forEach[clearCpuInfo]
+ }
+
+ static def void clearCpuInfo(Lifeline lifeline) {
+ lifeline.segments.forEach[clearCpuInfo]
+ }
+
+ static def void clearCpuInfo(Execution execution) {
+ execution.callStackLifelineSegments.forEach[clearCpuInfo]
+ }
+
+ static def void clearCpuInfo(LifelineSegment segement) {
+ segement.onCpuNanos = 0L
+ segement.waitCpuNanos = 0L
+ segement.waitOtherNanos = 0L
+ }
+}
\ No newline at end of file
diff --git a/plugins/nl.esi.pps.tmsc.cpu/xtend-gen/nl/esi/pps/tmsc/cpu/TmscCpuInfoProjection.java b/plugins/nl.esi.pps.tmsc.cpu/xtend-gen/nl/esi/pps/tmsc/cpu/TmscCpuInfoProjection.java
new file mode 100644
index 0000000..1d2184b
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu/xtend-gen/nl/esi/pps/tmsc/cpu/TmscCpuInfoProjection.java
@@ -0,0 +1,114 @@
+/**
+ * Copyright (c) 2018-2025 TNO and Contributors to the GitHub community
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT
+ *
+ * SPDX-License-Identifier: MIT
+ */
+package nl.esi.pps.tmsc.cpu;
+
+import java.util.Map;
+import java.util.Objects;
+import nl.esi.pps.tmsc.Dependency;
+import nl.esi.pps.tmsc.Event;
+import nl.esi.pps.tmsc.LifelineSegment;
+import nl.esi.pps.tmsc.util.DependencyFeatureProjection;
+import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor;
+import org.eclipse.xtext.xbase.lib.Functions.Function1;
+import org.eclipse.xtext.xbase.lib.IterableExtensions;
+import org.eclipse.xtext.xbase.lib.Procedures.Procedure2;
+
+@SuppressWarnings("all")
+public class TmscCpuInfoProjection {
+ @FinalFieldsConstructor
+ private static class LifelineSegmentCpuInfoProjection implements DependencyFeatureProjection {
+ private final Function1 super LifelineSegment, ? extends Long> getter;
+
+ private final Procedure2 super LifelineSegment, ? super Long> setter;
+
+ @Override
+ public Long getInitialValue(final Event projectionSource) {
+ return Long.valueOf(0L);
+ }
+
+ @Override
+ public Long calculateProjectedValue(final Event projectionSource, final Map projectionValues) {
+ final Function1, Boolean> _function = (Map.Entry it) -> {
+ Dependency _key = it.getKey();
+ return Boolean.valueOf((_key instanceof LifelineSegment));
+ };
+ final Function1, Boolean> _function_1 = (Map.Entry it) -> {
+ return Boolean.valueOf((it.getKey().isProjection() || (it.getValue() == null)));
+ };
+ final Iterable> validProjectionValues = IterableExtensions.>reject(IterableExtensions.>filter(projectionValues.entrySet(), _function), _function_1);
+ Long _switchResult = null;
+ final Iterable> it = validProjectionValues;
+ boolean _matched = false;
+ boolean _isEmpty = IterableExtensions.isEmpty(it);
+ if (_isEmpty) {
+ _matched=true;
+ _switchResult = null;
+ }
+ if (!_matched) {
+ int _size = IterableExtensions.size(it);
+ boolean _equals = (_size == 1);
+ if (_equals) {
+ _matched=true;
+ Long _value = IterableExtensions.>head(it).getValue();
+ Dependency _key = IterableExtensions.>head(it).getKey();
+ Long _apply = this.getter.apply(((LifelineSegment) _key));
+ _switchResult = Long.valueOf(((_value).longValue() + (_apply).longValue()));
+ }
+ }
+ if (!_matched) {
+ throw new IllegalStateException("Programming error, please contact PPS support!");
+ }
+ return _switchResult;
+ }
+
+ @Override
+ public void apply(final Dependency projection, final Long projectedValue) {
+ if ((projection instanceof LifelineSegment)) {
+ if ((((this.getter.apply(((LifelineSegment)projection))).longValue() > 0) && (!Objects.equals(this.getter.apply(((LifelineSegment)projection)), projectedValue)))) {
+ throw new IllegalArgumentException("Programming error, please contact PPS support!");
+ }
+ Long _elvis = null;
+ if (projectedValue != null) {
+ _elvis = projectedValue;
+ } else {
+ _elvis = Long.valueOf(0L);
+ }
+ this.setter.apply(((LifelineSegment)projection), _elvis);
+ }
+ }
+
+ public LifelineSegmentCpuInfoProjection(final Function1 super LifelineSegment, ? extends Long> getter, final Procedure2 super LifelineSegment, ? super Long> setter) {
+ super();
+ this.getter = getter;
+ this.setter = setter;
+ }
+ }
+
+ public static final TmscCpuInfoProjection.LifelineSegmentCpuInfoProjection ON_CPU_PROJECTION = new TmscCpuInfoProjection.LifelineSegmentCpuInfoProjection(((Function1) (LifelineSegment it) -> {
+ return Long.valueOf(TmscCpuInfoQueries.getOnCpuNanos(it));
+ }), ((Procedure2) (LifelineSegment $0, Long $1) -> {
+ TmscCpuInfoQueries.setOnCpuNanos($0, ($1).longValue());
+ }));
+
+ public static final TmscCpuInfoProjection.LifelineSegmentCpuInfoProjection WAIT_CPU_PROJECTION = new TmscCpuInfoProjection.LifelineSegmentCpuInfoProjection(((Function1) (LifelineSegment it) -> {
+ return Long.valueOf(TmscCpuInfoQueries.getWaitCpuNanos(it));
+ }), ((Procedure2) (LifelineSegment $0, Long $1) -> {
+ TmscCpuInfoQueries.setWaitCpuNanos($0, ($1).longValue());
+ }));
+
+ public static final TmscCpuInfoProjection.LifelineSegmentCpuInfoProjection WAIT_OTHER_PROJECTION = new TmscCpuInfoProjection.LifelineSegmentCpuInfoProjection(((Function1) (LifelineSegment it) -> {
+ return Long.valueOf(TmscCpuInfoQueries.getWaitOtherNanos(it));
+ }), ((Procedure2) (LifelineSegment $0, Long $1) -> {
+ TmscCpuInfoQueries.setWaitOtherNanos($0, ($1).longValue());
+ }));
+
+ private TmscCpuInfoProjection() {
+ }
+}
diff --git a/plugins/nl.esi.pps.tmsc.cpu/xtend-gen/nl/esi/pps/tmsc/cpu/TmscCpuInfoQueries.java b/plugins/nl.esi.pps.tmsc.cpu/xtend-gen/nl/esi/pps/tmsc/cpu/TmscCpuInfoQueries.java
new file mode 100644
index 0000000..535554e
--- /dev/null
+++ b/plugins/nl.esi.pps.tmsc.cpu/xtend-gen/nl/esi/pps/tmsc/cpu/TmscCpuInfoQueries.java
@@ -0,0 +1,187 @@
+/**
+ * Copyright (c) 2018-2025 TNO and Contributors to the GitHub community
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the MIT License which is available at
+ * https://opensource.org/licenses/MIT
+ *
+ * SPDX-License-Identifier: MIT
+ */
+package nl.esi.pps.tmsc.cpu;
+
+import com.google.common.collect.Iterables;
+import java.util.function.Consumer;
+import nl.esi.pps.tmsc.Execution;
+import nl.esi.pps.tmsc.FullScopeTMSC;
+import nl.esi.pps.tmsc.Lifeline;
+import nl.esi.pps.tmsc.LifelineSegment;
+import nl.esi.pps.tmsc.util.TmscQueries;
+import org.eclipse.xtext.xbase.lib.Functions.Function1;
+import org.eclipse.xtext.xbase.lib.Functions.Function2;
+import org.eclipse.xtext.xbase.lib.IterableExtensions;
+
+@SuppressWarnings("all")
+public class TmscCpuInfoQueries {
+ public static long getOnCpuNanos(final Execution execution, final boolean includeChildren) {
+ final Function2 _function = (Long sum, LifelineSegment segment) -> {
+ Long _xifexpression = null;
+ if ((includeChildren || (segment.getActiveExecution() == execution))) {
+ long _onCpuNanos = TmscCpuInfoQueries.getOnCpuNanos(segment);
+ _xifexpression = Long.valueOf(((sum).longValue() + _onCpuNanos));
+ } else {
+ _xifexpression = sum;
+ }
+ return _xifexpression;
+ };
+ return (long) IterableExtensions.fold(TmscQueries.getCallStackLifelineSegments(execution), Long.valueOf(0L), _function);
+ }
+
+ public static long getWaitCpuNanos(final Execution execution, final boolean includeChildren) {
+ final Function2 _function = (Long sum, LifelineSegment segment) -> {
+ Long _xifexpression = null;
+ if ((includeChildren || (segment.getActiveExecution() == execution))) {
+ long _waitCpuNanos = TmscCpuInfoQueries.getWaitCpuNanos(segment);
+ _xifexpression = Long.valueOf(((sum).longValue() + _waitCpuNanos));
+ } else {
+ _xifexpression = sum;
+ }
+ return _xifexpression;
+ };
+ return (long) IterableExtensions.fold(TmscQueries.getCallStackLifelineSegments(execution), Long.valueOf(0L), _function);
+ }
+
+ public static long getWaitOtherNanos(final Execution execution, final boolean includeChildren) {
+ final Function2 _function = (Long sum, LifelineSegment segment) -> {
+ Long _xifexpression = null;
+ if ((includeChildren || (segment.getActiveExecution() == execution))) {
+ long _waitOtherNanos = TmscCpuInfoQueries.getWaitOtherNanos(segment);
+ _xifexpression = Long.valueOf(((sum).longValue() + _waitOtherNanos));
+ } else {
+ _xifexpression = sum;
+ }
+ return _xifexpression;
+ };
+ return (long) IterableExtensions.fold(TmscQueries.getCallStackLifelineSegments(execution), Long.valueOf(0L), _function);
+ }
+
+ public static boolean hasCpuInfo(final FullScopeTMSC tmsc) {
+ final Function1 _function = (LifelineSegment it) -> {
+ return Boolean.valueOf(TmscCpuInfoQueries.hasCpuInfo(it));
+ };
+ return IterableExtensions.exists(Iterables.filter(tmsc.getDependencies(), LifelineSegment.class), _function);
+ }
+
+ public static boolean hasCpuInfo(final Lifeline lifeline) {
+ final Function1 _function = (LifelineSegment it) -> {
+ return Boolean.valueOf(TmscCpuInfoQueries.hasCpuInfo(it));
+ };
+ return IterableExtensions.exists(lifeline.getSegments(), _function);
+ }
+
+ public static boolean hasCpuInfo(final Execution execution) {
+ final Function1 _function = (LifelineSegment it) -> {
+ return Boolean.valueOf(TmscCpuInfoQueries.hasCpuInfo(it));
+ };
+ return IterableExtensions.exists(TmscQueries.getCallStackLifelineSegments(execution), _function);
+ }
+
+ public static boolean hasCpuInfo(final LifelineSegment segement) {
+ return (((TmscCpuInfoQueries.getOnCpuNanos(segement) > 0) || (TmscCpuInfoQueries.getWaitCpuNanos(segement) > 0)) || (TmscCpuInfoQueries.getWaitOtherNanos(segement) > 0));
+ }
+
+ public static void clearCpuInfo(final FullScopeTMSC tmsc) {
+ final Consumer _function = (LifelineSegment it) -> {
+ TmscCpuInfoQueries.clearCpuInfo(it);
+ };
+ Iterables.filter(tmsc.getDependencies(), LifelineSegment.class).forEach(_function);
+ }
+
+ public static void clearCpuInfo(final Lifeline lifeline) {
+ final Consumer _function = (LifelineSegment it) -> {
+ TmscCpuInfoQueries.clearCpuInfo(it);
+ };
+ lifeline.getSegments().forEach(_function);
+ }
+
+ public static void clearCpuInfo(final Execution execution) {
+ final Consumer _function = (LifelineSegment it) -> {
+ TmscCpuInfoQueries.clearCpuInfo(it);
+ };
+ TmscQueries.getCallStackLifelineSegments(execution).forEach(_function);
+ }
+
+ public static void clearCpuInfo(final LifelineSegment segement) {
+ TmscCpuInfoQueries.setOnCpuNanos(segement, 0L);
+ TmscCpuInfoQueries.setWaitCpuNanos(segement, 0L);
+ TmscCpuInfoQueries.setWaitOtherNanos(segement, 0L);
+ }
+
+ /**
+ * Default value for persisted {@code onCpuNanos} property on LifelineSegment
+ */
+ private static final long _DEFAULT_LIFELINESEGMENT_ONCPUNANOS = 0L;
+
+ public static long getOnCpuNanos(final LifelineSegment container) {
+ final String key = "onCpuNanos";
+ final Object value = container.getProperties().get(key);
+ if (value == null) {
+ return _DEFAULT_LIFELINESEGMENT_ONCPUNANOS;
+ }
+ return (long) value;
+ }
+
+ public static void setOnCpuNanos(final LifelineSegment container, final long value) {
+ final String key = "onCpuNanos";
+ if (value == _DEFAULT_LIFELINESEGMENT_ONCPUNANOS) {
+ container.getProperties().remove(key);
+ } else {
+ container.getProperties().put(key, value);
+ }
+ }
+
+ /**
+ * Default value for persisted {@code waitCpuNanos} property on LifelineSegment
+ */
+ private static final long _DEFAULT_LIFELINESEGMENT_WAITCPUNANOS = 0L;
+
+ public static long getWaitCpuNanos(final LifelineSegment container) {
+ final String key = "waitCpuNanos";
+ final Object value = container.getProperties().get(key);
+ if (value == null) {
+ return _DEFAULT_LIFELINESEGMENT_WAITCPUNANOS;
+ }
+ return (long) value;
+ }
+
+ public static void setWaitCpuNanos(final LifelineSegment container, final long value) {
+ final String key = "waitCpuNanos";
+ if (value == _DEFAULT_LIFELINESEGMENT_WAITCPUNANOS) {
+ container.getProperties().remove(key);
+ } else {
+ container.getProperties().put(key, value);
+ }
+ }
+
+ /**
+ * Default value for persisted {@code waitOtherNanos} property on LifelineSegment
+ */
+ private static final long _DEFAULT_LIFELINESEGMENT_WAITOTHERNANOS = 0L;
+
+ public static long getWaitOtherNanos(final LifelineSegment container) {
+ final String key = "waitOtherNanos";
+ final Object value = container.getProperties().get(key);
+ if (value == null) {
+ return _DEFAULT_LIFELINESEGMENT_WAITOTHERNANOS;
+ }
+ return (long) value;
+ }
+
+ public static void setWaitOtherNanos(final LifelineSegment container, final long value) {
+ final String key = "waitOtherNanos";
+ if (value == _DEFAULT_LIFELINESEGMENT_WAITOTHERNANOS) {
+ container.getProperties().remove(key);
+ } else {
+ container.getProperties().put(key, value);
+ }
+ }
+}
diff --git a/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/rendering/plot/AbstractRenderingStrategy.java b/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/rendering/plot/AbstractRenderingStrategy.java
index d7ee711..ee0e902 100644
--- a/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/rendering/plot/AbstractRenderingStrategy.java
+++ b/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/rendering/plot/AbstractRenderingStrategy.java
@@ -75,6 +75,7 @@ public void preRendering(XYEdgeSeriesCollection dependenciesDataset, Dependencie
}
protected void resetRenderer(DependenciesRenderer dependenciesRenderer) {
+ dependenciesRenderer.setDefaultItemLabelsVisible(false);
dependenciesRenderer.setComputeItemLabelContrastColor(true);
dependenciesRenderer.setDefaultSeriesVisibleInLegend(false);
@@ -97,6 +98,7 @@ protected void resetRenderer(DependenciesRenderer dependenciesRenderer) {
}
protected void resetRenderer(ExecutionsRenderer executionsRenderer) {
+ executionsRenderer.setDefaultItemLabelsVisible(true);
executionsRenderer.setComputeItemLabelContrastColor(true);
executionsRenderer.setDefaultSeriesVisibleInLegend(false);
@@ -108,6 +110,7 @@ protected void resetRenderer(ExecutionsRenderer executionsRenderer) {
executionsRenderer.clearSeriesOutlinePaints(false);
executionsRenderer.setDefaultPaintSupplier(RenderingPaint.CONTROL, false);
+ executionsRenderer.setDrawBarOutline(true);
executionsRenderer.setAutoPopulateSeriesOutlineStroke(false);
executionsRenderer.setDefaultOutlineStroke(RenderingStroke.FINE_SOLID.getStroke());
}
diff --git a/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/rendering/plot/IRenderingStrategy.java b/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/rendering/plot/IRenderingStrategy.java
index 81979a4..5b17589 100644
--- a/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/rendering/plot/IRenderingStrategy.java
+++ b/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/rendering/plot/IRenderingStrategy.java
@@ -12,6 +12,7 @@
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.trace4cps.common.jfreechart.chart.axis.Section;
+import org.eclipse.trace4cps.common.jfreechart.chart.axis.SectionAxis;
import org.eclipse.trace4cps.common.jfreechart.data.xy.XYEdgeSeriesCollection;
import org.jfree.data.xy.XYIntervalSeriesCollection;
@@ -54,8 +55,8 @@ default boolean isSupported(EditingDomain editingDomain) {
default boolean select(Viewer viewer, Object parentElement, Object element) {
if (element instanceof LifelineSegment) {
return false;
- } else if (element instanceof Dependency) {
- return !((Dependency) element).isProjection();
+ } else if (element instanceof Dependency dependency) {
+ return !dependency.isProjection();
} else {
return true;
}
@@ -63,6 +64,12 @@ default boolean select(Viewer viewer, Object parentElement, Object element) {
void preRendering(XYEdgeSeriesCollection dependenciesDataset, DependenciesRenderer dependenciesRenderer,
XYIntervalSeriesCollection executionsDataset, ExecutionsRenderer executionsRenderer);
+
+ default Section addLifelineSection(SectionAxis axis, Lifeline lifeline, String label, double length) {
+ final Section lifelineSection = axis.nextSection(label, length);
+ configureLifelineSection(lifeline, lifelineSection);
+ return lifelineSection;
+ }
void configureLifelineSection(Lifeline lifeline, Section section);
diff --git a/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/viewers/TmscPlotViewer.java b/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/viewers/TmscPlotViewer.java
index e281c68..cb3cab7 100644
--- a/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/viewers/TmscPlotViewer.java
+++ b/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/viewers/TmscPlotViewer.java
@@ -449,13 +449,13 @@ protected void refreshChart(Object element) {
boolean lifelineRendered = !lifeLineExecutions.isEmpty()
|| (lifeline.getExecutions().isEmpty() && !lifeline.getEvents().isEmpty());
if (lifelineRendered) {
- Section lifelineSection = rangeAxis.nextSection(getLabelProvider().getText(lifeline),
- getLifelineLength(lifeLineExecutions));
+ Section lifelineSection = renderingStrategy.addLifelineSection(rangeAxis, lifeline,
+ getLabelProvider().getText(lifeline), getLifelineLength(lifeLineExecutions));
lifelineRanges.put(lifeline, lifelineSection.getRange());
- renderingStrategy.configureLifelineSection(lifeline, lifelineSection);
for (Execution execution : lifeLineExecutions) {
- Range executionRange = getExecutionRange(execution, lifelineSection.getRange());
+ Range executionRange = getCallStackLevelRange(getCallStackLevel(execution),
+ lifelineSection.getRange());
Double executionStart = getEventX(execution.getEntry());
Double executionEnd = getEventX(execution.getExit());
renderingStrategy.add(
@@ -639,18 +639,24 @@ private Double getEventY(Event event) {
if (event == null) {
return null;
}
- Range eventYRange = lifelineRanges.get(event.getLifeline());
- if (eventYRange != null && event.getExecution() != null) {
- eventYRange = getExecutionRange(event.getExecution(), eventYRange);
+ Range lifelineRange = lifelineRanges.get(event.getLifeline());
+ if (lifelineRange == null) {
+ return null;
+ }
+ Execution execution = event.getExecution();
+ if (execution == null) {
+ return lifelineRange.getCentralValue();
}
- return eventYRange == null ? null : eventYRange.getCentralValue();
+ int callStackLevel =
+ Math.max(filter(from(execution).climbTree(true, Execution::getParent).toArray()).length - 1, 0);
+ return getCallStackLevelRange(callStackLevel, lifelineRange).getCentralValue();
}
/**
* The component range will be equal to the stack size of the component + 0.1
* for padding.
*
- * @see #getExecutionRange(Execution, Range)
+ * @see #getCallStackLevelRange(Execution, Range)
*/
private double getLifelineLength(Iterable componentExecutions) {
QueryableIterable callStackLevels = from(componentExecutions).xcollectOne(this::getCallStackLevel);
@@ -662,15 +668,18 @@ private double getLifelineLength(Iterable componentExecutions) {
/**
* @see #getLifelineLength(Iterable)
*/
- private Range getExecutionRange(Execution execution, Range componentRange) {
- Integer callStackLevel = getCallStackLevel(execution);
- if (callStackLevel == null) {
- // Execution is not visible
+ private Range getCallStackLevelRange(Integer callStackLevel, Range componentRange) {
+ if (callStackLevel == null || componentRange == null) {
return null;
}
// Add 0.1 for resource padding
- double executionLower = componentRange.getLowerBound() + callStackLevel + 0.1;
- return new Range(executionLower, executionLower + 1);
+ double callStackLower = componentRange.getLowerBound() + callStackLevel + 0.1;
+ Range callStackRange = new Range(callStackLower, callStackLower + 1);
+ if (!componentRange.contains(callStackRange)) {
+ throw new IllegalArgumentException(
+ "Call-stack " + callStackRange + " doesn't fit in component " + componentRange);
+ }
+ return new Range(callStackLower, callStackLower + 1);
}
private Integer getCallStackLevel(Execution execution) {
diff --git a/products/nl.esi.pps.product/category.xml b/products/nl.esi.pps.product/category.xml
index 13d6db2..fbd0d29 100644
--- a/products/nl.esi.pps.product/category.xml
+++ b/products/nl.esi.pps.product/category.xml
@@ -41,6 +41,12 @@
+
+
+
+
+
+
diff --git a/releng/nl.esi.pps.target/nl.esi.pps.target.target b/releng/nl.esi.pps.target/nl.esi.pps.target.target
index 4b52c5b..e4a80b3 100644
--- a/releng/nl.esi.pps.target/nl.esi.pps.target.target
+++ b/releng/nl.esi.pps.target/nl.esi.pps.target.target
@@ -1,6 +1,6 @@
-
+
@@ -133,12 +133,12 @@
+
-
@@ -164,7 +164,7 @@
-
+