Skip to content

Commit 0cae4ad

Browse files
authored
Support collecting perf profiles remotely (#275)
If we're running tests on a remote machine with -DTEST_SUITE_REMOTE_HOST and generate a perf profile with `lit --param profile=perf`, currently the profile step will be run on the local machine and fail. This patch fixes this by running the profile step on the remote, as well as copying the generated profiles back to the host so tools like LNT can inspect them. There's two parts to this, first we need to run the remote module after the perf (and hpmcount) module so that we can wrap the profile step with ssh etc. Secondly, we need to scp over the generated .perf_data files like we also do for the profilegen.py module. However today this is also done as part of the profile step which we now need to start running over ssh. So to fix this, this adds a new "profile collect" step that runs after the profile step, but always runs on the local machine. I've tested this out on a remote build configured with `-DTEST_SUITE_REMOTE_HOST=... -DTEST_SUITE_USE_PERF=ON -DTEST_SUITE_PROFILE_GENERATE=ON -DTEST_SUITE_USE_IR_PGO=ON` and running the tests with `lit --param profile=perf`, and it seems to work.
1 parent 76e14e3 commit 0cae4ad

File tree

4 files changed

+22
-8
lines changed

4 files changed

+22
-8
lines changed

lit.cfg

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,6 @@ config.traditional_output = False
2525
config.single_source = False
2626
if "SSH_AUTH_SOCK" in os.environ:
2727
config.environment["SSH_AUTH_SOCK"] = os.environ["SSH_AUTH_SOCK"]
28-
if not hasattr(config, "remote_host"):
29-
config.remote_host = ""
30-
config.remote_host = lit_config.params.get("remote_host", config.remote_host)
31-
if config.remote_host:
32-
config.test_modules.append("remote")
3328

3429
# Load previous test results so we can skip tests that did not change.
3530
previous_results_file = lit_config.params.get("previous", None)
@@ -55,3 +50,9 @@ if lit_config.params.get("profile") == "hpmcount":
5550
config.substitutions += [
5651
("%b", os.path.join(config.test_exec_root, "tools")),
5752
]
53+
54+
if not hasattr(config, "remote_host"):
55+
config.remote_host = ""
56+
config.remote_host = lit_config.params.get("remote_host", config.remote_host)
57+
if config.remote_host:
58+
config.test_modules.append("remote")

litsupport/modules/profilegen.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,4 @@ def mutatePlan(context, plan):
2727
profdatafile = context.executable + ".profdata"
2828
args = ["merge", "-output=%s" % profdatafile] + context.profilefiles
2929
mergecmd = shellcommand.ShellCommand(context.config.llvm_profdata, args)
30-
plan.profilescript += [mergecmd.toCommandline()]
30+
plan.profilecollectscript += [mergecmd.toCommandline()]

litsupport/modules/remote.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,18 @@ def mutatePlan(context, plan):
4343
plan.verifyscript = _mutateScript(context, plan.verifyscript)
4444
for name, script in plan.metricscripts.items():
4545
plan.metricscripts[name] = _mutateScript(context, script)
46+
plan.profilescript = _mutateScript(context, plan.profilescript)
4647

4748
# Merging profile data should happen on the host because that is where
4849
# the toolchain resides, however we have to retrieve the profile data
4950
# from the device first, add commands for that to the profile script.
50-
for path in plan.profile_files:
51+
profile_files = plan.profile_files
52+
if context.profilefile:
53+
profile_files += [context.profilefile]
54+
for path in profile_files:
5155
assert os.path.isabs(path)
5256
command = "scp %s:%s %s" % (context.config.remote_host, path, path)
53-
plan.profilescript.insert(0, command)
57+
plan.profilecollectscript.insert(0, command)
5458

5559
assert context.read_result_file is testplan.default_read_result_file
5660
context.read_result_file = remote_read_result_file

litsupport/testplan.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def __init__(self):
2424
self.preparescript = []
2525
self.profile_files = []
2626
self.profilescript = []
27+
self.profilecollectscript = []
2728

2829

2930
def mutateScript(context, script, mutator):
@@ -119,6 +120,13 @@ def _executePlan(context, plan):
119120
if exitCode != 0:
120121
logging.warning("Profile script '%s' failed", plan.profilescript)
121122

123+
# Execute steps to manage the generated profile data, on the host.
124+
_, _, exitCode, _ = _executeScript(
125+
context, plan.profilecollectscript, "profilecollect"
126+
)
127+
if exitCode != 0:
128+
logging.warning("Profile collect script '%s' failed", plan.profilecollectscript)
129+
122130
# Perform various metric extraction steps setup by testing modules.
123131
for metric_collector in plan.metric_collectors:
124132
try:
@@ -201,3 +209,4 @@ def __init__(self, test, litConfig, tmpDir, tmpBase):
201209
self.tmpDir = tmpDir
202210
self.tmpBase = tmpBase
203211
self.read_result_file = default_read_result_file
212+
self.profilefile = None

0 commit comments

Comments
 (0)