blob: 21136576ece360e03a39642df12e74b04fc95b94 [file] [log] [blame]
/**********************************************************************
* 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 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipse.tracecompass.analysis.os.linux.core.kernelmemoryusage;
import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
import org.eclipse.core.runtime.NullProgressMonitor;
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.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.
*
* Attribute tree:
*
* <pre>
* |- <TID number> -> current memory usage
* | |- THREAD_LOWEST_MEMORY_VALUE -> lowest memory value for thread
* </pre>
*
* @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 = 2;
private static final int PAGE_SIZE = 4096;
private static final long MAX_ORDER = 62; // Larger than that would overflow
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 {
String fieldOrder = fLayout.fieldOrder();
if (fieldOrder != null) {
Long value = event.getContent().getFieldValue(Long.class, fieldOrder);
if (value != null) {
if (value > MAX_ORDER || value < 0) {
Activator.getDefault().logWarning("Order of alloc is outside of acceptable range : " + value); //$NON-NLS-1$
return;
}
inc <<= value;
}
}
ITmfStateSystemBuilder ss = checkNotNull(getStateSystemBuilder());
long ts = event.getTimestamp().toNanos();
Integer tidField = KernelTidAspect.INSTANCE.resolve(event, true, new NullProgressMonitor());
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, currentMemoryValue, lowestMemoryQuark);
}
} catch (AttributeNotFoundException | InterruptedException e) {
Activator.getDefault().logError(String.valueOf(e.getMessage()), e);
}
}
}