blob: ddc709b7d1ffe57fcb30acf55146a2b1bb88e6c0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 É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.incubator.internal.xaf.core.statemachine.backend;
import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelAnalysisEventLayout;
import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelTrace;
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.TmfStateValue;
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.statesystem.AbstractTmfStateProvider;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
/**
* The state provider used by our state machine state system analysis.
*
* <pre>
* (root)
* `-- tid
* |-- (thread id 1)
* | |-- (timer:cpu_usage)
* | |-- (timer:wait_blocked)
* | |-- (timer:wait_for_cpu)
* | |-- (counter:syscalls)
* | `-- (counter:preempt)
* |-- (thread id 2)
* | ...
* |-- (thread id 3)
* | ...
* ...
* </pre>
*
* @author Raphaël Beamonte
*/
class StateMachineProviderEventTypes extends AbstractTmfStateProvider {
/**
* Version number of this input handler. Please bump this if you modify the
* contents of the generated state history in some way.
*/
private static final int VERSION = 2016070701;
/** Forgotten string chains */
private static final @NonNull String LAYOUT_CONTEXT_VTID = "context._vtid"; //$NON-NLS-1$
private static final @NonNull String LAYOUT_PREV_PRIO = "prev_prio"; //$NON-NLS-1$
private static final @NonNull String LAYOUT_STATE = "state"; //$NON-NLS-1$
private static final @NonNull String LAYOUT_CPU_ID = "cpu_id"; //$NON-NLS-1$
private static final @NonNull String EVENT_SCHED_WAKING = "sched_waking"; //$NON-NLS-1$
private static final @NonNull String EVENT_IRQ_SOFTIRQ_ENTRY = "irq_softirq_entry"; //$NON-NLS-1$
private static final @NonNull String EVENT_POWER_CPU_FREQUENCY = "power_cpu_frequency"; //$NON-NLS-1$
/**
* A map giving information about what process
* is on what CPU
*/
private Map<Integer, Long> threadByCPU = new TreeMap<>();
/**
* Save the information to compute the CPU Usage by TID
*/
private Map<Long, ThreadInfo> info_by_tid = new HashMap<>();
private @NonNull ThreadInfo getThreadInfoOrCreate(Long tid) {
ThreadInfo threadInfo = info_by_tid.get(tid);
if (threadInfo == null) {
threadInfo = new ThreadInfo();
info_by_tid.put(tid, threadInfo);
}
return threadInfo;
}
/**
* Constructor
*
* @param trace
* The trace for which we build this state system
*/
public StateMachineProviderEventTypes(@NonNull ITmfTrace trace) {
super(trace , StateMachineBackendAnalysis.NAME);
}
@Override
public int getVersion() {
return VERSION;
}
@Override
public StateMachineProviderEventTypes getNewInstance() {
return new StateMachineProviderEventTypes(this.getTrace());
}
@Override
protected void eventHandle(ITmfEvent event) {
ITmfStateSystemBuilder ss = checkNotNull(getStateSystemBuilder());
int quark;
/* Since this can be used for any trace types, normalize all the
* timestamp values to nanoseconds. */
final long ts = event.getTimestamp().toNanos();
final String eventName = event.getType().getName();
IKernelAnalysisEventLayout layout = ((IKernelTrace) getTrace()).getKernelEventLayout();
if (eventName.equals(layout.eventSchedSwitch())) {
ITmfEventField content = event.getContent();
Long prevTid = (Long)content.getField(layout.fieldPrevTid()).getValue();
Long nextTid = (Long)content.getField(layout.fieldNextTid()).getValue();
Long prevState = (Long)content.getField(layout.fieldPrevState()).getValue();
Integer nextPrio = ((Long)content.getField(layout.fieldNextPrio()).getValue()).intValue();
Integer prevPrio = ((Long)content.getField(LAYOUT_PREV_PRIO).getValue()).intValue();
Integer cpu = checkNotNull((Integer)TmfTraceUtils.resolveEventAspectOfClassForEvent(getTrace(), TmfCpuAspect.class, event));
threadByCPU.put(cpu, nextTid);
ThreadInfo prevThreadInfo = getThreadInfoOrCreate(prevTid);
ThreadInfo nextThreadInfo = getThreadInfoOrCreate(nextTid);
////////////////////////////////
// NEXT THREAD (BEING SCHEDULED)
int quarkNextTid = ss.getQuarkAbsoluteAndAdd(Attributes.TID, nextTid.toString());
// CPU: update the cpu number if needed
if (nextThreadInfo.cpu_last != cpu) {
try {
quark = ss.getQuarkRelativeAndAdd(quarkNextTid, Attributes.CPU);
TmfStateValue value = TmfStateValue.newValueInt(cpu);
ss.modifyAttribute(ts, value, quark);
nextThreadInfo.cpu_last = cpu;
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
// PRIO: update the priority if needed
if (nextThreadInfo.prio_last != nextPrio) {
try {
quark = ss.getQuarkRelativeAndAdd(quarkNextTid, Attributes.PRIO);
TmfStateValue value = TmfStateValue.newValueInt(nextPrio);
ss.modifyAttribute(ts, value, quark);
nextThreadInfo.prio_last = nextPrio;
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
// STATE: Change to RUNNING
BackendState s = null;
if (!nextThreadInfo.stack_state.isEmpty()) {
nextThreadInfo.stack_state.pop();
s = nextThreadInfo.stack_state.peek();
}
if (s == null) {
s = new BackendState(BackendStateValue.RUNNING.getValue());
}
try {
quark = ss.getQuarkRelativeAndAdd(quarkNextTid, Attributes.STATE);
TmfStateValue value = TmfStateValue.newValueLong(s.getValue());
ss.modifyAttribute(ts, value, quark);
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
// TIMER_WAIT_(BLOCKED|FOR_CPU)
// TODO: find a way to update the time spent in WAIT_FOR_SOMETHING
// for cases where the thread hasn't returned when finishing
if (nextThreadInfo.last_state != null) {
if (nextThreadInfo.last_state != 0 && nextThreadInfo.last_state != 1024) {
// TIMER_WAIT_BLOCKED
try {
quark = ss.getQuarkRelativeAndAdd(quarkNextTid, Attributes.TIMER_WAIT_BLOCKED);
if (nextThreadInfo.cumul_wait_blocked == 0L) {
TmfStateValue value = TmfStateValue.newValueLong(0L);
ss.modifyAttribute(getTrace().getStartTime().toNanos(), value, quark);
}
nextThreadInfo.cumul_wait_blocked += ts - nextThreadInfo.last_ts;
TmfStateValue value = TmfStateValue.newValueLong(nextThreadInfo.cumul_wait_blocked);
ss.modifyAttribute(ts, value, quark);
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
} else {
// TIMER_WAIT_FOR_CPU
try {
quark = ss.getQuarkRelativeAndAdd(quarkNextTid, Attributes.TIMER_WAIT_FOR_CPU);
if (nextThreadInfo.cumul_wait_for_cpu == 0L) {
TmfStateValue value = TmfStateValue.newValueLong(0L);
ss.modifyAttribute(getTrace().getStartTime().toNanos(), value, quark);
}
nextThreadInfo.cumul_wait_for_cpu += ts - nextThreadInfo.last_ts;
TmfStateValue value = TmfStateValue.newValueLong(nextThreadInfo.cumul_wait_for_cpu);
ss.modifyAttribute(ts, value, quark);
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
}
// TIMER_WAKEUP_LATENCY
if (nextThreadInfo.last_wakeup != null) {
try {
quark = ss.getQuarkRelativeAndAdd(quarkNextTid, Attributes.TIMER_WAKEUP_LATENCY);
if (nextThreadInfo.cumul_wakeup_latency == 0L) {
TmfStateValue value = TmfStateValue.newValueLong(0L);
ss.modifyAttribute(getTrace().getStartTime().toNanos(), value, quark);
}
nextThreadInfo.cumul_wakeup_latency += ts - nextThreadInfo.last_wakeup;
TmfStateValue value = TmfStateValue.newValueLong(nextThreadInfo.cumul_wakeup_latency);
ss.modifyAttribute(ts, value, quark);
// Reset last wakeup time to null, so that it will be used only next time we receive a sched_waking
nextThreadInfo.last_wakeup = null;
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
//////////////////////////////////////
// PREVIOUS THREAD (BEING UNSCHEDULED)
int quarkPrevTid = ss.getQuarkAbsoluteAndAdd(Attributes.TID, prevTid.toString());
// PRIO: update the priority if needed
if (prevThreadInfo.prio_last != prevPrio) {
try {
quark = ss.getQuarkRelativeAndAdd(quarkPrevTid, Attributes.PRIO);
TmfStateValue value = TmfStateValue.newValueInt(prevPrio);
ss.modifyAttribute(ts, value, quark);
prevThreadInfo.prio_last = prevPrio;
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
// TIMER_CPU_USAGE
// We chose here to consider the data from the trace, even if it's not the actual running duration
//if (prevThreadInfo.last_ts != null) {
try {
quark = ss.getQuarkRelativeAndAdd(quarkPrevTid, Attributes.TIMER_CPU_USAGE);
if (prevThreadInfo.cumul_cpu_usage == 0L) {
TmfStateValue value = TmfStateValue.newValueLong(0L);
ss.modifyAttribute(getTrace().getStartTime().toNanos(), value, quark);
//ss.modifyAttribute(prevThreadInfo.last_ts, value, quark);
}
long previousTs = (prevThreadInfo.last_ts != null)
? prevThreadInfo.last_ts
: getTrace().getStartTime().toNanos();
prevThreadInfo.cumul_cpu_usage += ts - previousTs;
TmfStateValue value = TmfStateValue.newValueLong(prevThreadInfo.cumul_cpu_usage);
ss.modifyAttribute(ts, value, quark);
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
//}
nextThreadInfo.last_ts = ts;
// For wait for CPU and wait blocked for next time
prevThreadInfo.last_ts = ts;
prevThreadInfo.last_state = prevState;
s = null;
if (prevState == 0 || prevState == 1024) {
// STATE: Change to PREEMPTED
s = new BackendState(BackendStateValue.PREEMPTED.getValue());
// COUNTER_PREEMPT: Increment
try {
quark = ss.getQuarkRelativeAndAdd(quarkPrevTid, Attributes.COUNTER_PREEMPT);
if (prevThreadInfo.counter_preempt == 0) {
TmfStateValue value = TmfStateValue.newValueInt(0);
ss.modifyAttribute(getTrace().getStartTime().toNanos(), value, quark);
}
prevThreadInfo.counter_preempt++;
TmfStateValue value = TmfStateValue.newValueInt(prevThreadInfo.counter_preempt);
ss.modifyAttribute(ts, value, quark);
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
} else {
// STATE: Change to BLOCKED
s = new BackendState(BackendStateValue.BLOCKED.getValue());
}
prevThreadInfo.stack_state.push(s);
try {
quark = ss.getQuarkRelativeAndAdd(quarkPrevTid, Attributes.STATE);
TmfStateValue value = TmfStateValue.newValueLong(s.getValue());
ss.modifyAttribute(ts, value, quark);
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
} else if (eventName.equals(layout.eventSchedPiSetprio())) {
ITmfEventField content = event.getContent();
Long fromTid = (Long)content.getField(LAYOUT_CONTEXT_VTID).getValue();
Long toTid = (Long)content.getField(layout.fieldTid()).getValue();
Integer newPrio = ((Long)content.getField(layout.fieldNewPrio()).getValue()).intValue();
// Get the threadInfo from the thread with raised priority
ThreadInfo toThreadInfo = getThreadInfoOrCreate(toTid);
// PRIO: update the priority if needed
if (toThreadInfo.prio_last != newPrio) {
try {
quark = ss.getQuarkAbsoluteAndAdd(Attributes.TID, toTid.toString(), Attributes.PRIO);
TmfStateValue value = TmfStateValue.newValueInt(newPrio);
ss.modifyAttribute(ts, value, quark);
toThreadInfo.prio_last = newPrio;
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
if (fromTid.equals(toTid)) {
// Going back to normal
// Then, for each thread that raised its priority, add to the cumulated time
for (Long tid : toThreadInfo.sched_pi_fromTids) {
ThreadInfo fromThreadInfo = getThreadInfoOrCreate(tid);
boolean wasZero = (fromThreadInfo.sched_pi_cumul == 0);
fromThreadInfo.sched_pi_cumul += ts - fromThreadInfo.sched_pi_lastTs;
fromThreadInfo.sched_pi_lastTs = null;
//fromThreadInfo.sched_pi_toTid = null;
// Update SS
try {
quark = ss.getQuarkAbsoluteAndAdd(Attributes.TID, tid.toString());
quark = ss.getQuarkRelativeAndAdd(quark, Attributes.TIMER_SCHED_PI);
if (wasZero) {
TmfStateValue value = TmfStateValue.newValueLong(0);
ss.modifyAttribute(getTrace().getStartTime().toNanos(), value, quark);
}
TmfStateValue value = TmfStateValue.newValueLong(fromThreadInfo.sched_pi_cumul);
ss.modifyAttribute(ts, value, quark);
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
// Then clear the list of fromTids
toThreadInfo.sched_pi_fromTids.clear();
} else {
// fromTid started giving its priority to toTid
// Update the threadInfo for the fromTid
ThreadInfo fromThreadInfo = getThreadInfoOrCreate(fromTid);
fromThreadInfo.sched_pi_lastTs = ts;
//fromThreadInfo.sched_pi_toTid = toTid;
// Update the threadInfo for the toTid
toThreadInfo.sched_pi_fromTids.add(fromTid);
}
} else if (eventName.equals(EVENT_SCHED_WAKING)) {
// Get the TID we want to wake up
ITmfEventField content = event.getContent();
Long tid = (Long)content.getField(layout.fieldTid()).getValue();
Integer prio = ((Long)content.getField(layout.fieldPrio()).getValue()).intValue();
ThreadInfo threadInfo = getThreadInfoOrCreate(tid);
threadInfo.last_wakeup = ts;
// Thread quark
int quarkTid = ss.getQuarkAbsoluteAndAdd(Attributes.TID, tid.toString());
// PRIO: update the priority if needed
if (threadInfo.prio_last != prio) {
try {
quark = ss.getQuarkAbsoluteAndAdd(Attributes.TID, tid.toString(), Attributes.PRIO);
TmfStateValue value = TmfStateValue.newValueInt(prio);
ss.modifyAttribute(ts, value, quark);
threadInfo.prio_last = prio;
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
// STATE: Change to WAKING
BackendState s = new BackendState(BackendStateValue.WAKING.getValue());
if (!threadInfo.stack_state.isEmpty()) {
// If not empty, the last status should either be PREEMPTED or BLOCKED,
// we don't need any of them anymore in the stack as they are over so...
threadInfo.stack_state.pop();
}
threadInfo.stack_state.push(s);
try {
quark = ss.getQuarkRelativeAndAdd(quarkTid, Attributes.STATE);
TmfStateValue value = TmfStateValue.newValueLong(s.getValue());
ss.modifyAttribute(ts, value, quark);
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
} else if (eventName.equals(EVENT_POWER_CPU_FREQUENCY)) {
ITmfEventField content = event.getContent();
Long cpu = (Long)content.getField(LAYOUT_CPU_ID).getValue();
Long freq = (Long)content.getField(LAYOUT_STATE).getValue();
try {
quark = ss.getQuarkAbsoluteAndAdd(Attributes.CPU_FREQ, cpu.toString());
TmfStateValue value = TmfStateValue.newValueLong(freq);
ss.modifyAttribute(ts, value, quark);
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
} else if (eventName.equals(layout.eventSoftIrqEntry()) || eventName.equals(EVENT_IRQ_SOFTIRQ_ENTRY)) {
ITmfEventField content = event.getContent();
Long tid = (Long)content.getField(LAYOUT_CONTEXT_VTID).getValue();
Long vec = (Long)content.getField("vec").getValue(); //$NON-NLS-1$
// Thread quark
int quarkTid = ss.getQuarkAbsoluteAndAdd(Attributes.TID, tid.toString());
// Thread info
ThreadInfo threadInfo = getThreadInfoOrCreate(tid);
// STATE: Change to the right SOFTIRQ
BackendState s = new BackendState(BackendState.TYPE_SOFTIRQ, vec);
threadInfo.stack_state.push(s);
try {
quark = ss.getQuarkRelativeAndAdd(quarkTid, Attributes.STATE);
TmfStateValue value = TmfStateValue.newValueLong(s.getValue());
ss.modifyAttribute(ts, value, quark);
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
} else if (eventName.equals(layout.eventHRTimerExpireEntry()) || eventName.equals("timer_hrtimer_expire_entry")) { //$NON-NLS-1$
ITmfEventField content = event.getContent();
Long tid = (Long)content.getField(LAYOUT_CONTEXT_VTID).getValue();
// Thread quark
int quarkTid = ss.getQuarkAbsoluteAndAdd(Attributes.TID, tid.toString());
// Thread info
ThreadInfo threadInfo = getThreadInfoOrCreate(tid);
// STATE: Change to HRTIMER
BackendState s = new BackendState(BackendStateValue.HRTIMER.getValue());
threadInfo.stack_state.push(s);
try {
quark = ss.getQuarkRelativeAndAdd(quarkTid, Attributes.STATE);
TmfStateValue value = TmfStateValue.newValueLong(s.getValue());
ss.modifyAttribute(ts, value, quark);
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
} else if (eventName.equals(layout.eventIrqHandlerEntry())) {
ITmfEventField content = event.getContent();
Long tid = (Long)content.getField(LAYOUT_CONTEXT_VTID).getValue();
Long irq = (Long)content.getField("irq").getValue(); //$NON-NLS-1$
// Thread quark
int quarkTid = ss.getQuarkAbsoluteAndAdd(Attributes.TID, tid.toString());
// Thread info
ThreadInfo threadInfo = getThreadInfoOrCreate(tid);
// STATE: Change to the right IRQ
BackendState s = new BackendState(BackendState.TYPE_IRQ, irq);
threadInfo.stack_state.push(s);
try {
quark = ss.getQuarkRelativeAndAdd(quarkTid, Attributes.STATE);
TmfStateValue value = TmfStateValue.newValueLong(s.getValue());
ss.modifyAttribute(ts, value, quark);
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
// TODO: démarrer le timer de IRQ preemption, qui sera stoppé lors du irq handler exit
// TODO: augmenter le compteur de préemptions ? (probablement!)
// TODO: stopper le timer de CPU Usage et démarrer le timer de preemption ?
// TODO: mettre à jour l'attribute state pour "IRQ_PREEMPTED" ?
} else if (eventName.startsWith(layout.eventSyscallEntryPrefix())) {
ITmfEventField content = event.getContent();
Long tid = (Long)content.getField(LAYOUT_CONTEXT_VTID).getValue();
/*
Integer cpu = checkNotNull((Integer)TmfTraceUtils.resolveEventAspectOfClassForEvent(getTrace(), TmfCpuAspect.class, event));
Long tid = threadByCPU.get(cpu);
if (tid == null) {
KernelAnalysisModule kernelAnalysisModule = (KernelAnalysisModule)TmfTraceUtils.getAnalysisModuleOfClass(getTrace(), TmfStateSystemAnalysisModule.class, KernelAnalysisModule.ID);
if (kernelAnalysisModule != null) {
Integer eventTid = KernelThreadInformationProvider.getThreadOnCpu(kernelAnalysisModule, cpu, ts);
if (eventTid != null) {
tid = new Long(eventTid);
threadByCPU.put(cpu, tid);
}
}
}
*/
if (tid != null) {
ThreadInfo threadInfo = getThreadInfoOrCreate(tid);
threadInfo.counter_syscalls += 1;
// Thread quark
int quarkTid = ss.getQuarkAbsoluteAndAdd(Attributes.TID, tid.toString());
// COUNTER_SYSCALLS
quark = ss.getQuarkRelativeAndAdd(quarkTid, Attributes.COUNTER_SYSCALLS);
if (threadInfo.counter_syscalls == 1) {
try {
TmfStateValue value = TmfStateValue.newValueInt(0);
ss.modifyAttribute(getTrace().getStartTime().toNanos(), value, quark);
} catch (StateValueTypeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
try {
TmfStateValue value = TmfStateValue.newValueInt(threadInfo.counter_syscalls);
ss.modifyAttribute(ts, value, quark);
} catch (StateValueTypeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
// STATE: Change to SYSCALL
BackendState s = new BackendState(BackendStateValue.SYSCALL.getValue());
threadInfo.stack_state.push(s);
try {
quark = ss.getQuarkRelativeAndAdd(quarkTid, Attributes.STATE);
TmfStateValue value = TmfStateValue.newValueLong(s.getValue());
ss.modifyAttribute(ts, value, quark);
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
} else if (eventName.equals(layout.eventSoftIrqExit()) || eventName.equals("irq_softirq_exit") //$NON-NLS-1$
|| eventName.equals(layout.eventHRTimerExpireExit()) || eventName.equals("timer_hrtimer_expire_exit") //$NON-NLS-1$
|| eventName.equals(layout.eventIrqHandlerExit())
|| eventName.startsWith(layout.eventSyscallExitPrefix())) {
ITmfEventField content = event.getContent();
Long tid = (Long)content.getField(LAYOUT_CONTEXT_VTID).getValue();
// Thread quark
int quarkTid = ss.getQuarkAbsoluteAndAdd(Attributes.TID, tid.toString());
// Thread info
ThreadInfo threadInfo = getThreadInfoOrCreate(tid);
// STATE: Change to the last state value
BackendState s = null;
if (!threadInfo.stack_state.isEmpty()) {
threadInfo.stack_state.pop();
s = threadInfo.stack_state.peek();
}
if (s == null) {
s = new BackendState(BackendStateValue.RUNNING.getValue());
}
try {
quark = ss.getQuarkRelativeAndAdd(quarkTid, Attributes.STATE);
TmfStateValue value = TmfStateValue.newValueLong(s.getValue());
ss.modifyAttribute(ts, value, quark);
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
//} else if (eventName.equals(layout.eventIrqHandlerExit())) {
// TODO: stopper le timer de IRQ preemption
// TODO: stopper le timer de preemption et redémarrer le timer de CPU Usage ?
}
}
/**
* @since 2.0
*/
@Override
public void done() {
int quark;
TmfStateValue value;
ITmfStateSystemBuilder ss = checkNotNull(getStateSystemBuilder());
long traceStartTime = getTrace().getStartTime().toNanos();
long traceEndTime = getTrace().getEndTime().toNanos();
// Update all the timers if necessary
for (@NonNull Entry<Long, ThreadInfo> entry : info_by_tid.entrySet()) {
Long tid = entry.getKey();
ThreadInfo threadInfo = entry.getValue();
int quarkTid = ss.getQuarkAbsoluteAndAdd(Attributes.TID, tid.toString());
// TIMER_WAKEUP_LATENCY
if (threadInfo.last_wakeup != null) {
try {
quark = ss.getQuarkRelativeAndAdd(quarkTid, Attributes.TIMER_WAKEUP_LATENCY);
if (threadInfo.cumul_wakeup_latency == 0L) {
value = TmfStateValue.newValueLong(0L);
ss.modifyAttribute(traceStartTime, value, quark);
}
threadInfo.cumul_wakeup_latency += traceEndTime - threadInfo.last_wakeup;
value = TmfStateValue.newValueLong(threadInfo.cumul_wakeup_latency);
ss.modifyAttribute(traceEndTime, value, quark);
// Reset last wakeup time to null, so that it will be used only next time we receive a sched_waking
threadInfo.last_wakeup = null;
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
BackendState state = threadInfo.stack_state.peek();
BackendStateValue stateValue = (state == null) ? null : BackendStateValue.getValue(state.getValue());
if (stateValue == BackendStateValue.BLOCKED) {
// TIMER_WAIT_BLOCKED
try {
quark = ss.getQuarkRelativeAndAdd(quarkTid, Attributes.TIMER_WAIT_BLOCKED);
if (threadInfo.cumul_wait_blocked == 0L) {
value = TmfStateValue.newValueLong(0L);
ss.modifyAttribute(traceStartTime, value, quark);
}
threadInfo.cumul_wait_blocked += traceEndTime - threadInfo.last_ts;
value = TmfStateValue.newValueLong(threadInfo.cumul_wait_blocked);
ss.modifyAttribute(traceEndTime, value, quark);
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
} else if (stateValue == BackendStateValue.PREEMPTED) {
// TIMER_WAIT_FOR_CPU
try {
quark = ss.getQuarkRelativeAndAdd(quarkTid, Attributes.TIMER_WAIT_FOR_CPU);
if (threadInfo.cumul_wait_for_cpu == 0L) {
value = TmfStateValue.newValueLong(0L);
ss.modifyAttribute(traceStartTime, value, quark);
}
threadInfo.cumul_wait_for_cpu += traceEndTime - threadInfo.last_ts;
value = TmfStateValue.newValueLong(threadInfo.cumul_wait_for_cpu);
ss.modifyAttribute(traceEndTime, value, quark);
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
} else {
// TIMER_CPU_USAGE
try {
quark = ss.getQuarkRelativeAndAdd(quarkTid, Attributes.TIMER_CPU_USAGE);
if (threadInfo.cumul_cpu_usage == 0L) {
value = TmfStateValue.newValueLong(0L);
ss.modifyAttribute(traceStartTime, value, quark);
}
long previousTs = (threadInfo.last_ts != null)
? threadInfo.last_ts
: traceStartTime;
threadInfo.cumul_cpu_usage += traceEndTime - previousTs;
value = TmfStateValue.newValueLong(threadInfo.cumul_cpu_usage);
ss.modifyAttribute(traceEndTime, value, quark);
} catch (StateValueTypeException | TimeRangeException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
threadInfo.last_ts = traceEndTime;
}
info_by_tid.clear();
}
}