Skip to content

Commit

Permalink
opentracing: Add flamegraph analysis to opentracing
Browse files Browse the repository at this point in the history
*The AbstractCalledFunction is updated
 to maintain a list of children Intervals.
 Because in Async. Executions the overlapped
 time of children is calculated twice for self
 time calculation. So we need to maintain a
 list of time Intervals of children to compute
 the intersection of them for Self Time Calculations.

Signed-off-by: Fariba Daneshgar <faraji.daneshgar@gmail.com>
  • Loading branch information
farajidaneshgar committed Apr 24, 2024
1 parent cbbd65c commit 3f0cf28
Show file tree
Hide file tree
Showing 10 changed files with 755 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -181,5 +181,16 @@ public boolean equals(@Nullable Object obj) {
Objects.equals(fParent, other.getParent()) &&
Objects.equals(getSymbol(), other.getSymbol()));
}

private long getChildIntersection(TmfTimeRange chlInt) {
long intersection = 0;
for (TmfTimeRange childInterval:fChildrenIntervals ) {
TmfTimeRange intersect = chlInt.getIntersection(childInterval);
if (intersect!=null) {
intersection += (intersect.getEndTime().getValue())-(intersect.getStartTime().getValue());
}
}
return intersection;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,20 @@ Require-Bundle: org.eclipse.core.runtime,
org.eclipse.core.resources,
org.eclipse.tracecompass.common.core,
org.eclipse.tracecompass.tmf.core,
org.eclipse.tracecompass.segmentstore.core;bundle-version="3.1.0",
org.eclipse.tracecompass.incubator.callstack.core;bundle-version="0.1.4",
org.eclipse.tracecompass.analysis.os.linux.core;bundle-version="8.2.0",
org.eclipse.tracecompass.incubator.analysis.core;bundle-version="0.1.1",
org.eclipse.tracecompass.analysis.counters.core;bundle-version="2.2.1",
org.eclipse.tracecompass.analysis.timing.core;bundle-version="5.5.0",
com.google.gson,
com.google.guava,
org.apache.commons.lang3,
org.eclipse.tracecompass.ctf.core,
org.eclipse.tracecompass.jsontrace.core,
org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional
org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional,
org.eclipse.tracecompass.datastore.core;bundle-version="1.3.0",
org.eclipse.tracecompass.incubator.concurrentcallstack.core;bundle-version="0.1.0"
Export-Package: org.eclipse.tracecompass.incubator.internal.opentracing.core;x-friends:="org.eclipse.tracecompass.incubator.opentracing.core.tests",
org.eclipse.tracecompass.incubator.internal.opentracing.core.analysis.spanlife;x-friends:="org.eclipse.tracecompass.incubator.opentracing.core.tests,org.eclipse.tracecompass.incubator.opentracing.ui",
org.eclipse.tracecompass.incubator.internal.opentracing.core.event,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@
class="org.eclipse.tracecompass.incubator.internal.opentracing.core.trace.OpenTracingExperiment">
</tracetype>
</module>
<module
analysis_module="org.eclipse.tracecompass.incubator.opentracing.core.analysis.callstack.OpenTracingCallstackAnalysis"
automatic="false"
icon="icons/callstack_view.gif"
id="org.eclipse.tracecompass.incubator.opentracing.analysis.callstack"
name="Open Tracing Callstack">
<tracetype
applies="true"
class="org.eclipse.tracecompass.incubator.internal.opentracing.core.trace.OpenTracingTrace">
</tracetype>
</module>

</extension>
<extension
point="org.eclipse.tracecompass.tmf.core.dataprovider">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
package org.eclipse.tracecompass.incubator.internal.opentracing.core;

import org.eclipse.tracecompass.common.core.TraceCompassActivator;
import org.eclipse.tracecompass.incubator.concurrentstatesystem.core.SpanCustomValue;
import org.eclipse.tracecompass.internal.provisional.statesystem.core.statevalue.CustomStateValue;

/**
* Activator
Expand Down Expand Up @@ -39,6 +41,7 @@ public static TraceCompassActivator getInstance() {

@Override
protected void startActions() {
CustomStateValue.registerCustomFactory(SpanCustomValue.CUSTOM_TYPE_ID, SpanCustomValue.FACTORY);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
package org.eclipse.tracecompass.incubator.opentracing.core.analysis.callstack;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.incubator.callstack.core.instrumented.statesystem.InstrumentedCallStackAnalysis;
import org.eclipse.tracecompass.incubator.internal.opentracing.core.event.IOpenTracingConstants;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
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.statesystem.AbstractTmfStateProvider;
import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;

/**
* Span Callstack state provider
*
* @author Fateme Faraji Daneshgar
*
*/
public class AsincCallStackStateProvider extends AbstractTmfStateProvider {

/**
* Thread attribute
*
* @since 2.0
*/
public static final String PROCESSES = "Processes"; //$NON-NLS-1$

/**
* Unknown process ID
*
* @since 2.0
*/
public static final int UNKNOWN_PID = -1;

/**
* Unknown name
*
* @since 2.0
*/
public static final String UNKNOWN = "UNKNOWN"; //$NON-NLS-1$


private static final int MAX_STACK_DEPTH = 100000;

private final Map<String, Integer> fStackDepthMap;
private TreeMap<Long, List<Integer>> fPrevEvent;
private int fStateQuark = 3;

/**
* Constructor
*
* @param trace
* the trace to follow
*/
public AsincCallStackStateProvider(@NonNull ITmfTrace trace) {
super(trace, OpenTracingCallstackAnalysis.ID);
// fSpanMap = new HashMap<>();
fStackDepthMap = new HashMap<>();
fPrevEvent = new TreeMap<>();
}

@Override
public int getVersion() {
return 3;
}

@Override
public @NonNull ITmfStateProvider getNewInstance() {
return new AsincCallStackStateProvider(getTrace());
}

@Override
protected void eventHandle(@NonNull ITmfEvent event) {
ITmfStateSystemBuilder ss = getStateSystemBuilder();
if (ss == null) {
return;
}
handleSpan(event,ss);
}

private void handleSpan(ITmfEvent event, ITmfStateSystemBuilder ss) {
long timestamp = event.getTimestamp().toNanos();
if (timestamp == getTrace().getStartTime().toNanos()) {
timestamp++;
}
Long duration = event.getContent().getFieldValue(Long.class, IOpenTracingConstants.DURATION);
if (duration == null) {
return;
}
while (!(fPrevEvent.isEmpty()) && (fPrevEvent.firstKey() < timestamp)) {
long prevTime = fPrevEvent.firstKey();
List<Integer> quarks = Objects.requireNonNull(fPrevEvent.get(fPrevEvent.firstKey()));
ss.modifySpanAttribute(prevTime, (Object) null, quarks.get(0), quarks.get(1));
fPrevEvent.remove(fPrevEvent.firstKey());
}

String processName = event.getContent().getFieldValue(String.class, IOpenTracingConstants.TRACE_ID);

int processId = getProcessId(event);
if (processName == null) {
processName = (processId == UNKNOWN_PID) ? UNKNOWN : Integer.toString(processId);
}

int pq = ss.getQuarkAbsoluteAndAdd(PROCESSES, processName);
ss.updateOngoingState(TmfStateValue.newValueInt(processId), 1);

String Opname = String.valueOf(TmfTraceUtils.resolveAspectOfNameForEvent(event.getTrace(), "Name", event)); //$NON-NLS-1$
String spanId = event.getContent().getFieldValue(String.class, IOpenTracingConstants.SPAN_ID);
String parentId = event.getContent().getFieldValue(String.class, IOpenTracingConstants.REFERENCES + "/CHILD_OF"); //$NON-NLS-1$

int callStackQuark = ss.getQuarkRelativeAndAdd(pq, InstrumentedCallStackAnalysis.CALL_STACK);
int stackDepth = getStackDepth(parentId);

Object functionEntryName = functionEntry(spanId, parentId, Opname);
stackDepth++;

int spanQuark = ss.getQuarkRelativeAndAdd(callStackQuark, String.valueOf(stackDepth));

ss.modifySpanAttribute(timestamp, functionEntryName, fStateQuark, spanQuark);

fStackDepthMap.put(spanId, stackDepth);

List<Integer> quarksList = Arrays.asList(fStateQuark, spanQuark);
fPrevEvent.put(timestamp + duration, quarksList);
fStateQuark++;

}

protected @Nullable String getProcessName(ITmfEvent event) {

Long fieldValue = event.getContent().getFieldValue(Long.class, "trace_id");
if (fieldValue == null) {
fieldValue = event.getContent().getFieldValue(Long.class, "trace_id_low");
}

return fieldValue == null ? "eduroam" : Long.toHexString(fieldValue);
}

protected int getProcessId(ITmfEvent event) {
Long resolve = event.getContent().getFieldValue(Long.class, "trace_id");
return resolve == null ? -1 : resolve.intValue();
}

private int getStackDepth(String parentId) {
Integer stackDepth = fStackDepthMap.get(parentId);
if (stackDepth == null) {
stackDepth = 0;
}
if (stackDepth >= MAX_STACK_DEPTH) {
/*
* Limit stackDepth to 100000, to avoid having Attribute Trees grow
* out of control due to buggy insertions
*/
String message = " Stack limit reached, not pushing"; //$NON-NLS-1$
throw new IllegalStateException(" Quark:" + parentId + message); //$NON-NLS-1$
}
return stackDepth;

}

protected @Nullable Object functionEntry(String spanId, String parentId, String name) {
return new SpanCustomValue(spanId, (parentId == null) ? "0" : parentId, name);

}

protected Map<String, String> MessageHashMapExtractor(ITmfEventField value) {
// split the string to creat key-value pairs
Map<String, String> map = new HashMap<>();
// iterate over the pairs
for (ITmfEventField field : value.getFields()) {
Objects.requireNonNull(field);
map.put(field.getName(), field.getValue().toString().trim());
}
if (map.isEmpty()) {
String valueString = (String) Objects.requireNonNull(value.getValue());
String[] values = valueString.split(",");
for (String tuple : values) {
String[] parts = tuple.split("=");
map.put(parts[0], parts[1].trim());
}
}
return map;
}

@Override
public void done() {
ITmfStateSystemBuilder ss = getStateSystemBuilder();
if (ss == null) {
return;
}
while (!(fPrevEvent.isEmpty())) {
long prevTime = fPrevEvent.firstKey();
List<Integer> quarks = Objects.requireNonNull(fPrevEvent.get(fPrevEvent.firstKey()));
ss.modifySpanAttribute(prevTime, (Object) null, quarks.get(0), quarks.get(1));
fPrevEvent.remove(fPrevEvent.firstKey());
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.eclipse.tracecompass.incubator.opentracing.core.analysis.callstack;

import java.util.Collections;
import java.util.Objects;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.tracecompass.tmf.core.analysis.requirements.TmfAbstractAnalysisRequirement;
import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider;

/**
*
*/
public class OpenTracingCallstackAnalysis extends SpanCallStackAnalysis {
/**
* ID
*/
public static final @NonNull String ID = "org.eclipse.tracecompass.incubator.opentracing.analysis.callstack"; //$NON-NLS-1$


@Override
protected ITmfStateProvider createStateProvider() {
return new AsincCallStackStateProvider(Objects.requireNonNull(getTrace()));
}


@Override
public @NonNull Iterable<@NonNull TmfAbstractAnalysisRequirement> getAnalysisRequirements() {
return Collections.emptyList();
}



}
Loading

0 comments on commit 3f0cf28

Please sign in to comment.