1 /*******************************************************************************
2 * Copyright (c) 2016 Ericsson
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 *******************************************************************************/
10 package org
.eclipse
.tracecompass
.analysis
.timing
.core
.tests
.callgraph
;
12 import static org
.junit
.Assert
.assertEquals
;
13 import static org
.junit
.Assert
.assertNotNull
;
14 import static org
.junit
.Assert
.assertTrue
;
16 import java
.util
.Collections
;
17 import java
.util
.List
;
19 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
20 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
21 import org
.eclipse
.jdt
.annotation
.NonNull
;
22 import org
.eclipse
.jdt
.annotation
.Nullable
;
23 import org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
;
24 import org
.eclipse
.tracecompass
.internal
.analysis
.timing
.core
.callgraph
.CallGraphAnalysis
;
25 import org
.eclipse
.tracecompass
.internal
.analysis
.timing
.core
.callgraph
.ICalledFunction
;
26 import org
.eclipse
.tracecompass
.segmentstore
.core
.ISegment
;
27 import org
.eclipse
.tracecompass
.segmentstore
.core
.ISegmentStore
;
28 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystem
;
29 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystemBuilder
;
30 import org
.eclipse
.tracecompass
.statesystem
.core
.StateSystemFactory
;
31 import org
.eclipse
.tracecompass
.statesystem
.core
.backend
.IStateHistoryBackend
;
32 import org
.eclipse
.tracecompass
.statesystem
.core
.backend
.StateHistoryBackendFactory
;
33 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.TmfStateValue
;
34 import org
.eclipse
.tracecompass
.tmf
.core
.segment
.ISegmentAspect
;
35 import org
.junit
.Test
;
38 * Test the CallGraphAnalysis.This creates a virtual state system in each test
39 * and tests the segment store returned by the CallGraphAnalysis.
41 * @author Sonia Farrah
44 public class CallGraphAnalysisTest
{
46 private static final @NonNull String PROCESS_PATH
= "Processes";
47 private static final @NonNull String THREAD_PATH
= "Thread";
48 private static final @NonNull String CALLSTACK_PATH
= "CallStack";
49 private static final String QUARK_0
= "0";
50 private static final String QUARK_1
= "1";
51 private static final String QUARK_2
= "2";
52 private static final Integer SMALL_AMOUNT_OF_SEGMENT
= 3;
53 private static final int LARGE_AMOUNT_OF_SEGMENTS
= 1000;
54 private static final String
@NonNull [] CSP
= { CALLSTACK_PATH
};
55 private static final String
@NonNull [] PP
= { PROCESS_PATH
};
56 private static final String
@NonNull [] TP
= { THREAD_PATH
};
59 * This class is used to make the CallGraphAnalysis's method
60 * iterateOverStateSystem() visible to test
62 private class CGAnalysis
extends CallGraphAnalysis
{
65 protected boolean iterateOverStateSystem(@Nullable ITmfStateSystem ss
, String
[] threadsPattern
, String
[] processesPattern
, String
[] callStackPath
, IProgressMonitor monitor
) {
66 return super.iterateOverStateSystem(ss
, threadsPattern
, processesPattern
, callStackPath
, monitor
);
70 public @NonNull Iterable
<@NonNull ISegmentAspect
> getSegmentAspects() {
71 return Collections
.EMPTY_LIST
;
76 private static ITmfStateSystemBuilder
createFixture() {
77 IStateHistoryBackend backend
;
78 backend
= StateHistoryBackendFactory
.createInMemoryBackend("Test", 0L);
79 ITmfStateSystemBuilder fixture
= StateSystemFactory
.newStateSystem(backend
);
84 * Test cascade state system. The call stack's structure used in this test
95 public void CascadeTest() {
96 ITmfStateSystemBuilder fixture
= createFixture();
97 // Build the state system
100 int parentQuark
= fixture
.getQuarkAbsoluteAndAdd(PROCESS_PATH
, THREAD_PATH
, CALLSTACK_PATH
);
101 for (int i
= 1; i
<= SMALL_AMOUNT_OF_SEGMENT
; i
++) {
102 int quark
= fixture
.getQuarkRelativeAndAdd(parentQuark
, Integer
.toString(i
));
103 TmfStateValue statev
= TmfStateValue
.newValueLong(i
);
104 fixture
.modifyAttribute(start
, TmfStateValue
.nullValue(), quark
);
105 fixture
.modifyAttribute(start
+ i
, statev
, quark
);
106 fixture
.modifyAttribute(end
- i
, TmfStateValue
.nullValue(), quark
);
109 fixture
.closeHistory(1002);
110 // Execute the CallGraphAnalysis
111 CGAnalysis cga
= new CGAnalysis();
112 assertTrue(cga
.iterateOverStateSystem(fixture
, TP
, PP
, CSP
, new NullProgressMonitor()));
113 ISegmentStore
<@NonNull ISegment
> segmentStore
= cga
.getSegmentStore();
114 // Test the segment store generated by the analysis
115 assertNotNull(segmentStore
);
116 Object
[] segments
= segmentStore
.toArray();
117 assertEquals("Number of segments Found", 3, segments
.length
);
118 ICalledFunction f1
= (ICalledFunction
) segments
[0];
119 ICalledFunction f2
= (ICalledFunction
) segments
[1];
120 ICalledFunction f3
= (ICalledFunction
) segments
[2];
121 assertEquals("Test the parenthood", NonNullUtils
.checkNotNull(f2
.getParent()).getSymbol(), f1
.getSymbol());
122 assertEquals("Children number:First parent", 1, f1
.getChildren().size());
123 assertEquals("Children number:Second parent", 1, f2
.getChildren().size());
124 assertTrue("Children number:Second parent", f3
.getChildren().isEmpty());
125 assertTrue("Children number:Child(leaf)", ((ICalledFunction
) segments
[2]).getChildren().isEmpty());
126 assertEquals("Parent's self time", 2, f1
.getSelfTime());
127 assertEquals("Child's self time", 2, f2
.getSelfTime());
128 assertEquals("The leaf's self time", 994, f3
.getSelfTime());
129 assertEquals("Test first function's duration", 998, f1
.getLength());
130 assertEquals("Test second function's duration", 996, f2
.getLength());
131 assertEquals("Test third function's duration", 994, f3
.getLength());
132 assertEquals("Depth:First parent", 0, f1
.getDepth());
133 assertEquals("Depth:Second parent", 1, f2
.getDepth());
134 assertEquals("Depth:Last child", 2, f3
.getDepth());
138 * Build a pyramid shaped call stack.This call stack contains three
139 * functions ,Its structure is shown below :
147 private static void buildPyramidCallStack(ITmfStateSystemBuilder fixture
) {
148 int parentQuark
= fixture
.getQuarkAbsoluteAndAdd(PROCESS_PATH
, THREAD_PATH
, CALLSTACK_PATH
);
149 // Create the first function
150 int quark
= fixture
.getQuarkRelativeAndAdd(parentQuark
, QUARK_0
);
151 TmfStateValue statev
= TmfStateValue
.newValueLong(0);
152 fixture
.modifyAttribute(0, TmfStateValue
.nullValue(), quark
);
153 fixture
.modifyAttribute(10, statev
, quark
);
154 fixture
.modifyAttribute(20, TmfStateValue
.nullValue(), quark
);
155 // Create the second function
156 quark
= fixture
.getQuarkRelativeAndAdd(parentQuark
, QUARK_1
);
157 statev
= TmfStateValue
.newValueLong(1);
158 fixture
.modifyAttribute(0, TmfStateValue
.nullValue(), quark
);
159 fixture
.modifyAttribute(5, statev
, quark
);
160 fixture
.modifyAttribute(25, TmfStateValue
.nullValue(), quark
);
161 // Create the third function
162 quark
= fixture
.getQuarkRelativeAndAdd(parentQuark
, QUARK_2
);
163 statev
= TmfStateValue
.newValueLong(2);
164 fixture
.modifyAttribute(0, statev
, quark
);
165 fixture
.modifyAttribute(30, TmfStateValue
.nullValue(), quark
);
167 fixture
.closeHistory(31);
171 * Test pyramid state system. The call stack's structure used in this test
181 public void PyramidTest() {
182 ITmfStateSystemBuilder fixture
= createFixture();
183 buildPyramidCallStack(fixture
);
184 // Execute the callGraphAnalysis
185 CGAnalysis cga
= new CGAnalysis();
186 assertTrue(cga
.iterateOverStateSystem(fixture
, TP
, PP
, CSP
, new NullProgressMonitor()));
187 ISegmentStore
<@NonNull ISegment
> segmentStore
= cga
.getSegmentStore();
188 assertNotNull(segmentStore
);
189 Object
[] segments
= segmentStore
.toArray();
190 ICalledFunction f1
= (ICalledFunction
) segments
[0];
191 assertEquals("Number of segments Found", 1, segments
.length
);
192 assertEquals("Callees number", 0, f1
.getChildren().size());
193 assertEquals("Function's self time", 10, f1
.getSelfTime());
194 assertEquals("Compare the function's self time and total time", f1
.getLength(), f1
.getSelfTime());
195 assertEquals("Function's depth", 0, f1
.getDepth());
199 * Test mutliRoots state system. The call stack's structure used in this
200 * test is shown below:
208 public void multiFunctionRootsTest() {
209 ITmfStateSystemBuilder fixture
= createFixture();
210 int parentQuark
= fixture
.getQuarkAbsoluteAndAdd(PROCESS_PATH
, THREAD_PATH
, CALLSTACK_PATH
);
211 // Create the first root function
212 int quark
= fixture
.getQuarkRelativeAndAdd(parentQuark
, QUARK_0
);
213 TmfStateValue statev
= TmfStateValue
.newValueLong(0);
214 fixture
.modifyAttribute(0, statev
, quark
);
215 fixture
.modifyAttribute(20, TmfStateValue
.nullValue(), quark
);
216 // Create the second root function
217 statev
= TmfStateValue
.newValueLong(1);
218 fixture
.modifyAttribute(30, statev
, quark
);
219 fixture
.modifyAttribute(50, TmfStateValue
.nullValue(), quark
);
220 // Create the first root function's callee
221 quark
= fixture
.getQuarkRelativeAndAdd(parentQuark
, QUARK_1
);
222 statev
= TmfStateValue
.newValueLong(2);
223 fixture
.modifyAttribute(0, statev
, quark
);
224 fixture
.modifyAttribute(10, TmfStateValue
.nullValue(), quark
);
225 // Create the second root function's callee
226 statev
= TmfStateValue
.newValueLong(3);
227 fixture
.modifyAttribute(30, statev
, quark
);
228 fixture
.modifyAttribute(40, TmfStateValue
.nullValue(), quark
);
229 fixture
.closeHistory(51);
231 // Execute the callGraphAnalysis
232 CGAnalysis cga
= new CGAnalysis();
233 assertTrue(cga
.iterateOverStateSystem(fixture
, TP
, PP
, CSP
, new NullProgressMonitor()));
234 ISegmentStore
<@NonNull ISegment
> segmentStore
= cga
.getSegmentStore();
235 // Test the segment store
236 assertNotNull(segmentStore
);
237 Object
[] segments
= segmentStore
.toArray();
238 List
<@NonNull ICalledFunction
> threads
= cga
.getRootFunctions();
239 assertEquals("Number of root functions", 2, threads
.size());
240 assertEquals("Number of children: first root function", 1, threads
.get(0).getChildren().size());
241 assertEquals("Number of children: first root function", 1, threads
.get(1).getChildren().size());
242 ICalledFunction firstChild
= threads
.get(0).getChildren().get(0);
243 ICalledFunction secondChild
= threads
.get(1).getChildren().get(0);
244 assertEquals("Number of segments found", 4, segments
.length
);
245 assertNotNull(firstChild
.getParent());
246 assertNotNull(secondChild
.getParent());
248 assertEquals("Test of parenthood", NonNullUtils
.checkNotNull(firstChild
.getParent()).getSymbol(), threads
.get(0).getSymbol());
249 assertEquals("Test of parenthood", NonNullUtils
.checkNotNull(secondChild
.getParent()).getSymbol(), threads
.get(1).getSymbol());
254 * Test state system with a Large amount of segments. All segments have the
255 * same length. The call stack's structure used in this test is shown below:
265 public void LargeTest() {
266 // Build the state system
267 ITmfStateSystemBuilder fixture
= createFixture();
268 int parentQuark
= fixture
.getQuarkAbsoluteAndAdd(PROCESS_PATH
, THREAD_PATH
, CALLSTACK_PATH
);
269 for (int i
= 0; i
< LARGE_AMOUNT_OF_SEGMENTS
; i
++) {
270 int quark
= fixture
.getQuarkRelativeAndAdd(parentQuark
, Integer
.toString(i
));
271 TmfStateValue statev
= TmfStateValue
.newValueLong(i
);
272 fixture
.pushAttribute(0, statev
, quark
);
274 for (int i
= 0; i
< LARGE_AMOUNT_OF_SEGMENTS
; i
++) {
275 int quark
= fixture
.getQuarkRelativeAndAdd(parentQuark
, Integer
.toString(i
));
276 fixture
.popAttribute(10, quark
);
278 fixture
.closeHistory(11);
279 // Execute the callGraphAnalysis
280 CGAnalysis cga
= new CGAnalysis();
281 assertTrue(cga
.iterateOverStateSystem(fixture
, TP
, PP
, CSP
, new NullProgressMonitor()));
282 ISegmentStore
<@NonNull ISegment
> segmentStore
= cga
.getSegmentStore();
283 // Test segment store
284 assertNotNull(segmentStore
);
285 Object
[] segments
= segmentStore
.toArray();
286 assertEquals("Number of segments found", LARGE_AMOUNT_OF_SEGMENTS
, segments
.length
);
287 for (int i
= 1; i
< LARGE_AMOUNT_OF_SEGMENTS
; i
++) {
288 assertEquals("Test parenthood", ((ICalledFunction
) segments
[i
- 1]).getSymbol(), NonNullUtils
.checkNotNull(((ICalledFunction
) segments
[i
]).getParent()).getSymbol());
293 * Test an empty state system
296 public void EmptyStateSystemTest() {
297 ITmfStateSystemBuilder fixture
= createFixture();
298 fixture
.closeHistory(1002);
299 CGAnalysis cga
= new CGAnalysis();
300 assertTrue(cga
.iterateOverStateSystem(fixture
, TP
, PP
, CSP
, new NullProgressMonitor()));
301 ISegmentStore
<@NonNull ISegment
> segmentStore
= cga
.getSegmentStore();
302 assertNotNull(segmentStore
);
303 Object
[] segments
= segmentStore
.toArray();
304 assertEquals("Number of root functions", 0, segments
.length
);
308 * Test a tree shaped call stack. The root function calls the same function
309 * twice. The call stack's structure used in this test is shown below:
312 *---------1----------
318 public void treeTest() {
319 // Build the state system
320 ITmfStateSystemBuilder fixture
= createFixture();
321 int parentQuark
= fixture
.getQuarkAbsoluteAndAdd(PROCESS_PATH
, THREAD_PATH
, CALLSTACK_PATH
);
322 // Create the root function
323 int quark
= fixture
.getQuarkRelativeAndAdd(parentQuark
, QUARK_0
);
324 TmfStateValue statev
= TmfStateValue
.newValueLong(0);
325 fixture
.modifyAttribute(0, statev
, quark
);
326 fixture
.modifyAttribute(100, TmfStateValue
.nullValue(), quark
);
327 // Create the first child
328 quark
= fixture
.getQuarkRelativeAndAdd(parentQuark
, QUARK_1
);
329 statev
= TmfStateValue
.newValueLong(1);
330 fixture
.modifyAttribute(0, TmfStateValue
.nullValue(), quark
);
331 fixture
.modifyAttribute(10, statev
, quark
);
332 fixture
.modifyAttribute(40, TmfStateValue
.nullValue(), quark
);
333 // Create the second child
334 statev
= TmfStateValue
.newValueLong(2);
335 fixture
.modifyAttribute(50, statev
, quark
);
336 fixture
.modifyAttribute(70, TmfStateValue
.nullValue(), quark
);
337 // Create the third child
338 statev
= TmfStateValue
.newValueLong(1);
339 fixture
.modifyAttribute(80, statev
, quark
);
340 fixture
.modifyAttribute(100, TmfStateValue
.nullValue(), quark
);
342 quark
= fixture
.getQuarkRelativeAndAdd(parentQuark
, QUARK_2
);
343 statev
= TmfStateValue
.newValueLong(3);
344 fixture
.modifyAttribute(0, TmfStateValue
.nullValue(), quark
);
345 fixture
.modifyAttribute(15, statev
, quark
);
346 fixture
.modifyAttribute(20, TmfStateValue
.nullValue(), quark
);
347 fixture
.closeHistory(102);
349 // Execute the callGraphAnalysis
350 CGAnalysis cga
= new CGAnalysis();
351 assertTrue(cga
.iterateOverStateSystem(fixture
, TP
, PP
, CSP
, new NullProgressMonitor()));
352 ISegmentStore
<@NonNull ISegment
> segmentStore
= cga
.getSegmentStore();
353 // Test segment store
354 assertNotNull(segmentStore
);
355 Object
[] segments
= segmentStore
.toArray();
356 assertEquals("Number of segments found", 5, segments
.length
);
357 List
<@NonNull ICalledFunction
> rootFunctions
= cga
.getRootFunctions();
358 assertEquals("Test the number of root functions found", 1, rootFunctions
.size());
359 ICalledFunction rootFunction
= rootFunctions
.get(0);
361 // Test the segments links
362 assertEquals("Children number:First parent", 3, rootFunction
.getChildren().size());
363 List
<@NonNull ICalledFunction
> firstDepthFunctions
= rootFunctions
.get(0).getChildren();
364 ICalledFunction firstChild
= firstDepthFunctions
.get(0);
365 ICalledFunction secondChild
= firstDepthFunctions
.get(1);
366 ICalledFunction thirdChild
= firstDepthFunctions
.get(2);
367 assertEquals("Test parenthood: First child", rootFunction
.getSymbol(), NonNullUtils
.checkNotNull(firstChild
.getParent()).getSymbol());
368 assertEquals("Test parenthood: Second parent", rootFunction
.getSymbol(), NonNullUtils
.checkNotNull(secondChild
.getParent()).getSymbol());
369 assertEquals("Test parenthood: Third parent", rootFunction
.getSymbol(), NonNullUtils
.checkNotNull(thirdChild
.getParent()).getSymbol());
370 assertEquals("Children number: First child", 1, firstChild
.getChildren().size());
371 ICalledFunction leaf
= firstChild
.getChildren().get(0);
372 assertEquals("Test parenthood: Third parent", firstChild
.getSymbol(), NonNullUtils
.checkNotNull(leaf
.getParent()).getSymbol());
373 assertTrue("Children number:leaf", leaf
.getChildren().isEmpty());
375 // Test the segments self time
376 assertEquals("Parent's self time", 30, rootFunction
.getSelfTime());
377 assertEquals("First child's self time", 25, firstChild
.getSelfTime());
378 assertEquals("Second child's self time", 20, secondChild
.getSelfTime());
379 assertEquals("Third child's self time", 20, thirdChild
.getSelfTime());
380 assertEquals("Leaf's self time", 5, leaf
.getSelfTime());
381 // Test the segments duration
382 assertEquals("Test first function's duration", 100, rootFunction
.getLength());
383 assertEquals("Test first child's duration", 30, firstChild
.getLength());
384 assertEquals("Test second child's duration", 20, secondChild
.getLength());
385 assertEquals("Test third child's duration", 20, thirdChild
.getLength());
386 assertEquals("Test leaf's duration", 5, leaf
.getLength());
388 // Test the segments Depth
389 assertEquals("Depth: Parent", 0, rootFunction
.getDepth());
390 assertEquals("Depth: First child", 1, firstChild
.getDepth());
391 assertEquals("Depth: Second child", 1, secondChild
.getDepth());
392 assertEquals("Depth: Third child", 1, thirdChild
.getDepth());
393 assertEquals("Depth: Leaf", 2, leaf
.getDepth());
395 // Test if the first child and the third one have the same address
396 assertEquals("Test the address of two functions", firstChild
.getSymbol(), thirdChild
.getSymbol());