From: Najib Arbaoui Date: Thu, 31 Mar 2016 22:56:19 +0000 (-0400) Subject: analysis.os: New kernel memory usage view with Unit tests X-Git-Url: http://git.efficios.com/?a=commitdiff_plain;h=aa19e48b07dfaf40852550ac20f01fcd5346f43b;p=deliverable%2Ftracecompass.git analysis.os: New kernel memory usage view with Unit tests This view keeps track of page allocation/deallocation events in the kernel. It consists of a plot and a menu for thread selection. For a given time range, the menu only lists threads in which there was activity. Values in the plot are relative to the beginning of the selected trace. Change-Id: Ie5605b7211828fd01accb920a5a735500fcae4b2 Signed-off-by: Najib Arbaoui Signed-off-by: Samuel Gagnon Reviewed-on: https://git.eclipse.org/r/65957 Reviewed-by: Genevieve Bastien Tested-by: Genevieve Bastien Reviewed-by: Hudson CI Reviewed-by: Matthew Khouzam --- diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/plugin.xml b/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/plugin.xml index 11d77441b0..ec3944bc1b 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/plugin.xml +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/plugin.xml @@ -32,6 +32,16 @@ class="org.eclipse.tracecompass.analysis.os.linux.core.tests.stubs.trace.TmfXmlKernelTraceStub"> + + + + diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/src/org/eclipse/tracecompass/analysis/os/linux/core/tests/kernelmemoryusage/KernelMemoryStateProviderTest.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/src/org/eclipse/tracecompass/analysis/os/linux/core/tests/kernelmemoryusage/KernelMemoryStateProviderTest.java new file mode 100644 index 0000000000..5142dab832 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/src/org/eclipse/tracecompass/analysis/os/linux/core/tests/kernelmemoryusage/KernelMemoryStateProviderTest.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright (c) 2016 É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 v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.analysis.os.linux.core.tests.kernelmemoryusage; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.tracecompass.analysis.os.linux.core.kernelmemoryusage.KernelMemoryAnalysisModule; +import org.eclipse.tracecompass.analysis.os.linux.core.kernelmemoryusage.KernelMemoryStateProvider; +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.statesystem.core.ITmfStateSystem; +import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; +import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException; +import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval; +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.tests.shared.TmfTestHelper; +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; + +/** + * Test suite for the {@link KernelMemoryAnalysisModule} class + * + * @author Julien Daoust + * @author Najib Arbaoui + */ +public class KernelMemoryStateProviderTest { + + private static final String KERNEL_MEMORY_USAGE_FILE = "testfiles/KernelMemoryAnalysis_testTrace.xml"; + private static final long PAGE_SIZE = 4096; + private ITmfTrace fTrace; + private KernelMemoryAnalysisModule fModule = null; + private SortedMap threadEvent = new TreeMap<>(); + + private static void deleteSuppFiles(ITmfTrace trace) { + /* Remove supplementary files */ + File suppDir = new File(TmfTraceManager.getSupplementaryFileDir(trace)); + for (File file : suppDir.listFiles()) { + file.delete(); + } + } + + /** + * Setup the trace for the tests + */ + @Before + public void setUp() { + ITmfTrace trace = new TmfXmlKernelTraceStub(); + IPath filePath = Activator.getAbsoluteFilePath(KERNEL_MEMORY_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, KernelMemoryAnalysisModule.class, KernelMemoryAnalysisModule.ID); + assertNotNull(fModule); + fTrace = trace; + } + + /** + * Clean up + */ + @After + public void tearDown() { + deleteSuppFiles(fTrace); + fTrace.dispose(); + } + + /** + * Test that the analysis executes without problems + */ + @Test + public void testAnalysisExecution() { + /* Make sure the analysis hasn't run yet */ + assertNull(fModule.getStateSystem()); + + /* Execute the analysis */ + assertTrue(TmfTestHelper.executeAnalysis(fModule)); + assertNotNull(fModule.getStateSystem()); + } + + /** + * Test allocation and deallocation of kernel Memory + */ + @Test + public void testAllocationDeallocationMemory() { + fModule.schedule(); + fModule.waitForCompletion(); + ITmfStateSystem ss = fModule.getStateSystem(); + assertNotNull(ss); + assertEquals(1L, ss.getStartTime()); + assertEquals(30L, ss.getCurrentEndTime()); + long totalMemory = 0; + threadEvent.put(1L, PAGE_SIZE); // kmem_mm_page_alloc at timestamp = 1 + threadEvent.put(2L, -PAGE_SIZE); // kmem_mm_page_free at timestamp = 2 + threadEvent.put(3L, -PAGE_SIZE); // kmem_mm_page_free at timestamp = 3 + threadEvent.put(17L, PAGE_SIZE); // kmem_mm_page_alloc at timestamp = 17 + threadEvent.put(22L, -PAGE_SIZE); // kmem_mm_page_free at timestamp = 22 + threadEvent.put(28L, -PAGE_SIZE); // kmem_mm_page_free at timestamp = 28 + threadEvent.put(29L, PAGE_SIZE); // kmem_mm_page_alloc at timestamp = 29 + threadEvent.put(30L, PAGE_SIZE); // kmem_mm_page_alloc at timestamp = 30 + + // loop a Map and check if all allocation and deallocation of kernel + // memory are done proprely + for (Map.Entry entry : threadEvent.entrySet()) { + try { + int tidQuark = ss.getQuarkAbsolute(KernelMemoryStateProvider.OTHER_TID); + ITmfStateInterval kernelState = ss.querySingleState(entry.getKey(), tidQuark); + long value = kernelState.getStateValue().unboxLong(); + totalMemory += entry.getValue(); + assertEquals(totalMemory, value); + + } catch (StateSystemDisposedException | AttributeNotFoundException e) { + fail(e.getMessage()); + } + } + } +} \ No newline at end of file diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/testfiles/KernelMemoryAnalysis_testTrace.xml b/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/testfiles/KernelMemoryAnalysis_testTrace.xml new file mode 100644 index 0000000000..b82e4d1679 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/testfiles/KernelMemoryAnalysis_testTrace.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file 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 a0831cecb0..3aac568a11 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 @@ -21,6 +21,7 @@ Export-Package: org.eclipse.tracecompass.analysis.os.linux.core.contextswitch, org.eclipse.tracecompass.analysis.os.linux.core.cpuusage, org.eclipse.tracecompass.analysis.os.linux.core.event.aspect, org.eclipse.tracecompass.analysis.os.linux.core.kernel, + org.eclipse.tracecompass.analysis.os.linux.core.kernelmemoryusage, org.eclipse.tracecompass.analysis.os.linux.core.latency, org.eclipse.tracecompass.analysis.os.linux.core.model, org.eclipse.tracecompass.analysis.os.linux.core.signals, 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 251a750aad..a2ce49c91b 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.properties +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.properties @@ -14,9 +14,10 @@ Bundle-Vendor = Eclipse Trace Compass Bundle-Name = Trace Compass Linux Kernel Analysis Core Plug-in tracetype.type.kernel = Linux Kernel Trace -analysis.linuxkernel = Linux Kernel +analysis.linuxkernel = Linux Kernel analysis.cpuusage = CPU usage analysis.latency = System Call Latency analysis.contextswitch = Context switch +analysis.kernelmemory = Kernel memory usage 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 bd74cfccf1..fbb793191d 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.xml +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.xml @@ -42,5 +42,14 @@ 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/kernelmemoryusage/KernelMemoryAnalysisModule.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/kernelmemoryusage/KernelMemoryAnalysisModule.java new file mode 100644 index 0000000000..5186d3a174 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/kernelmemoryusage/KernelMemoryAnalysisModule.java @@ -0,0 +1,54 @@ +/********************************************************************** + * Copyright (c) 2016 É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 v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + **********************************************************************/ +package org.eclipse.tracecompass.analysis.os.linux.core.kernelmemoryusage; + +import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelAnalysisEventLayout; +import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelTrace; +import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider; +import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; + +/** + * This analysis module creates a stateprovider that keeps track of the memory + * allocated and deallocated by the kernel + * + * @author Samuel Gagnon + * @since 2.0 + */ +public class KernelMemoryAnalysisModule extends TmfStateSystemAnalysisModule { + + /** + * Analysis ID, it should match that in the plugin.xml file + */ + public static final @NonNull String ID = "org.eclipse.tracecompass.analysis.os.linux.core.kernelmemory"; //$NON-NLS-1$ + + /** + * Each thread attribute in the tree has an attribute for keeping the lowest memory + * value for that thread during the trace. (Those values can be negative because we + * don't have access to a memory dump before the trace) + */ + public static final @NonNull String THREAD_LOWEST_MEMORY_VALUE = "lowestMemory"; //$NON-NLS-1$ + + @Override + protected @NonNull ITmfStateProvider createStateProvider() { + ITmfTrace trace = checkNotNull(getTrace()); + IKernelAnalysisEventLayout layout; + + if (trace instanceof IKernelTrace) { + layout = ((IKernelTrace) trace).getKernelEventLayout(); + } else { + /* Fall-back to the base LttngEventLayout */ + layout = IKernelAnalysisEventLayout.DEFAULT_LAYOUT; + } + return new KernelMemoryStateProvider(trace, layout); + } +} diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/kernelmemoryusage/KernelMemoryStateProvider.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/kernelmemoryusage/KernelMemoryStateProvider.java new file mode 100644 index 0000000000..dc061eac07 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/kernelmemoryusage/KernelMemoryStateProvider.java @@ -0,0 +1,121 @@ +/********************************************************************** + * Copyright (c) 2016 Polytechnique de Montréal + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + **********************************************************************/ +package org.eclipse.tracecompass.analysis.os.linux.core.kernelmemoryusage; + +import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelTidAspect; +import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelAnalysisEventLayout; +import org.eclipse.tracecompass.internal.analysis.os.linux.core.Activator; +import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder; +import org.eclipse.tracecompass.statesystem.core.StateSystemBuilderUtils; +import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; +import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue; +import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue; +import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; +import org.eclipse.tracecompass.tmf.core.statesystem.AbstractTmfStateProvider; +import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; + +/** + * Creates a state system and computes the total memory usage for all threads + * and for each selected thread from a kernel trace. It examines the page + * allocation and deallocation events in the kernel to do so. + * + * The state provider also contains code that can query the state system. + * + * @author Samuel Gagnon + * @since 2.0 + */ +public class KernelMemoryStateProvider extends AbstractTmfStateProvider { + + /** + * Special string to save memory allocation when tid is not known + */ + public static final String OTHER_TID = "other"; //$NON-NLS-1$ + + /* Version of this state provider */ + private static final int VERSION = 1; + + private static final int PAGE_SIZE = 4096; + + private IKernelAnalysisEventLayout fLayout; + + /** + * Constructor + * + * @param trace + * trace + * @param layout + * layout + */ + public KernelMemoryStateProvider(@NonNull ITmfTrace trace, IKernelAnalysisEventLayout layout) { + super(trace, "Kernel:Memory"); //$NON-NLS-1$ + fLayout = layout; + } + + @Override + public int getVersion() { + return VERSION; + } + + @Override + public ITmfStateProvider getNewInstance() { + return new KernelMemoryStateProvider(getTrace(), fLayout); + } + + @Override + protected void eventHandle(@NonNull ITmfEvent event) { + String name = event.getName(); + + long inc; + if (name.equals(fLayout.eventKmemPageAlloc())) { + inc = PAGE_SIZE; + } else if (name.equals(fLayout.eventKmemPageFree())) { + inc = -PAGE_SIZE; + } else { + return; + } + + try { + ITmfStateSystemBuilder ss = checkNotNull(getStateSystemBuilder()); + long ts = event.getTimestamp().getValue(); + + Integer tidField = KernelTidAspect.INSTANCE.resolve(event); + String tid; + if (tidField == null) { + // if the TID is not available + tid = OTHER_TID; + } else { + tid = tidField.toString(); + } + + int tidQuark = ss.getQuarkAbsoluteAndAdd(tid); + StateSystemBuilderUtils.incrementAttributeLong(ss, ts, tidQuark, inc); + long currentMemoryValue = ss.queryOngoingState(tidQuark).unboxLong(); + + /** + * We add an attribute to keep the lowest memory value for each + * thread. This quantity is used when we plot to avoid negative + * values. + */ + int lowestMemoryQuark = ss.getQuarkRelativeAndAdd(tidQuark, KernelMemoryAnalysisModule.THREAD_LOWEST_MEMORY_VALUE); + ITmfStateValue lowestMemoryValue = ss.queryOngoingState(lowestMemoryQuark); + long previousLowest = lowestMemoryValue.isNull() ? 0 : lowestMemoryValue.unboxLong(); + + if (previousLowest > currentMemoryValue) { + ss.modifyAttribute(ts, TmfStateValue.newValueLong(currentMemoryValue), lowestMemoryQuark); + } + } catch (AttributeNotFoundException e) { + Activator.getDefault().logError(e.getMessage(), e); + } + } + +} diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/trace/DefaultEventLayout.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/trace/DefaultEventLayout.java index 149600c72d..e34d32cff1 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/trace/DefaultEventLayout.java +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/trace/DefaultEventLayout.java @@ -84,6 +84,8 @@ public class DefaultEventLayout implements IKernelAnalysisEventLayout { private static final String EXPIRES = "expires"; //$NON-NLS-1$ private static final String NOW = "now"; //$NON-NLS-1$ private static final String SOFT_EXPIRES = "softexpires"; //$NON-NLS-1$ + private static final String KMEM_ALLOC = "kmem_mm_page_alloc"; //$NON-NLS-1$ + private static final String KMEM_FREE = "kmem_mm_page_free"; //$NON-NLS-1$ /** * Constructor, to be used by classes extending this one. To get an instance @@ -189,6 +191,22 @@ public class DefaultEventLayout implements IKernelAnalysisEventLayout { public String eventCompatSyscallExitPrefix() { return SYSCALL_EXIT_PREFIX; } + /** + * @since 2.0 + */ + @Override + public String eventKmemPageAlloc() { + return KMEM_ALLOC; + } + + /** + * @since 2.0 + */ + @Override + public String eventKmemPageFree() { + return KMEM_FREE; + + } // ------------------------------------------------------------------------ // Event field names diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/trace/IKernelAnalysisEventLayout.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/trace/IKernelAnalysisEventLayout.java index 75e43fa7c8..73692aae52 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/trace/IKernelAnalysisEventLayout.java +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/trace/IKernelAnalysisEventLayout.java @@ -290,6 +290,27 @@ public interface IKernelAnalysisEventLayout { */ String eventHRTimerExpireExit(); + /** + * The kernel just allocated a page of memory. + *

