Skip to content

Commit c67edb8

Browse files
committed
Merge remote-tracking branch 'origin/main' into rebranch
2 parents 4f33f70 + caf9bf5 commit c67edb8

File tree

4 files changed

+104
-24
lines changed

4 files changed

+104
-24
lines changed

utils/build-script

+5-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ from swift_build_support.swift_build_support.toolchain import host_toolchain
4040
from swift_build_support.swift_build_support.utils \
4141
import exit_rejecting_arguments
4242
from swift_build_support.swift_build_support.utils import fatal_error
43+
from swift_build_support.swift_build_support.utils import log_analyzer
4344

4445

4546
# -----------------------------------------------------------------------------
@@ -716,6 +717,9 @@ def main():
716717

717718
if __name__ == "__main__":
718719
try:
719-
sys.exit(main())
720+
exit_code = main()
720721
except KeyboardInterrupt:
721722
sys.exit(1)
723+
finally:
724+
log_analyzer()
725+
sys.exit(exit_code)

utils/build-script-impl

-11
Original file line numberDiff line numberDiff line change
@@ -293,15 +293,6 @@ for component in ${components[@]} ; do
293293
)
294294
done
295295

296-
function log_event() {
297-
build_script_log_path=${BUILD_DIR}/.build_script_log
298-
event_type=$1
299-
event_command=$2
300-
evnet_duration=$3
301-
302-
build_event="{\"event\":\"${event_type}\", \"command\":\"${event_command}\", \"duration\":\"${evnet_duration}\"}"
303-
echo "${build_event}" >> ${build_script_log_path}
304-
}
305296

306297
# Centralized access point for traced command invocation.
307298
# Every operation that might mutates file system should be called via
@@ -314,11 +305,9 @@ function call() {
314305

315306
SECONDS=0
316307
if [[ ! ${DRY_RUN} ]]; then
317-
log_event "start" "$(quoted_print "$@")" "${SECONDS}"
318308
{ set -x; } 2>/dev/null
319309
"$@"
320310
{ set +x; } 2>/dev/null
321-
log_event "finish" "$(quoted_print "$@")" "${SECONDS}"
322311
fi
323312
}
324313

utils/swift_build_support/swift_build_support/build_script_invocation.py

+25-12
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@
3131
import ProductPipelineListBuilder
3232
from swift_build_support.swift_build_support.targets \
3333
import StdlibDeploymentTarget
34+
from swift_build_support.swift_build_support.utils import clear_log_time
3435
from swift_build_support.swift_build_support.utils \
3536
import exit_rejecting_arguments
3637
from swift_build_support.swift_build_support.utils import fatal_error
38+
from swift_build_support.swift_build_support.utils import log_time_in_scope
3739

3840

3941
class BuildScriptInvocation(object):
@@ -50,6 +52,8 @@ def __init__(self, toolchain, args):
5052

5153
self.build_libparser_only = args.build_libparser_only
5254

55+
clear_log_time()
56+
5357
@property
5458
def install_all(self):
5559
return self.args.install_all or self.args.infer_dependencies
@@ -790,10 +794,11 @@ def _execute_merged_host_lipo_core_action(self):
790794
self._execute_action("merged-hosts-lipo-core")
791795

792796
def _execute_action(self, action_name):
793-
shell.call_without_sleeping(
794-
[BUILD_SCRIPT_IMPL_PATH] + self.impl_args +
795-
["--only-execute", action_name],
796-
env=self.impl_env, echo=self.args.verbose_build)
797+
with log_time_in_scope(action_name):
798+
shell.call_without_sleeping(
799+
[BUILD_SCRIPT_IMPL_PATH] + self.impl_args +
800+
["--only-execute", action_name],
801+
env=self.impl_env, echo=self.args.verbose_build)
797802

