blob: 89df6b5c5be13cf49027ee14b67966d4c5231b8e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017, 2018 É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.analysis.profiling.core.callstack;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.analysis.profiling.core.base.IProfilingElement;
import org.eclipse.tracecompass.internal.analysis.profiling.core.callstack.InstrumentedProfilingElement;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
/**
* Contains interfaces and classes to resolve the host ID in instrumented
* callstack analyses.
*
* @author Geneviève Bastien
* @since 1.1
*/
public final class CallStackHostUtils {
private CallStackHostUtils() {
// Nothing to do
}
/**
* Interface for classes that provide a host ID at time t for a callstack. The
* host ID is used to identify the machine on which the callstack was taken and
* can be correlated with the model of a system to obtain additional data.
*/
public interface IHostIdProvider extends Function<Long, @NonNull String> {
}
/**
* The host ID is always the same, so return that string
*/
private static class TraceHostIdProvider implements IHostIdProvider {
private final String fHostId;
public TraceHostIdProvider(String hostId) {
fHostId = hostId;
}
@Override
public @NonNull String apply(Long time) {
return fHostId;
}
}
/**
* This class uses the value of an attribute as a host ID.
*/
private static final class AttributeValueHostProvider implements IHostIdProvider {
private final ITmfStateSystem fSs;
private final int fQuark;
private @Nullable ITmfStateInterval fInterval;
private String fLastHostId = StringUtils.EMPTY;
public AttributeValueHostProvider(ITmfStateSystem ss, int quark) {
fSs = ss;
fQuark = quark;
}
@Override
public @NonNull String apply(Long time) {
ITmfStateInterval interval = fInterval;
String hostId = fLastHostId;
if (interval != null && interval.intersects(time)) {
return hostId;
}
try {
interval = fSs.querySingleState(time, fQuark);
hostId = String.valueOf(interval.getValue());
} catch (StateSystemDisposedException e) {
interval = null;
hostId = StringUtils.EMPTY;
}
fInterval = interval;
fLastHostId = hostId;
return hostId;
}
}
/**
* This class uses the value of an attribute as a host ID.
*/
private static final class AttributeNameHostProvider implements IHostIdProvider {
private final String fHostId;
public AttributeNameHostProvider(ITmfStateSystem ss, int quark) {
String host = StringUtils.EMPTY;
try {
host = ss.getAttributeName(quark);
} catch (IndexOutOfBoundsException e) {
}
fHostId = host;
}
@Override
public @NonNull String apply(Long time) {
return fHostId;
}
}
/**
* Interface for describing how a callstack will get the host ID, it will return
* the host ID provider for a callstack element
*/
public interface IHostIdResolver extends Function<IProfilingElement, @NonNull IHostIdProvider> {
}
/**
* A host ID resolver that gets the host ID from the trace
*/
public static final class TraceHostIdResolver implements IHostIdResolver {
private final String fHostId;
/**
* @param trace
* The trace to use to provide the host ID
*/
public TraceHostIdResolver(@Nullable ITmfTrace trace) {
fHostId = trace == null ? StringUtils.EMPTY : trace.getHostId();
}
@Override
public @NonNull IHostIdProvider apply(IProfilingElement element) {
return new TraceHostIdProvider(fHostId);
}
}
/**
* This class will resolve the host ID provider by the value of a attribute at
* a given depth
*/
public static final class AttributeValueHostResolver implements IHostIdResolver {
private int fLevel;
/**
* Constructor
*
* @param level
* The depth of the element whose value will be used to retrieve the
* host ID
*/
public AttributeValueHostResolver(int level) {
fLevel = level;
}
@Override
public @NonNull IHostIdProvider apply(IProfilingElement element) {
if (!(element instanceof InstrumentedProfilingElement)) {
throw new IllegalArgumentException();
}
InstrumentedProfilingElement insElement = (InstrumentedProfilingElement) element;
List<InstrumentedProfilingElement> elements = new ArrayList<>();
InstrumentedProfilingElement el = insElement;
while (el != null) {
elements.add(el);
el = el.getParentElement();
}
Collections.reverse(elements);
if (elements.size() <= fLevel) {
throw new NullPointerException("The host should never resolve to null, level " + fLevel + " is not available"); //$NON-NLS-1$ //$NON-NLS-2$
}
InstrumentedProfilingElement stackElement = elements.get(fLevel);
return new AttributeValueHostProvider(stackElement.getStateSystem(), stackElement.getQuark());
}
}
/**
* This class will resolve the thread ID provider by the value of a attribute at
* a given depth
*/
public static final class AttributeNameHostResolver implements IHostIdResolver {
private int fLevel;
/**
* Constructor
*
* @param level
* The depth of the element whose value will be used to retrieve the
* thread ID
*/
public AttributeNameHostResolver(int level) {
fLevel = level;
}
@Override
public @NonNull IHostIdProvider apply(IProfilingElement element) {
if (!(element instanceof InstrumentedProfilingElement)) {
throw new IllegalArgumentException();
}
InstrumentedProfilingElement insElement = (InstrumentedProfilingElement) element;
List<InstrumentedProfilingElement> elements = new ArrayList<>();
InstrumentedProfilingElement el = insElement;
while (el != null) {
elements.add(el);
el = el.getParentElement();
}
Collections.reverse(elements);
if (elements.size() <= fLevel) {
throw new NullPointerException("The host should never resolve to null, level " + fLevel + " is not available"); //$NON-NLS-1$ //$NON-NLS-2$
}
InstrumentedProfilingElement stackElement = elements.get(fLevel);
return new AttributeNameHostProvider(stackElement.getStateSystem(), stackElement.getQuark());
}
}
}