+ * In Linux, this typically means a user space application just got a page of + * ram. + * + * @return the event name + * @since 2.0 + */ + String eventKmemPageAlloc(); + + /** + * The kernel just deallocated a page of memory. + *

+ * In Linux, this typically means a page of ram was just freed + * + * @return the event name + * @since 2.0 + */ + String eventKmemPageFree(); + // ------------------------------------------------------------------------ // Event field names // ------------------------------------------------------------------------ diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/META-INF/MANIFEST.MF b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/META-INF/MANIFEST.MF index 6356d8d4db..285fc3f502 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/META-INF/MANIFEST.MF +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/META-INF/MANIFEST.MF @@ -28,6 +28,7 @@ Export-Package: org.eclipse.tracecompass.analysis.os.linux.ui.views.controlflow, org.eclipse.tracecompass.internal.analysis.os.linux.ui;x-friends:="org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests", org.eclipse.tracecompass.internal.analysis.os.linux.ui.actions;x-internal:=true, org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow;x-friends:="org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests,org.eclipse.tracecompass.analysis.os.linux.ui.tests", + org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.kernelmemoryusage;x-internal:=true, org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.latency;x-friends:="org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests", org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.latency.statistics;x-friends:="org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests", org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.resources;x-friends:="org.eclipse.tracecompass.analysis.os.linux.ui.swtbot.tests" diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/icons/eview16/memory-usage.png b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/icons/eview16/memory-usage.png new file mode 100644 index 0000000000..1101147693 Binary files /dev/null and b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/icons/eview16/memory-usage.png differ diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.properties b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.properties index 709c85c3db..ba96e867a2 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.properties +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.properties @@ -22,3 +22,4 @@ latency.view.name = System Call Latencies latency.scatter.view.name = System Call Latency vs Time latency.stats.view.name = System Call Latency Statistics latency.density.view.name = System Call Density +kernelmemoryusageview.view.name = Kernel Memory Usage View diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.xml b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.xml index cafcd338af..c99d611ecf 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.xml +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.xml @@ -65,6 +65,14 @@ name="%latency.density.view.name" restorable="true"> + + @@ -117,5 +125,12 @@ class="org.eclipse.tracecompass.analysis.os.linux.core.latency.SystemCallLatencyAnalysis"> + + + + diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/KernelMemoryUsageEntry.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/KernelMemoryUsageEntry.java new file mode 100644 index 0000000000..ed9a58cbc7 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/KernelMemoryUsageEntry.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2016 É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 v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.kernelmemoryusage; + +import org.eclipse.tracecompass.tmf.ui.viewers.tree.TmfTreeViewerEntry; + +/** + * This class represents an entry in the tree viewer of the kernel memory usage + * View. + * + * @author mahdi zolnouri + */ +public class KernelMemoryUsageEntry extends TmfTreeViewerEntry { + + private final String fTid; + private final String fProcessName; + + /** + * Constructor + * + * @param tid + * The TID of the process + * @param name + * The thread's name + */ + public KernelMemoryUsageEntry(String tid, String name) { + super(tid); + fTid = tid; + fProcessName = name; + } + + /** + * Get the TID of the thread represented by this entry + * + * @return The thread's TID + */ + public String getTid() { + return fTid; + } + + /** + * Get the process name + * + * @return The process name + */ + public String getProcessName() { + return fProcessName; + } +} diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/KernelMemoryUsageTreeViewer.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/KernelMemoryUsageTreeViewer.java new file mode 100644 index 0000000000..c40c262c85 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/KernelMemoryUsageTreeViewer.java @@ -0,0 +1,227 @@ +/********************************************************************** + * Copyright (c) 2016 Polytechnique de Montréal + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + **********************************************************************/ +package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.kernelmemoryusage; + +import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerComparator; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule; +import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelThreadInformationProvider; +import org.eclipse.tracecompass.analysis.os.linux.core.kernelmemoryusage.KernelMemoryAnalysisModule; +import org.eclipse.tracecompass.analysis.os.linux.core.kernelmemoryusage.KernelMemoryStateProvider; +import org.eclipse.tracecompass.internal.analysis.os.linux.ui.Activator; +import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; +import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; +import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException; +import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; +import org.eclipse.tracecompass.tmf.ui.viewers.tree.AbstractTmfTreeViewer; +import org.eclipse.tracecompass.tmf.ui.viewers.tree.ITmfTreeColumnDataProvider; +import org.eclipse.tracecompass.tmf.ui.viewers.tree.ITmfTreeViewerEntry; +import org.eclipse.tracecompass.tmf.ui.viewers.tree.TmfTreeColumnData; +import org.eclipse.tracecompass.tmf.ui.viewers.tree.TmfTreeViewerEntry; + +/** + * Tree viewer to select which process to display in the kernel memory usage + * chart. + * + * @author Mahdi Zolnouri + * @author Wassim Nasrallah + * @author Najib Arbaoui + */ +public class KernelMemoryUsageTreeViewer extends AbstractTmfTreeViewer { + + private KernelMemoryAnalysisModule fModule = null; + private String fSelectedThread = null; + private static final String[] COLUMN_NAMES = new String[] { + Messages.KernelMemoryUsageComposite_ColumnTID, + Messages.KernelMemoryUsageComposite_ColumnProcess + }; + + /* A map that saves the mapping of a thread ID to its executable name */ + private final Map fProcessNameMap = new HashMap<>(); + + /** Provides label for the Kernel memory usage tree viewer cells */ + protected static class KernelMemoryLabelProvider extends TreeLabelProvider { + + @Override + public String getColumnText(Object element, int columnIndex) { + KernelMemoryUsageEntry obj = (KernelMemoryUsageEntry) element; + if (columnIndex == 0) { + return obj.getTid(); + } else if (columnIndex == 1) { + return obj.getProcessName(); + } + return element.toString(); + } + } + + /** + * Constructor + * + * @param parent + * The parent composite that holds this viewer + */ + public KernelMemoryUsageTreeViewer(Composite parent) { + super(parent, false); + setLabelProvider(new KernelMemoryLabelProvider()); + } + + @Override + protected ITmfTreeColumnDataProvider getColumnDataProvider() { + return new ITmfTreeColumnDataProvider() { + + @Override + public List getColumnData() { + /* All columns are sortable */ + List columns = new ArrayList<>(); + TmfTreeColumnData column = new TmfTreeColumnData(COLUMN_NAMES[0]); + column.setComparator(new ViewerComparator() { + @Override + public int compare(Viewer viewer, Object e1, Object e2) { + KernelMemoryUsageEntry n1 = (KernelMemoryUsageEntry) e1; + KernelMemoryUsageEntry n2 = (KernelMemoryUsageEntry) e2; + + return n1.getTid().compareTo(n2.getTid()); + } + }); + columns.add(column); + column = new TmfTreeColumnData(COLUMN_NAMES[1]); + column.setComparator(new ViewerComparator() { + @Override + public int compare(Viewer viewer, Object e1, Object e2) { + KernelMemoryUsageEntry n1 = (KernelMemoryUsageEntry) e1; + KernelMemoryUsageEntry n2 = (KernelMemoryUsageEntry) e2; + + return n1.getProcessName().compareTo(n2.getProcessName()); + } + }); + columns.add(column); + return columns; + } + }; + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + @Override + protected void contentChanged(ITmfTreeViewerEntry rootEntry) { + String selectedThread = fSelectedThread; + if (selectedThread != null) { + /* Find the selected thread among the inputs */ + for (ITmfTreeViewerEntry entry : rootEntry.getChildren()) { + if (entry instanceof KernelMemoryUsageEntry) { + if (selectedThread.equals(((KernelMemoryUsageEntry) entry).getTid())) { + List list = Collections.singletonList(entry); + super.setSelection(list); + return; + } + } + } + } + } + + @Override + public void initializeDataSource() { + /* Should not be called while trace is still null */ + ITmfTrace trace = checkNotNull(getTrace()); + + fModule = TmfTraceUtils.getAnalysisModuleOfClass(trace, KernelMemoryAnalysisModule.class, KernelMemoryAnalysisModule.ID); + if (fModule == null) { + return; + } + fModule.schedule(); + fModule.waitForInitialization(); + fProcessNameMap.clear(); + } + + @Override + protected ITmfTreeViewerEntry updateElements(long start, long end, boolean isSelection) { + if (isSelection || (start == end)) { + return null; + } + KernelMemoryAnalysisModule module = fModule; + if (getTrace() == null || module == null) { + return null; + } + module.waitForInitialization(); + ITmfStateSystem ss = module.getStateSystem(); + if (ss == null) { + return null; + } + ss.waitUntilBuilt(); + TmfTreeViewerEntry root = new TmfTreeViewerEntry(""); //$NON-NLS-1$ + List entryList = root.getChildren(); + + try { + List memoryStates = ss.queryFullState(start); + List threadQuarkList = ss.getSubAttributes(ITmfStateSystem.ROOT_ATTRIBUTE, false); + + for (Integer threadQuark : threadQuarkList) { + ITmfStateInterval threadMemoryInterval = memoryStates.get(threadQuark); + if (threadMemoryInterval.getEndTime() < end) { + String tid = ss.getAttributeName(threadQuark); + String procname = getProcessName(tid); + KernelMemoryUsageEntry obj = new KernelMemoryUsageEntry(tid, procname); + entryList.add(obj); + } + } + } catch (StateSystemDisposedException | AttributeNotFoundException e) { + Activator.getDefault().logError(e.getMessage(), e); + } + return root; + } + + /* + * Get the process name from its TID by using the LTTng kernel analysis + * module + */ + private String getProcessName(String tid) { + String execName = fProcessNameMap.get(tid); + if (execName != null) { + return execName; + } + if (tid.equals(KernelMemoryStateProvider.OTHER_TID)) { + fProcessNameMap.put(tid, tid); + return tid; + } + ITmfTrace trace = checkNotNull(getTrace()); + KernelAnalysisModule kernelModule = TmfTraceUtils.getAnalysisModuleOfClass(trace, KernelAnalysisModule.class, KernelAnalysisModule.ID); + if (kernelModule == null) { + return tid; + } + execName = KernelThreadInformationProvider.getExecutableName(kernelModule, Integer.parseInt(tid)); + if (execName == null) { + return tid; + } + fProcessNameMap.put(tid, execName); + return execName; + } + + /** + * Set the currently selected thread ID + * + * @param tid + * The selected thread ID + */ + public void setSelectedThread(String tid) { + fSelectedThread = tid; + } +} \ No newline at end of file diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/KernelMemoryUsageView.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/KernelMemoryUsageView.java new file mode 100644 index 0000000000..1bfa5f09b8 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/KernelMemoryUsageView.java @@ -0,0 +1,94 @@ +/********************************************************************** + * Copyright (c) 2016 É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 v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + **********************************************************************/ +package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.kernelmemoryusage; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; +import org.eclipse.tracecompass.tmf.ui.viewers.TmfViewer; +import org.eclipse.tracecompass.tmf.ui.viewers.xycharts.TmfXYChartViewer; +import org.eclipse.tracecompass.tmf.ui.views.TmfChartView; + +/** + * Memory usage view + * + * @author Samuel Gagnon + * @author Mahdi Zolnouri + * @author Wassim Nasrallah + */ +public class KernelMemoryUsageView extends TmfChartView { + + /** ID string */ + public static final String ID = "org.eclipse.tracecompass.analysis.os.linux.ui.kernelmemoryusageview"; //$NON-NLS-1$ + + /* + * We need this reference to update the viewer when there is a new selection + */ + private KernelMemoryUsageTreeViewer fTreeViewerReference = null; + + /** + * Constructor + */ + public KernelMemoryUsageView() { + super(Messages.MemoryUsageView_title); + } + + @Override + protected TmfXYChartViewer createChartViewer(Composite parent) { + return new KernelMemoryUsageViewer(parent); + } + + private final class SelectionChangeListener implements ISelectionChangedListener { + @Override + public void selectionChanged(SelectionChangedEvent event) { + ISelection selection = event.getSelection(); + if (selection instanceof IStructuredSelection) { + Object structSelection = ((IStructuredSelection) selection).getFirstElement(); + if (structSelection instanceof KernelMemoryUsageEntry) { + KernelMemoryUsageEntry entry = (KernelMemoryUsageEntry) structSelection; + fTreeViewerReference.setSelectedThread(entry.getTid()); + ((KernelMemoryUsageViewer) getChartViewer()).setSelectedThread(entry.getTid()); + } + } + } + } + + @Override + protected @NonNull TmfViewer createLeftChildViewer(Composite parent) { + @NonNull + KernelMemoryUsageTreeViewer fTreeViewer = new KernelMemoryUsageTreeViewer(parent); + fTreeViewerReference = fTreeViewer; + + fTreeViewer.addSelectionChangeListener(new SelectionChangeListener()); + + /* Initialize the viewers with the currently selected trace */ + ITmfTrace trace = TmfTraceManager.getInstance().getActiveTrace(); + if (trace != null) { + TmfTraceSelectedSignal signal = new TmfTraceSelectedSignal(this, trace); + fTreeViewer.traceSelected(signal); + fTreeViewerReference.traceSelected(signal); + } + + fTreeViewer.getControl().addControlListener(new ControlAdapter() { + @Override + public void controlResized(ControlEvent e) { + super.controlResized(e); + } + }); + return fTreeViewer; + } +} diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/KernelMemoryUsageViewer.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/KernelMemoryUsageViewer.java new file mode 100644 index 0000000000..11e3a97e83 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/KernelMemoryUsageViewer.java @@ -0,0 +1,227 @@ +/********************************************************************** + * Copyright (c) 2016 É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 v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + **********************************************************************/ +package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.kernelmemoryusage; + +import java.text.DecimalFormat; +import java.text.FieldPosition; +import java.text.Format; +import java.text.ParsePosition; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tracecompass.analysis.os.linux.core.kernelmemoryusage.KernelMemoryAnalysisModule; +import org.eclipse.tracecompass.internal.analysis.os.linux.ui.Activator; +import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; +import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; +import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException; +import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException; +import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval; +import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; +import org.eclipse.tracecompass.tmf.ui.viewers.xycharts.linecharts.TmfCommonXLineChartViewer; +import org.swtchart.Chart; + +/** + * Memory usage view + * + * @author Samuel Gagnon + * @author Wassim Nasrallah + */ +public class KernelMemoryUsageViewer extends TmfCommonXLineChartViewer { + + /** + * MemoryFormat + * + * @author Matthew Khouzam + */ + private static final class MemoryFormat extends Format { + private static final long serialVersionUID = 3934127385682676804L; + private static final String KB = "KB"; //$NON-NLS-1$ + private static final String MB = "MB"; //$NON-NLS-1$ + private static final String GB = "GB"; //$NON-NLS-1$ + private static final String TB = "TB"; //$NON-NLS-1$ + private static final long KILO = 1024; + private static final Format FORMAT = new DecimalFormat("#.###"); //$NON-NLS-1$ + + @Override + public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { + if (obj instanceof Double) { + Double value = (Double) obj; + if (value == 0) { + return toAppendTo.append("0"); //$NON-NLS-1$ + } + if (value > KILO * KILO * KILO * KILO) { + return toAppendTo.append(FORMAT.format(value / (KILO * KILO * KILO * KILO))).append(' ').append(TB); + } + if (value > KILO * KILO * KILO) { + return toAppendTo.append(FORMAT.format(value / (KILO * KILO * KILO))).append(' ').append(GB); + } + if (value > KILO * KILO) { + return toAppendTo.append(FORMAT.format(value / (KILO * KILO))).append(' ').append(MB); + } + return toAppendTo.append(FORMAT.format(value / (KILO))).append(' ').append(KB); + } + return toAppendTo; + } + + @Override + public Object parseObject(String source, ParsePosition pos) { + return null; + } + } + + private static final String NOT_SELECTED = "-1"; //$NON-NLS-1$ + + private TmfStateSystemAnalysisModule fModule = null; + private String fSelectedThread = NOT_SELECTED; + + /** + * Constructor + * + * @param parent + * parent view + */ + public KernelMemoryUsageViewer(Composite parent) { + super(parent, Messages.MemoryUsageViewer_title, Messages.MemoryUsageViewer_xAxis, Messages.MemoryUsageViewer_yAxis); + Chart chart = getSwtChart(); + chart.getAxisSet().getYAxis(0).getTick().setFormat(new MemoryFormat()); + chart.getLegend().setPosition(SWT.BOTTOM); + } + + @Override + protected void initializeDataSource() { + ITmfTrace trace = getTrace(); + if (trace != null) { + fModule = TmfTraceUtils.getAnalysisModuleOfClass(trace, TmfStateSystemAnalysisModule.class, KernelMemoryAnalysisModule.ID); + if (fModule == null) { + return; + } + fModule.schedule(); + } + } + + @Override + protected void updateData(long start, long end, int nb, IProgressMonitor monitor) { + TmfStateSystemAnalysisModule module = fModule; + if (getTrace() == null || module == null) { + return; + } + + if (!module.waitForInitialization()) { + return; + } + + ITmfStateSystem ss = module.getStateSystem(); + if (ss == null) { + throw new IllegalStateException(); + } + + double[] xvalues = getXAxis(start, end, nb); + if (xvalues.length == 0) { + return; + } + setXAxis(xvalues); + + try { + /** + * For a given time range, we plot two lines representing the memory + * allocation. The first line represent the total memory allocation + * of every process. The second line represent the memory allocation + * of the selected thread. + */ + double[] totalKernelMemoryValues = new double[xvalues.length]; + double[] selectedThreadValues = new double[xvalues.length]; + for (int i = 0; i < xvalues.length; i++) { + if (monitor.isCanceled()) { + return; + } + + double x = xvalues[i]; + long t = (long) x + getTimeOffset(); + + List kernelState = ss.queryFullState(t); + + /* The subattributes of the root are the different threads */ + List threadQuarkList = ss.getSubAttributes(-1, false); + /* We add the value of each thread to the total quantity */ + for (Integer threadQuark : threadQuarkList) { + ITmfStateInterval threadMemoryInterval = kernelState.get(threadQuark); + long value = threadMemoryInterval.getStateValue().unboxLong(); + totalKernelMemoryValues[i] += value; + + String tid = ss.getAttributeName(threadQuark); + if (tid.equals(fSelectedThread)) { + selectedThreadValues[i] = value; + } + } + } + + /** + * For each thread, we look for its lowest value since the beginning + * of the trace. This way, we can avoid negative values in the plot. + */ + double totalKernelMemoryValuesShift = 0; + double selectThreadValuesShift = 0; + + /* + * The lowest value we are searching is at the end of the current + * selected zone + */ + List kernelState = ss.queryFullState(end); + List threadQuarkList = ss.getSubAttributes(-1, false); + /* We add the lowest value of each thread */ + for (Integer threadQuark : threadQuarkList) { + int lowestMemoryQuark = ss.getQuarkRelative(threadQuark, KernelMemoryAnalysisModule.THREAD_LOWEST_MEMORY_VALUE); + ITmfStateInterval lowestMemoryInterval = kernelState.get(lowestMemoryQuark); + long lowestMemoryValue = lowestMemoryInterval.getStateValue().unboxLong(); + // We want to add up a positive quantity. + totalKernelMemoryValuesShift -= lowestMemoryValue; + + String tid = ss.getAttributeName(threadQuark); + if (tid.equals(fSelectedThread)) { + // We want to add up a positive quantity. + selectThreadValuesShift = -lowestMemoryValue; + } + } + + /** + * We shift the two displayed lines up. + */ + for (int i = 0; i < xvalues.length; i++) { + totalKernelMemoryValues[i] += totalKernelMemoryValuesShift; + selectedThreadValues[i] += selectThreadValuesShift; + } + setSeries(Messages.MemoryUsageViewer_Total, totalKernelMemoryValues); + if (fSelectedThread != NOT_SELECTED) { + setSeries(fSelectedThread, selectedThreadValues); + } + updateDisplay(); + + } catch (TimeRangeException | StateSystemDisposedException | AttributeNotFoundException e) { + Activator.getDefault().logError(e.getMessage(), e); + } + } + + /** + * Set the selected thread ID, which will be graphed in this viewer + * + * @param tid + * The selected thread ID + */ + public void setSelectedThread(String tid) { + cancelUpdate(); + deleteSeries(fSelectedThread); + fSelectedThread = tid; + updateContent(); + } + +} diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/Messages.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/Messages.java new file mode 100644 index 0000000000..975a46de59 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/Messages.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2016 É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 v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.kernelmemoryusage; + +import org.eclipse.osgi.util.NLS; + +@SuppressWarnings("javadoc") +public class Messages { + private static final String BUNDLE_NAME = "org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.kernelmemoryusage.messages"; //$NON-NLS-1$ + + public static String KernelMemoryUsageComposite_ColumnProcess; + public static String KernelMemoryUsageComposite_ColumnTID; + public static String MemoryUsageView_title; + public static String MemoryUsageViewer_title; + public static String MemoryUsageViewer_xAxis; + public static String MemoryUsageViewer_yAxis; + public static String MemoryUsageViewer_Total; + + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/messages.properties b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/messages.properties new file mode 100644 index 0000000000..eaf2514b4e --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/messages.properties @@ -0,0 +1,16 @@ +############################################################################### +# Copyright (c) 2016 É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 v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################### + +MemoryUsageView_title=Memory Usage +MemoryUsageViewer_title=Relative Kernel Memory Usage +MemoryUsageViewer_xAxis=Time +MemoryUsageViewer_yAxis=Memory Variation +KernelMemoryUsageComposite_ColumnProcess=Process +KernelMemoryUsageComposite_ColumnTID=TID +MemoryUsageViewer_Total=Total \ No newline at end of file diff --git a/lttng/org.eclipse.tracecompass.lttng2.kernel.core/src/org/eclipse/tracecompass/internal/lttng2/kernel/core/trace/layout/Lttng27EventLayout.java b/lttng/org.eclipse.tracecompass.lttng2.kernel.core/src/org/eclipse/tracecompass/internal/lttng2/kernel/core/trace/layout/Lttng27EventLayout.java index 18dd70fc8a..349e10c4b1 100644 --- a/lttng/org.eclipse.tracecompass.lttng2.kernel.core/src/org/eclipse/tracecompass/internal/lttng2/kernel/core/trace/layout/Lttng27EventLayout.java +++ b/lttng/org.eclipse.tracecompass.lttng2.kernel.core/src/org/eclipse/tracecompass/internal/lttng2/kernel/core/trace/layout/Lttng27EventLayout.java @@ -124,6 +124,16 @@ public class Lttng27EventLayout extends Lttng26EventLayout { return "irq_softirq_exit"; //$NON-NLS-1$ } + @Override + public String eventKmemPageAlloc() { + return "kmem_mm_page_alloc"; //$NON-NLS-1$ + } + + @Override + public String eventKmemPageFree() { + return "kmem_mm_page_free"; //$NON-NLS-1$ + } + public String x86IrqVectorsLocalTimerEntry() { return X86_IRQ_VECTORS_LOCAL_TIMER_ENTRY; } diff --git a/lttng/org.eclipse.tracecompass.lttng2.kernel.core/src/org/eclipse/tracecompass/internal/lttng2/kernel/core/trace/layout/LttngEventLayout.java b/lttng/org.eclipse.tracecompass.lttng2.kernel.core/src/org/eclipse/tracecompass/internal/lttng2/kernel/core/trace/layout/LttngEventLayout.java index 72c26b0611..af7b1796a1 100644 --- a/lttng/org.eclipse.tracecompass.lttng2.kernel.core/src/org/eclipse/tracecompass/internal/lttng2/kernel/core/trace/layout/LttngEventLayout.java +++ b/lttng/org.eclipse.tracecompass.lttng2.kernel.core/src/org/eclipse/tracecompass/internal/lttng2/kernel/core/trace/layout/LttngEventLayout.java @@ -85,6 +85,8 @@ public class LttngEventLayout implements IKernelAnalysisEventLayout { private static final String HRTIMER_EXPIRES = "expires"; private static final String HRTIMER_NOW = "now"; private static final String HRTIMER_SOFT_EXPIRES = "softexpires"; + private static final String KMEM_ALLOC = "mm_page_alloc"; + private static final String KMEM_FREE = "mm_page_free"; /** All instances are the same. Only provide a static instance getter */ protected LttngEventLayout() { @@ -192,6 +194,22 @@ public class LttngEventLayout implements IKernelAnalysisEventLayout { return SYSCALL_EXIT_PREFIX; } + /** + * @since 2.0 + */ + @Override + public String eventKmemPageAlloc() { + return KMEM_ALLOC; + } + + /** + * @since 2.0 + */ + @Override + public String eventKmemPageFree() { + return KMEM_FREE; + } + // ------------------------------------------------------------------------ // Event field names // ------------------------------------------------------------------------ diff --git a/lttng/org.eclipse.tracecompass.lttng2.kernel.core/src/org/eclipse/tracecompass/internal/lttng2/kernel/core/trace/layout/PerfEventLayout.java b/lttng/org.eclipse.tracecompass.lttng2.kernel.core/src/org/eclipse/tracecompass/internal/lttng2/kernel/core/trace/layout/PerfEventLayout.java index 4fa93c93e0..2a0c93c3a4 100644 --- a/lttng/org.eclipse.tracecompass.lttng2.kernel.core/src/org/eclipse/tracecompass/internal/lttng2/kernel/core/trace/layout/PerfEventLayout.java +++ b/lttng/org.eclipse.tracecompass.lttng2.kernel.core/src/org/eclipse/tracecompass/internal/lttng2/kernel/core/trace/layout/PerfEventLayout.java @@ -162,6 +162,16 @@ public class PerfEventLayout implements IKernelAnalysisEventLayout { return "timer:hrtimer_expire_exit"; //$NON-NLS-1$ } + @Override + public String eventKmemPageAlloc() { + return "kmem:page_alloc"; //$NON-NLS-1$ + } + + @Override + public String eventKmemPageFree() { + return "kmem:page_free"; //$NON-NLS-1$ + } + // ------------------------------------------------------------------------ // Field names // ------------------------------------------------------------------------ @@ -280,5 +290,4 @@ public class PerfEventLayout implements IKernelAnalysisEventLayout { public String fieldHRtimerNow() { return "now"; //$NON-NLS-1$ } - }