Skip to content

Commit 831b987

Browse files
committed
callStack: add Annotations handlers for instant events
implement IOutputAnnotationProvider and override methods add marker data to tooltips add unit tests (boilerplate tests generated by amazon Q) move Annotations to InstrumentedCallStackAnalysis create new xml trace for instant events Add instant events to old callStak Signed-off-by: Yassine Ibhir <[email protected]>
1 parent 7f18609 commit 831b987

File tree

11 files changed

+694
-11
lines changed

11 files changed

+694
-11
lines changed

analysis/org.eclipse.tracecompass.analysis.profiling.core.tests/src/org/eclipse/tracecompass/analysis/profiling/core/tests/CallStackTestBase2.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,25 @@ public class CallStackTestBase2 {
4747
private CallStackAnalysisStub fModule;
4848
private KernelAnalysisModuleStub fKernelModule;
4949

50+
private final String fCallstackFile;
51+
52+
53+
protected CallStackTestBase2(String callstackFile) {
54+
fCallstackFile = callstackFile;
55+
}
56+
57+
public CallStackTestBase2() {
58+
fCallstackFile = CALLSTACK_FILE;
59+
}
60+
61+
5062
/**
5163
* Setup the trace for the tests
5264
*/
5365
@Before
5466
public void setUp() {
5567
TmfXmlTraceStub trace = new TmfXmlTraceStubNs();
56-
IPath filePath = ActivatorTest.getAbsoluteFilePath(CALLSTACK_FILE);
68+
IPath filePath = ActivatorTest.getAbsoluteFilePath(fCallstackFile);
5769
IStatus status = trace.validate(null, filePath.toOSString());
5870
if (!status.isOK()) {
5971
fail(status.getException().getMessage());

analysis/org.eclipse.tracecompass.analysis.profiling.core.tests/src/org/eclipse/tracecompass/analysis/profiling/core/tests/FlameChartDataProviderTest.java

Lines changed: 168 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,16 @@
2424
import java.util.List;
2525
import java.util.Map;
2626
import java.util.Objects;
27+
2728
import java.util.Set;
29+
//import java.util.stream.Collectors;
30+
import java.util.stream.Collectors;
2831

2932
import org.eclipse.core.runtime.IProgressMonitor;
3033
import org.eclipse.core.runtime.NullProgressMonitor;
3134
import org.eclipse.jdt.annotation.NonNull;
3235
import org.eclipse.jdt.annotation.Nullable;
36+
import org.eclipse.tracecompass.analysis.profiling.core.instrumented.InstrumentedCallStackAnalysis;
3337
import org.eclipse.tracecompass.analysis.profiling.core.tests.stubs2.CallStackAnalysisStub;
3438
import org.eclipse.tracecompass.internal.analysis.os.linux.core.registry.LinuxStyle;
3539
import org.eclipse.tracecompass.internal.analysis.profiling.core.instrumented.FlameChartDataProvider;
@@ -38,7 +42,10 @@
3842
import org.eclipse.tracecompass.internal.analysis.profiling.core.instrumented.FlameChartEntryModel.EntryType;
3943
import org.eclipse.tracecompass.internal.tmf.core.model.filters.FetchParametersUtils;
4044
import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderDescriptor;
45+
import org.eclipse.tracecompass.tmf.core.model.CommonStatusMessage;
4146
import org.eclipse.tracecompass.tmf.core.model.OutputElementStyle;
47+
import org.eclipse.tracecompass.tmf.core.model.StyleProperties;
48+
import org.eclipse.tracecompass.tmf.core.model.StyleProperties.SymbolType;
4249
import org.eclipse.tracecompass.tmf.core.model.filters.SelectionTimeQueryFilter;
4350
import org.eclipse.tracecompass.tmf.core.model.filters.TimeQueryFilter;
4451
import org.eclipse.tracecompass.tmf.core.model.timegraph.ITimeGraphArrow;
@@ -48,6 +55,10 @@
4855
import org.eclipse.tracecompass.tmf.core.model.timegraph.TimeGraphModel;
4956
import org.eclipse.tracecompass.tmf.core.model.timegraph.TimeGraphState;
5057
import org.eclipse.tracecompass.tmf.core.model.tree.TmfTreeModel;
58+
import org.eclipse.tracecompass.tmf.core.model.annotations.Annotation;
59+
//import org.eclipse.tracecompass.tmf.core.model.annotations.Annotation;
60+
import org.eclipse.tracecompass.tmf.core.model.annotations.AnnotationCategoriesModel;
61+
import org.eclipse.tracecompass.tmf.core.model.annotations.AnnotationModel;
5162
import org.eclipse.tracecompass.tmf.core.response.ITmfResponse;
5263
import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse;
5364
import org.junit.Test;
@@ -63,6 +74,11 @@ public class FlameChartDataProviderTest extends CallStackTestBase2 {
6374

6475
private static final @Nullable IProgressMonitor MONITOR = new NullProgressMonitor();
6576
private static final String FOR_ENTRY = " for entry ";
77+
private static final String CALLSTACKIEVENTS_FILE = "testfiles/traces/callstackIevents.xml";
78+
79+
public FlameChartDataProviderTest() {
80+
super( CALLSTACKIEVENTS_FILE);
81+
}
6682

6783
private FlameChartDataProvider getDataProvider() {
6884
CallStackAnalysisStub module = getModule();
@@ -436,10 +452,161 @@ private static void verifyStates(List<ITimeGraphRowModel> rowModels, FlameChartE
436452
}
437453
}
438454

455+
/**
456+
* Test fetching annotation categories
457+
*/
458+
@Test
459+
public void testFetchAnnotationCategories() {
460+
FlameChartDataProvider dataProvider = getDataProvider();
461+
462+
TmfModelResponse<AnnotationCategoriesModel> response = dataProvider.fetchAnnotationCategories(Collections.emptyMap(), MONITOR);
463+
assertEquals(ITmfResponse.Status.COMPLETED, response.getStatus());
464+
assertEquals(CommonStatusMessage.COMPLETED, response.getStatusMessage());
465+
466+
AnnotationCategoriesModel model = response.getModel();
467+
assertNotNull(model);
468+
assertEquals(1, model.getAnnotationCategories().size());
469+
assertEquals(InstrumentedCallStackAnalysis.ANNOTATIONS, model.getAnnotationCategories().get(0));
470+
}
471+
472+
/**
473+
* Test fetchAnnotations with empty result
474+
*/
475+
@Test
476+
public void testFetchAnnotations() {
477+
FlameChartDataProvider dataProvider = getDataProvider();
478+
Map<String, Object> parameters = FetchParametersUtils.selectionTimeQueryToMap(
479+
new SelectionTimeQueryFilter(0, Long.MAX_VALUE, 2, Collections.emptySet()));
480+
TmfModelResponse<AnnotationModel> response = dataProvider.fetchAnnotations(parameters, MONITOR);
481+
assertEquals(ITmfResponse.Status.COMPLETED, response.getStatus());
482+
assertEquals(CommonStatusMessage.COMPLETED, response.getStatusMessage());
483+
484+
AnnotationModel model = response.getModel();
485+
assertNotNull(model);
486+
assertTrue(model.getAnnotations().containsKey(InstrumentedCallStackAnalysis.ANNOTATIONS));
487+
}
488+
/**
489+
* Test fetchAnnotations with null filter returns completed with null model
490+
*/
491+
@Test
492+
public void testFetchAnnotationsNullFilter() {
493+
FlameChartDataProvider dataProvider = getDataProvider();
494+
495+
Map<String, Object> parameters = Collections.emptyMap();
496+
TmfModelResponse<AnnotationModel> response = dataProvider.fetchAnnotations(parameters, MONITOR);
497+
assertEquals(ITmfResponse.Status.COMPLETED, response.getStatus());
498+
assertEquals(CommonStatusMessage.COMPLETED, response.getStatusMessage());
499+
assertNull(response.getModel());
500+
}
501+
502+
/**
503+
* Test fetchAnnotations style
504+
*/
505+
@Test
506+
public void testFetchAnnotationsOutputElementStyle() {
507+
FlameChartDataProvider dataProvider = getDataProvider();
508+
509+
// Get tree to find entry IDs
510+
TmfModelResponse<@NonNull TmfTreeModel<@NonNull FlameChartEntryModel>> treeResponse =
511+
dataProvider.fetchTree(FetchParametersUtils.timeQueryToMap(new TimeQueryFilter(0, Long.MAX_VALUE, 2)), null);
512+
TmfTreeModel<@NonNull FlameChartEntryModel> model = treeResponse.getModel();
513+
514+
if (model != null) {
515+
List<FlameChartEntryModel> entries = model.getEntries();
516+
517+
// Find a function entry that should have annotations
518+
FlameChartEntryModel functionEntry = entries.stream()
519+
.filter(e -> e.getEntryType() == EntryType.FUNCTION)
520+
.findFirst()
521+
.orElse(null);
522+
assertNotNull(functionEntry);
523+
524+
// 15 and 18 are timestamps with instant events
525+
Map<String, Object> fetchParams = FetchParametersUtils.selectionTimeQueryToMap(
526+
new SelectionTimeQueryFilter(15, 18, 2, Collections.singleton(functionEntry.getId())));
527+
528+
// Fetch annotations
529+
TmfModelResponse<AnnotationModel> response = dataProvider.fetchAnnotations(fetchParams, MONITOR);
530+
531+
assertEquals(ITmfResponse.Status.COMPLETED, response.getStatus());
532+
AnnotationModel m = response.getModel();
533+
assertNotNull(m);
534+
Collection<@NonNull Annotation> annotations = m.getAnnotations().get(InstrumentedCallStackAnalysis.ANNOTATIONS);
535+
assertNotNull(annotations);
536+
assertFalse(annotations.isEmpty());
537+
538+
// Verify OutputElementStyle properties
539+
Annotation annotation = annotations.iterator().next();
540+
OutputElementStyle style = annotation.getStyle();
541+
assertNotNull(style);
542+
543+
Map<String, Object> styleMap = style.getStyleValues();
544+
assertEquals("#7D3D31", styleMap.get(StyleProperties.COLOR));
545+
assertEquals(0.33f, styleMap.get(StyleProperties.HEIGHT));
546+
assertEquals(SymbolType.DIAMOND, styleMap.get(StyleProperties.SYMBOL_TYPE));
547+
}
548+
549+
}
550+
551+
/**
552+
* Test annotation model structure and properties
553+
*/
554+
@Test
555+
public void testAnnotationModelStructure() {
556+
FlameChartDataProvider dataProvider = getDataProvider();
557+
558+
Map<String, Object> parameters = FetchParametersUtils.selectionTimeQueryToMap(
559+
new SelectionTimeQueryFilter(0, Long.MAX_VALUE, 2,Collections.emptySet()));
560+
TmfModelResponse<AnnotationModel> response = dataProvider.fetchAnnotations(parameters, MONITOR);
561+
assertEquals(ITmfResponse.Status.COMPLETED, response.getStatus());
562+
563+
AnnotationModel model = response.getModel();
564+
assertNotNull(model);
565+
566+
assertEquals(1, model.getAnnotations().size());
567+
assertTrue(model.getAnnotations().containsKey(InstrumentedCallStackAnalysis.ANNOTATIONS));
568+
assertNotNull(model.getAnnotations().get(InstrumentedCallStackAnalysis.ANNOTATIONS));
569+
}
570+
571+
/**
572+
* Test annotation model structure and properties
573+
*/
574+
@SuppressWarnings("null")
575+
@Test
576+
public void testFetchValidAnnotations() {
577+
FlameChartDataProvider dataProvider = getDataProvider();
578+
TmfModelResponse<@NonNull TmfTreeModel<@NonNull FlameChartEntryModel>> treeResponse =
579+
dataProvider.fetchTree(FetchParametersUtils.timeQueryToMap(new TimeQueryFilter(1, Long.MAX_VALUE, 2)), MONITOR);
580+
assertEquals(ITmfResponse.Status.COMPLETED, treeResponse.getStatus());
581+
582+
TmfTreeModel<@NonNull FlameChartEntryModel> m = treeResponse.getModel();
583+
// Get entry IDs from the same tree response
584+
if(m != null) {
585+
Set<Long> allEntryIds = m.getEntries().stream()
586+
.map(FlameChartEntryModel::getId)
587+
.collect(Collectors.toSet());
588+
589+
590+
Map<String, Object> parameters = FetchParametersUtils.selectionTimeQueryToMap(
591+
new SelectionTimeQueryFilter(1, Long.MAX_VALUE, 2, allEntryIds));
592+
593+
TmfModelResponse<AnnotationModel> response = dataProvider.fetchAnnotations(parameters, MONITOR);
594+
595+
assertNotNull(response);
596+
assertEquals(ITmfResponse.Status.COMPLETED, response.getStatus());
597+
598+
AnnotationModel model = response.getModel();
599+
assertNotNull(model);
600+
601+
Map<String, Collection<Annotation>> annotations = model.getAnnotations();
602+
assertNotNull(annotations );
603+
}
604+
}
605+
439606
private static void verifyArrows(List<ITimeGraphArrow> arrows, List<ITimeGraphArrow> expectedArrows) {
440607
assertEquals(expectedArrows.size(), arrows.size());
441608
for (ITimeGraphArrow expectedArrow : expectedArrows) {
442-
for (ITimeGraphArrow arrow: arrows) {
609+
for (ITimeGraphArrow arrow : arrows) {
443610
if (arrow.getValue() == expectedArrow.getValue()) {
444611
assertEquals("Duration for arrow " + arrow.getValue(), expectedArrow.getDuration(), arrow.getDuration());
445612
assertEquals("Start time for arrow " + arrow.getValue(), expectedArrow.getStartTime(), arrow.getStartTime());

analysis/org.eclipse.tracecompass.analysis.profiling.core.tests/stubs/org/eclipse/tracecompass/analysis/profiling/core/tests/stubs/CallStackProviderStub.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@
1111

1212
package org.eclipse.tracecompass.analysis.profiling.core.tests.stubs;
1313

14+
import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
15+
1416
import org.eclipse.jdt.annotation.NonNull;
1517
import org.eclipse.jdt.annotation.Nullable;
1618
import org.eclipse.tracecompass.analysis.profiling.core.callstack.CallStackStateProvider;
19+
import org.eclipse.tracecompass.analysis.profiling.core.instrumented.InstrumentedCallStackAnalysis;
20+
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
1721
import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
1822
import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
1923
import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
@@ -126,4 +130,48 @@ public static long getThreadIdFromEvent(@NonNull ITmfEvent event) {
126130
return CallStackStateProvider.UNKNOWN_PID;
127131
}
128132

133+
@Override
134+
protected void eventHandle(ITmfEvent event) {
135+
if (!considerEvent(event)) {
136+
return;
137+
}
138+
// Handle instant events
139+
ITmfEventField phField = event.getContent().getField("ph");
140+
if (phField != null && "i".equals(phField.getValue())) {
141+
handleInstant(event);
142+
return;
143+
}
144+
// Call parent for regular entry/exit events
145+
super.eventHandle(event);
146+
}
147+
148+
private void handleInstant(@NonNull ITmfEvent event) {
149+
super.addMarker(event);
150+
151+
ITmfStateSystemBuilder ss = checkNotNull(getStateSystemBuilder());
152+
long timestamp = event.getTimestamp().toNanos();
153+
Object contents = event.getContent().getFieldValue( String.class,"name");
154+
String toStore = (contents != null ? contents.toString() : "");
155+
156+
String processName = getProcessName(event);
157+
int processId = getProcessId(event);
158+
if (processName == null) {
159+
processName = (processId == UNKNOWN_PID) ? UNKNOWN : Integer.toString(processId);
160+
}
161+
int processQuark = ss.getQuarkAbsoluteAndAdd(PROCESSES, processName);
162+
ss.updateOngoingState(TmfStateValue.newValueInt(processId), processQuark);
163+
164+
String threadName = getThreadName(event);
165+
long threadId = getThreadId(event);
166+
if (threadName == null) {
167+
threadName = Long.toString(threadId);
168+
}
169+
int threadQuark = ss.getQuarkRelativeAndAdd(processQuark, threadName);
170+
ss.updateOngoingState(TmfStateValue.newValueLong(threadId), threadQuark);
171+
172+
int callStackQuark = ss.getQuarkRelativeAndAdd(threadQuark, InstrumentedCallStackAnalysis.ANNOTATIONS);
173+
ss.pushAttribute(timestamp, toStore, callStackQuark);
174+
return;
175+
176+
}
129177
}

analysis/org.eclipse.tracecompass.analysis.profiling.core.tests/stubs/org/eclipse/tracecompass/analysis/profiling/core/tests/stubs2/CallStackProviderStub.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,20 @@
1111

1212
package org.eclipse.tracecompass.analysis.profiling.core.tests.stubs2;
1313

14+
import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
15+
1416
import org.eclipse.jdt.annotation.NonNull;
1517
import org.eclipse.jdt.annotation.Nullable;
1618
import org.eclipse.tracecompass.analysis.profiling.core.callstack.CallStackStateProvider;
19+
import org.eclipse.tracecompass.analysis.profiling.core.instrumented.InstrumentedCallStackAnalysis;
20+
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
1721
import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
1822
import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
1923
import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
2024
import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
2125
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
2226

27+
2328
/**
2429
* A call stack state provider stub
2530
*
@@ -96,4 +101,49 @@ protected long getThreadId(ITmfEvent event) {
96101
}
97102
return CallStackStateProvider.UNKNOWN_PID;
98103
}
104+
105+
@Override
106+
protected void eventHandle(ITmfEvent event) {
107+
if (!considerEvent(event)) {
108+
return;
109+
}
110+
// Handle instant events
111+
ITmfEventField phField = event.getContent().getField("ph");
112+
if (phField != null && "i".equals(phField.getValue())) {
113+
handleInstant(event);
114+
return;
115+
}
116+
// Call parent for regular entry/exit events
117+
super.eventHandle(event);
118+
}
119+
120+
private void handleInstant(@NonNull ITmfEvent event) {
121+
super.addMarker(event);
122+
123+
ITmfStateSystemBuilder ss = checkNotNull(getStateSystemBuilder());
124+
long timestamp = event.getTimestamp().toNanos();
125+
Object contents = event.getContent().getFieldValue( String.class,"name");
126+
String toStore = (contents != null ? contents.toString() : "");
127+
128+
String processName = getProcessName(event);
129+
int processId = getProcessId(event);
130+
if (processName == null) {
131+
processName = (processId == UNKNOWN_PID) ? UNKNOWN : Integer.toString(processId);
132+
}
133+
int processQuark = ss.getQuarkAbsoluteAndAdd(PROCESSES, processName);
134+
ss.updateOngoingState(TmfStateValue.newValueInt(processId), processQuark);
135+
136+
String threadName = getThreadName(event);
137+
long threadId = getThreadId(event);
138+
if (threadName == null) {
139+
threadName = Long.toString(threadId);
140+
}
141+
int threadQuark = ss.getQuarkRelativeAndAdd(processQuark, threadName);
142+
ss.updateOngoingState(TmfStateValue.newValueLong(threadId), threadQuark);
143+
144+
int callStackQuark = ss.getQuarkRelativeAndAdd(threadQuark, InstrumentedCallStackAnalysis.ANNOTATIONS);
145+
ss.pushAttribute(timestamp, toStore, callStackQuark);
146+
return;
147+
148+
}
99149
}

0 commit comments

Comments
 (0)