Skip to content

Commit 2e7d88e

Browse files
committed
[build-script][lto] Migrate the num_*_parallel_lto_link_jobs code from build-script-impl into build support.
rdar://24717107
1 parent a5d8172 commit 2e7d88e

File tree

4 files changed

+181
-67
lines changed

4 files changed

+181
-67
lines changed

utils/build-script

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ sys.path.append(os.path.join(os.path.dirname(__file__), 'swift_build_support'))
3737
# E402 means module level import not at top of file
3838
from swift_build_support import arguments # noqa (E402)
3939
from swift_build_support import diagnostics # noqa (E402)
40+
from swift_build_support import host # noqa (E402)
4041
from swift_build_support.toolchain import host_toolchain # noqa (E402)
4142
import swift_build_support.debug # noqa (E402)
4243
from swift_build_support import migration # noqa (E402)
@@ -986,6 +987,21 @@ details of the setups of other systems or automated environments.""")
986987
default=False,
987988
const=True)
988989

990+
default_max_lto_link_job_counts = host.max_lto_link_job_counts()
991+
parser.add_argument(
992+
"--llvm-max-parallel-lto-link-jobs",
993+
help="the maximum number of parallel link jobs to use when compiling "
994+
"llvm",
995+
metavar="COUNT",
996+
default=default_max_lto_link_job_counts['llvm'])
997+
998+
parser.add_argument(
999+
"--swift-tools-max-parallel-lto-link-jobs",
1000+
help="the maximum number of parallel link jobs to use when compiling "
1001+
"swift tools.",
1002+
metavar="COUNT",
1003+
default=default_max_lto_link_job_counts['swift'])
1004+
9891005
parser.add_argument(
9901006
# Explicitly unavailable options here.
9911007
"--build-jobs",
@@ -1457,7 +1473,17 @@ details of the setups of other systems or automated environments.""")
14571473
"--llvm-enable-lto",
14581474
"--swift-tools-enable-lto"
14591475
]
1460-
1476+
if args.llvm_max_parallel_lto_link_jobs is not None:
1477+
build_script_impl_args += [
1478+
"--llvm-num-parallel-lto-link-jobs=%s" %
1479+
min(args.llvm_max_parallel_lto_link_jobs, args.build_jobs)
1480+
]
1481+
if args.swift_tools_max_parallel_lto_link_jobs is not None:
1482+
build_script_impl_args += [
1483+
"--swift-tools-num-parallel-lto-link-jobs=%s" %
1484+
min(args.swift_tools_max_parallel_lto_link_jobs,
1485+
args.build_jobs)
1486+
]
14611487
build_script_impl_args += args.build_script_impl_args
14621488

14631489
if args.dry_run:

utils/build-script-impl

Lines changed: 4 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ KNOWN_SETTINGS=(
7676
swift-analyze-code-coverage "not-merged" "Code coverage analysis mode for Swift (false, not-merged, merged). Defaults to false if the argument is not present, and not-merged if the argument is present without a modifier."
7777
swift-tools-enable-lto "0" "enable LTO compilation of Swift tools. *NOTE* This does not include the swift standard library and runtime."
7878
llvm-enable-lto "0" "enable LTO compilation of LLVM/Clang."
79+
swift-tools-num-parallel-lto-link-jobs "" "The number of parallel link jobs to use when compiling swift tools"
80+
llvm-num-parallel-lto-link-jobs "" "The number of parallel link jobs to use when compiling llvm"
7981
swift-stdlib-build-type "Debug" "the CMake build variant for Swift"
8082
swift-stdlib-enable-assertions "1" "enable assertions in Swift"
8183
swift-stdlib-enable-resilience "0" "build the Swift stdlib and overlays with resilience enabled"
@@ -287,28 +289,6 @@ function set_lldb_build_mode() {
287289
LLDB_BUILD_MODE="CustomSwift-${LLDB_BUILD_TYPE}"
288290
}
289291

290-
function system_memory_in_bytes() {
291-
case "$(uname -s -m)" in
292-
Darwin\ x86_64)
293-
sysctl hw.memsize | cut -f 2 -d " "
294-
;;
295-
*)
296-
echo "Unknown operating system"
297-
exit 1
298-
;;
299-
esac
300-
}
301-
302-
function float_min() {
303-
local LHS=$1
304-
local RHS=$2
305-
if (( $(echo "${LHS} < ${RHS}" | bc -l) )); then
306-
echo ${LHS}
307-
else
308-
echo ${RHS}
309-
fi
310-
}
311-
312292
# Support for performing isolated actions.
313293
#
314294
# This is part of refactoring more work to be done or controllable via
@@ -354,48 +334,6 @@ function should_execute_host_actions_for_phase() {
354334
fi
355335
}
356336

