/*******************************************************************************
* Copyright (c) 2015 Ericsson
*
* 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.analysis.os.linux.core.kernel.handlers;
import java.util.List;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.analysis.os.linux.core.kernel.StateValues;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.Attributes;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
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;
/**
* Kernel Event Handler Utils is a collection of static methods to be used in
* subclasses of IKernelEventHandler.
*
* @author Matthew Khouzam
* @author Francis Giraldeau
*/
public final class KernelEventHandlerUtils {
private KernelEventHandlerUtils() {
}
/**
* Get CPU
*
* @param event
* The event containing the cpu
*
* @return the CPU number (null for not set)
*/
public static @Nullable Integer getCpu(ITmfEvent event) {
Integer cpuObj = TmfTraceUtils.resolveIntEventAspectOfClassForEvent(event.getTrace(), TmfCpuAspect.class, event);
if (cpuObj == null) {
/* We couldn't find any CPU information, ignore this event */
return null;
}
return cpuObj;
}
/**
* Gets the current CPU quark
*
* @param cpuNumber
* The cpu number
* @param ss
* the state system
*
* @return the current CPU quark -1 for not set
*/
public static int getCurrentCPUNode(Integer cpuNumber, ITmfStateSystemBuilder ss) {
return ss.getQuarkRelativeAndAdd(getNodeCPUs(ss), cpuNumber.toString());
}
/**
* Get the timestamp of the event
*
* @param event
* the event containing the timestamp
*
* @return the timestamp in long format
*/
public static long getTimestamp(ITmfEvent event) {
return event.getTimestamp().toNanos();
}
/**
* Get the current thread node
*
* @param cpuNumber
* The cpu number
* @param ss
* the state system
*
* @return the current thread node quark
*/
public static int getCurrentThreadNode(Integer cpuNumber, ITmfStateSystemBuilder ss) {
/*
* Shortcut for the "current thread" attribute node. It requires
* querying the current CPU's current thread.
*/
int quark = ss.getQuarkRelativeAndAdd(getCurrentCPUNode(cpuNumber, ss), Attributes.CURRENT_THREAD);
ITmfStateValue value = ss.queryOngoingState(quark);
int thread = value.isNull() ? -1 : value.unboxInt();
return ss.getQuarkRelativeAndAdd(getNodeThreads(ss), Attributes.buildThreadAttributeName(thread, cpuNumber));
}
/**
* When we want to set a process back to a "running" state, first check its
* current System_call attribute. If there is a system call active, we put
* the process back in the syscall state. If not, we put it back in user
* mode state.
*
* @param timestamp
* the time in the state system of the change
* @param currentThreadNode
* The current thread node
* @param ssb
* the state system
* @throws TimeRangeException
* the time is out of range
* @throws StateValueTypeException
* the attribute was not set with int values
*/
public static void setProcessToRunning(long timestamp, int currentThreadNode, ITmfStateSystemBuilder ssb)
throws TimeRangeException,
StateValueTypeException {
int quark;
ITmfStateValue value;
quark = ssb.getQuarkRelativeAndAdd(currentThreadNode, Attributes.SYSTEM_CALL);
if (ssb.queryOngoingState(quark).isNull()) {
/* We were in user mode before the interruption */
value = StateValues.PROCESS_STATUS_RUN_USERMODE_VALUE;
} else {
/* We were previously in kernel mode */
value = StateValues.PROCESS_STATUS_RUN_SYSCALL_VALUE;
}
ssb.modifyAttribute(timestamp, value, currentThreadNode);
}
/**
* Get the IRQs node
*
* @param cpuNumber
* the cpu core
* @param ss
* the state system
* @return the IRQ node quark
*/
public static int getNodeIRQs(int cpuNumber, ITmfStateSystemBuilder ss) {
return ss.getQuarkAbsoluteAndAdd(Attributes.CPUS, Integer.toString(cpuNumber), Attributes.IRQS);
}
/**
* Get the CPUs node
*
* @param ss
* the state system
* @return the CPU node quark
*/
public static int getNodeCPUs(ITmfStateSystemBuilder ss) {
return ss.getQuarkAbsoluteAndAdd(Attributes.CPUS);
}
/**
* Get the Soft IRQs node
*
* @param cpuNumber
* the cpu core
* @param ss
* the state system
* @return the Soft IRQ node quark
*/
public static int getNodeSoftIRQs(int cpuNumber, ITmfStateSystemBuilder ss) {
return ss.getQuarkAbsoluteAndAdd(Attributes.CPUS, Integer.toString(cpuNumber), Attributes.SOFT_IRQS);
}
/**
* Get the threads node
*
* @param ss
* the state system
* @return the threads quark
*/
public static int getNodeThreads(ITmfStateSystemBuilder ss) {
return ss.getQuarkAbsoluteAndAdd(Attributes.THREADS);
}
/**
* Reset the CPU's status when it's coming out of an interruption.
*
* @param timestamp
* the time when the status of the cpu is "leaving irq"
* @param cpuNumber
* the cpu returning to its previous state
*
* @param ssb
* State system
* @throws StateValueTypeException
* the attribute is not set as an int
* @throws TimeRangeException
* the time is out of range
*/
public static void cpuExitInterrupt(long timestamp, Integer cpuNumber, ITmfStateSystemBuilder ssb)
throws StateValueTypeException, TimeRangeException {
int currentCPUNode = getCurrentCPUNode(cpuNumber, ssb);
ITmfStateValue value = getCpuStatus(ssb, currentCPUNode);
ssb.modifyAttribute(timestamp, value, currentCPUNode);
}
/**
* Get the ongoing Status state of a CPU.
*
* This will look through the states of the
*
* <ul>
* <li>IRQ</li>
* <li>Soft IRQ</li>
* <li>Process</li>
* </ul>
*
* under the CPU, giving priority to states higher in the list. If the state
* is a null value, we continue looking down the list.
*
* @param ssb
* The state system
* @param cpuQuark
* The *quark* of the CPU we are looking for. Careful, this is
* NOT the CPU number (or attribute name)!
* @return The state value that represents the status of the given CPU
*/
private static ITmfStateValue getCpuStatus(ITmfStateSystemBuilder ssb, int cpuQuark) {
/* Check if there is a IRQ running */
int irqQuarks = ssb.getQuarkRelativeAndAdd(cpuQuark, Attributes.IRQS);
List<Integer> irqs = ssb.getSubAttributes(irqQuarks, false);
for (Integer quark : irqs) {
final ITmfStateValue irqState = ssb.queryOngoingState(quark.intValue());
if (!irqState.isNull()) {
return irqState;
}
}
/* Check if there is a soft IRQ running */
int softIrqQuarks = ssb.getQuarkRelativeAndAdd(cpuQuark, Attributes.SOFT_IRQS);
List<Integer> softIrqs = ssb.getSubAttributes(softIrqQuarks, false);
for (Integer quark : softIrqs) {
final ITmfStateValue softIrqState = ssb.queryOngoingState(quark.intValue());
if (!softIrqState.isNull()) {
return softIrqState;
}
}
/*
* Check if there is a thread running. If not, report IDLE. If there is,
* report the running state of the thread (usermode or system call).
*/
int currentThreadQuark = ssb.getQuarkRelativeAndAdd(cpuQuark, Attributes.CURRENT_THREAD);
ITmfStateValue currentThreadState = ssb.queryOngoingState(currentThreadQuark);
if (currentThreadState.isNull()) {
return TmfStateValue.nullValue();
}
int tid = currentThreadState.unboxInt();
if (tid == 0) {
return StateValues.CPU_STATUS_IDLE_VALUE;
}
int threadSystemCallQuark = ssb.getQuarkAbsoluteAndAdd(Attributes.THREADS, Integer.toString(tid), Attributes.SYSTEM_CALL);
return (ssb.queryOngoingState(threadSystemCallQuark).isNull() ? StateValues.CPU_STATUS_RUN_USERMODE_VALUE : StateValues.CPU_STATUS_RUN_SYSCALL_VALUE);
}
}