blob: 14f946b0f1fbfc24a329676f6ac10cb816869946 [file] [log] [blame]
#!/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()