Skip to content

Commit df0d18b

Browse files
committed
Add tests for parallel compilation to make sure that the various optimization modes interact as we expect.
The tests highlight a couple cases that are currently known to be wrong so we can fix and test them without just manually building all possible combinations. Chery-pick: f6302a2
1 parent 9e79864 commit df0d18b

File tree

5 files changed

+250
-0
lines changed

5 files changed

+250
-0
lines changed

test/BUILD

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ load(":module_cache_settings_tests.bzl", "module_cache_settings_test_suite")
1616
load(":module_interface_tests.bzl", "module_interface_test_suite")
1717
load(":module_mapping_tests.bzl", "module_mapping_test_suite")
1818
load(":output_file_map_tests.bzl", "output_file_map_test_suite")
19+
load(":parallel_compilation_tests.bzl", "parallel_compilation_test_suite")
1920
load(":pch_output_dir_tests.bzl", "pch_output_dir_test_suite")
2021
load(":private_deps_tests.bzl", "private_deps_test_suite")
2122
load(":private_swiftinterface_tests.bzl", "private_swiftinterface_test_suite")
@@ -80,6 +81,10 @@ synthesize_interface_test_suite(
8081
],
8182
)
8283

84+
parallel_compilation_test_suite(
85+
name = "parallel_compilation",
86+
)
87+
8388
pch_output_dir_test_suite(name = "pch_output_dir_settings")
8489

