blob: 25ddeb3615aa2a4bc3f299be012ef5d9a9c79d5d [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 org.eclipse.tracecompass.analysis.os.linux.core.execution.graph.OsExecutionGraphProvider;
import org.eclipse.tracecompass.analysis.os.linux.core.execution.graph.OsSystemModel;
import org.eclipse.tracecompass.analysis.os.linux.core.execution.graph.OsWorker;
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.model.ProcessStatus;
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.model.EventField;
import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
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 {
private static final String TASK_UNKNOWN = "Unknown"; //$NON-NLS-1$
/**
* Constructor
*
* @param provider
* The parent graph provider
* @param priority
* The priority of this handler. It will determine when it will be
* executed
*/
public TraceEventHandlerSched(OsExecutionGraphProvider provider, int priority) {
super(provider, priority);
}
@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());
OsSystemModel system = getProvider().getSystem();
ITmfEventField content = event.getContent();
Integer next = content.getFieldValue(Integer.class, eventLayout.fieldNextTid());
Integer prev = content.getFieldValue(Integer.class, eventLayout.fieldPrevTid());
if (next == null || prev == null) {
return;
}
long ts = event.getTimestamp().getValue();
Integer prev_state = content.getFieldValue(Integer.class, eventLayout.fieldPrevState());
prev_state = prev_state == null ? 0 : 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);
OsWorker nextTask = system.findWorker(nextHt);
if (nextTask == null) {
String name = EventField.getOrDefault(event, eventLayout.fieldNextComm(), NonNullUtils.checkNotNull(Messages.TraceEventHandlerSched_UnknownThreadName));
nextTask = new OsWorker(nextHt, name, ts);
system.addWorker(nextTask);
}
nextTask.setStatus(ProcessStatus.RUN);
HostThread prevHt = new HostThread(host, prev);
OsWorker prevTask = system.findWorker(prevHt);
String name = EventField.getOrDefault(event, eventLayout.fieldPrevComm(), NonNullUtils.checkNotNull(Messages.TraceEventHandlerSched_UnknownThreadName));
if (prevTask == null) {
prevTask = new OsWorker(prevHt, name, ts);
system.addWorker(prevTask);
} else if (prev != 0) {
/* update the process name if changed at runtime */
prevTask.setName(name);
}
/* 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());
OsSystemModel system = getProvider().getSystem();
ITmfEventField content = event.getContent();
Integer childTid = content.getFieldValue(Integer.class, eventLayout.fieldChildTid());
String name = content.getFieldValue(String.class, eventLayout.fieldChildComm());
if (childTid == null) {
return;
}
name = (name == null ? String.valueOf(childTid) : name);
long ts = event.getTimestamp().getValue();
HostThread childHt = new HostThread(host, childTid);
OsWorker childTask = system.findWorker(childHt);
if (childTask == null) {
childTask = new OsWorker(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());
OsSystemModel system = getProvider().getSystem();
Integer tid = event.getContent().getFieldValue(Integer.class, eventLayout.fieldTid());
if (tid == null) {
return;
}
HostThread targetHt = new HostThread(host, tid);
OsWorker target = system.findWorker(targetHt);
OsWorker current = system.getWorkerOnCpu(host, cpu);
if (target == null) {
String name = EventField.getOrDefault(event, eventLayout.fieldComm(), NonNullUtils.checkNotNull(Messages.TraceEventHandlerSched_UnknownThreadName));
target = new OsWorker(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());
OsSystemModel system = getProvider().getSystem();
Integer tid = event.getContent().getFieldValue(Integer.class, eventLayout.fieldTid());
if (tid == null) {
return;
}
OsWorker 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());
OsSystemModel system = getProvider().getSystem();
String filename = event.getContent().getFieldValue(String.class, eventLayout.fieldFilename());
OsWorker task = system.getWorkerOnCpu(host, cpu);
if (task == null) {
return;
}
task.setName(filename == null ? TASK_UNKNOWN : filename);
}
}