timing: add statistics analysis to functions calls
[deliverable/tracecompass.git] / analysis / org.eclipse.tracecompass.analysis.timing.core.tests / src / org / eclipse / tracecompass / analysis / timing / core / tests / callgraph / CallGraphAnalysisTest.java
CommitLineData
4cc15e51
SF
1/*******************************************************************************
2 * Copyright (c) 2016 Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *******************************************************************************/
9
10package org.eclipse.tracecompass.analysis.timing.core.tests.callgraph;
11
55f777f4 12import static org.junit.Assert.assertEquals;
5eed83df 13import static org.junit.Assert.assertFalse;
55f777f4
PT
14import static org.junit.Assert.assertNotNull;
15import static org.junit.Assert.assertTrue;
4cc15e51 16
5eed83df 17import java.util.Collection;
4cc15e51 18import java.util.Collections;
5eed83df 19import java.util.Iterator;
4cc15e51 20import java.util.List;
5eed83df 21import java.util.Objects;
4cc15e51
SF
22
23import org.eclipse.core.runtime.IProgressMonitor;
24import org.eclipse.core.runtime.NullProgressMonitor;
25import org.eclipse.jdt.annotation.NonNull;
26import org.eclipse.jdt.annotation.Nullable;
27import org.eclipse.tracecompass.common.core.NonNullUtils;
5eed83df 28import org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.AggregatedCalledFunction;
4cc15e51 29import org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.CallGraphAnalysis;
55f777f4 30import org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.ICalledFunction;
5eed83df 31import org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.ThreadNode;
4cc15e51
SF
32import org.eclipse.tracecompass.segmentstore.core.ISegment;
33import org.eclipse.tracecompass.segmentstore.core.ISegmentStore;
34import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
35import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
36import org.eclipse.tracecompass.statesystem.core.StateSystemFactory;
37import org.eclipse.tracecompass.statesystem.core.backend.IStateHistoryBackend;
38import org.eclipse.tracecompass.statesystem.core.backend.StateHistoryBackendFactory;
39import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
40import org.eclipse.tracecompass.tmf.core.segment.ISegmentAspect;
5eed83df 41import org.junit.Assert;
4cc15e51
SF
42import org.junit.Test;
43
44/**
45 * Test the CallGraphAnalysis.This creates a virtual state system in each test
46 * and tests the segment store returned by the CallGraphAnalysis.
47 *
48 * @author Sonia Farrah
49 *
50 */
51public class CallGraphAnalysisTest {
52
53 private static final @NonNull String PROCESS_PATH = "Processes";
54 private static final @NonNull String THREAD_PATH = "Thread";
55 private static final @NonNull String CALLSTACK_PATH = "CallStack";
56 private static final String QUARK_0 = "0";
57 private static final String QUARK_1 = "1";
58 private static final String QUARK_2 = "2";
59 private static final Integer SMALL_AMOUNT_OF_SEGMENT = 3;
60 private static final int LARGE_AMOUNT_OF_SEGMENTS = 1000;
61 private static final String @NonNull [] CSP = { CALLSTACK_PATH };
62 private static final String @NonNull [] PP = { PROCESS_PATH };
63 private static final String @NonNull [] TP = { THREAD_PATH };
64
65 /**
66 * This class is used to make the CallGraphAnalysis's method
67 * iterateOverStateSystem() visible to test
68 */
69 private class CGAnalysis extends CallGraphAnalysis {
70
71 @Override
72 protected boolean iterateOverStateSystem(@Nullable ITmfStateSystem ss, String[] threadsPattern, String[] processesPattern, String[] callStackPath, IProgressMonitor monitor) {
73 return super.iterateOverStateSystem(ss, threadsPattern, processesPattern, callStackPath, monitor);
74 }
75
76 @Override
77 public @NonNull Iterable<@NonNull ISegmentAspect> getSegmentAspects() {
78 return Collections.EMPTY_LIST;
79 }
80
81 }
82
83 private static ITmfStateSystemBuilder createFixture() {
84 IStateHistoryBackend backend;
85 backend = StateHistoryBackendFactory.createInMemoryBackend("Test", 0L);
86 ITmfStateSystemBuilder fixture = StateSystemFactory.newStateSystem(backend);
87 return fixture;
88 }
89
90 /**
91 * Test cascade state system. The call stack's structure used in this test
92 * is shown below:
93 *
94 * <pre>
95 * ________
96 * ______
97 * ____
98 *
99 * </pre>
100 */
101 @Test
102 public void CascadeTest() {
103 ITmfStateSystemBuilder fixture = createFixture();
104 // Build the state system
105 long start = 1;
106 long end = 1001;
107 int parentQuark = fixture.getQuarkAbsoluteAndAdd(PROCESS_PATH, THREAD_PATH, CALLSTACK_PATH);
108 for (int i = 1; i <= SMALL_AMOUNT_OF_SEGMENT; i++) {
109 int quark = fixture.getQuarkRelativeAndAdd(parentQuark, Integer.toString(i));
110 TmfStateValue statev = TmfStateValue.newValueLong(i);
111 fixture.modifyAttribute(start, TmfStateValue.nullValue(), quark);
112 fixture.modifyAttribute(start + i, statev, quark);
113 fixture.modifyAttribute(end - i, TmfStateValue.nullValue(), quark);
114 }
115
116 fixture.closeHistory(1002);
117 // Execute the CallGraphAnalysis
118 CGAnalysis cga = new CGAnalysis();
119 assertTrue(cga.iterateOverStateSystem(fixture, TP, PP, CSP, new NullProgressMonitor()));
120 ISegmentStore<@NonNull ISegment> segmentStore = cga.getSegmentStore();
121 // Test the segment store generated by the analysis
122 assertNotNull(segmentStore);
123 Object[] segments = segmentStore.toArray();
124 assertEquals("Number of segments Found", 3, segments.length);
55f777f4
PT
125 ICalledFunction f1 = (ICalledFunction) segments[0];
126 ICalledFunction f2 = (ICalledFunction) segments[1];
127 ICalledFunction f3 = (ICalledFunction) segments[2];
128 assertEquals("Test the parenthood", NonNullUtils.checkNotNull(f2.getParent()).getSymbol(), f1.getSymbol());
4cc15e51
SF
129 assertEquals("Children number:First parent", 1, f1.getChildren().size());
130 assertEquals("Children number:Second parent", 1, f2.getChildren().size());
131 assertTrue("Children number:Second parent", f3.getChildren().isEmpty());
55f777f4 132 assertTrue("Children number:Child(leaf)", ((ICalledFunction) segments[2]).getChildren().isEmpty());
4cc15e51
SF
133 assertEquals("Parent's self time", 2, f1.getSelfTime());
134 assertEquals("Child's self time", 2, f2.getSelfTime());
135 assertEquals("The leaf's self time", 994, f3.getSelfTime());
136 assertEquals("Test first function's duration", 998, f1.getLength());
137 assertEquals("Test second function's duration", 996, f2.getLength());
138 assertEquals("Test third function's duration", 994, f3.getLength());
139 assertEquals("Depth:First parent", 0, f1.getDepth());
140 assertEquals("Depth:Second parent", 1, f2.getDepth());
141 assertEquals("Depth:Last child", 2, f3.getDepth());
ded2b27f 142 cga.dispose();
4cc15e51
SF
143 }
144
145 /**
146 * Build a pyramid shaped call stack.This call stack contains three
147 * functions ,Its structure is shown below :
148 *
149 * <pre>
150 * __
151 * ____
152 * ______
153 * </pre>
154 */
155 private static void buildPyramidCallStack(ITmfStateSystemBuilder fixture) {
156 int parentQuark = fixture.getQuarkAbsoluteAndAdd(PROCESS_PATH, THREAD_PATH, CALLSTACK_PATH);
157 // Create the first function
158 int quark = fixture.getQuarkRelativeAndAdd(parentQuark, QUARK_0);
159 TmfStateValue statev = TmfStateValue.newValueLong(0);
160 fixture.modifyAttribute(0, TmfStateValue.nullValue(), quark);
161 fixture.modifyAttribute(10, statev, quark);
162 fixture.modifyAttribute(20, TmfStateValue.nullValue(), quark);
163 // Create the second function
164 quark = fixture.getQuarkRelativeAndAdd(parentQuark, QUARK_1);
165 statev = TmfStateValue.newValueLong(1);
166 fixture.modifyAttribute(0, TmfStateValue.nullValue(), quark);
167 fixture.modifyAttribute(5, statev, quark);
168 fixture.modifyAttribute(25, TmfStateValue.nullValue(), quark);
169 // Create the third function
170 quark = fixture.getQuarkRelativeAndAdd(parentQuark, QUARK_2);
171 statev = TmfStateValue.newValueLong(2);
172 fixture.modifyAttribute(0, statev, quark);
173 fixture.modifyAttribute(30, TmfStateValue.nullValue(), quark);
174
175 fixture.closeHistory(31);
176 }
177
178 /**
179 * Test pyramid state system. The call stack's structure used in this test
180 * is shown below:
181 *
182 * <pre>
183 * __
184 * ____
185 * ______
186 * </pre>
187 */
188 @Test
189 public void PyramidTest() {
190 ITmfStateSystemBuilder fixture = createFixture();
191 buildPyramidCallStack(fixture);
192 // Execute the callGraphAnalysis
193 CGAnalysis cga = new CGAnalysis();
194 assertTrue(cga.iterateOverStateSystem(fixture, TP, PP, CSP, new NullProgressMonitor()));
195 ISegmentStore<@NonNull ISegment> segmentStore = cga.getSegmentStore();
196 assertNotNull(segmentStore);
197 Object[] segments = segmentStore.toArray();
55f777f4 198 ICalledFunction f1 = (ICalledFunction) segments[0];
4cc15e51
SF
199 assertEquals("Number of segments Found", 1, segments.length);
200 assertEquals("Callees number", 0, f1.getChildren().size());
201 assertEquals("Function's self time", 10, f1.getSelfTime());
202 assertEquals("Compare the function's self time and total time", f1.getLength(), f1.getSelfTime());
203 assertEquals("Function's depth", 0, f1.getDepth());
ded2b27f 204 cga.dispose();
4cc15e51
SF
205 }
206
207 /**
208 * Test mutliRoots state system. The call stack's structure used in this
209 * test is shown below:
210 *
211 * <pre>
212 * ___ ___
213 * _ _
214 * </pre>
215 */
216 @Test
217 public void multiFunctionRootsTest() {
218 ITmfStateSystemBuilder fixture = createFixture();
219 int parentQuark = fixture.getQuarkAbsoluteAndAdd(PROCESS_PATH, THREAD_PATH, CALLSTACK_PATH);
220 // Create the first root function
221 int quark = fixture.getQuarkRelativeAndAdd(parentQuark, QUARK_0);
222 TmfStateValue statev = TmfStateValue.newValueLong(0);
223 fixture.modifyAttribute(0, statev, quark);
224 fixture.modifyAttribute(20, TmfStateValue.nullValue(), quark);
225 // Create the second root function
226 statev = TmfStateValue.newValueLong(1);
227 fixture.modifyAttribute(30, statev, quark);
228 fixture.modifyAttribute(50, TmfStateValue.nullValue(), quark);
229 // Create the first root function's callee
230 quark = fixture.getQuarkRelativeAndAdd(parentQuark, QUARK_1);
231 statev = TmfStateValue.newValueLong(2);
232 fixture.modifyAttribute(0, statev, quark);
233 fixture.modifyAttribute(10, TmfStateValue.nullValue(), quark);
234 // Create the second root function's callee
235 statev = TmfStateValue.newValueLong(3);
236 fixture.modifyAttribute(30, statev, quark);
237 fixture.modifyAttribute(40, TmfStateValue.nullValue(), quark);
238 fixture.closeHistory(51);
239
240 // Execute the callGraphAnalysis
241 CGAnalysis cga = new CGAnalysis();
242 assertTrue(cga.iterateOverStateSystem(fixture, TP, PP, CSP, new NullProgressMonitor()));
243 ISegmentStore<@NonNull ISegment> segmentStore = cga.getSegmentStore();
244 // Test the segment store
245 assertNotNull(segmentStore);
246 Object[] segments = segmentStore.toArray();
55f777f4 247 List<@NonNull ICalledFunction> threads = cga.getRootFunctions();
4cc15e51
SF
248 assertEquals("Number of root functions", 2, threads.size());
249 assertEquals("Number of children: first root function", 1, threads.get(0).getChildren().size());
250 assertEquals("Number of children: first root function", 1, threads.get(1).getChildren().size());
55f777f4
PT
251 ICalledFunction firstChild = threads.get(0).getChildren().get(0);
252 ICalledFunction secondChild = threads.get(1).getChildren().get(0);
4cc15e51
SF
253 assertEquals("Number of segments found", 4, segments.length);
254 assertNotNull(firstChild.getParent());
255 assertNotNull(secondChild.getParent());
256
55f777f4
PT
257 assertEquals("Test of parenthood", NonNullUtils.checkNotNull(firstChild.getParent()).getSymbol(), threads.get(0).getSymbol());
258 assertEquals("Test of parenthood", NonNullUtils.checkNotNull(secondChild.getParent()).getSymbol(), threads.get(1).getSymbol());
ded2b27f 259 cga.dispose();
4cc15e51
SF
260 }
261
262 /**
263 * Test state system with a Large amount of segments. All segments have the
264 * same length. The call stack's structure used in this test is shown below:
265 *
266 * <pre>
267 * _____
268 * _____
269 * _____
270 * .....
271 * </pre>
272 */
273 @Test
274 public void LargeTest() {
275 // Build the state system
276 ITmfStateSystemBuilder fixture = createFixture();
277 int parentQuark = fixture.getQuarkAbsoluteAndAdd(PROCESS_PATH, THREAD_PATH, CALLSTACK_PATH);
278 for (int i = 0; i < LARGE_AMOUNT_OF_SEGMENTS; i++) {
279 int quark = fixture.getQuarkRelativeAndAdd(parentQuark, Integer.toString(i));
280 TmfStateValue statev = TmfStateValue.newValueLong(i);
281 fixture.pushAttribute(0, statev, quark);
282 }
283 for (int i = 0; i < LARGE_AMOUNT_OF_SEGMENTS; i++) {
284 int quark = fixture.getQuarkRelativeAndAdd(parentQuark, Integer.toString(i));
285 fixture.popAttribute(10, quark);
286 }
287 fixture.closeHistory(11);
288 // Execute the callGraphAnalysis
289 CGAnalysis cga = new CGAnalysis();
290 assertTrue(cga.iterateOverStateSystem(fixture, TP, PP, CSP, new NullProgressMonitor()));
291 ISegmentStore<@NonNull ISegment> segmentStore = cga.getSegmentStore();
292 // Test segment store
293 assertNotNull(segmentStore);
294 Object[] segments = segmentStore.toArray();
295 assertEquals("Number of segments found", LARGE_AMOUNT_OF_SEGMENTS, segments.length);
296 for (int i = 1; i < LARGE_AMOUNT_OF_SEGMENTS; i++) {
55f777f4 297 assertEquals("Test parenthood", ((ICalledFunction) segments[i - 1]).getSymbol(), NonNullUtils.checkNotNull(((ICalledFunction) segments[i]).getParent()).getSymbol());
4cc15e51 298 }
ded2b27f 299 cga.dispose();
4cc15e51
SF
300 }
301
302 /**
303 * Test an empty state system
304 */
305 @Test
306 public void EmptyStateSystemTest() {
307 ITmfStateSystemBuilder fixture = createFixture();
308 fixture.closeHistory(1002);
309 CGAnalysis cga = new CGAnalysis();
310 assertTrue(cga.iterateOverStateSystem(fixture, TP, PP, CSP, new NullProgressMonitor()));
311 ISegmentStore<@NonNull ISegment> segmentStore = cga.getSegmentStore();
312 assertNotNull(segmentStore);
313 Object[] segments = segmentStore.toArray();
314 assertEquals("Number of root functions", 0, segments.length);
ded2b27f 315 cga.dispose();
4cc15e51
SF
316 }
317
318 /**
319 * Test a tree shaped call stack. The root function calls the same function
320 * twice. The call stack's structure used in this test is shown below:
321 *
322 * <pre>
323 *---------1----------
324 * --2-- -3- -2-
325 * -3-
326 * </pre>
327 */
328 @Test
329 public void treeTest() {
330 // Build the state system
331 ITmfStateSystemBuilder fixture = createFixture();
332 int parentQuark = fixture.getQuarkAbsoluteAndAdd(PROCESS_PATH, THREAD_PATH, CALLSTACK_PATH);
333 // Create the root function
334 int quark = fixture.getQuarkRelativeAndAdd(parentQuark, QUARK_0);
335 TmfStateValue statev = TmfStateValue.newValueLong(0);
336 fixture.modifyAttribute(0, statev, quark);
337 fixture.modifyAttribute(100, TmfStateValue.nullValue(), quark);
338 // Create the first child
339 quark = fixture.getQuarkRelativeAndAdd(parentQuark, QUARK_1);
340 statev = TmfStateValue.newValueLong(1);
341 fixture.modifyAttribute(0, TmfStateValue.nullValue(), quark);
342 fixture.modifyAttribute(10, statev, quark);
343 fixture.modifyAttribute(40, TmfStateValue.nullValue(), quark);
344 // Create the second child
345 statev = TmfStateValue.newValueLong(2);
346 fixture.modifyAttribute(50, statev, quark);
347 fixture.modifyAttribute(70, TmfStateValue.nullValue(), quark);
348 // Create the third child
349 statev = TmfStateValue.newValueLong(1);
350 fixture.modifyAttribute(80, statev, quark);
351 fixture.modifyAttribute(100, TmfStateValue.nullValue(), quark);
352 // Create the leaf
353 quark = fixture.getQuarkRelativeAndAdd(parentQuark, QUARK_2);
354 statev = TmfStateValue.newValueLong(3);
355 fixture.modifyAttribute(0, TmfStateValue.nullValue(), quark);
356 fixture.modifyAttribute(15, statev, quark);
357 fixture.modifyAttribute(20, TmfStateValue.nullValue(), quark);
358 fixture.closeHistory(102);
359
360 // Execute the callGraphAnalysis
361 CGAnalysis cga = new CGAnalysis();
362 assertTrue(cga.iterateOverStateSystem(fixture, TP, PP, CSP, new NullProgressMonitor()));
363 ISegmentStore<@NonNull ISegment> segmentStore = cga.getSegmentStore();
364 // Test segment store
365 assertNotNull(segmentStore);
366 Object[] segments = segmentStore.toArray();
367 assertEquals("Number of segments found", 5, segments.length);
55f777f4 368 List<@NonNull ICalledFunction> rootFunctions = cga.getRootFunctions();
4cc15e51 369 assertEquals("Test the number of root functions found", 1, rootFunctions.size());
55f777f4 370 ICalledFunction rootFunction = rootFunctions.get(0);
4cc15e51
SF
371
372 // Test the segments links
373 assertEquals("Children number:First parent", 3, rootFunction.getChildren().size());
55f777f4
PT
374 List<@NonNull ICalledFunction> firstDepthFunctions = rootFunctions.get(0).getChildren();
375 ICalledFunction firstChild = firstDepthFunctions.get(0);
376 ICalledFunction secondChild = firstDepthFunctions.get(1);
377 ICalledFunction thirdChild = firstDepthFunctions.get(2);
378 assertEquals("Test parenthood: First child", rootFunction.getSymbol(), NonNullUtils.checkNotNull(firstChild.getParent()).getSymbol());
379 assertEquals("Test parenthood: Second parent", rootFunction.getSymbol(), NonNullUtils.checkNotNull(secondChild.getParent()).getSymbol());
380 assertEquals("Test parenthood: Third parent", rootFunction.getSymbol(), NonNullUtils.checkNotNull(thirdChild.getParent()).getSymbol());
4cc15e51 381 assertEquals("Children number: First child", 1, firstChild.getChildren().size());
55f777f4
PT
382 ICalledFunction leaf = firstChild.getChildren().get(0);
383 assertEquals("Test parenthood: Third parent", firstChild.getSymbol(), NonNullUtils.checkNotNull(leaf.getParent()).getSymbol());
4cc15e51
SF
384 assertTrue("Children number:leaf", leaf.getChildren().isEmpty());
385
386 // Test the segments self time
387 assertEquals("Parent's self time", 30, rootFunction.getSelfTime());
388 assertEquals("First child's self time", 25, firstChild.getSelfTime());
389 assertEquals("Second child's self time", 20, secondChild.getSelfTime());
390 assertEquals("Third child's self time", 20, thirdChild.getSelfTime());
391 assertEquals("Leaf's self time", 5, leaf.getSelfTime());
392 // Test the segments duration
393 assertEquals("Test first function's duration", 100, rootFunction.getLength());
394 assertEquals("Test first child's duration", 30, firstChild.getLength());
395 assertEquals("Test second child's duration", 20, secondChild.getLength());
396 assertEquals("Test third child's duration", 20, thirdChild.getLength());
397 assertEquals("Test leaf's duration", 5, leaf.getLength());
398
399 // Test the segments Depth
400 assertEquals("Depth: Parent", 0, rootFunction.getDepth());
401 assertEquals("Depth: First child", 1, firstChild.getDepth());
402 assertEquals("Depth: Second child", 1, secondChild.getDepth());
403 assertEquals("Depth: Third child", 1, thirdChild.getDepth());
404 assertEquals("Depth: Leaf", 2, leaf.getDepth());
405
406 // Test if the first child and the third one have the same address
55f777f4 407 assertEquals("Test the address of two functions", firstChild.getSymbol(), thirdChild.getSymbol());
5eed83df
MK
408
409 // test Flamegraph
410 Collection<@NonNull ThreadNode> flameGraph = cga.getFlameGraph();
411 assertNotNull("Test Flamegraph", flameGraph);
412 assertFalse(flameGraph.isEmpty());
413 ThreadNode flamegraphRoot = flameGraph.iterator().next();
414 assertNotNull("Test Flamegraph root", flamegraphRoot);
415
416 Collection<@NonNull ThreadNode> threadGraph = cga.getThreadNodes();
417 assertNotNull("Test ThreadNodes", threadGraph);
418 assertFalse(threadGraph.isEmpty());
419 ThreadNode threadgraphRoot = threadGraph.iterator().next();
420 localAssertEquals("Test Flamegraph root", threadgraphRoot, flamegraphRoot);
421
ded2b27f 422 cga.dispose();
4cc15e51 423 }
5eed83df
MK
424
425 private void localAssertEquals(String message, AggregatedCalledFunction aggregatedCalledFunction, AggregatedCalledFunction actualElem) {
426 if (Objects.equals(aggregatedCalledFunction, actualElem)) {
427 return;
428 }
429 assertNotNull(message, aggregatedCalledFunction);
430 assertNotNull(message, actualElem);
431 Assert.assertEquals(message, aggregatedCalledFunction.getDepth(), actualElem.getDepth());
432 Assert.assertEquals(message, aggregatedCalledFunction.getDuration(), actualElem.getDuration());
433 Assert.assertEquals(message, aggregatedCalledFunction.getMaxDepth(), actualElem.getMaxDepth());
434 Assert.assertEquals(message, aggregatedCalledFunction.getMaxDepth(), actualElem.getMaxDepth());
435 Assert.assertEquals(message, aggregatedCalledFunction.getSelfTime(), actualElem.getSelfTime());
436 localAssertEquals(message, aggregatedCalledFunction.getChildren(), actualElem.getChildren());
437 }
438
439 private void localAssertEquals(String message, @NonNull Collection<@NonNull AggregatedCalledFunction> expected, @NonNull Collection<@NonNull AggregatedCalledFunction> actual) {
440 Iterator<@NonNull AggregatedCalledFunction> expectedIter = expected.iterator();
441 for (AggregatedCalledFunction actualElem : actual) {
442 localAssertEquals(message, expectedIter.next(), actualElem);
443 }
444 }
4cc15e51 445}
This page took 0.046687 seconds and 5 git commands to generate.