os.linux: Add per cpu thread 0 modeling
[deliverable/tracecompass.git] / analysis / org.eclipse.tracecompass.analysis.os.linux.core / src / org / eclipse / tracecompass / internal / analysis / os / linux / core / kernel / handlers / KernelEventHandlerUtils.java
1 /*******************************************************************************
2 * Copyright (c) 2015 Ericsson
3 *
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
8 *******************************************************************************/
9
10 package org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers;
11
12 import java.util.List;
13
14 import org.eclipse.jdt.annotation.Nullable;
15 import org.eclipse.tracecompass.analysis.os.linux.core.kernel.Attributes;
16 import org.eclipse.tracecompass.analysis.os.linux.core.kernel.StateValues;
17 import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
18 import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
19 import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
20 import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
21 import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
22 import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
23 import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
24 import org.eclipse.tracecompass.tmf.core.event.aspect.TmfCpuAspect;
25 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
26 import org.eclipse.tracecompass.tmf.core.util.Pair;
27
28 /**
29 * Kernel Event Handler Utils is a collection of static methods to be used in
30 * subclasses of IKernelEventHandler.
31 *
32 * @author Matthew Khouzam
33 * @author Francis Giraldeau
34 */
35 public final class KernelEventHandlerUtils {
36
37 private KernelEventHandlerUtils() {
38 }
39
40 /**
41 * Get CPU
42 *
43 * @param event
44 * The event containing the cpu
45 *
46 * @return the CPU number (null for not set)
47 */
48 public static @Nullable Integer getCpu(ITmfEvent event) {
49 Integer cpuObj = TmfTraceUtils.resolveIntEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event);
50 if (cpuObj == null) {
51 /* We couldn't find any CPU information, ignore this event */
52 return null;
53 }
54 return cpuObj;
55 }
56
57 /**
58 * Gets the current CPU quark
59 *
60 * @param cpuNumber
61 * The cpu number
62 * @param ss
63 * the state system
64 *
65 * @return the current CPU quark -1 for not set
66 */
67 public static int getCurrentCPUNode(Integer cpuNumber, ITmfStateSystemBuilder ss) {
68 return ss.getQuarkRelativeAndAdd(getNodeCPUs(ss), cpuNumber.toString());
69 }
70
71 /**
72 * Get the timestamp of the event
73 *
74 * @param event
75 * the event containing the timestamp
76 *
77 * @return the timestamp in long format
78 */
79 public static long getTimestamp(ITmfEvent event) {
80 return event.getTimestamp().toNanos();
81 }
82
83 /**
84 * Get the current thread node
85 *
86 * @param cpuNumber
87 * The cpu number
88 * @param ss
89 * the state system
90 *
91 * @return the current thread node quark
92 * @throws AttributeNotFoundException
93 * current cpu node not found
94 */
95 public static int getCurrentThreadNode(Integer cpuNumber, ITmfStateSystemBuilder ss) throws AttributeNotFoundException {
96 /*
97 * Shortcut for the "current thread" attribute node. It requires
98 * querying the current CPU's current thread.
99 */
100 int quark = ss.getQuarkRelativeAndAdd(getCurrentCPUNode(cpuNumber, ss), Attributes.CURRENT_THREAD);
101 ITmfStateValue value = ss.queryOngoingState(quark);
102 int thread = value.isNull() ? -1 : value.unboxInt();
103 return ss.getQuarkRelativeAndAdd(getNodeThreads(ss), buildThreadAttributeName(thread, cpuNumber));
104 }
105
106 /**
107 * When we want to set a process back to a "running" state, first check its
108 * current System_call attribute. If there is a system call active, we put
109 * the process back in the syscall state. If not, we put it back in user
110 * mode state.
111 *
112 * @param timestamp
113 * the time in the state system of the change
114 * @param currentThreadNode
115 * The current thread node
116 * @param ssb
117 * the state system
118 * @throws AttributeNotFoundException
119 * an attribute does not exists yet
120 * @throws TimeRangeException
121 * the time is out of range
122 * @throws StateValueTypeException
123 * the attribute was not set with int values
124 */
125 public static void setProcessToRunning(long timestamp, int currentThreadNode, ITmfStateSystemBuilder ssb)
126 throws AttributeNotFoundException, TimeRangeException,
127 StateValueTypeException {
128 int quark;
129 ITmfStateValue value;
130
131 quark = ssb.getQuarkRelativeAndAdd(currentThreadNode, Attributes.SYSTEM_CALL);
132 if (ssb.queryOngoingState(quark).isNull()) {
133 /* We were in user mode before the interruption */
134 value = StateValues.PROCESS_STATUS_RUN_USERMODE_VALUE;
135 } else {
136 /* We were previously in kernel mode */
137 value = StateValues.PROCESS_STATUS_RUN_SYSCALL_VALUE;
138 }
139 quark = ssb.getQuarkRelativeAndAdd(currentThreadNode, Attributes.STATUS);
140 ssb.modifyAttribute(timestamp, value, quark);
141 }
142
143 /**
144 * Get the IRQs node
145 *
146 * @param cpuNumber
147 * the cpu core
148 * @param ss
149 * the state system
150 * @return the IRQ node quark
151 */
152 public static int getNodeIRQs(int cpuNumber, ITmfStateSystemBuilder ss) {
153 return ss.getQuarkAbsoluteAndAdd(Attributes.CPUS, Integer.toString(cpuNumber), Attributes.IRQS);
154 }
155
156 /**
157 * Get the CPUs node
158 *
159 * @param ss
160 * the state system
161 * @return the CPU node quark
162 */
163 public static int getNodeCPUs(ITmfStateSystemBuilder ss) {
164 return ss.getQuarkAbsoluteAndAdd(Attributes.CPUS);
165 }
166
167 /**
168 * Get the Soft IRQs node
169 *
170 * @param cpuNumber
171 * the cpu core
172 * @param ss
173 * the state system
174 * @return the Soft IRQ node quark
175 */
176 public static int getNodeSoftIRQs(int cpuNumber, ITmfStateSystemBuilder ss) {
177 return ss.getQuarkAbsoluteAndAdd(Attributes.CPUS, Integer.toString(cpuNumber), Attributes.SOFT_IRQS);
178 }
179
180 /**
181 * Get the threads node
182 *
183 * @param ss
184 * the state system
185 * @return the threads quark
186 */
187 public static int getNodeThreads(ITmfStateSystemBuilder ss) {
188 return ss.getQuarkAbsoluteAndAdd(Attributes.THREADS);
189 }
190
191 /**
192 * Reset the CPU's status when it's coming out of an interruption.
193 *
194 * @param timestamp
195 * the time when the status of the cpu is "leaving irq"
196 * @param cpuNumber
197 * the cpu returning to its previous state
198 *
199 * @param ssb
200 * State system
201 * @throws StateValueTypeException
202 * the attribute is not set as an int
203 * @throws AttributeNotFoundException
204 * the attribute was not created yet
205 * @throws TimeRangeException
206 * the time is out of range
207 */
208 public static void cpuExitInterrupt(long timestamp, Integer cpuNumber, ITmfStateSystemBuilder ssb)
209 throws StateValueTypeException, AttributeNotFoundException,
210 TimeRangeException {
211 int quark;
212 int currentCPUNode = getCurrentCPUNode(cpuNumber, ssb);
213
214 quark = ssb.getQuarkRelativeAndAdd(currentCPUNode, Attributes.STATUS);
215 ITmfStateValue value = getCpuStatus(ssb, currentCPUNode);
216 ssb.modifyAttribute(timestamp, value, quark);
217 }
218
219 /**
220 * Get the ongoing Status state of a CPU.
221 *
222 * This will look through the states of the
223 *
224 * <ul>
225 * <li>IRQ</li>
226 * <li>Soft IRQ</li>
227 * <li>Process</li>
228 * </ul>
229 *
230 * under the CPU, giving priority to states higher in the list. If the state
231 * is a null value, we continue looking down the list.
232 *
233 * @param ssb
234 * The state system
235 * @param cpuQuark
236 * The *quark* of the CPU we are looking for. Careful, this is
237 * NOT the CPU number (or attribute name)!
238 * @return The state value that represents the status of the given CPU
239 * @throws AttributeNotFoundException
240 */
241 private static ITmfStateValue getCpuStatus(ITmfStateSystemBuilder ssb, int cpuQuark)
242 throws AttributeNotFoundException {
243
244 /* Check if there is a IRQ running */
245 int irqQuarks = ssb.getQuarkRelativeAndAdd(cpuQuark, Attributes.IRQS);
246 List<Integer> irqs = ssb.getSubAttributes(irqQuarks, false);
247 for (Integer quark : irqs) {
248 final ITmfStateValue irqState = ssb.queryOngoingState(quark.intValue());
249 if (!irqState.isNull()) {
250 return irqState;
251 }
252 }
253
254 /* Check if there is a soft IRQ running */
255 int softIrqQuarks = ssb.getQuarkRelativeAndAdd(cpuQuark, Attributes.SOFT_IRQS);
256 List<Integer> softIrqs = ssb.getSubAttributes(softIrqQuarks, false);
257 for (Integer quark : softIrqs) {
258 final ITmfStateValue softIrqState = ssb.queryOngoingState(quark.intValue());
259 if (!softIrqState.isNull()) {
260 return softIrqState;
261 }
262 }
263
264 /*
265 * Check if there is a thread running. If not, report IDLE. If there is,
266 * report the running state of the thread (usermode or system call).
267 */
268 int currentThreadQuark = ssb.getQuarkRelativeAndAdd(cpuQuark, Attributes.CURRENT_THREAD);
269 ITmfStateValue currentThreadState = ssb.queryOngoingState(currentThreadQuark);
270 if (currentThreadState.isNull()) {
271 return TmfStateValue.nullValue();
272 }
273 int tid = currentThreadState.unboxInt();
274 if (tid == 0) {
275 return StateValues.CPU_STATUS_IDLE_VALUE;
276 }
277 int threadSystemCallQuark = ssb.getQuarkAbsoluteAndAdd(Attributes.THREADS, Integer.toString(tid), Attributes.SYSTEM_CALL);
278 return (ssb.queryOngoingState(threadSystemCallQuark).isNull() ?
279 StateValues.CPU_STATUS_RUN_USERMODE_VALUE :
280 StateValues.CPU_STATUS_RUN_SYSCALL_VALUE);
281 }
282
283 /**
284 * Build the thread attribute name.
285 *
286 * For all threads except "0" this is the string representation of the threadId.
287 * For thread "0" which is the idle thread and can be running concurrently on multiple
288 * CPUs, append "_cpuId".
289 *
290 * @param threadId
291 * the thread id
292 * @param cpuId
293 * the cpu id
294 *
295 * @return the thread attribute name
296 * null if the threadId is zero and the cpuId is null
297 */
298 public static @Nullable String buildThreadAttributeName(int threadId, @Nullable Integer cpuId) {
299
300 if (threadId == 0) {
301 if (cpuId == null) {
302 return null;
303 }
304 return Attributes.THREAD_0_PREFIX + String.valueOf(cpuId);
305 }
306
307 return String.valueOf(threadId);
308 }
309
310 /**
311 * Parse the thread id and CPU id from the thread attribute name string
312 *
313 * For thread "0" the attribute name is in the form "threadId_cpuId", extract both
314 * values from the string.
315 *
316 * For all other threads, the attribute name is the string representation of the
317 * threadId and there is no cpuId.
318 *
319 * @param threadAttributeName
320 * the thread attribute name
321 * @return the thread id and cpu id
322 */
323 public static Pair<Integer, Integer> parseThreadAttributeName(String threadAttributeName) {
324 Integer threadId = -1;
325 Integer cpuId = -1;
326
327 try {
328 if (threadAttributeName.startsWith(Attributes.THREAD_0_PREFIX)) {
329 threadId = 0;
330 String[] tokens = threadAttributeName.split(Attributes.THREAD_0_SEPARATOR);
331 cpuId = Integer.parseInt(tokens[1]);
332 } else {
333 threadId = Integer.parseInt(threadAttributeName);
334 }
335 } catch (NumberFormatException e1) {
336 //pass
337 }
338
339 return new Pair<>(threadId, cpuId);
340 }
341 }
This page took 0.0429 seconds and 5 git commands to generate.