1 /*******************************************************************************
2 * Copyright (c) 2015 Ericsson
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Matthew Khouzam - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.tracecompass
.internal
.analysis
.os
.linux
.core
.kernel
.handlers
;
15 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
17 import org
.eclipse
.tracecompass
.analysis
.os
.linux
.core
.kernel
.LinuxValues
;
18 import org
.eclipse
.tracecompass
.analysis
.os
.linux
.core
.kernel
.StateValues
;
19 import org
.eclipse
.tracecompass
.analysis
.os
.linux
.core
.trace
.IKernelAnalysisEventLayout
;
20 import org
.eclipse
.tracecompass
.internal
.analysis
.os
.linux
.core
.kernel
.Attributes
;
21 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystemBuilder
;
22 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.AttributeNotFoundException
;
23 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
24 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.TmfStateValue
;
25 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEvent
;
26 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEventField
;
29 * Scheduler switch event handler
31 public class SchedSwitchHandler
extends KernelEventHandler
{
39 public SchedSwitchHandler(IKernelAnalysisEventLayout layout
) {
44 public void handleEvent(ITmfStateSystemBuilder ss
, ITmfEvent event
) throws AttributeNotFoundException
{
45 Integer cpu
= KernelEventHandlerUtils
.getCpu(event
);
50 ITmfEventField content
= event
.getContent();
51 String prevProcessName
= checkNotNull((String
) content
.getField(getLayout().fieldPrevComm()).getValue());
52 Integer prevTid
= ((Long
) content
.getField(getLayout().fieldPrevTid()).getValue()).intValue();
53 Long prevState
= checkNotNull((Long
) content
.getField(getLayout().fieldPrevState()).getValue());
54 Integer prevPrio
= ((Long
) content
.getField(getLayout().fieldPrevPrio()).getValue()).intValue();
55 String nextProcessName
= checkNotNull((String
) content
.getField(getLayout().fieldNextComm()).getValue());
56 Integer nextTid
= ((Long
) content
.getField(getLayout().fieldNextTid()).getValue()).intValue();
57 Integer nextPrio
= ((Long
) content
.getField(getLayout().fieldNextPrio()).getValue()).intValue();
59 /* Will never return null since "cpu" is null checked */
60 String formerThreadAttributeName
= Attributes
.buildThreadAttributeName(prevTid
, cpu
);
61 String currenThreadAttributeName
= Attributes
.buildThreadAttributeName(nextTid
, cpu
);
63 int nodeThreads
= KernelEventHandlerUtils
.getNodeThreads(ss
);
64 int formerThreadNode
= ss
.getQuarkRelativeAndAdd(nodeThreads
, formerThreadAttributeName
);
65 int newCurrentThreadNode
= ss
.getQuarkRelativeAndAdd(nodeThreads
, currenThreadAttributeName
);
67 long timestamp
= KernelEventHandlerUtils
.getTimestamp(event
);
68 /* Set the status of the process that got scheduled out. */
69 setOldProcessStatus(ss
, prevState
, formerThreadNode
, timestamp
);
71 /* Set the status of the new scheduled process */
72 KernelEventHandlerUtils
.setProcessToRunning(timestamp
, newCurrentThreadNode
, ss
);
74 /* Set the exec name of the former process */
75 setNewProcessExecName(ss
, prevProcessName
, formerThreadNode
, timestamp
);
77 /* Set the exec name of the new process */
78 setNewProcessExecName(ss
, nextProcessName
, newCurrentThreadNode
, timestamp
);
80 /* Set the current prio for the former process */
81 setNewProcessPrio(ss
, prevPrio
, formerThreadNode
, timestamp
);
83 /* Set the current prio for the new process */
84 setNewProcessPrio(ss
, nextPrio
, newCurrentThreadNode
, timestamp
);
86 /* Make sure the PPID and system_call sub-attributes exist */
87 ss
.getQuarkRelativeAndAdd(newCurrentThreadNode
, Attributes
.SYSTEM_CALL
);
88 ss
.getQuarkRelativeAndAdd(newCurrentThreadNode
, Attributes
.PPID
);
90 /* Set the current scheduled process on the relevant CPU */
91 int currentCPUNode
= KernelEventHandlerUtils
.getCurrentCPUNode(cpu
, ss
);
92 setCpuProcess(ss
, nextTid
, timestamp
, currentCPUNode
);
94 /* Set the status of the CPU itself */
95 setCpuStatus(ss
, nextTid
, newCurrentThreadNode
, timestamp
, currentCPUNode
);
98 private static void setOldProcessStatus(ITmfStateSystemBuilder ss
, Long prevState
, Integer formerThreadNode
, long timestamp
) throws AttributeNotFoundException
{
101 * Empirical observations and look into the linux code have
102 * shown that the TASK_STATE_MAX flag is used internally and
103 * |'ed with other states, most often the running state, so it
104 * is ignored from the prevState value.
106 * Since Linux 4.1, the TASK_NOLOAD state was created and
107 * TASK_STATE_MAX is now 2048. We use TASK_NOLOAD as the new max
108 * because it does not modify the displayed state value.
110 int state
= (int) (prevState
& (LinuxValues
.TASK_NOLOAD
- 1));
112 if (isRunning(state
)) {
113 value
= StateValues
.PROCESS_STATUS_WAIT_FOR_CPU_VALUE
;
114 } else if (isWaiting(state
)) {
115 value
= StateValues
.PROCESS_STATUS_WAIT_BLOCKED_VALUE
;
116 } else if (isDead(state
)) {
117 value
= TmfStateValue
.nullValue();
119 value
= StateValues
.PROCESS_STATUS_WAIT_UNKNOWN_VALUE
;
121 int quark
= ss
.getQuarkRelativeAndAdd(formerThreadNode
, Attributes
.STATUS
);
122 ss
.modifyAttribute(timestamp
, value
, quark
);
126 private static boolean isDead(int state
) {
127 return (state
& LinuxValues
.TASK_DEAD
) != 0;
130 private static boolean isWaiting(int state
) {
131 return (state
& (LinuxValues
.TASK_INTERRUPTIBLE
| LinuxValues
.TASK_UNINTERRUPTIBLE
)) != 0;
134 private static boolean isRunning(int state
) {
135 // special case, this means ALL STATES ARE 0
136 // this is effectively an anti-state
140 private static void setCpuStatus(ITmfStateSystemBuilder ss
, Integer nextTid
, Integer newCurrentThreadNode
, long timestamp
, int currentCPUNode
) throws AttributeNotFoundException
{
142 ITmfStateValue value
;
144 /* Check if the entering process is in kernel or user mode */
145 quark
= ss
.getQuarkRelativeAndAdd(newCurrentThreadNode
, Attributes
.SYSTEM_CALL
);
146 ITmfStateValue queryOngoingState
= ss
.queryOngoingState(quark
);
147 if (queryOngoingState
.isNull()) {
148 value
= StateValues
.CPU_STATUS_RUN_USERMODE_VALUE
;
150 value
= StateValues
.CPU_STATUS_RUN_SYSCALL_VALUE
;
153 value
= StateValues
.CPU_STATUS_IDLE_VALUE
;
155 quark
= ss
.getQuarkRelativeAndAdd(currentCPUNode
, Attributes
.STATUS
);
156 ss
.modifyAttribute(timestamp
, value
, quark
);
159 private static void setCpuProcess(ITmfStateSystemBuilder ss
, Integer nextTid
, long timestamp
, int currentCPUNode
) throws AttributeNotFoundException
{
161 ITmfStateValue value
;
162 quark
= ss
.getQuarkRelativeAndAdd(currentCPUNode
, Attributes
.CURRENT_THREAD
);
163 value
= TmfStateValue
.newValueInt(nextTid
);
164 ss
.modifyAttribute(timestamp
, value
, quark
);
167 private static void setNewProcessPrio(ITmfStateSystemBuilder ss
, Integer nextPrio
, Integer newCurrentThreadNode
, long timestamp
) throws AttributeNotFoundException
{
169 ITmfStateValue value
;
170 quark
= ss
.getQuarkRelativeAndAdd(newCurrentThreadNode
, Attributes
.PRIO
);
171 value
= TmfStateValue
.newValueInt(nextPrio
);
172 ss
.modifyAttribute(timestamp
, value
, quark
);
175 private static void setNewProcessExecName(ITmfStateSystemBuilder ss
, String nextProcessName
, Integer newCurrentThreadNode
, long timestamp
) throws AttributeNotFoundException
{
177 ITmfStateValue value
;
178 quark
= ss
.getQuarkRelativeAndAdd(newCurrentThreadNode
, Attributes
.EXEC_NAME
);
179 value
= TmfStateValue
.newValueString(nextProcessName
);
180 ss
.modifyAttribute(timestamp
, value
, quark
);