8590
private_swiftinterface_test_suite(name = "private_swiftinterface")
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
load(
2+
"//swift:swift_library.bzl",
3+
"swift_library",
4+
)
5+
load("//test/fixtures:common.bzl", "FIXTURE_TAGS")
6+
7+
package(
8+
default_visibility = ["//test:__subpackages__"],
9+
features = ["swift.compile_in_parallel"],
10+
)
11+
12+
licenses(["notice"])
13+
14+
###############################################################################
15+
16+
swift_library(
17+
name = "no_opt_no_wmo",
18+
srcs = ["Empty.swift"],
19+
tags = FIXTURE_TAGS,
20+
)
21+
22+
swift_library(
23+
name = "no_opt_with_wmo",
24+
srcs = ["Empty.swift"],
25+
copts = ["-wmo"],
26+
tags = FIXTURE_TAGS,
27+
)
28+
29+
swift_library(
30+
name = "with_opt_no_wmo",
31+
srcs = ["Empty.swift"],
32+
copts = ["-O"],
33+
tags = FIXTURE_TAGS,
34+
)
35+
36+
swift_library(
37+
name = "with_opt_with_wmo",
38+
srcs = ["Empty.swift"],
39+
copts = [
40+
"-O",
41+
"-wmo",
42+
],
43+
tags = FIXTURE_TAGS,
44+
)
45+
46+
swift_library(
47+
name = "onone_with_wmo",
48+
srcs = ["Empty.swift"],
49+
copts = [
50+
"-Onone",
51+
"-wmo",
52+
],
53+
tags = FIXTURE_TAGS,
54+
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// Intentionally empty.
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Copyright 2024 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Tests for parallel compilation."""
16+
17+
load("@bazel_skylib//rules:build_test.bzl", "build_test")
18+
load(
19+
"@build_bazel_rules_swift//test/rules:actions_created_test.bzl",
20+
"actions_created_test",
21+
)
22+
23+
visibility("private")
24+
25+
def parallel_compilation_test_suite(name, tags = []):
26+
"""Test suite for parallel compilation.
27+
28+
Args:
29+
name: The base name to be used in targets created by this macro.
30+
tags: Additional tags to apply to each test.
31+
"""
32+
all_tags = [name] + tags
33+
34+
# Non-optimized, non-WMO can be compiled in parallel.
35+
actions_created_test(
36+
name = "{}_no_opt_no_wmo".format(name),
37+
mnemonics = ["SwiftCompileModule", "SwiftCompileCodegen", "-SwiftCompile"],
38+
tags = all_tags,
39+
target_under_test = "@build_bazel_rules_swift//test/fixtures/parallel_compilation:no_opt_no_wmo",
40+
)
41+
42+
# Non-optimized, with-WMO can be compiled in parallel.
43+
actions_created_test(
44+
name = "{}_no_opt_with_wmo".format(name),
45+
mnemonics = ["SwiftCompileModule", "SwiftCompileCodegen", "-SwiftCompile"],
46+
tags = all_tags,
47+
target_under_test = "@build_bazel_rules_swift//test/fixtures/parallel_compilation:no_opt_with_wmo",
48+
)
49+
50+
# Optimized, non-WMO cannot be compiled in parallel.
51+
# TODO: b/351801556 - This is actually incorrect based on further driver
52+
# testing; update the rules to allow compiling these in parallel.
53+
actions_created_test(
54+
name = "{}_with_opt_no_wmo".format(name),
55+
mnemonics = ["-SwiftCompileModule", "-SwiftCompileCodegen", "SwiftCompile"],
56+
tags = all_tags,
57+
target_under_test = "@build_bazel_rules_swift//test/fixtures/parallel_compilation:with_opt_no_wmo",
58+
)
59+
60+
# Optimized, with-WMO cannot be compiled in parallel.
61+
# TODO: b/351801556 - This should be allowed if cross-module-optimization is
62+
# disabled. Update the rules to allow this and add a new version of this
63+
# target that disables CMO so we can test both situtations.
64+
actions_created_test(
65+
name = "{}_with_opt_with_wmo".format(name),
66+
mnemonics = ["-SwiftCompileModule", "-SwiftCompileCodegen", "SwiftCompile"],
67+
tags = all_tags,
68+
target_under_test = "@build_bazel_rules_swift//test/fixtures/parallel_compilation:with_opt_with_wmo",
69+
)
70+
71+
# Make sure that when we look for optimizer flags, we don't treat `-Onone`
72+
# as being optimized.
73+
actions_created_test(
74+
name = "{}_onone_with_wmo".format(name),
75+
mnemonics = ["SwiftCompileModule", "SwiftCompileCodegen", "-SwiftCompile"],
76+
tags = all_tags,
77+
target_under_test = "@build_bazel_rules_swift//test/fixtures/parallel_compilation:onone_with_wmo",
78+
)
79+
80+
# The analysis tests verify that we register the actions we expect. Use a
81+
# `build_test` to make sure the actions execute successfully.
82+
build_test(
83+
name = "{}_build_test".format(name),
84+
targets = [
85+
"@build_bazel_rules_swift//test/fixtures/parallel_compilation:no_opt_no_wmo",
86+
"@build_bazel_rules_swift//test/fixtures/parallel_compilation:no_opt_with_wmo",
87+
"@build_bazel_rules_swift//test/fixtures/parallel_compilation:with_opt_no_wmo",
88+
"@build_bazel_rules_swift//test/fixtures/parallel_compilation:with_opt_with_wmo",
89+
"@build_bazel_rules_swift//test/fixtures/parallel_compilation:onone_with_wmo",
90+
],
91+
tags = all_tags,
92+
)
93+
94+
native.test_suite(
95+
name = name,
96+
tags = all_tags,
97+
)
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Copyright 2020 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Rules for testing whether or not actions are simply created by a rule."""
16+
17+
load("@bazel_skylib//lib:collections.bzl", "collections")
18+
load("@bazel_skylib//lib:unittest.bzl", "analysistest", "unittest")
19+
20+
visibility([
21+
"//test/...",
22+
])
23+
24+
def _actions_created_test_impl(ctx):
25+
env = analysistest.begin(ctx)
26+
target_under_test = analysistest.target_under_test(env)
27+
28+
actions = analysistest.target_actions(env)
29+
for mnemonic in ctx.attr.mnemonics:
30+
is_negative_test = mnemonic.startswith("-")
31+
if is_negative_test:
32+
mnemonic = mnemonic[1:]
33+
34+
matching_actions = [
35+
action
36+
for action in actions
37+
if action.mnemonic == mnemonic
38+
]
39+
actual_mnemonics = collections.uniq(
40+
[action.mnemonic for action in actions],
41+
)
42+
43+
if is_negative_test and matching_actions:
44+
unittest.fail(
45+
env,
46+
("Target '{}' registered actions with the mnemonic '{}', " +
47+
"but it was not expected to (it had {}).").format(
48+
str(target_under_test.label),
49+
mnemonic,
50+
actual_mnemonics,
51+
),
52+
)
53+
elif not is_negative_test and not matching_actions:
54+
unittest.fail(
55+
env,
56+
("Target '{}' registered no actions with the expected " +
57+
"mnemonic '{}' (it had {}).").format(
58+
str(target_under_test.label),
59+
mnemonic,
60+
actual_mnemonics,
61+
),
62+
)
63+
64+
return analysistest.end(env)
65+
66+
def make_actions_created_test_rule(config_settings = {}):
67+
"""Returns a new `actions_created_test`-like rule with custom configs.
68+
69+
Args:
70+
config_settings: A dictionary of configuration settings and their values
71+
that should be applied during tests.
72+
73+
Returns:
74+
A rule returned by `analysistest.make` that has the
75+
`actions_created_test` interface and the given config settings.
76+
"""
77+
return analysistest.make(
78+
_actions_created_test_impl,
79+
attrs = {
80+
"mnemonics": attr.string_list(
81+
mandatory = True,
82+
doc = """\
83+
A list of mnemonics that are expected to be created by the target under test.
84+
A mnemonic may also be preceded by a `-` to indicate that it is not expected
85+
to be created and the test should fail if it finds one.
86+
""",
87+
),
88+
},
89+
config_settings = config_settings,
90+
)
91+
92+
# A default instantiation of the rule when no custom config settings are needed.
93+
actions_created_test = make_actions_created_test_rule()

0 commit comments

Comments
 (0)