blob: 01f90cc2495de312b9b2e173044788ac3f705738 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015, 2016 EfficiOS Inc., Ericsson
*
* 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.internal.analysis.os.linux.core.latency;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelTidAspect;
import org.eclipse.tracecompass.analysis.os.linux.core.model.OsStrings;
import org.eclipse.tracecompass.analysis.os.linux.core.tid.TidAnalysisModule;
import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelAnalysisEventLayout;
import org.eclipse.tracecompass.analysis.os.linux.core.trace.IKernelTrace;
import org.eclipse.tracecompass.analysis.timing.core.segmentstore.AbstractSegmentStoreAnalysisEventBasedModule;
import org.eclipse.tracecompass.analysis.timing.core.segmentstore.IGroupingSegmentAspect;
import org.eclipse.tracecompass.datastore.core.interval.IHTIntervalReader;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.SyscallLookup;
import org.eclipse.tracecompass.segmentstore.core.ISegment;
import org.eclipse.tracecompass.segmentstore.core.ISegmentStore;
import org.eclipse.tracecompass.segmentstore.core.SegmentStoreFactory.SegmentStoreType;
import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule;
import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
import org.eclipse.tracecompass.tmf.core.event.lookup.TmfCallsite;
import org.eclipse.tracecompass.tmf.core.segment.ISegmentAspect;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
/**
* @author Alexandre Montplaisir
* @since 2.0
*/
public class SystemCallLatencyAnalysis extends AbstractSegmentStoreAnalysisEventBasedModule {
/**
* The ID of this analysis
*/
public static final String ID = "org.eclipse.tracecompass.analysis.os.linux.latency.syscall"; //$NON-NLS-1$
private static final String RET_FIELD = "ret"; //$NON-NLS-1$
private static final int VERSION = 2;
private static final Collection<ISegmentAspect> BASE_ASPECTS = ImmutableList.of(SyscallNameAspect.INSTANCE, SyscallTidAspect.INSTANCE, SyscallRetAspect.INSTANCE, SyscallComponentAspect.INSTANCE, SyscallFileAspect.INSTANCE);
/**
* Constructor
*/
public SystemCallLatencyAnalysis() {
// do nothing
}
@Override
public String getId() {
return ID;
}
@Override
protected Iterable<IAnalysisModule> getDependentAnalyses() {
ITmfTrace trace = getTrace();
if (trace == null) {
throw new IllegalStateException();
}
IAnalysisModule module = trace.getAnalysisModule(TidAnalysisModule.ID);
if (module == null) {
return Collections.emptySet();
}
return ImmutableSet.of(module);
}
@Override
public Iterable<ISegmentAspect> getSegmentAspects() {
return BASE_ASPECTS;
}
@Override
protected int getVersion() {
return VERSION;
}
@Override
protected @NonNull SegmentStoreType getSegmentStoreType() {
return SegmentStoreType.OnDisk;
}
@Override
protected AbstractSegmentStoreAnalysisRequest createAnalysisRequest(ISegmentStore<ISegment> syscalls, IProgressMonitor monitor) {
return new SyscallLatencyAnalysisRequest(syscalls, monitor);
}
@Override
protected @NonNull IHTIntervalReader<ISegment> getSegmentReader() {
return SystemCall.READER;
}
private class SyscallLatencyAnalysisRequest extends AbstractSegmentStoreAnalysisRequest {
private final Map<Integer, SystemCall.InitialInfo> fOngoingSystemCalls = new HashMap<>();
private @Nullable IKernelAnalysisEventLayout fLayout;
private final IProgressMonitor fMonitor;
public SyscallLatencyAnalysisRequest(ISegmentStore<ISegment> syscalls, IProgressMonitor monitor) {
super(syscalls);
fMonitor = monitor;
}
@Override
public void handleData(final ITmfEvent event) {
super.handleData(event);
IKernelAnalysisEventLayout layout = fLayout;
if (layout == null) {
IKernelTrace trace = (IKernelTrace) event.getTrace();
layout = trace.getKernelEventLayout();
fLayout = layout;
}
final String eventName = event.getName();
if (eventName.startsWith(layout.eventSyscallEntryPrefix()) ||
eventName.startsWith(layout.eventCompatSyscallEntryPrefix())) {
/* This is a system call entry event */
Integer tid;
try {
tid = KernelTidAspect.INSTANCE.resolve(event, true, fMonitor);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
if (tid == null) {
// no information on this event/trace ?
return;
}
/* Record the event's data into the intial system call info */
// String syscallName = fLayout.getSyscallNameFromEvent(event);
long startTime = event.getTimestamp().toNanos();
String syscallName = eventName.substring(layout.eventSyscallEntryPrefix().length());
SystemCall.InitialInfo newSysCall = new SystemCall.InitialInfo(startTime, syscallName.intern(), tid);
fOngoingSystemCalls.put(tid, newSysCall);
} else if (eventName.startsWith(layout.eventSyscallExitPrefix())) {
/* This is a system call exit event */
Integer tid;
try {
tid = KernelTidAspect.INSTANCE.resolve(event, true, fMonitor);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
if (tid == null) {
return;
}
SystemCall.InitialInfo info = fOngoingSystemCalls.remove(tid);
if (info == null) {
/*
* We have not seen the entry event corresponding to this
* exit (lost event, or before start of trace).
*/
return;
}
long endTime = event.getTimestamp().toNanos();
Integer ret = event.getContent().getFieldValue(Integer.class, RET_FIELD);
SystemCall syscall = new SystemCall(info, endTime, ret == null ? -1 : ret);
getSegmentStore().add(syscall);
}
}
@Override
public void handleCompleted() {
fOngoingSystemCalls.clear();
super.handleCompleted();
}
@Override
public void handleCancel() {
fMonitor.setCanceled(true);
super.handleCancel();
}
}
private static final class SyscallNameAspect implements ISegmentAspect {
public static final ISegmentAspect INSTANCE = new SyscallNameAspect();
private SyscallNameAspect() {
// Do nothing
}
@Override
public String getHelpText() {
return Messages.getMessage(Messages.SegmentAspectHelpText_SystemCall);
}
@Override
public String getName() {
return Messages.getMessage(Messages.SegmentAspectName_SystemCall);
}
@Override
public @Nullable Comparator<?> getComparator() {
return null;
}
@Override
public @Nullable String resolve(ISegment segment) {
if (segment instanceof SystemCall) {
return ((SystemCall) segment).getName();
}
return EMPTY_STRING;
}
}
private static final class SyscallTidAspect implements ISegmentAspect {
public static final ISegmentAspect INSTANCE = new SyscallTidAspect();
private SyscallTidAspect() {
// Do nothing
}
@Override
public String getHelpText() {
return Messages.getMessage(Messages.SegmentAspectHelpText_SystemCallTid);
}
@Override
public String getName() {
return OsStrings.tid();
}
@Override
public @Nullable Comparator<?> getComparator() {
return null;
}
@Override
public @Nullable Integer resolve(ISegment segment) {
if (segment instanceof SystemCall) {
return ((SystemCall) segment).getTid();
}
return -1;
}
}
private static final class SyscallComponentAspect implements IGroupingSegmentAspect {
public static final ISegmentAspect INSTANCE = new SyscallComponentAspect();
private SyscallComponentAspect() {
// Do nothing
}
@Override
public String getName() {
return Messages.getMessage(Messages.SystemCallLatencyAnalysis_componentName);
}
@Override
public String getHelpText() {
return Messages.getMessage(Messages.SystemCallLatencyAnalysis_componentDescription);
}
@Override
public @Nullable Comparator<?> getComparator() {
return null;
}
@Override
public @Nullable Object resolve(ISegment segment) {
if (segment instanceof SystemCall) {
return SyscallLookup.getInstance().getComponent(((SystemCall) segment).getName());
}
return EMPTY_STRING;
}
}
private static final class SyscallRetAspect implements ISegmentAspect {
public static final ISegmentAspect INSTANCE = new SyscallRetAspect();
private SyscallRetAspect() {
// Do nothing
}
@Override
public String getHelpText() {
return Messages.getMessage(Messages.SegmentAspectHelpText_SystemCallRet);
}
@Override
public String getName() {
return Messages.getMessage(Messages.SegmentAspectName_SystemCallRet);
}
@Override
public @Nullable Object resolve(ISegment segment) {
if (segment instanceof SystemCall) {
return ((SystemCall) segment).getReturnValue();
}
return EMPTY_STRING;
}
@Override
public @Nullable Comparator<?> getComparator() {
return null;
}
}
private static final class SyscallFileAspect implements ISegmentAspect {
public static final ISegmentAspect INSTANCE = new SyscallFileAspect();
private SyscallFileAspect() {
// Do nothing
}
@Override
public String getName() {
return Messages.getMessage(Messages.SystemCallLatencyAnalysis_fileName);
}
@Override
public String getHelpText() {
return Messages.getMessage(Messages.SystemCallLatencyAnalysis_fileDescription);
}
@Override
public @Nullable Comparator<?> getComparator() {
return null;
}
@Override
public @Nullable Object resolve(ISegment segment) {
if (segment instanceof SystemCall) {
return SyscallLookup.getInstance().getFile(((SystemCall) segment).getName());
}
return EMPTY_STRING;
}
}
/**
* Callsite aspect for system calls
*/
public static final class SyscallCallsiteAspect implements ISegmentAspect {
/**
* Instance
*/
public static final ISegmentAspect INSTANCE = new SyscallCallsiteAspect();
private SyscallCallsiteAspect() {
// Do nothing
}
@Override
public String getName() {
return Messages.getMessage(Messages.SystemCallLatencyAnalysis_sourceLookupName);
}
@Override
public String getHelpText() {
return Messages.getMessage(Messages.SystemCallLatencyAnalysis_sourceLookupDescription);
}
@Override
public @Nullable Comparator<?> getComparator() {
return null;
}
@Override
public @Nullable Object resolve(ISegment segment) {
String file = (String) SyscallFileAspect.INSTANCE.resolve(segment);
if (file == null || file.isEmpty()) {
return null;
}
return new TmfCallsite(file, 0L);
}
}
}