/*******************************************************************************
* 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 v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.handlers;
import org.eclipse.tracecompass.analysis.os.linux.core.kernel.LinuxValues;
import org.eclipse.tracecompass.analysis.os.linux.core.model.HostThread;
import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelAnalysisEventLayout;
import org.eclipse.tracecompass.common.core.NonNullUtils;
import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building.LttngKernelExecGraphProvider;
import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.building.LttngKernelExecGraphProvider.ProcessStatus;
import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model.EventField;
import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model.LttngSystemModel;
import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.graph.model.LttngWorker;
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;
/**
* Provides the current task running on a CPU according to scheduling events
*
* @author Francis Giraldeau
* @author Geneviève Bastien
*/
public class TraceEventHandlerSched extends BaseHandler {
/**
* Constructor
*
* @param provider
* The parent graph provider
*/
public TraceEventHandlerSched(LttngKernelExecGraphProvider provider) {
super(provider);
}
@Override
public void handleEvent(ITmfEvent ev) {
String eventName = ev.getName();
IKernelAnalysisEventLayout eventLayout = getProvider().getEventLayout(ev.getTrace());
if (eventName.equals(eventLayout.eventSchedSwitch())) {
handleSchedSwitch(ev);
} else if (eventName.equals(eventLayout.eventSchedProcessFork())) {
handleSchedProcessFork(ev);
} else if (eventName.equals(eventLayout.eventSchedProcessExit())) {
handleSchedProcessExit(ev);
} else if (eventName.equals(eventLayout.eventSchedProcessExec())) {
handleSchedProcessExec(ev);
} else if (isWakeupEvent(ev)) {
handleSchedWakeup(ev);
}
}
private void handleSchedSwitch(ITmfEvent event) {
Integer cpu = NonNullUtils.checkNotNull(TmfTraceUtils.resolveIntEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event));
IKernelAnalysisEventLayout eventLayout = getProvider().getEventLayout(event.getTrace());
LttngSystemModel system = getProvider().getSystem();
Integer next = EventField.getInt(event, eventLayout.fieldNextTid());
Integer prev = EventField.getInt(event, eventLayout.fieldPrevTid());
long ts = event.getTimestamp().getValue();
long prev_state = EventField.getLong(event, eventLayout.fieldPrevState());
prev_state = (long) ((int) prev_state) & (LinuxValues.TASK_STATE_RUNNING | LinuxValues.TASK_INTERRUPTIBLE | LinuxValues.TASK_UNINTERRUPTIBLE);
String host = event.getTrace().getHostId();
system.cacheTidOnCpu(cpu, new HostThread(event.getTrace().getHostId(), next));
HostThread nextHt = new HostThread(host, next);
LttngWorker nextTask = system.findWorker(nextHt);
if (nextTask == null) {
String name = EventField.getOrDefault(event, eventLayout.fieldNextComm(), NonNullUtils.checkNotNull(Messages.TraceEventHandlerSched_UnknownThreadName));
nextTask = new LttngWorker(nextHt, name, ts);
system.addWorker(nextTask);
}
nextTask.setStatus(ProcessStatus.RUN);
HostThread prevHt = new HostThread(host, prev);
LttngWorker prevTask = system.findWorker(prevHt);
if (prevTask == null) {
String name = EventField.getOrDefault(event, eventLayout.fieldPrevComm(), NonNullUtils.checkNotNull(Messages.TraceEventHandlerSched_UnknownThreadName));
prevTask = new LttngWorker(prevHt, name, ts);
system.addWorker(prevTask);
}
/* prev_state == 0 means runnable, thus waits for cpu */
if (prev_state == 0) {
prevTask.setStatus(ProcessStatus.WAIT_CPU);
} else {
prevTask.setStatus(ProcessStatus.WAIT_BLOCKED);
}
}
private void handleSchedProcessFork(ITmfEvent event) {
String host = event.getTrace().getHostId();
IKernelAnalysisEventLayout eventLayout = getProvider().getEventLayout(event.getTrace());
LttngSystemModel system = getProvider().getSystem();
Integer childTid = EventField.getInt(event, eventLayout.fieldChildTid());
String name = EventField.getString(event, eventLayout.fieldChildComm());
long ts = event.getTimestamp().getValue();
HostThread childHt = new HostThread(host, childTid);
LttngWorker childTask = system.findWorker(childHt);
if (childTask == null) {
childTask = new LttngWorker(childHt, name, ts);
system.addWorker(childTask);
}
childTask.setStatus(ProcessStatus.WAIT_FORK);
}
private void handleSchedWakeup(ITmfEvent event) {
String host = event.getTrace().getHostId();
Integer cpu = NonNullUtils.checkNotNull(TmfTraceUtils.resolveIntEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event));
IKernelAnalysisEventLayout eventLayout = getProvider().getEventLayout(event.getTrace());
LttngSystemModel system = getProvider().getSystem();
Integer tid = EventField.getInt(event, eventLayout.fieldTid());
HostThread targetHt = new HostThread(host, tid);
LttngWorker target = system.findWorker(targetHt);
LttngWorker current = system.getWorkerOnCpu(host, cpu);
if (target == null) {
String name = EventField.getOrDefault(event, eventLayout.fieldComm(), NonNullUtils.checkNotNull(Messages.TraceEventHandlerSched_UnknownThreadName));
target = new LttngWorker(targetHt, name, event.getTimestamp().getValue());
system.addWorker(target);
target.setStatus(ProcessStatus.WAIT_BLOCKED);
}
// spurious wakeup
ProcessStatus status = target.getStatus();
if ((current != null && target.getHostThread().equals(current.getHostThread())) ||
status == ProcessStatus.WAIT_CPU) {
return;
}
if (status == ProcessStatus.WAIT_BLOCKED ||
status == ProcessStatus.WAIT_FORK ||
status == ProcessStatus.UNKNOWN) {
target.setStatus(ProcessStatus.WAIT_CPU);
return;
}
}
private void handleSchedProcessExit(ITmfEvent event) {
String host = event.getTrace().getHostId();
IKernelAnalysisEventLayout eventLayout = getProvider().getEventLayout(event.getTrace());
LttngSystemModel system = getProvider().getSystem();
Integer tid = EventField.getInt(event, eventLayout.fieldTid());
LttngWorker task = system.findWorker(new HostThread(host, tid));
if (task == null) {
return;
}
task.setStatus(ProcessStatus.EXIT);
}
private void handleSchedProcessExec(ITmfEvent event) {
String host = event.getTrace().getHostId();
Integer cpu = NonNullUtils.checkNotNull(TmfTraceUtils.resolveIntEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event));
IKernelAnalysisEventLayout eventLayout = getProvider().getEventLayout(event.getTrace());
LttngSystemModel system = getProvider().getSystem();
String filename = EventField.getString(event, eventLayout.fieldFilename());
LttngWorker task = system.getWorkerOnCpu(host, cpu);
if (task == null) {
return;
}
task.setName(filename);
}
}