147 lines
3.6 KiB
Python
Executable File
147 lines
3.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
# Copyright 2020 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
"""Tests for remove_cold_functions."""
|
|
|
|
from __future__ import print_function
|
|
|
|
import io
|
|
from unittest.mock import patch
|
|
import unittest
|
|
|
|
from afdo_redaction import remove_cold_functions
|
|
|
|
|
|
def _construct_profile(indices=None):
|
|
real_world_profile_functions = [
|
|
"""SomeFunction1:24150:300
|
|
2: 75
|
|
3: 23850
|
|
39: 225
|
|
""",
|
|
"""SomeFunction2:8925:225
|
|
0: 225
|
|
0.2: 150
|
|
0.1: SomeFunction2:6300
|
|
3: 6300
|
|
0.2: SomeFunction2:150
|
|
3: 75
|
|
""",
|
|
"""SomeFunction3:7500:75
|
|
0: 75
|
|
0.2: 75
|
|
0.1: SomeFunction3:6600
|
|
1: 6600
|
|
0.2: SomeFunction3:75
|
|
1: 75
|
|
""",
|
|
"""LargerFunction4:51450:0
|
|
1: 0
|
|
3: 0
|
|
3.1: 7350
|
|
4: 7350
|
|
7: 7350
|
|
8: 7350
|
|
9: 7350
|
|
12: 0
|
|
15: 0
|
|
13: AnotherFunction5:0
|
|
3: 0
|
|
3.1: 0
|
|
3.2: 0
|
|
4: 0
|
|
5: 0
|
|
6: 0
|
|
7: 0
|
|
8: 0
|
|
9: 0
|
|
""",
|
|
"""SomeFakeFunction5:7500:75
|
|
0: 75
|
|
0.2: 75
|
|
0.1: SomeFakeFunction5:6600
|
|
1: 6600
|
|
0.2: SomeFakeFunction5:75
|
|
1: 75
|
|
""",
|
|
]
|
|
|
|
ret = []
|
|
if not indices:
|
|
for x in real_world_profile_functions:
|
|
ret += x.strip().splitlines()
|
|
return ret
|
|
|
|
ret = []
|
|
for i in indices:
|
|
ret += real_world_profile_functions[i].strip().splitlines()
|
|
return ret
|
|
|
|
|
|
def _run_test(input_lines, goal, cwp_file=None, benchmark_file=None):
|
|
input_buf = io.StringIO('\n'.join(input_lines))
|
|
output_buf = io.StringIO()
|
|
remove_cold_functions.run(input_buf, output_buf, goal, cwp_file,
|
|
benchmark_file)
|
|
return output_buf.getvalue().splitlines()
|
|
|
|
|
|
class Test(unittest.TestCase):
|
|
"""Test functions in remove_cold_functions.py"""
|
|
|
|
def test_empty_profile(self):
|
|
self.assertEqual(_run_test([], 0), [])
|
|
|
|
def test_remove_all_functions_fail(self):
|
|
input_profile_lines = _construct_profile()
|
|
with self.assertRaises(Exception) as context:
|
|
_run_test(input_profile_lines, 0)
|
|
self.assertEqual(
|
|
str(context.exception),
|
|
"It's invalid to remove all functions in the profile")
|
|
|
|
def test_remove_cold_functions_work(self):
|
|
input_profile_lines = _construct_profile()
|
|
# To make sure the cold functions are removed in order
|
|
expected_profile_lines = {
|
|
5: input_profile_lines,
|
|
# Entry 4 wins the tie breaker because the name is smaller
|
|
# alphabetically.
|
|
4: _construct_profile([0, 1, 3, 4]),
|
|
3: _construct_profile([0, 1, 3]),
|
|
2: _construct_profile([0, 3]),
|
|
1: _construct_profile([3]),
|
|
}
|
|
|
|
for num in expected_profile_lines:
|
|
self.assertCountEqual(
|
|
_run_test(input_profile_lines, num), expected_profile_lines[num])
|
|
|
|
def test_analyze_cwp_and_benchmark_work(self):
|
|
input_profile_lines = _construct_profile()
|
|
cwp_profile = _construct_profile([0, 1, 3, 4])
|
|
benchmark_profile = _construct_profile([1, 2, 3, 4])
|
|
cwp_buf = io.StringIO('\n'.join(cwp_profile))
|
|
benchmark_buf = io.StringIO('\n'.join(benchmark_profile))
|
|
with patch('sys.stderr', new=io.StringIO()) as fake_output:
|
|
_run_test(input_profile_lines, 3, cwp_buf, benchmark_buf)
|
|
|
|
output = fake_output.getvalue()
|
|
self.assertIn('Retained 3/5 (60.0%) functions in the profile', output)
|
|
self.assertIn(
|
|
'Retained 1/1 (100.0%) functions only appear in the CWP profile',
|
|
output)
|
|
self.assertIn(
|
|
'Retained 0/1 (0.0%) functions only appear in the benchmark profile',
|
|
output)
|
|
self.assertIn(
|
|
'Retained 2/3 (66.7%) functions appear in both CWP and benchmark'
|
|
' profiles', output)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|