Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / tools / memory_inspector / memory_inspector / classification / native_heap_classifier_unittest.py
1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 import unittest
6
7 from memory_inspector.classification import native_heap_classifier
8 from memory_inspector.core import native_heap
9 from memory_inspector.core import stacktrace
10 from memory_inspector.core import symbol
11
12
13 _TEST_RULES = """
14 [
15 {
16   'name': 'content',
17   'source_path': r'content/',
18   'children': [
19     {
20       'name': 'browser',
21       'stacktrace': r'content::browser',
22       'source_path': r'content/browser',
23     },
24     {
25       'name': 'renderer',
26       'stacktrace': r'content::renderer',
27     },
28   ],
29 },
30 {
31   'name': 'ashmem_in_skia',
32   'stacktrace': [r'sk::', r'ashmem::'],
33 },
34 ]
35 """
36
37 _TEST_STACK_TRACES = [
38     (3, [('stack_frame_0::foo()', '/ignored.c'),
39          ('this_goes_under_totals_other', '/ignored.c')]),
40     (5, [('foo', '/ignored.c'),
41          ('content::browser::something()', '/content/browser/something.cc'),
42          ('bar', '/ignored.c')]),
43     (7, [('content::browser::something_else()', '/content/browser/else.cc')]),
44     (11, [('content::browser::not_really()', '/content/subtle/something.cc'),
45           ('foo', '/ignored.c')]),
46     (13, [('foo', '/ignored.c'),
47           ('content::renderer::something()', '/content/renderer/foo.c'),
48           ('bar', '/ignored.c')]),
49     (17, [('content::renderer::something_else()', '/content/renderer/foo.c')]),
50     (19, [('content::renderer::something_else_2()', '/content/renderer/bar.c'),
51           ('foo', '/ignored.c')]),
52     (23, [('content::something_different', '/content/foo.c')]),
53     (29, [('foo', '/ignored.c'),
54           ('sk::something', '/skia/something.c'),
55           ('not_ashsmem_goes_into_totals_other', '/ignored.c')]),
56     (31, [('foo', '/ignored.c'),
57           ('sk::something', '/skia/something.c'),
58           ('foo::bar', '/ignored.c'),
59           ('sk::foo::ashmem::alloc()', '/skia/ashmem.c')]),
60     (37, [('foo', '/ignored.c'),
61           ('sk::something', '/ignored.c'),
62           ('sk::foo::ashmem::alloc()', '/ignored.c')]),
63     (43, [('foo::ashmem::alloc()', '/ignored.c'),
64           ('sk::foo', '/ignored.c'),
65           ('wrong_order_goes_into_totals', '/ignored.c')])
66 ]
67
68 _EXPECTED_RESULTS = {
69     'Total':                         [238],
70     'Total::content':                [95],
71     'Total::content::browser':       [12],  # 5 + 7.
72     'Total::content::renderer':      [49],  # 13 + 17 + 19.
73     'Total::content::content-other': [34],
74     'Total::ashmem_in_skia':         [68],  # 31 + 37.
75     'Total::Total-other':            [75],  # 3 + 29 + 43.
76 }
77
78 _HEURISTIC_TEST_STACK_TRACES = [
79     (10, '/root/base1/foo/bar/file.cc'),  # Contrib: 0.13
80     (20, '/root/base1/foo/baz/file.cc'),  # Contrib: 0.26
81     (1, '/root/base1/foo/nah/file.cc'),   # Contrib: 0.01
82     (3, '/root/base2/file.cc'),           # Contrib: 0.03
83     (22, '/root/base2/subpath/file.cc'),  # Contrib: 0.28
84     (18, '/root/base2/subpath2/file.cc'), # Contrib: 0.23
85     (2, '/root/whatever/file.cc'),        # Contrib: 0.02
86 ]
87
88 _HEURISTIC_EXPECTED_RESULTS = {
89     'Total':                                        [76],
90     'Total::/root/':                                [76],
91     'Total::/root/::base1/foo/':                    [31],  # 10 + 20 +1
92     'Total::/root/::base1/foo/::bar/':              [10],
93     'Total::/root/::base1/foo/::baz/':              [20],
94     'Total::/root/::base1/foo/::base1/foo/-other':  [1],
95     'Total::/root/::base2/':                        [43],  # 3 + 22 + 18
96     'Total::/root/::base2/::subpath/':              [22],
97     'Total::/root/::base2/::subpath2/':             [18],
98     'Total::/root/::base2/::base2/-other':          [3],
99     'Total::/root/::/root/-other':                  [2],
100     'Total::Total-other':                           [0],
101 }
102
103
104 class NativeHeapClassifierTest(unittest.TestCase):
105   def testStandardRuleParsingAndProcessing(self):
106     rule_tree = native_heap_classifier.LoadRules(_TEST_RULES)
107     nheap = native_heap.NativeHeap()
108     mock_addr = 0
109     for test_entry in _TEST_STACK_TRACES:
110       mock_strace = stacktrace.Stacktrace()
111       for (mock_btstr, mock_source_path) in test_entry[1]:
112         mock_addr += 4  # Addr is irrelevant, just keep it distinct.
113         mock_frame = stacktrace.Frame(mock_addr)
114         mock_frame.SetSymbolInfo(symbol.Symbol(mock_btstr, mock_source_path))
115         mock_strace.Add(mock_frame)
116       nheap.Add(native_heap.Allocation(
117           size=test_entry[0], count=1, stack_trace=mock_strace))
118
119     res = native_heap_classifier.Classify(nheap, rule_tree)
120     self._CheckResult(res.total, '', _EXPECTED_RESULTS)
121
122   def testInferHeuristicRules(self):
123     nheap = native_heap.NativeHeap()
124     mock_addr = 0
125     for (mock_alloc_size, mock_source_path) in _HEURISTIC_TEST_STACK_TRACES:
126       mock_strace = stacktrace.Stacktrace()
127       mock_addr += 4  # Addr is irrelevant, just keep it distinct.
128       mock_frame = stacktrace.Frame(mock_addr)
129       mock_frame.SetSymbolInfo(symbol.Symbol(str(mock_addr), mock_source_path))
130       for _ in xrange(10):  # Just repeat the same stack frame 10 times
131         mock_strace.Add(mock_frame)
132       nheap.Add(native_heap.Allocation(
133           size=mock_alloc_size, count=1, stack_trace=mock_strace))
134
135     rule_tree = native_heap_classifier.InferHeuristicRulesFromHeap(
136         nheap, threshold=0.05)
137     res = native_heap_classifier.Classify(nheap, rule_tree)
138     self._CheckResult(res.total, '', _HEURISTIC_EXPECTED_RESULTS)
139
140   def _CheckResult(self, node, prefix, expected_results):
141     node_name = prefix + node.name
142     self.assertIn(node_name, expected_results)
143     self.assertEqual(node.values, expected_results[node_name])
144     for child in node.children:
145       self._CheckResult(child, node_name + '::', expected_results)