mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-22 00:17:32 +09:00
139 lines
5.5 KiB
Python
139 lines
5.5 KiB
Python
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from distutils.spawn import find_executable
|
|
|
|
from llvm_pgo import LLVMProfile
|
|
|
|
|
|
class LLVMProfileTest(unittest.TestCase):
|
|
def setUp(self):
|
|
self.directory = tempfile.mkdtemp(prefix='llvm pgo test ')
|
|
self.profile = LLVMProfile(self.directory, sys.executable)
|
|
self.check_call = subprocess.check_call
|
|
|
|
def tearDown(self):
|
|
subprocess.check_call = self.check_call
|
|
shutil.rmtree(self.directory)
|
|
|
|
def write(self, path, data):
|
|
with open(path, 'w') as stream:
|
|
stream.write(data)
|
|
|
|
def test_missing_tool(self):
|
|
with self.assertRaises(RuntimeError):
|
|
LLVMProfile(self.directory, None)
|
|
|
|
def test_prepare_isolates_runs(self):
|
|
self.write(self.profile.output, 'stale merged profile')
|
|
env = {}
|
|
self.profile.prepare(env)
|
|
first = self.profile.directory
|
|
self.write(os.path.join(first, 'stale.profraw'), 'stale raw profile')
|
|
self.profile.prepare(env)
|
|
self.assertNotEqual(first, self.profile.directory)
|
|
self.assertFalse(os.path.exists(self.profile.output))
|
|
self.assertEqual(env['LLVM_PROFILE_FILE'],
|
|
os.path.join(self.profile.directory, '%m-%p.profraw'))
|
|
with self.assertRaises(RuntimeError):
|
|
self.profile.merge()
|
|
|
|
def test_empty_profiles(self):
|
|
self.profile.prepare({})
|
|
self.write(os.path.join(self.profile.directory, 'empty.profraw'), '')
|
|
with self.assertRaises(RuntimeError):
|
|
self.profile.merge()
|
|
|
|
def test_merge_uses_input_list(self):
|
|
self.profile.prepare({})
|
|
raw = os.path.join(self.profile.directory, 'module-process.profraw')
|
|
self.write(raw, 'raw profile')
|
|
def merge(args):
|
|
self.assertEqual(args[:4], [sys.executable, 'merge', '-o',
|
|
self.profile.output])
|
|
self.assertEqual(args[4], '-f')
|
|
with open(args[5]) as stream:
|
|
self.assertEqual(stream.read().splitlines(), [raw])
|
|
self.write(self.profile.output, 'merged profile')
|
|
subprocess.check_call = merge
|
|
self.profile.merge()
|
|
|
|
def test_merge_failure_propagates(self):
|
|
self.profile.prepare({})
|
|
self.write(os.path.join(self.profile.directory, 'bad.profraw'), 'bad')
|
|
def fail(args):
|
|
raise subprocess.CalledProcessError(1, args)
|
|
subprocess.check_call = fail
|
|
with self.assertRaises(subprocess.CalledProcessError):
|
|
self.profile.merge()
|
|
|
|
def test_merge_requires_output(self):
|
|
self.profile.prepare({})
|
|
self.write(os.path.join(self.profile.directory, 'data.profraw'), 'raw')
|
|
subprocess.check_call = lambda args: None
|
|
with self.assertRaises(RuntimeError):
|
|
self.profile.merge()
|
|
|
|
|
|
class PGOConfigurationTest(unittest.TestCase):
|
|
def setUp(self):
|
|
self.make = (os.environ.get('MAKE') or find_executable('mozmake') or
|
|
find_executable('make'))
|
|
if not self.make:
|
|
self.skipTest('GNU make is required')
|
|
self.directory = tempfile.mkdtemp(prefix='pgo configuration ')
|
|
config = os.path.join(os.path.dirname(__file__), '..', '..',
|
|
'config', 'config.mk')
|
|
with open(config) as stream:
|
|
source = stream.read()
|
|
start = source.index('# Reject stale Windows PGO configuration')
|
|
end = source.index('# Enable profile-based feedback', start)
|
|
self.makefile = os.path.join(self.directory, 'Makefile')
|
|
with open(self.makefile, 'w') as stream:
|
|
stream.write(source[start:end] + '\nall:;\n')
|
|
|
|
def tearDown(self):
|
|
if hasattr(self, 'directory'):
|
|
shutil.rmtree(self.directory)
|
|
|
|
def run_make(self, *variables):
|
|
process = subprocess.Popen([self.make, '-f', self.makefile] +
|
|
list(variables), stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT)
|
|
output = process.communicate()[0].decode('utf-8')
|
|
return process.returncode, output
|
|
|
|
def test_missing_profdata_fails_before_build(self):
|
|
code, output = self.run_make('MOZ_PGO=1', 'CLANG_CL=1', 'LLVM_PROFDATA=')
|
|
self.assertNotEqual(code, 0)
|
|
self.assertIn('requires LLVM_PROFDATA', output)
|
|
|
|
def test_msvc_flags_rejected_for_clang(self):
|
|
code, output = self.run_make('MOZ_PGO=1', 'CLANG_CL=1',
|
|
'LLVM_PROFDATA=llvm-profdata.exe',
|
|
'PROFILE_GEN_CFLAGS=-GL')
|
|
self.assertNotEqual(code, 0)
|
|
self.assertIn('requires LLVM instrumentation flags', output)
|
|
|
|
def test_llvm_configuration_accepted(self):
|
|
code, output = self.run_make('MOZ_PGO=1', 'CLANG_CL=1',
|
|
'LLVM_PROFDATA=llvm-profdata.exe',
|
|
'PROFILE_GEN_CFLAGS=-clang:-fprofile-instr-generate')
|
|
self.assertEqual(code, 0, output)
|
|
|
|
def test_non_pgo_and_msvc_unaffected(self):
|
|
for variables in [('MOZ_PGO=', 'CLANG_CL=1'),
|
|
('MOZ_PGO=1', 'CLANG_CL=')]:
|
|
code, output = self.run_make(*variables)
|
|
self.assertEqual(code, 0, output)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|