| #!/usr/bin/env vpython3 |
| # Copyright 2018 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Tests for cluster.py.""" |
| |
| import unittest |
| import json |
| |
| import cluster |
| import process_profiles |
| from test_utils import (ProfileFile, |
| SimpleTestSymbol, |
| TestProfileManager, |
| TestSymbolOffsetProcessor) |
| |
| |
| class ClusteringTestCase(unittest.TestCase): |
| def testClusterOf(self): |
| clstr = cluster.Clustering() |
| c = clstr.ClusterOf('a') |
| self.assertEqual(['a'], c.syms) |
| c = clstr._MakeCluster(['a', 'b', 'c']) |
| self.assertEqual(c, clstr.ClusterOf('a')) |
| self.assertEqual(c, clstr.ClusterOf('b')) |
| self.assertEqual(c, clstr.ClusterOf('c')) |
| |
| def testClusterCombine(self): |
| clstr = cluster.Clustering() |
| x = clstr._MakeCluster(['a', 'b']) |
| self.assertEqual(x, clstr.ClusterOf('a')) |
| self.assertEqual(x, clstr.ClusterOf('b')) |
| |
| y = clstr._MakeCluster(['c']) |
| self.assertEqual(y, clstr.ClusterOf('c')) |
| |
| z = clstr.Combine(y, x) |
| self.assertEqual(['c', 'a', 'b'], z.syms) |
| self.assertEqual(z, clstr.ClusterOf('a')) |
| self.assertEqual(z, clstr.ClusterOf('b')) |
| self.assertEqual(z, clstr.ClusterOf('c')) |
| |
| def testClusteringDistances(self): |
| c = cluster.Clustering() |
| c.NEIGHBOR_DISTANCE = 3 |
| c.AddSymbolLists([list('abcd'), list('acbe'), list('bacf'), |
| list('badf'), list('baef')]) |
| distances = {} |
| for n in c._neighbors: |
| self.assertFalse((n.src, n.dst) in distances) |
| distances[(n.src, n.dst)] = n.dist |
| self.assertEqual(13, len(distances)) |
| self.assertEqual((2 + 1 + 1 + 2000) / 5., distances[('a', 'c')]) |
| self.assertEqual((1 + 4000) / 5., distances[('a', 'd')]) |
| self.assertEqual((1 + 4000) / 5., distances[('a', 'e')]) |
| self.assertEqual((2 + 2 + 2 + 2000) / 5., distances[('a', 'f')]) |
| self.assertEqual(0, distances[('b', 'a')]) |
| self.assertEqual((1 + -1 + 2 + 2000) / 5., distances[('b', 'c')]) |
| self.assertTrue(('b', 'd') in distances) |
| self.assertTrue(('b', 'e') in distances) |
| self.assertTrue(('c', 'd') in distances) |
| self.assertTrue(('c', 'e') in distances) |
| self.assertTrue(('c', 'f') in distances) |
| self.assertTrue(('d', 'f') in distances) |
| self.assertTrue(('e', 'f') in distances) |
| |
| def testClusterToList(self): |
| c = cluster.Clustering() |
| c.NEIGHBOR_DISTANCE = 3 |
| c.AddSymbolLists([list('abcd'), list('acbe'), list('bacf'), |
| list('badf'), list('baef')]) |
| self.assertEqual(list('bacfed'), c.ClusterToList()) |
| |
| def testClusterOneList(self): |
| c = cluster.Clustering() |
| c.NEIGHBOR_DISTANCE = 3 |
| c.AddSymbolLists([list('fedcba')]) |
| self.assertEqual(list('fedcba'), c.ClusterToList()) |
| |
| def testClusterShortList(self): |
| c = cluster.Clustering() |
| c.NEIGHBOR_DISTANCE = 3 |
| c.AddSymbolLists([list('ab')]) |
| self.assertEqual(list('ab'), c.ClusterToList()) |
| |
| def testClusterReallyShortList(self): |
| c = cluster.Clustering() |
| c.NEIGHBOR_DISTANCE = 3 |
| c.AddSymbolLists([list('a')]) |
| self.assertEqual([], c.ClusterToList()) |
| |
| def testSizedClusterToList(self): |
| c = cluster.Clustering() |
| c.NEIGHBOR_DISTANCE = 3 |
| c.MAX_CLUSTER_SIZE = 1 # Will supress all clusters |
| size_map = {'a': 3, |
| 'b': 4, |
| 'c': 5, |
| 'd': 6, |
| 'e': 7, |
| 'f': 8} |
| c.AddSymbolLists([list('abcd'), list('acbe'), list('bacf'), |
| list('badf'), list('baef')]) |
| self.assertEqual(list('fedcba'), c.ClusterToList(size_map)) |
| |
| def testClusterOffsets(self): |
| processor = TestSymbolOffsetProcessor([ |
| SimpleTestSymbol('linker_script_start_of_text', 0, 0), |
| SimpleTestSymbol('1', 1000, 999), |
| SimpleTestSymbol('2', 2000, 999), |
| SimpleTestSymbol('3', 3000, 999), |
| SimpleTestSymbol('4', 4000, 16), |
| SimpleTestSymbol('5', 5000, 16), |
| SimpleTestSymbol('6', 6000, 999), |
| SimpleTestSymbol('7', 7000, 16), |
| SimpleTestSymbol('8', 8000, 999), |
| SimpleTestSymbol('9', 9000, 16), |
| ]) |
| mgr = TestProfileManager({ |
| ProfileFile(40, 0, ''): [1000, 2000, 3000], |
| ProfileFile(50, 1, ''): [3000, 4000, 5000], |
| ProfileFile(51, 0, 'renderer'): [2000, 3000, 6000], |
| ProfileFile(51, 1, 'gpu-process'): [6000, 7000], |
| ProfileFile(70, 0, ''): [1000, 2000, 6000, 8000, 9000], |
| ProfileFile(70, 1, ''): [9000, 5000, 3000]}) |
| syms = cluster.ClusterOffsets(mgr, processor, limit_cluster_size=False) |
| self.assertListEqual(list('236148957'), syms) |
| |
| syms = cluster.ClusterOffsets(mgr, processor, limit_cluster_size=True) |
| self.assertListEqual(list('236489517'), syms) |
| |
| def testClusteringDistancesForCallGraph(self): |
| c = cluster.Clustering() |
| callerA = cluster.CallerInfo(caller_symbol='a', count=1) |
| callerB = cluster.CallerInfo(caller_symbol='b', count=2) |
| callerC = cluster.CallerInfo(caller_symbol='c', count=3) |
| callerD = cluster.CallerInfo(caller_symbol='d', count=100) |
| callerE = cluster.CallerInfo(caller_symbol='e', count=200) |
| |
| calleeA = cluster.CalleeInfo(index=4, callee_symbol='a', misses=0, |
| caller_and_count=[]) |
| calleeB = cluster.CalleeInfo(index=8, callee_symbol='b', misses=1, |
| caller_and_count=[callerA]) |
| calleeC = cluster.CalleeInfo(index=12, callee_symbol='c', misses=1, |
| caller_and_count=[callerA, callerE]) |
| calleeD = cluster.CalleeInfo(index=20, callee_symbol='d', misses=1, |
| caller_and_count=[callerB, callerC, callerE]) |
| calleeF = cluster.CalleeInfo(index=28, callee_symbol='f', misses=10, |
| caller_and_count=[callerD]) |
| process1 = [calleeA, calleeB, calleeC, calleeD] |
| process2 = [calleeA, calleeB, calleeC, calleeD, calleeF] |
| call_graph = [process1, process2] |
| whitelist = ['e', 'g', 'h', 'k', 'l'] |
| c.AddSymbolCallGraph(call_graph, whitelist) |
| distances = {} |
| for n in c._neighbors: |
| self.assertFalse((n.src, n.dst) in distances) |
| distances[(n.src, n.dst)] = n.dist |
| self.assertEqual(5, len(distances)) |
| self.assertEquals(-2, distances[('a', 'b')]) |
| self.assertEquals(-2, distances[('a', 'c')]) |
| self.assertEquals(-4, distances[('b', 'd')]) |
| self.assertEquals(-6, distances[('c', 'd')]) |
| self.assertEquals(-100, distances[('d', 'f')]) |
| self.assertEquals(list('abcdf'), c.ClusterToList()) |
| |
| def testClusterOffsetsFromCallGraph(self): |
| process1 = ('{"call_graph": [ {' |
| '"callee_offset": "1000",' |
| '"caller_and_count": [ {' |
| '"caller_offset": "0",' |
| '"count": "2"' |
| '} ],' |
| '"index": "61496"' |
| '}, {' |
| '"callee_offset": "7000",' |
| '"caller_and_count": [ {' |
| '"caller_offset": "1000",' |
| '"count": "2"' |
| '}, {' |
| '"caller_offset": "7500",' |
| '"count": "100"' |
| '} ],' |
| '"index": "61500"' |
| '}, {' |
| '"callee_offset": "6000",' |
| '"caller_and_count": [ {' |
| '"caller_offset": "1000",' |
| '"count": "4"' |
| '}, {' |
| '"caller_offset": "7000",' |
| '"count": "3"' |
| '}, {' |
| '"caller_offset": "7500",' |
| '"count": "2"' |
| '}, {' |
| '"caller_offset": "0",' |
| '"count": "3"' |
| '} ],' |
| '"index": "47860"' |
| '}, {' |
| '"callee_offset": "3000",' |
| '"caller_and_count": [ {' |
| '"caller_offset": "6000",' |
| '"count": "11"' |
| '} ],' |
| '"index": "47900"' |
| '} ],' |
| '"total_calls_count": "127"' |
| '}') |
| |
| process2 = ('{"call_graph": [ {' |
| '"callee_offset": "1000",' |
| '"caller_and_count": [ {' |
| '"caller_offset": "0",' |
| '"count": "2"' |
| '} ],' |
| '"index": "61496"' |
| '}, {' |
| '"callee_offset": "5000",' |
| '"caller_and_count": [ {' |
| '"caller_offset": "1000",' |
| '"count": "20"' |
| '}, {' |
| '"caller_offset": "5000",' |
| '"count": "100"' |
| '}, {' |
| '"caller_offset": "3000",' |
| '"count": "40"' |
| '} ],' |
| '"index": "61500"' |
| '}, {' |
| '"callee_offset": "3000",' |
| '"caller_and_count": [ {' |
| '"caller_offset": "5000",' |
| '"count": "10"' |
| '}, {' |
| '"caller_offset": "0",' |
| '"count": "10"' |
| '} ],' |
| '"index": "47860"' |
| '} ],' |
| '"total_calls_count": "182"' |
| '}') |
| |
| process3 = ('{"call_graph": [ {' |
| '"callee_offset": "8000",' |
| '"caller_and_count": [ {' |
| '"caller_offset": "0",' |
| '"count": "5"' |
| '} ],' |
| '"index": "61496"' |
| '}, {' |
| '"callee_offset": "2000",' |
| '"caller_and_count": [ {' |
| '"caller_offset": "8000",' |
| '"count": "100"' |
| '} ],' |
| '"index": "61500"' |
| '}, {' |
| '"callee_offset": "4000",' |
| '"caller_and_count": [ {' |
| '"caller_offset": "8000",' |
| '"count": "20"' |
| '} ],' |
| '"index": "61504"' |
| '}, {' |
| '"callee_offset": "9000",' |
| '"caller_and_count": [ {' |
| '"caller_offset": "8000",' |
| '"count": "50"' |
| '} ],' |
| '"index": "61512"' |
| '}, {' |
| '"callee_offset": "7000",' |
| '"caller_and_count": [ {' |
| '"caller_offset": "2000",' |
| '"count": "15"' |
| '}, {' |
| '"caller_offset": "4000",' |
| '"count": "20"' |
| '}, {' |
| '"caller_offset": "9000",' |
| '"count": "80"' |
| '}, {' |
| '"caller_offset": "0",' |
| '"count": "400"' |
| '} ],' |
| '"index": "61516"' |
| '} ],' |
| '"total_calls_count": "690"' |
| '}') |
| |
| process4 = ('{"call_graph": [ {' |
| '"callee_offset": "8000",' |
| '"caller_and_count": [ {' |
| '"caller_offset": "0",' |
| '"count": "10"' |
| '} ],' |
| '"index": "61496"' |
| '}, {' |
| '"callee_offset": "2000",' |
| '"caller_and_count": [ {' |
| '"caller_offset": "8000",' |
| '"count": "100"' |
| '} ],' |
| '"index": "61500"' |
| '}, {' |
| '"callee_offset": "6000",' |
| '"caller_and_count": [ {' |
| '"caller_offset": "7000",' |
| '"count": "10"' |
| '} , {' |
| '"caller_offset": "7500",' |
| '"count": "2"' |
| '} ],' |
| '"index": "61504"' |
| '}, {' |
| '"callee_offset": "7000",' |
| '"caller_and_count": [ {' |
| '"caller_offset": "8000",' |
| '"count": "300"' |
| '}, {' |
| '"caller_offset": "7500",' |
| '"count": "100"' |
| '}, {' |
| '"caller_offset": "2000",' |
| '"count": "15"' |
| '}, {' |
| '"caller_offset": "0",' |
| '"count": "50"' |
| '} ],' |
| '"index": "61516"' |
| '} ],' |
| '"total_calls_count": "587"' |
| '}') |
| |
| processor = TestSymbolOffsetProcessor([ |
| SimpleTestSymbol('linker_script_start_of_text', 0, 0), |
| SimpleTestSymbol('1', 1000, 999), |
| SimpleTestSymbol('2', 2000, 999), |
| SimpleTestSymbol('3', 3000, 999), |
| SimpleTestSymbol('4', 4000, 16), |
| SimpleTestSymbol('5', 5000, 16), |
| SimpleTestSymbol('6', 6000, 999), |
| SimpleTestSymbol('7', 7000, 16), |
| SimpleTestSymbol('8', 7100, 0), # whitelist |
| SimpleTestSymbol('9', 8000, 999), |
| SimpleTestSymbol('10', 9000, 16)]) |
| mgr = TestProfileManager({ |
| ProfileFile(40, 0, 'renderer'): json.loads(process1), |
| ProfileFile(50, 1, 'renderer'): json.loads(process2), |
| ProfileFile(51, 0, 'browser'): json.loads(process3), |
| ProfileFile(51, 1, 'gpu-process'): json.loads(process4)}) |
| syms = cluster.ClusterOffsets(mgr, processor, limit_cluster_size=False, |
| call_graph=True) |
| self.assertListEqual(['7', '6', '1', '5', '3', '9', '2', '10', '4'], syms) |
| |
| |
| |
| if __name__ == "__main__": |
| unittest.main() |