blob: 2e4faa04ba7250374dfa6a59a255ce5bd4b9af19 [file] [log] [blame]
# Copyright 2017 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Provides functionality common for all tools."""
import ctypes
import os
import re
import subprocess
import sys
def GetPath(name, **kwargs):
"""Computes a path to a tool.
All tools understand the same 4 path-related arguments: 'path', 'dir',
'prefix', and 'name'. When the 'path' argument is provided, it overrides the
path to a tool. Otherwise, 'dir', 'prefix', and 'name' arguments, all of which
are optional, are joined as {dir}/{prefix}{name} to compute the path.
Args:
name: A default name of a tool.
**kwargs: A dictionary that optionally contains 'path', 'dir', 'prefix', and
'name' arguments.
Returns:
The computed path.
"""
if 'path' in kwargs:
return kwargs['path']
path = kwargs.get('prefix', '') + kwargs.get('name', name)
if 'dir' in kwargs:
path = os.path.join(kwargs['dir'], path)
return path
def GetRuleName(rule_name_base, toolset):
"""Computes a Ninja name for target and host rules."""
suffix = '' if toolset == 'target' else '_{0}'.format(toolset)
return rule_name_base + suffix
def EstimateMaxConcurrentLinkers():
"""Estimates a number of dynamic linkers to run concurrently.
The estimate takes into account available RAM and conservatively assumes that
Chromium is being built.
Returns:
An estimated number of processes.
"""
# TODO: Introduce _TryGetPhysicalMemoryInBytes().
if sys.platform in ('win32', 'cygwin'):
class MEMORYSTATUSEX(ctypes.Structure):
_fields_ = [
('dwLength', ctypes.c_ulong),
('dwMemoryLoad', ctypes.c_ulong),
('ullTotalPhys', ctypes.c_ulonglong),
('ullAvailPhys', ctypes.c_ulonglong),
('ullTotalPageFile', ctypes.c_ulonglong),
('ullAvailPageFile', ctypes.c_ulonglong),
('ullTotalVirtual', ctypes.c_ulonglong),
('ullAvailVirtual', ctypes.c_ulonglong),
('sullAvailExtendedVirtual', ctypes.c_ulonglong),
] # pylint: disable=invalid-name
stat = MEMORYSTATUSEX()
stat.dwLength = ctypes.sizeof(stat)
ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(stat))
# VS 2015 uses 20% more working set than VS 2013 and can consume all RAM
# on a 64 GB machine.
return max(1, stat.ullTotalPhys / (5 * (2**30))) # total / 5GB
elif sys.platform.startswith('linux'):
if os.path.exists('/proc/meminfo'):
with open('/proc/meminfo') as meminfo:
memtotal_re = re.compile(r'^MemTotal:\s*(\d*)\s*kB')
for line in meminfo:
match = memtotal_re.match(line)
if not match:
continue
# Allow 6Gb per link on Linux because Gold is quite memory hungry
return max(1, int(match.group(1)) / (6 * (2**20)))
return 1
elif sys.platform == 'darwin':
try:
avail_bytes = int(subprocess.check_output(['sysctl', '-n', 'hw.memsize']))
# A static library debug build of Chromium's unit_tests takes ~2.7GB, so
# 4GB per ld process allows for some more bloat.
return max(1, avail_bytes / (4 * (2**30))) # total / 4GB
except subprocess.CalledProcessError:
return 1
else:
return 1