/*******************************************************************************
* Copyright (c) 2012, 2015 Ericsson
* Copyright (c) 2010, 2011 École Polytechnique de Montréal
* Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
*
* 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.core.kernel;
import java.util.Map;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelAnalysisEventLayout;
import org.eclipse.tracecompass.common.core.NonNullUtils;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.Activator;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers.IPIEntryHandler;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers.IPIExitHandler;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers.IrqEntryHandler;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers.IrqExitHandler;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers.KernelEventHandler;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers.PiSetprioHandler;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers.ProcessExitHandler;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers.ProcessForkHandler;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers.ProcessFreeHandler;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers.SchedSwitchHandler;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers.SchedWakeupHandler;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers.SoftIrqEntryHandler;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers.SoftIrqExitHandler;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers.SoftIrqRaiseHandler;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers.StateDumpHandler;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers.SysEntryHandler;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers.SysExitHandler;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
import org.eclipse.tracecompass.tmf.core.statesystem.AbstractTmfStateProvider;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import com.google.common.collect.ImmutableMap;
/**
* This is the state change input plugin for the state system which handles the
* kernel traces.
*
* Attribute tree:
*
* <pre>
* |- CPUs
* | |- <CPU number> -> CPU Status
* | | |- CURRENT_THREAD
* | | |- SOFT_IRQS
* | | | |- <Soft IRQ number> -> Soft IRQ Status
* | | |- IRQS
* | | | |- <IRQ number> -> IRQ Status
* |- THREADS
* | |- <Thread number> -> Thread Status
* | | |- PPID
* | | |- EXEC_NAME
* | | |- PRIO
* | | |- SYSTEM_CALL
* </pre>
*
* @author Alexandre Montplaisir
*/
public class KernelStateProvider extends AbstractTmfStateProvider {
// ------------------------------------------------------------------------
// Static fields
// ------------------------------------------------------------------------
/**
* Version number of this state provider. Please bump this if you modify the
* contents of the generated state history in some way.
*/
private static final int VERSION = 23;
// ------------------------------------------------------------------------
// Fields
// ------------------------------------------------------------------------
private final Map<String, KernelEventHandler> fEventNames;
private final IKernelAnalysisEventLayout fLayout;
private final KernelEventHandler fSysEntryHandler;
private final KernelEventHandler fSysExitHandler;
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
/**
* Instantiate a new state provider plugin.
*
* @param trace
* The LTTng 2.0 kernel trace directory
* @param layout
* The event layout to use for this state provider. Usually
* depending on the tracer implementation.
*/
public KernelStateProvider(ITmfTrace trace, IKernelAnalysisEventLayout layout) {
super(trace, "Kernel"); //$NON-NLS-1$
fLayout = layout;
fEventNames = buildEventNames(layout);
fSysEntryHandler = new SysEntryHandler(fLayout);
fSysExitHandler = new SysExitHandler(fLayout);
}
// ------------------------------------------------------------------------
// Event names management
// ------------------------------------------------------------------------
private static Map<String, KernelEventHandler> buildEventNames(IKernelAnalysisEventLayout layout) {
ImmutableMap.Builder<String, KernelEventHandler> builder = ImmutableMap.builder();
builder.put(layout.eventIrqHandlerEntry(), new IrqEntryHandler(layout));
builder.put(layout.eventIrqHandlerExit(), new IrqExitHandler(layout));
builder.put(layout.eventSoftIrqEntry(), new SoftIrqEntryHandler(layout));
builder.put(layout.eventSoftIrqExit(), new SoftIrqExitHandler(layout));
builder.put(layout.eventSoftIrqRaise(), new SoftIrqRaiseHandler(layout));
builder.put(layout.eventSchedSwitch(), new SchedSwitchHandler(layout));
builder.put(layout.eventSchedPiSetprio(), new PiSetprioHandler(layout));
builder.put(layout.eventSchedProcessFork(), new ProcessForkHandler(layout));
builder.put(layout.eventSchedProcessExit(), new ProcessExitHandler(layout));
builder.put(layout.eventSchedProcessFree(), new ProcessFreeHandler(layout));
builder.put(layout.eventSchedProcessWaking(), new SchedWakeupHandler(layout));
for (String s : layout.getIPIIrqVectorsEntries()) {
builder.put(s, new IPIEntryHandler(layout));
}
for (String s : layout.getIPIIrqVectorsExits()) {
builder.put(s, new IPIExitHandler(layout));
}
final String eventStatedumpProcessState = layout.eventStatedumpProcessState();
if (eventStatedumpProcessState != null) {
builder.put(eventStatedumpProcessState, new StateDumpHandler(layout));
}
for (String eventSchedWakeup : layout.eventsSchedWakeup()) {
builder.put(eventSchedWakeup, new SchedWakeupHandler(layout));
}
return builder.build();
}
// ------------------------------------------------------------------------
// IStateChangeInput
// ------------------------------------------------------------------------
@Override
public int getVersion() {
return VERSION;
}
@Override
public KernelStateProvider getNewInstance() {
return new KernelStateProvider(this.getTrace(), fLayout);
}
@Override
protected void eventHandle(@Nullable ITmfEvent event) {
if (event == null) {
return;
}
final String eventName = event.getName();
try {
final ITmfStateSystemBuilder ss = NonNullUtils.checkNotNull(getStateSystemBuilder());
/*
* Feed event to the history system if it's known to cause a state
* transition.
*/
KernelEventHandler handler = fEventNames.get(eventName);
if (handler == null) {
if (isSyscallExit(eventName)) {
handler = fSysExitHandler;
} else if (isSyscallEntry(eventName)) {
handler = fSysEntryHandler;
}
}
if (handler != null) {
handler.handleEvent(ss, event);
}
} catch (AttributeNotFoundException ae) {
/*
* This would indicate a problem with the logic of the manager here,
* so it shouldn't happen.
*/
Activator.getDefault().logError("Attribute not found: " + ae.getMessage(), ae); //$NON-NLS-1$
} catch (TimeRangeException tre) {
/*
* This would happen if the events in the trace aren't ordered
* chronologically, which should never be the case ...
*/
Activator.getDefault().logError("TimeRangeExcpetion caught in the state system's event manager.\n" + //$NON-NLS-1$
"Are the events in the trace correctly ordered?\n" + tre.getMessage(), tre); //$NON-NLS-1$
} catch (StateValueTypeException sve) {
/*
* This would happen if we were trying to push/pop attributes not of
* type integer. Which, once again, should never happen.
*/
Activator.getDefault().logError("State value error: " + sve.getMessage(), sve); //$NON-NLS-1$
}
}
private boolean isSyscallEntry(String eventName) {
return (eventName.startsWith(fLayout.eventSyscallEntryPrefix())
|| eventName.startsWith(fLayout.eventCompatSyscallEntryPrefix()));
}
private boolean isSyscallExit(String eventName) {
return (eventName.startsWith(fLayout.eventSyscallExitPrefix()) ||
eventName.startsWith(fLayout.eventCompatSyscallExitPrefix()));
}
}