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
.lttng
.scope
.lttng
.kernel
.core
.analysis
.os
.handlers
.internal
;
15 import static java
.util
.Objects
.requireNonNull
;
17 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEvent
;
18 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEventField
;
19 import org
.lttng
.scope
.lttng
.kernel
.core
.analysis
.os
.Attributes
;
20 import org
.lttng
.scope
.lttng
.kernel
.core
.analysis
.os
.LinuxValues
;
21 import org
.lttng
.scope
.lttng
.kernel
.core
.analysis
.os
.StateValues
;
22 import org
.lttng
.scope
.lttng
.kernel
.core
.trace
.layout
.ILttngKernelEventLayout
;
24 import ca
.polymtl
.dorsal
.libdelorean
.ITmfStateSystemBuilder
;
25 import ca
.polymtl
.dorsal
.libdelorean
.exceptions
.AttributeNotFoundException
;
26 import ca
.polymtl
.dorsal
.libdelorean
.exceptions
.StateValueTypeException
;
27 import ca
.polymtl
.dorsal
.libdelorean
.statevalue
.ITmfStateValue
;
28 import ca
.polymtl
.dorsal
.libdelorean
.statevalue
.TmfStateValue
;
31 * Scheduler switch event handler
33 public class SchedSwitchHandler
extends KernelEventHandler
{
41 public SchedSwitchHandler(ILttngKernelEventLayout layout
) {
46 public void handleEvent(ITmfStateSystemBuilder ss
, ITmfEvent event
) throws AttributeNotFoundException
{
47 Integer cpu
= KernelEventHandlerUtils
.getCpu(event
);
52 ITmfEventField content
= event
.getContent();
53 String prevProcessName
= requireNonNull((String
) content
.getField(getLayout().fieldPrevComm()).getValue());
54 Integer prevTid
= ((Long
) content
.getField(getLayout().fieldPrevTid()).getValue()).intValue();
55 Long prevState
= requireNonNull((Long
) content
.getField(getLayout().fieldPrevState()).getValue());
56 Integer prevPrio
= ((Long
) content
.getField(getLayout().fieldPrevPrio()).getValue()).intValue();
57 String nextProcessName
= requireNonNull((String
) content
.getField(getLayout().fieldNextComm()).getValue());
58 Integer nextTid
= ((Long
) content
.getField(getLayout().fieldNextTid()).getValue()).intValue();
59 Integer nextPrio
= ((Long
) content
.getField(getLayout().fieldNextPrio()).getValue()).intValue();
61 /* Will never return null since "cpu" is null checked */
62 String formerThreadAttributeName
= Attributes
.buildThreadAttributeName(prevTid
, cpu
);
63 String currenThreadAttributeName
= Attributes
.buildThreadAttributeName(nextTid
, cpu
);
65 int nodeThreads
= KernelEventHandlerUtils
.getNodeThreads(ss
);
66 int formerThreadNode
= ss
.getQuarkRelativeAndAdd(nodeThreads
, formerThreadAttributeName
);
67 int newCurrentThreadNode
= ss
.getQuarkRelativeAndAdd(nodeThreads
, currenThreadAttributeName
);
69 long timestamp
= KernelEventHandlerUtils
.getTimestamp(event
);
71 * Set the status of the process that got scheduled out. This will also
72 * set it's current CPU run queue accordingly.
74 setOldProcessStatus(ss
, prevState
, formerThreadNode
, cpu
, timestamp
);
76 /* Set the status of the new scheduled process */
77 KernelEventHandlerUtils
.setProcessToRunning(timestamp
, newCurrentThreadNode
, ss
);
80 * Set the current CPU run queue of the new process. Should be already
81 * set if we've seen the previous sched_wakeup, but doesn't hurt to set
84 int quark
= ss
.getQuarkRelativeAndAdd(newCurrentThreadNode
, Attributes
.CURRENT_CPU_RQ
);
85 ITmfStateValue value
= TmfStateValue
.newValueInt(cpu
);
86 ss
.modifyAttribute(timestamp
, value
, quark
);
88 /* Set the exec name of the former process */
89 setProcessExecName(ss
, prevProcessName
, formerThreadNode
, timestamp
);
91 /* Set the exec name of the new process */
92 setProcessExecName(ss
, nextProcessName
, newCurrentThreadNode
, timestamp
);
94 /* Set the current prio for the former process */
95 setProcessPrio(ss
, prevPrio
, formerThreadNode
, timestamp
);
97 /* Set the current prio for the new process */
98 setProcessPrio(ss
, nextPrio
, newCurrentThreadNode
, timestamp
);
100 /* Set the current scheduled process on the relevant CPU */
101 int currentCPUNode
= KernelEventHandlerUtils
.getCurrentCPUNode(cpu
, ss
);
102 setCpuProcess(ss
, nextTid
, timestamp
, currentCPUNode
);
104 /* Set the status of the CPU itself */
105 setCpuStatus(ss
, nextTid
, newCurrentThreadNode
, timestamp
, currentCPUNode
);
108 private static void setOldProcessStatus(ITmfStateSystemBuilder ss
,
109 long prevState
, int formerThreadNode
, int cpu
, long timestamp
) {
110 ITmfStateValue value
;
111 boolean staysOnRunQueue
= false;
113 * Empirical observations and look into the linux code have
114 * shown that the TASK_STATE_MAX flag is used internally and
115 * |'ed with other states, most often the running state, so it
116 * is ignored from the prevState value.
118 * Since Linux 4.1, the TASK_NOLOAD state was created and
119 * TASK_STATE_MAX is now 2048. We use TASK_NOLOAD as the new max
120 * because it does not modify the displayed state value.
122 int state
= (int) (prevState
& (LinuxValues
.TASK_NOLOAD
- 1));
124 if (isRunning(state
)) {
125 value
= StateValues
.PROCESS_STATUS_WAIT_FOR_CPU_VALUE
;
126 staysOnRunQueue
= true;
127 } else if (isWaiting(state
)) {
128 value
= StateValues
.PROCESS_STATUS_WAIT_BLOCKED_VALUE
;
129 } else if (isDead(state
)) {
130 value
= TmfStateValue
.nullValue();
132 value
= StateValues
.PROCESS_STATUS_WAIT_UNKNOWN_VALUE
;
134 ss
.modifyAttribute(timestamp
, value
, formerThreadNode
);
136 int quark
= ss
.getQuarkRelativeAndAdd(formerThreadNode
, Attributes
.CURRENT_CPU_RQ
);
137 if (staysOnRunQueue
) {
139 * Set the thread's run queue. This will often be redundant with
140 * previous events, but it may be the first time we see the
143 value
= TmfStateValue
.newValueInt(cpu
);
145 value
= TmfStateValue
.nullValue();
147 ss
.modifyAttribute(timestamp
, value
, quark
);
150 private static boolean isDead(int state
) {
151 return (state
& LinuxValues
.TASK_DEAD
) != 0;
154 private static boolean isWaiting(int state
) {
155 return (state
& (LinuxValues
.TASK_INTERRUPTIBLE
| LinuxValues
.TASK_UNINTERRUPTIBLE
)) != 0;
158 private static boolean isRunning(int state
) {
159 // special case, this means ALL STATES ARE 0
160 // this is effectively an anti-state
164 private static void setCpuStatus(ITmfStateSystemBuilder ss
, Integer nextTid
, Integer newCurrentThreadNode
, long timestamp
, int currentCPUNode
)
165 throws StateValueTypeException
, AttributeNotFoundException
{
167 ITmfStateValue value
;
169 /* Check if the entering process is in kernel or user mode */
170 quark
= ss
.getQuarkRelativeAndAdd(newCurrentThreadNode
, Attributes
.SYSTEM_CALL
);
171 ITmfStateValue queryOngoingState
= ss
.queryOngoingState(quark
);
172 if (queryOngoingState
.isNull()) {
173 value
= StateValues
.CPU_STATUS_RUN_USERMODE_VALUE
;
175 value
= StateValues
.CPU_STATUS_RUN_SYSCALL_VALUE
;
178 value
= StateValues
.CPU_STATUS_IDLE_VALUE
;
180 ss
.modifyAttribute(timestamp
, value
, currentCPUNode
);
183 private static void setCpuProcess(ITmfStateSystemBuilder ss
, Integer nextTid
, long timestamp
, int currentCPUNode
)
184 throws StateValueTypeException
, AttributeNotFoundException
{
186 ITmfStateValue value
;
187 quark
= ss
.getQuarkRelativeAndAdd(currentCPUNode
, Attributes
.CURRENT_THREAD
);
188 value
= TmfStateValue
.newValueInt(nextTid
);
189 ss
.modifyAttribute(timestamp
, value
, quark
);
192 private static void setProcessPrio(ITmfStateSystemBuilder ss
, Integer prio
, Integer threadNode
, long timestamp
)
193 throws StateValueTypeException
, AttributeNotFoundException
{
195 ITmfStateValue value
;
196 quark
= ss
.getQuarkRelativeAndAdd(threadNode
, Attributes
.PRIO
);
197 value
= TmfStateValue
.newValueInt(prio
);
198 ss
.modifyAttribute(timestamp
, value
, quark
);
201 private static void setProcessExecName(ITmfStateSystemBuilder ss
, String processName
, Integer threadNode
, long timestamp
)
202 throws StateValueTypeException
, AttributeNotFoundException
{
204 ITmfStateValue value
;
205 quark
= ss
.getQuarkRelativeAndAdd(threadNode
, Attributes
.EXEC_NAME
);
206 value
= TmfStateValue
.newValueString(processName
);
207 ss
.modifyAttribute(timestamp
, value
, quark
);