analysis.os: New kernel memory usage view with Unit tests
authorNajib Arbaoui <arbaouinajib@gmail.com>
Thu, 31 Mar 2016 22:56:19 +0000 (18:56 -0400)
committerGenevieve Bastien <gbastien+lttng@versatic.net>
Fri, 1 Apr 2016 20:22:39 +0000 (16:22 -0400)
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 <arbaouinajib@gmail.com>
Signed-off-by: Samuel Gagnon <samuel.gagnon92@gmail.com>
Reviewed-on: https://git.eclipse.org/r/65957
Reviewed-by: Genevieve Bastien <gbastien+lttng@versatic.net>
Tested-by: Genevieve Bastien <gbastien+lttng@versatic.net>
Reviewed-by: Hudson CI
Reviewed-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
23 files changed:
analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/plugin.xml
analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/src/org/eclipse/tracecompass/analysis/os/linux/core/tests/kernelmemoryusage/KernelMemoryStateProviderTest.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/testfiles/KernelMemoryAnalysis_testTrace.xml [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF
analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.properties
analysis/org.eclipse.tracecompass.analysis.os.linux.core/plugin.xml
analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/kernelmemoryusage/KernelMemoryAnalysisModule.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/kernelmemoryusage/KernelMemoryStateProvider.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/trace/DefaultEventLayout.java
analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/analysis/os/linux/core/trace/IKernelAnalysisEventLayout.java
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/META-INF/MANIFEST.MF
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/icons/eview16/memory-usage.png [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.properties
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.xml
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/KernelMemoryUsageEntry.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/KernelMemoryUsageTreeViewer.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/KernelMemoryUsageView.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/KernelMemoryUsageViewer.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/Messages.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/kernelmemoryusage/messages.properties [new file with mode: 0644]
lttng/org.eclipse.tracecompass.lttng2.kernel.core/src/org/eclipse/tracecompass/internal/lttng2/kernel/core/trace/layout/Lttng27EventLayout.java
lttng/org.eclipse.tracecompass.lttng2.kernel.core/src/org/eclipse/tracecompass/internal/lttng2/kernel/core/trace/layout/LttngEventLayout.java
lttng/org.eclipse.tracecompass.lttng2.kernel.core/src/org/eclipse/tracecompass/internal/lttng2/kernel/core/trace/layout/PerfEventLayout.java

index 11d77441b036eac965e89e1bbc8022eca5706e82..ec3944bc1b43dd2dc550f67e7724409df7b02856 100644 (file)
                class="org.eclipse.tracecompass.analysis.os.linux.core.tests.stubs.trace.TmfXmlKernelTraceStub">
          </tracetype>
       </module>
+      <module
+            analysis_module="org.eclipse.tracecompass.analysis.os.linux.core.kernelmemoryusage.KernelMemoryAnalysisModule"
+            automatic="false"
+            id="org.eclipse.tracecompass.analysis.os.linux.core.kernelmemoryanalysismodule"
+            name="Kernel Memory Usage Test Analysis">
+         <tracetype
+               applies="true"
+               class="org.eclipse.tracecompass.tmf.tests.stubs.trace.xml.TmfXmlTraceStub">
+         </tracetype>
+      </module>
    </extension>
    <extension
          point="org.eclipse.linuxtools.tmf.core.tracetype">
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 (file)
index 0000000..5142dab
--- /dev/null
@@ -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<Long, Long> 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<Long, Long> 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 (file)
index 0000000..b82e4d1
--- /dev/null
@@ -0,0 +1,40 @@
+<!-- **************************************************************************************
+* Simple  Kernel Memory trace, with simple events kmem_mm_page_alloc et kmem_mm_page_free
+**************************************************************************************** -->
+<trace>
+<set_aspects>
+<field name="cpu" value="1" type="int" />
+</set_aspects>
+<event timestamp="1" name="kmem_mm_page_alloc">
+<field name="cpu" value="0" type="int" />
+<field name="tid" value="proc1" type="string" />
+</event>
+<event timestamp="2" name="kmem_mm_page_free">
+<field name="cpu" value="1" type="int" />
+<field name="tid" value="proc2" type="string" />
+</event>
+<event timestamp="3" name="kmem_mm_page_free">
+<field name="cpu" value="1" type="int" />
+<field name="tid" value="proc1" type="string" />
+</event>
+<event timestamp="17" name="kmem_mm_page_alloc">
+<field name="cpu" value="0" type="int" />
+<field name="tid" value="proc3" type="string" />
+</event>
+<event timestamp="22" name="kmem_mm_page_free">
+<field name="cpu" value="1" type="int" />
+<field name="tid" value="proc4" type="string" />
+</event>
+<event timestamp="28" name="kmem_mm_page_free">
+<field name="cpu" value="1" type="int" />
+<field name="tid" value="proc2" type="string" />
+</event>
+<event timestamp="29" name="kmem_mm_page_alloc">
+<field name="cpu" value="0" type="int" />
+<field name="tid" value="proc4" type="string" />
+</event>
+<event timestamp="30" name="kmem_mm_page_alloc">
+<field name="cpu" value="0" type="int" />
+<field name="tid" value="proc3" type="string" />
+</event>
+</trace>
\ No newline at end of file
index a0831cecb08208839e242b987f5029838700e1c6..3aac568a111362fc4911f3e02aa2ba3900f06dab 100644 (file)
@@ -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,
index 251a750aad16ed85ca87b3a4b23666f97d5e9540..a2ce49c91bf3ba4fc34cffc9ce9f5ef21c75ddbd 100644 (file)
@@ -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
 
index bd74cfccf115251832afd6bf02bbfc79342b7696..fbb793191d9b9cae3b6e3ca06e7f8d0cce88f8a2 100644 (file)
                class="org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelTrace">
          </tracetype>
       </module>
+      <module
+            analysis_module="org.eclipse.tracecompass.analysis.os.linux.core.kernelmemoryusage.KernelMemoryAnalysisModule"
+            id="org.eclipse.tracecompass.analysis.os.linux.core.kernelmemory"
+            name="%analysis.kernelmemory">
+            <tracetype
+               applies="true"
+               class="org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelTrace">
+         </tracetype>
+      </module>
    </extension>
 </plugin>
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 (file)
index 0000000..5186d3a
--- /dev/null
@@ -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 (file)
index 0000000..dc061ea
--- /dev/null
@@ -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);
+        }
+    }
+
+}
index 149600c72d21997b14355ccdf391bca6931032e9..e34d32cff164cef7d4e2b00fee0b7a9ddcfd3211 100644 (file)
@@ -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
index 75e43fa7c8dcc4e4081b7ff9eec47f8da4b957f3..73692aae520389c6e939052cb21e8bd3ecc579fd 100644 (file)
@@ -290,6 +290,27 @@ public interface IKernelAnalysisEventLayout {
      */
     String eventHRTimerExpireExit();
 
+    /**
+     * The kernel just allocated a page of memory.
+     * <p>
+     * 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.
+     * <p>
+     * In Linux, this typically means a page of ram was just freed
+     *
+     * @return the event name
+     * @since 2.0
+     */
+    String eventKmemPageFree();
+
     // ------------------------------------------------------------------------
     // Event field names
     // ------------------------------------------------------------------------
index 6356d8d4db3840cad38a4e26978137054fe5cb0e..285fc3f502dc40a4537b6775a9d6df6203dfaa32 100644 (file)
@@ -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 (file)
index 0000000..1101147
Binary files /dev/null and b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/icons/eview16/memory-usage.png differ
index 709c85c3dbd32dad96ea4b5eeaa1bd3b93b85e13..ba96e867a21c793f60dab696cb5155af3d0e5af5 100644 (file)
@@ -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
index cafcd338afa82e2cf4495100ae1124bc1d612855..c99d611ecfcdbbe7076f6f3fc5fd31f2ac1cb016 100644 (file)
             name="%latency.density.view.name"
             restorable="true">
       </view>
+      <view
+            category="org.eclipse.linuxtools.lttng2.ui.views.category"
+            class="org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.kernelmemoryusage.KernelMemoryUsageView"
+            icon="icons/eview16/memory-usage.png"
+            id="org.eclipse.tracecompass.analysis.os.linux.ui.kernelmemoryusageview"
+            name="%kernelmemoryusageview.view.name"
+            restorable="true">
+      </view>
    </extension>
    <extension
          point="org.eclipse.linuxtools.tmf.core.analysis">
                class="org.eclipse.tracecompass.analysis.os.linux.core.latency.SystemCallLatencyAnalysis">
          </analysisModuleClass>
       </output>
+      <output
+            class="org.eclipse.tracecompass.tmf.ui.analysis.TmfAnalysisViewOutput"
+            id="org.eclipse.tracecompass.analysis.os.linux.ui.kernelmemoryusageview">
+         <analysisModuleClass
+               class="org.eclipse.tracecompass.analysis.os.linux.core.kernelmemoryusage.KernelMemoryAnalysisModule">
+         </analysisModuleClass>
+      </output>
    </extension>
 </plugin>
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 (file)
index 0000000..ed9a58c
--- /dev/null
@@ -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 (file)
index 0000000..c40c262
--- /dev/null
@@ -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<String, String> 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<TmfTreeColumnData> getColumnData() {
+                /* All columns are sortable */
+                List<TmfTreeColumnData> 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<ITmfTreeViewerEntry> 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<ITmfTreeViewerEntry> entryList = root.getChildren();
+
+        try {
+            List<ITmfStateInterval> memoryStates = ss.queryFullState(start);
+            List<Integer> 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 (file)
index 0000000..1bfa5f0
--- /dev/null
@@ -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 (file)
index 0000000..11e3a97
--- /dev/null
@@ -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<ITmfStateInterval> kernelState = ss.queryFullState(t);
+
+                /* The subattributes of the root are the different threads */
+                List<Integer> 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<ITmfStateInterval> kernelState = ss.queryFullState(end);
+            List<Integer> 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 (file)
index 0000000..975a46d
--- /dev/null
@@ -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 (file)
index 0000000..eaf2514
--- /dev/null
@@ -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
index 18dd70fc8aadee81a7cad71067db2e28ef0624f4..349e10c4b1055464bb6cba3ffd7a9fb5e3f2c350 100644 (file)
@@ -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;
     }
index 72c26b0611bf346e8cd22c72d8e54fae08f58202..af7b1796a124c72e3c11c5c905fb57a5784787c9 100644 (file)
@@ -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
     // ------------------------------------------------------------------------
index 4fa93c93e022136a0a688f538c6e32ebf063e3b5..2a0c93c3a4acf94640e0ff3107c6543f7cd31e57 100644 (file)
@@ -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$
     }
-
 }
This page took 0.043131 seconds and 5 git commands to generate.