Dactyloidae/build/pgo/llvm_pgo.py
2026-09-12 04:29:47 -07:00

43 lines
2 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/.
"""Collect LLVM profiles outside the directories cleaned between PGO passes."""
import glob
import os
import subprocess
import tempfile
class LLVMProfile(object):
def __init__(self, topobjdir, profdata):
if not profdata or not os.path.isfile(profdata):
raise RuntimeError("clang-cl PGO requires a configured llvm-profdata")
self.topobjdir = os.path.abspath(topobjdir)
self.profdata = profdata
self.output = os.path.join(self.topobjdir, 'merged.profdata')
self.directory = None
def prepare(self, env):
# Never reuse a previous training run's merged or raw profiles.
if os.path.exists(self.output):
os.remove(self.output)
self.directory = tempfile.mkdtemp(prefix='pgo-profiles-', dir=self.topobjdir)
# %m distinguishes instrumented DLLs; %p distinguishes child processes.
env['LLVM_PROFILE_FILE'] = os.path.join(self.directory, '%m-%p.profraw')
def merge(self):
profiles = sorted(glob.glob(os.path.join(self.directory, '*.profraw')))
if not profiles or not any(os.path.getsize(p) for p in profiles):
raise RuntimeError("PGO training produced no LLVM profile data")
# An input list avoids Windows command-line length limits. Keep profiles
# on failure so that corrupt or incompatible data can be diagnosed.
inputs = os.path.join(self.directory, 'profiles.list')
with open(inputs, 'w') as stream:
for profile in profiles:
stream.write(profile + '\n')
subprocess.check_call([self.profdata, 'merge', '-o', self.output,
'-f', inputs])
if not os.path.isfile(self.output) or not os.path.getsize(self.output):
raise RuntimeError("llvm-profdata did not produce a merged profile")