798803
def execute_product_build_steps(self, product_class, host_target):
799804
product_source = product_class.product_source_name()
@@ -810,14 +815,20 @@ def execute_product_build_steps(self, product_class, host_target):
810815
source_dir=self.workspace.source_dir(product_source),
811816
build_dir=build_dir)
812817
if product.should_clean(host_target):
813-
print("--- Cleaning %s ---" % product_name)
814-
product.clean(host_target)
818+
log_message = "Cleaning %s" % product_name
819+
print("--- {} ---".format(log_message))
820+
with log_time_in_scope(log_message):
821+
product.clean(host_target)
815822
if product.should_build(host_target):
816-
print("--- Building %s ---" % product_name)
817-
product.build(host_target)
823+
log_message = "Building %s" % product_name
824+
print("--- {} ---".format(log_message))
825+
with log_time_in_scope(log_message):
826+
product.build(host_target)
818827
if product.should_test(host_target):
819-
print("--- Running tests for %s ---" % product_name)
820-
product.test(host_target)
828+
log_message = "Running tests for %s" % product_name
829+
print("--- {} ---".format(log_message))
830+
with log_time_in_scope(log_message):
831+
product.test(host_target)
821832
print("--- Finished tests for %s ---" % product_name)
822833
# Install the product if it should be installed specifically, or
823834
# if it should be built and `install_all` is set to True.
@@ -827,5 +838,7 @@ def execute_product_build_steps(self, product_class, host_target):
827838
if product.should_install(host_target) or \
828839
(self.install_all and product.should_build(host_target) and
829840
not product.is_ignore_install_all_product()):
830-
print("--- Installing %s ---" % product_name)
831-
product.install(host_target)
841+
log_message = "Installing %s" % product_name
842+
print("--- {} ---".format(log_message))
843+
with log_time_in_scope(log_message):
844+
product.install(host_target)

utils/swift_build_support/swift_build_support/utils.py

+74
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,14 @@
1010
#
1111
# ===---------------------------------------------------------------------===#
1212

13+
import contextlib
14+
import json
15+
import os
1316
import sys
17+
import time
18+
19+
20+
from build_swift.build_swift.constants import SWIFT_BUILD_ROOT
1421

1522

1623
def fatal_error(message, stream=sys.stderr):
@@ -28,3 +35,70 @@ def exit_rejecting_arguments(message, parser=None):
2835
if parser:
2936
parser.print_usage(sys.stderr)
3037
sys.exit(2) # 2 is the same as `argparse` error exit code.
38+
39+
40+
def log_time_path():
41+
return os.path.join(SWIFT_BUILD_ROOT, '.build_script_log')
42+
43+
44+
def clear_log_time():
45+
if os.path.exists(log_time_path()):
46+
f = open(log_time_path(), "w")
47+
f.close()
48+
49+
50+
def log_time(event, command, duration=0):
51+
f = open(log_time_path(), "a")
52+
53+
log_event = {
54+
"event": event,
55+
"command": command,
56+
"duration": "%.2f" % float(duration),
57+
}
58+
59+
f.write("{}\n".format(json.dumps(log_event)))
60+
f.close()
61+
62+
63+
@contextlib.contextmanager
64+
def log_time_in_scope(action_name):
65+
log_time('start', action_name)
66+
t_start = time.time()
67+
try:
68+
yield
69+
finally:
70+
log_time('end', action_name, time.time() - t_start)
71+
72+
73+
def log_analyzer():
74+
"""
75+
Analyze .build_script_log and provide a summary of the time execution.
76+
"""
77+
build_script_log_path = log_time_path()
78+
print("--- Build Script Analyzer ---")
79+
build_events = []
80+
total_duration = 0
81+
if os.path.exists(build_script_log_path):
82+
print("Build Script Log: {}".format(build_script_log_path))
83+
with open(build_script_log_path) as f:
84+
for event in f:
85+
build_event = json.loads(event)
86+
build_event["duration"] = float(build_event["duration"])
87+
total_duration += build_event["duration"]
88+
build_events.append(build_event)
89+
finish_events = [x for x in build_events if x["event"] == "end"]
90+
finish_events.sort(key=lambda x: x["duration"], reverse=True)
91+
92+
print("Build Percentage \t Build Duration (sec) \t Build Phase")
93+
print("================ \t ==================== \t ===========")
94+
event_row = '{:<17.1%} \t {:<21} \t {}'
95+
for build_event in finish_events:
96+
duration_percentage = \
97+
(float(build_event["duration"]) / float(total_duration))
98+
print(event_row.format(duration_percentage,
99+
build_event["duration"],
100+
build_event["command"]))
101+
print("Total Duration: {}".format(total_duration))
102+
else:
103+
print("Skip build script analyzer")
104+
print(".build_script_log file not found at {}".format(build_script_log_path))

0 commit comments

Comments
 (0)