Skip to content

Commit b10a35b

Browse files
authored
ci: parallelize API report generation (#10269)
Run `abi-dumper; abi-compliance-checker` in parallel for each library. This reduces the run time of "check-api" (in a totally unscientific, one-off, "ninja: no work to do" test) from around 20m30s to about 7m30s. Also take this opportunity to improve the output by discarding the noise ("cmake --install" messages, "missed type id" errors, etc.) and by including the elapsed time for each library. On the latter front, the outliers are ... ``` bigtable completed in 4m2s dialogflow_cx completed in 6m7s dialogflow_es completed in 6m56s ``` where we can see that the "6m56" dominates the overall run time. Fixes #10234
1 parent 29ffdb9 commit b10a35b

File tree

2 files changed

+63
-44
lines changed

2 files changed

+63
-44
lines changed

ci/cloudbuild/builds/check-api.sh

Lines changed: 62 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,13 @@ mapfile -t cmake_args < <(cmake::common_args)
2525

2626
mapfile -t feature_list < <(bazelisk --batch query \
2727
--noshow_progress --noshow_loading_progress \
28-
'kind(cc_library, //:all) except filter("experimental|mocks", kind(cc_library, //:all))' |
28+
'kind(cc_library, //:all)
29+
except filter("experimental|mocks", kind(cc_library, //:all))' |
2930
sed -e 's;//:;;')
3031
enabled="$(printf ";%s" "${feature_list[@]}")"
32+
# These two are not libraries that require enabling.
33+
enabled="${enabled/;common/}"
34+
enabled="${enabled/;grpc_utils/}"
3135
enabled="${enabled:1}"
3236

3337
INSTALL_PREFIX=/var/tmp/google-cloud-cpp
@@ -43,30 +47,37 @@ cmake "${cmake_args[@]}" \
4347
-DGOOGLE_CLOUD_CPP_ENABLE="${enabled}" \
4448
-DCMAKE_CXX_FLAGS="-Og -Wno-maybe-uninitialized"
4549
cmake --build cmake-out
46-
cmake --install cmake-out
50+
cmake --install cmake-out >/dev/null
4751

48-
# Uses `abi-dumper` to dump the ABI for the given library, which should be
49-
# installed at the given prefix. This function will be called from a subshell,
50-
# so it cannot use other variables or functions (including io::log*).
51-
function dump_abi() {
52+
# Uses `abi-dumper` to dump the ABI for the given library, which should
53+
# be installed at the given @p prefix, and `abi-compliance-checker` to
54+
# produce a report comparing the old and new dumps. The (compressed) new
55+
# dump is left in the @p project_root tree.
56+
#
57+
# This function will be called from a subshell, so it cannot use other
58+
# variables or functions (including io::log*).
59+
function check_abi() {
5260
local library="$1"
5361
local prefix="$2"
54-
local public_headers="${prefix}/include/google/cloud/${library#google_cloud_cpp_}"
55-
if [[ "${library}" == "google_cloud_cpp_common" || "${library}" == "google_cloud_cpp_grpc_utils" ]]; then
56-
# These two are special
62+
local project_root="$3"
63+
64+
local shortlib="${library#google_cloud_cpp_}"
65+
local public_headers="${prefix}/include/google/cloud/${shortlib}"
66+
# These two are special
67+
if [[ "${shortlib}" == "common" || "${shortlib}" == "grpc_utils" ]]; then
5768
public_headers="${prefix}/include/google/cloud"
5869
fi
5970

60-
echo "Dumping ${library} (may be slow)..."
6171
local version
6272
version=$(git rev-parse --short HEAD)
73+
local actual_dump_file="${library}.actual.abi.dump"
6374
local -a dump_options=(
6475
# The source .so file
6576
"${prefix}/lib64/lib${library}.so"
6677
# Use the git version as the library version number for reporting purposes
6778
-lver "${version}"
6879
# The dump destination
69-
-o "cmake-out/${library}.actual.abi.dump"
80+
-o "cmake-out/${actual_dump_file}"
7081
# Where to find the headers
7182
-include-paths "${prefix}/include"
7283
-include-paths "/usr/local/include"
@@ -81,57 +92,65 @@ function dump_abi() {
8192
# Use the system's debuginfo
8293
-search-debuginfo /usr
8394
)
84-
abi-dumper "${dump_options[@]}"
85-
}
86-
export -f dump_abi # enables this function to be called from a subshell
87-
88-
mapfile -t libraries < <(printf "google_cloud_cpp_%s\n" "${feature_list[@]}")
89-
90-
# Run the dump_abi function for each library in parallel since its slow.
91-
echo "${libraries[@]}" | xargs -P "$(nproc)" -n 1 \
92-
bash -c "dump_abi \$0 ${INSTALL_PREFIX}"
93-
94-
# A count of the number of libraries that fail the api compliance check.
95-
# This will become the script's exit code.
96-
errors=0
95+
abi-dumper "${dump_options[@]}" >/dev/null 2>&1 |
96+
grep -v "ERROR: missed type id" || true
9797

98-
for lib in "${libraries[@]}"; do
99-
io::log_h2 "Checking ${lib}"
100-
actual_dump_file="${lib}.actual.abi.dump"
101-
expected_dump_file="${lib}.expected.abi.dump"
102-
expected_dump_path="${PROJECT_ROOT}/ci/abi-dumps/${expected_dump_file}.gz"
98+
local project_dir="${project_root}/ci/abi-dumps"
99+
local expected_dump_file="${library}.expected.abi.dump"
100+
local expected_dump_path="${project_dir}/${expected_dump_file}.gz"
103101
if [[ -r "${expected_dump_path}" ]]; then
104102
zcat "${expected_dump_path}" >"cmake-out/${expected_dump_file}"
105-
report="cmake-out/compat_reports/${lib}/src_compat_report.html"
103+
report="cmake-out/compat_reports/${library}/src_compat_report.html"
106104
compliance_flags=(
107105
# Put the output report in a separate directory for each library
108106
-report-path "${report}"
109107
# We only want a source-level report. We make no ABI guarantees, such
110108
# as data structure sizes or virtual table ordering
111109
-src
112-
# We ignore all symbols in internal namespaces, because these are not part
113-
# of our public API. We do this by specifying a regex that matches against
114-
# the mangled symbol names. For example, 8 is the number of characters in
115-
# the string "internal", and it should again be followed by some other
116-
# number indicating the length of the symbol within the "internal"
117-
# namespace. See: https://en.wikipedia.org/wiki/Name_mangling
110+
# We ignore all symbols in internal namespaces, because these are not
111+
# part of our public API. We do this by specifying a regex that matches
112+
# against the mangled symbol names. For example, 8 is the number of
113+
# characters in the string "internal", and it should again be followed
114+
# by some other number indicating the length of the symbol within the
115+
# "internal" namespace. See: https://en.wikipedia.org/wiki/Name_mangling
118116
-skip-internal-symbols "(8internal|_internal)\d"
119117
# The library to compare
120-
-l "${lib}"
118+
-l "${library}"
121119
# Compared the saved baseline vs. the dump for the current version
122120
-old "cmake-out/${expected_dump_file}"
123121
-new "cmake-out/${actual_dump_file}"
124122
)
125-
if ! io::run abi-compliance-checker "${compliance_flags[@]}"; then
126-
io::log_red "ABI Compliance error: ${lib}"
127-
((++errors))
128-
io::log "Report file: ${report}"
129-
w3m -dump "${report}"
130-
fi
123+
abi-compliance-checker "${compliance_flags[@]}" >/dev/null || true
131124
fi
125+
132126
# Replaces the (old) expected dump file with the (new) actual one.
133127
gzip -n "cmake-out/${actual_dump_file}"
134128
mv -f "cmake-out/${actual_dump_file}.gz" "${expected_dump_path}"
129+
}
130+
export -f check_abi # enables this function to be called from a subshell
131+
132+
mapfile -t libraries < <(printf "google_cloud_cpp_%s\n" "${feature_list[@]}")
133+
134+
# Run the check_abi function for each library in parallel since its slow.
135+
echo "${libraries[@]}" | xargs -P "$(nproc)" -n 1 \
136+
bash -c "TIMEFORMAT=\"\${0#google_cloud_cpp_} completed in %0lR\";
137+
time check_abi \${0} ${INSTALL_PREFIX} ${PROJECT_ROOT}"
138+
139+
# A count of the number of libraries that fail the api compliance check.
140+
# This will become the script's exit code.
141+
errors=0
142+
143+
for library in "${libraries[@]}"; do
144+
report="cmake-out/compat_reports/${library}/src_compat_report.html"
145+
if grep --silent "<td class='compatible'>100%</td>" "${report}"; then
146+
io::log_green "ABI Compliance OK: ${library}"
147+
else
148+
io::log_red "ABI Compliance error: ${library}"
149+
io::log "Report file: ${report}"
150+
w3m -dump "${report}"
151+
((++errors))
152+
fi
135153
done
154+
136155
echo
137156
exit "${errors}"

ci/generate-markdown/generate-readme.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ file="README.md"
3636
(
3737
mapfile -t libraries < <(bazelisk --batch query \
3838
--noshow_progress --noshow_loading_progress \
39-
'kind(cc_library, //:all) except filter("experimental|mocks|common|grpc_utils|internal", kind(cc_library, //:all))' |
39+
'kind(cc_library, //:all) except filter("experimental|mocks|common|grpc_utils", kind(cc_library, //:all))' |
4040
sed -e 's;//:;;' |
4141
LC_ALL=C sort)
4242
sed '/<!-- inject-GA-libraries-start -->/q' "${file}"

0 commit comments

Comments
 (0)