blob: f88ace948fbdfebfe227abc3cf819ec54c0f638f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 É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 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.internal.lttng2.kernel.core.analysis.graph.handlers;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import org.eclipse.tracecompass.analysis.os.linux.core.execution.graph.OsExecutionGraphProvider;
import org.eclipse.tracecompass.analysis.os.linux.core.execution.graph.OsExecutionGraphProvider.Context;
import org.eclipse.tracecompass.analysis.os.linux.core.execution.graph.OsInterruptContext;
import org.eclipse.tracecompass.analysis.os.linux.core.execution.graph.OsSystemModel;
import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelAnalysisEventLayout;
import org.eclipse.tracecompass.common.core.NonNullUtils;
import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
import org.eclipse.tracecompass.tmf.core.event.aspect.TmfCpuAspect;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
/**
* Event Handler to handle the interrupt context stack of the model
*
* @author Francis Giraldeau
* @author Geneviève Bastien
*/
public class EventContextHandler extends BaseHandler {
private final Map<String, Consumer<ITmfEvent>> fHandlers = new HashMap<>();
private final Set<IKernelAnalysisEventLayout> fLayouts = new HashSet<>();
private final Consumer<ITmfEvent> fDefault = event -> {
// Do nothing
};
private final Consumer<ITmfEvent> fSoftIrqEntryHandler = event -> pushInterruptContext(event, Context.SOFTIRQ);
private final Consumer<ITmfEvent> fSoftIrqExitHandler = event -> popInterruptContext(event, Context.SOFTIRQ);
private final Consumer<ITmfEvent> fHRTimerExpireEntry = event -> pushInterruptContext(event, Context.HRTIMER);
private final Consumer<ITmfEvent> fHRTimerExpireExit = event -> popInterruptContext(event, Context.HRTIMER);
private final Consumer<ITmfEvent> fIrqHandlerEntry = event -> pushInterruptContext(event, Context.IRQ);
private final Consumer<ITmfEvent> fIrqHandlerExit = event -> popInterruptContext(event, Context.IRQ);
private final Consumer<ITmfEvent> fIpiEntry = event -> pushInterruptContext(event, Context.IPI);
private final Consumer<ITmfEvent> fIpiExit = event -> popInterruptContext(event, Context.IPI);
private final Consumer<ITmfEvent> fCompleteHandlerEntry = event -> pushInterruptContext(event, Context.COMPLETE_IRQ);
private final Consumer<ITmfEvent> fCompleteHandlerExit = event -> popInterruptContext(event, Context.COMPLETE_IRQ);
private final Consumer<ITmfEvent> fPacketReceptionEntry = event -> pushInterruptContext(event, Context.PACKET_RECEPTION);
private final Consumer<ITmfEvent> fPacketReceptionExit = event -> popInterruptContext(event, Context.PACKET_RECEPTION);
/**
* Constructor
*
* @param provider
* The parent graph provider
* @param priority
* The priority of this handler. It will determine when it will be
* executed
*/
public EventContextHandler(OsExecutionGraphProvider provider, int priority) {
super(provider, priority);
}
@Override
public void handleEvent(ITmfEvent event) {
IKernelAnalysisEventLayout eventLayout = getProvider().getEventLayout(event.getTrace());
if (!fLayouts.contains(eventLayout)) {
populateHandlerMap(eventLayout);
fLayouts.add(eventLayout);
}
fHandlers.getOrDefault(event.getName(), fDefault).accept(event);
}
private void populateHandlerMap(IKernelAnalysisEventLayout eventLayout) {
fHandlers.put(eventLayout.eventSoftIrqEntry(), fSoftIrqEntryHandler);
fHandlers.put(eventLayout.eventSoftIrqExit(), fSoftIrqExitHandler);
fHandlers.put(eventLayout.eventHRTimerExpireEntry(), fHRTimerExpireEntry);
fHandlers.put(eventLayout.eventHRTimerExpireExit(), fHRTimerExpireExit);
fHandlers.put(eventLayout.eventIrqHandlerEntry(), fIrqHandlerEntry);
fHandlers.put(eventLayout.eventIrqHandlerExit(), fIrqHandlerExit);
for (String ipiName : eventLayout.getIPIIrqVectorsEntries()) {
fHandlers.put(ipiName, fIpiEntry);
}
for (String ipiName : eventLayout.getIPIIrqVectorsEntries()) {
fHandlers.put(ipiName, fIpiExit);
}
fHandlers.put(eventLayout.eventIrqEntry(), fCompleteHandlerEntry);
fHandlers.put(eventLayout.eventIrqExit(), fCompleteHandlerExit);
for (String networkEvent : eventLayout.eventsNetworkReceiveEntry()) {
fHandlers.put(networkEvent, fPacketReceptionEntry);
}
for (String networkEvent : eventLayout.eventsNetworkReceiveExit()) {
fHandlers.put(networkEvent, fPacketReceptionExit);
}
}
private void pushInterruptContext(ITmfEvent event, Context ctx) {
Integer cpu = NonNullUtils.checkNotNull(TmfTraceUtils.resolveIntEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event));
OsSystemModel system = getProvider().getSystem();
OsInterruptContext interruptCtx = new OsInterruptContext(event, ctx);
system.pushContextStack(event.getTrace().getHostId(), cpu, interruptCtx);
}
private void popInterruptContext(ITmfEvent event, Context ctx) {
Integer cpu = NonNullUtils.checkNotNull(TmfTraceUtils.resolveIntEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event));
OsSystemModel system = getProvider().getSystem();
/* TODO: add a warning bookmark if the interrupt context is not coherent */
OsInterruptContext interruptCtx = system.peekContextStack(event.getTrace().getHostId(), cpu);
if (interruptCtx.getContext() == ctx) {
system.popContextStack(event.getTrace().getHostId(), cpu);
}
}
}