357-
function num_llvm_parallel_lto_link_jobs() {
358-
case "$(uname -s -m)" in
359-
Darwin\ x86_64)
360-
# *WARNING! HEURISTIC!*
361-
#
362-
# Use the formula (GB Memory - 3)/6.0GB to get the number of
363-
# parallel link threads we can support. This gives the OS 3 GB of
364-
# room to work with.
365-
#
366-
# This is a bit conservative, but I have found that this number
367-
# prevents me from swapping on my test machine.
368-
local NUM_MEMORY_THREADS=$(echo \( $(system_memory_in_bytes)/1000000000.0 - 3.0 \) / 6.0 | bc)
369-
echo $(float_min "${NUM_MEMORY_THREADS}" "${BUILD_JOBS}")
370-
;;
371-
*)
372-
echo "Unknown operating system"
373-
exit 1
374-
;;
375-
esac
376-
}
377-
378-
function num_swift_parallel_lto_link_jobs() {
379-
case "$(uname -s -m)" in
380-
Darwin\ x86_64)
381-
# *WARNING! HEURISTIC!*
382-
#
383-
# Use the formula (GB Memory - 3)/8.0GB to get the number of
384-
# parallel link threads we can support. This gives the OS 3 GB of
385-
# room to work with.
386-
#
387-
# This is a bit conservative, but I have found that this number
388-
# prevents me from swapping on my test machine.
389-
local NUM_MEMORY_THREADS=$(echo \( $(system_memory_in_bytes)/1000000000 - 3.0 \) / 8.0 | bc)
390-
echo $(float_min "${NUM_MEMORY_THREADS}" "${BUILD_JOBS}")
391-
;;
392-
*)
393-
echo "Unknown operating system"
394-
exit 1
395-
;;
396-
esac
397-
}
398-
399337
function set_build_options_for_host() {
400338
llvm_cmake_options=()
401339
swift_cmake_options=()
@@ -638,7 +576,7 @@ function set_build_options_for_host() {
638576
fi
639577

640578
llvm_cmake_options+=(
641-
"-DLLVM_PARALLEL_LINK_JOBS=$(num_llvm_parallel_lto_link_jobs)"
579+
"-DLLVM_PARALLEL_LINK_JOBS=${LLVM_NUM_PARALLEL_LTO_LINK_JOBS}"
642580
)
643581
fi
644582

@@ -659,7 +597,7 @@ function set_build_options_for_host() {
659597
)
660598
fi
661599
swift_cmake_options+=(
662-
"-DSWIFT_PARALLEL_LINK_JOBS=$(num_swift_parallel_lto_link_jobs)"
600+
"-DSWIFT_PARALLEL_LINK_JOBS=${SWIFT_TOOLS_NUM_PARALLEL_LTO_LINK_JOBS}"
663601
)
664602
fi
665603

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# swift_build_support/host.py ----------- Migrating build-script -*- python -*-
2+
#
3+
# This source file is part of the Swift.org open source project
4+
#
5+
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
# Licensed under Apache License v2.0 with Runtime Library Exception
7+
#
8+
# See http://swift.org/LICENSE.txt for license information
9+
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
#
11+
# -----------------------------------------------------------------------------
12+
#
13+
# This file contains routines for determining information about the host for
14+
# use in utils/build-script.
15+
#
16+
# -----------------------------------------------------------------------------
17+
18+
from __future__ import absolute_import
19+
20+
import platform
21+
22+
from . import shell
23+
24+
25+
# Utilities
26+
def _return_none_fun():
27+
return None
28+
29+
30+
def _return_none_fun_pair():
31+
return (_return_none_fun, _return_none_fun)
32+
33+
34+
def _compute_system_key():
35+
return (platform.system(), platform.machine())
36+
37+
38+
# System Memory
39+
def _darwin_system_memory():
40+
# Output looks like "hw.memsize: \d+\n"
41+
return int(shell.capture(["sysctl", "hw.memsize"],
42+
dry_run=False, echo=False,
43+
optional=False).strip().split(" ")[1])
44+
45+
_PER_PLATFORM_SYSTEM_MEMORY = {
46+
('Darwin', 'x86_64'): _darwin_system_memory
47+
}
48+
49+
50+
def system_memory():
51+
return _PER_PLATFORM_SYSTEM_MEMORY.get(_compute_system_key(),
52+
_return_none_fun)()
53+
54+
55+
# Max Num CPU Threads for use with LTO
56+
def _darwin_max_num_llvm_parallel_lto_link_jobs():
57+
# *WARNING! HEURISTIC!*
58+
#
59+
# Use the formula (GB Memory - 3)/6.0GB to get the number of
60+
# parallel link threads we can support. This gives the OS 3 GB of
61+
# room to work with.
62+
#
63+
# This is a bit conservative, but I have found that this number
64+
# prevents me from swapping on my test machine.
65+
return int((_darwin_system_memory()/1000000000.0 - 3.0)/6.0)
66+
67+
68+
def _darwin_max_num_swift_parallel_lto_link_jobs():
69+
# *WARNING! HEURISTIC!*
70+
#
71+
# Use the formula (GB Memory - 3)/8.0GB to get the number of
72+
# parallel link threads we can support. This gives the OS 3 GB of
73+
# room to work with.
74+
#
75+
# This is a bit conservative, but I have found that this number
76+
# prevents me from swapping on my test machine.
77+
return int((_darwin_system_memory()/1000000000.0 - 3.0)/8.0)
78+
79+
_PER_PLATFORM_MAX_PARALLEL_LTO_JOBS = {
80+
('Darwin', 'x86_64'): (_darwin_max_num_llvm_parallel_lto_link_jobs,
81+
_darwin_max_num_swift_parallel_lto_link_jobs)
82+
}
83+
84+
85+
def max_lto_link_job_counts():
86+
key = _compute_system_key()
87+
info = _PER_PLATFORM_MAX_PARALLEL_LTO_JOBS.get(key,
88+
_return_none_fun_pair())
89+
return {'llvm': info[0](), 'swift': info[1]()}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# test_host.py - Unit tests for swift_build_support.cmake -*-- python -*-
2+
#
3+
# This source file is part of the Swift.org open source project
4+
#
5+
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
# Licensed under Apache License v2.0 with Runtime Library Exception
7+
#
8+
# See http://swift.org/LICENSE.txt for license information
9+
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
11+
import platform
12+
import unittest
13+
14+
import swift_build_support.host as sbs_host
15+
16+
17+
class HostTestCase(unittest.TestCase):
18+
19+
def test_system_memory(self):
20+
# We make sure that we get an integer back. If we get an integer back,
21+
# we know that we at least were able to get some sort of information
22+
# from the system and it could be parsed as an integer. This is just a
23+
# smoke test.
24+
supported_platforms = [('Darwin', 'x86_64')]
25+
26+
mem = sbs_host.system_memory()
27+
28+
if (platform.system(), platform.machine()) not in supported_platforms:
29+
self.assertIsNone(mem)
30+
else:
31+
self.assertIsInstance(mem, int)
32+
33+
def test_lto_link_job_counts(self):
34+
# Make sure that:
35+
#
36+
# 1. we get back a dictionary with two keys in it, the first called
37+
# llvm, the other called swift.
38+
#
39+
# 2. The values associated with these keys is either None (if we do not
40+
# support the platform) or is an int that is reasonable (i.e. <
41+
# 100). The number 100 is just a heuristic number that is appropriate
42+
# currently since LTO uses so much memory. If and when that changes,
43+
# this number should change.
44+
supported_platforms = [('Darwin', 'x86_64')]
45+
reasonable_upper_bound_of_lto_threads = 100
46+
47+
result = sbs_host.max_lto_link_job_counts()
48+
self.assertIsInstance(result, dict)
49+
self.assertEqual(len(result), 2)
50+
51+
if (platform.system(), platform.machine()) not in supported_platforms:
52+
self.assertIsNone(result['llvm'])
53+
self.assertIsNone(result['swift'])
54+
return
55+
56+
self.assertIsNotNone(result['llvm'])
57+
self.assertIsNotNone(result['swift'])
58+
self.assertIsInstance(result['llvm'], int)
59+
self.assertIsInstance(result['swift'], int)
60+
self.assertLess(result['llvm'], reasonable_upper_bound_of_lto_threads)
61+
self.assertLess(result['swift'], reasonable_upper_bound_of_lto_threads)

0 commit comments

Comments
 (0)