1*8975f5c5SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*8975f5c5SAndroid Build Coastguard Worker# Copyright 2014 The Chromium Authors 3*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file. 5*8975f5c5SAndroid Build Coastguard Worker 6*8975f5c5SAndroid Build Coastguard Worker# This script computs the number of concurrent links we want to run in the build 7*8975f5c5SAndroid Build Coastguard Worker# as a function of machine spec. It's based on GetDefaultConcurrentLinks in GYP. 8*8975f5c5SAndroid Build Coastguard Worker 9*8975f5c5SAndroid Build Coastguard Workerimport argparse 10*8975f5c5SAndroid Build Coastguard Workerimport multiprocessing 11*8975f5c5SAndroid Build Coastguard Workerimport os 12*8975f5c5SAndroid Build Coastguard Workerimport re 13*8975f5c5SAndroid Build Coastguard Workerimport subprocess 14*8975f5c5SAndroid Build Coastguard Workerimport sys 15*8975f5c5SAndroid Build Coastguard Worker 16*8975f5c5SAndroid Build Coastguard Workersys.path.insert(1, os.path.join(os.path.dirname(__file__), '..')) 17*8975f5c5SAndroid Build Coastguard Workerimport gn_helpers 18*8975f5c5SAndroid Build Coastguard Worker 19*8975f5c5SAndroid Build Coastguard Worker 20*8975f5c5SAndroid Build Coastguard Workerdef _GetTotalMemoryInBytes(): 21*8975f5c5SAndroid Build Coastguard Worker if sys.platform in ('win32', 'cygwin'): 22*8975f5c5SAndroid Build Coastguard Worker import ctypes 23*8975f5c5SAndroid Build Coastguard Worker 24*8975f5c5SAndroid Build Coastguard Worker class MEMORYSTATUSEX(ctypes.Structure): 25*8975f5c5SAndroid Build Coastguard Worker _fields_ = [ 26*8975f5c5SAndroid Build Coastguard Worker ("dwLength", ctypes.c_ulong), 27*8975f5c5SAndroid Build Coastguard Worker ("dwMemoryLoad", ctypes.c_ulong), 28*8975f5c5SAndroid Build Coastguard Worker ("ullTotalPhys", ctypes.c_ulonglong), 29*8975f5c5SAndroid Build Coastguard Worker ("ullAvailPhys", ctypes.c_ulonglong), 30*8975f5c5SAndroid Build Coastguard Worker ("ullTotalPageFile", ctypes.c_ulonglong), 31*8975f5c5SAndroid Build Coastguard Worker ("ullAvailPageFile", ctypes.c_ulonglong), 32*8975f5c5SAndroid Build Coastguard Worker ("ullTotalVirtual", ctypes.c_ulonglong), 33*8975f5c5SAndroid Build Coastguard Worker ("ullAvailVirtual", ctypes.c_ulonglong), 34*8975f5c5SAndroid Build Coastguard Worker ("sullAvailExtendedVirtual", ctypes.c_ulonglong), 35*8975f5c5SAndroid Build Coastguard Worker ] 36*8975f5c5SAndroid Build Coastguard Worker 37*8975f5c5SAndroid Build Coastguard Worker stat = MEMORYSTATUSEX(dwLength=ctypes.sizeof(MEMORYSTATUSEX)) 38*8975f5c5SAndroid Build Coastguard Worker ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(stat)) 39*8975f5c5SAndroid Build Coastguard Worker return stat.ullTotalPhys 40*8975f5c5SAndroid Build Coastguard Worker elif sys.platform.startswith('linux'): 41*8975f5c5SAndroid Build Coastguard Worker if os.path.exists("/proc/meminfo"): 42*8975f5c5SAndroid Build Coastguard Worker with open("/proc/meminfo") as meminfo: 43*8975f5c5SAndroid Build Coastguard Worker memtotal_re = re.compile(r'^MemTotal:\s*(\d*)\s*kB') 44*8975f5c5SAndroid Build Coastguard Worker for line in meminfo: 45*8975f5c5SAndroid Build Coastguard Worker match = memtotal_re.match(line) 46*8975f5c5SAndroid Build Coastguard Worker if not match: 47*8975f5c5SAndroid Build Coastguard Worker continue 48*8975f5c5SAndroid Build Coastguard Worker return float(match.group(1)) * 2**10 49*8975f5c5SAndroid Build Coastguard Worker elif sys.platform == 'darwin': 50*8975f5c5SAndroid Build Coastguard Worker try: 51*8975f5c5SAndroid Build Coastguard Worker return int(subprocess.check_output(['sysctl', '-n', 'hw.memsize'])) 52*8975f5c5SAndroid Build Coastguard Worker except Exception: 53*8975f5c5SAndroid Build Coastguard Worker return 0 54*8975f5c5SAndroid Build Coastguard Worker # TODO(scottmg): Implement this for other platforms. 55*8975f5c5SAndroid Build Coastguard Worker return 0 56*8975f5c5SAndroid Build Coastguard Worker 57*8975f5c5SAndroid Build Coastguard Worker 58*8975f5c5SAndroid Build Coastguard Workerdef _GetDefaultConcurrentLinks(per_link_gb, reserve_gb, thin_lto_type, 59*8975f5c5SAndroid Build Coastguard Worker secondary_per_link_gb, override_ram_in_gb): 60*8975f5c5SAndroid Build Coastguard Worker explanation = [] 61*8975f5c5SAndroid Build Coastguard Worker explanation.append( 62*8975f5c5SAndroid Build Coastguard Worker 'per_link_gb={} reserve_gb={} secondary_per_link_gb={}'.format( 63*8975f5c5SAndroid Build Coastguard Worker per_link_gb, reserve_gb, secondary_per_link_gb)) 64*8975f5c5SAndroid Build Coastguard Worker if override_ram_in_gb: 65*8975f5c5SAndroid Build Coastguard Worker mem_total_gb = override_ram_in_gb 66*8975f5c5SAndroid Build Coastguard Worker else: 67*8975f5c5SAndroid Build Coastguard Worker mem_total_gb = float(_GetTotalMemoryInBytes()) / 2**30 68*8975f5c5SAndroid Build Coastguard Worker adjusted_mem_total_gb = max(0, mem_total_gb - reserve_gb) 69*8975f5c5SAndroid Build Coastguard Worker 70*8975f5c5SAndroid Build Coastguard Worker # Ensure that there is at least as many links allocated for the secondary as 71*8975f5c5SAndroid Build Coastguard Worker # there is for the primary. The secondary link usually uses fewer gbs. 72*8975f5c5SAndroid Build Coastguard Worker mem_cap = int( 73*8975f5c5SAndroid Build Coastguard Worker max(1, adjusted_mem_total_gb / (per_link_gb + secondary_per_link_gb))) 74*8975f5c5SAndroid Build Coastguard Worker 75*8975f5c5SAndroid Build Coastguard Worker try: 76*8975f5c5SAndroid Build Coastguard Worker cpu_count = multiprocessing.cpu_count() 77*8975f5c5SAndroid Build Coastguard Worker except: 78*8975f5c5SAndroid Build Coastguard Worker cpu_count = 1 79*8975f5c5SAndroid Build Coastguard Worker 80*8975f5c5SAndroid Build Coastguard Worker # A local LTO links saturate all cores, but only for some amount of the link. 81*8975f5c5SAndroid Build Coastguard Worker cpu_cap = cpu_count 82*8975f5c5SAndroid Build Coastguard Worker if thin_lto_type is not None: 83*8975f5c5SAndroid Build Coastguard Worker assert thin_lto_type == 'local' 84*8975f5c5SAndroid Build Coastguard Worker cpu_cap = min(cpu_count, 6) 85*8975f5c5SAndroid Build Coastguard Worker 86*8975f5c5SAndroid Build Coastguard Worker explanation.append( 87*8975f5c5SAndroid Build Coastguard Worker 'cpu_count={} cpu_cap={} mem_total_gb={:.1f}GiB adjusted_mem_total_gb={:.1f}GiB' 88*8975f5c5SAndroid Build Coastguard Worker .format(cpu_count, cpu_cap, mem_total_gb, adjusted_mem_total_gb)) 89*8975f5c5SAndroid Build Coastguard Worker 90*8975f5c5SAndroid Build Coastguard Worker num_links = min(mem_cap, cpu_cap) 91*8975f5c5SAndroid Build Coastguard Worker if num_links == cpu_cap: 92*8975f5c5SAndroid Build Coastguard Worker if cpu_cap == cpu_count: 93*8975f5c5SAndroid Build Coastguard Worker reason = 'cpu_count' 94*8975f5c5SAndroid Build Coastguard Worker else: 95*8975f5c5SAndroid Build Coastguard Worker reason = 'cpu_cap (thinlto)' 96*8975f5c5SAndroid Build Coastguard Worker else: 97*8975f5c5SAndroid Build Coastguard Worker reason = 'RAM' 98*8975f5c5SAndroid Build Coastguard Worker 99*8975f5c5SAndroid Build Coastguard Worker # static link see too many open files if we have many concurrent links. 100*8975f5c5SAndroid Build Coastguard Worker # ref: http://b/233068481 101*8975f5c5SAndroid Build Coastguard Worker if num_links > 30: 102*8975f5c5SAndroid Build Coastguard Worker num_links = 30 103*8975f5c5SAndroid Build Coastguard Worker reason = 'nofile' 104*8975f5c5SAndroid Build Coastguard Worker 105*8975f5c5SAndroid Build Coastguard Worker explanation.append('concurrent_links={} (reason: {})'.format( 106*8975f5c5SAndroid Build Coastguard Worker num_links, reason)) 107*8975f5c5SAndroid Build Coastguard Worker 108*8975f5c5SAndroid Build Coastguard Worker # Use remaining RAM for a secondary pool if needed. 109*8975f5c5SAndroid Build Coastguard Worker if secondary_per_link_gb: 110*8975f5c5SAndroid Build Coastguard Worker mem_remaining = adjusted_mem_total_gb - num_links * per_link_gb 111*8975f5c5SAndroid Build Coastguard Worker secondary_size = int(max(0, mem_remaining / secondary_per_link_gb)) 112*8975f5c5SAndroid Build Coastguard Worker if secondary_size > cpu_count: 113*8975f5c5SAndroid Build Coastguard Worker secondary_size = cpu_count 114*8975f5c5SAndroid Build Coastguard Worker reason = 'cpu_count' 115*8975f5c5SAndroid Build Coastguard Worker else: 116*8975f5c5SAndroid Build Coastguard Worker reason = 'mem_remaining={:.1f}GiB'.format(mem_remaining) 117*8975f5c5SAndroid Build Coastguard Worker explanation.append('secondary_size={} (reason: {})'.format( 118*8975f5c5SAndroid Build Coastguard Worker secondary_size, reason)) 119*8975f5c5SAndroid Build Coastguard Worker else: 120*8975f5c5SAndroid Build Coastguard Worker secondary_size = 0 121*8975f5c5SAndroid Build Coastguard Worker 122*8975f5c5SAndroid Build Coastguard Worker return num_links, secondary_size, explanation 123*8975f5c5SAndroid Build Coastguard Worker 124*8975f5c5SAndroid Build Coastguard Worker 125*8975f5c5SAndroid Build Coastguard Workerdef main(): 126*8975f5c5SAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 127*8975f5c5SAndroid Build Coastguard Worker parser.add_argument('--mem_per_link_gb', type=int, default=8) 128*8975f5c5SAndroid Build Coastguard Worker parser.add_argument('--reserve_mem_gb', type=int, default=0) 129*8975f5c5SAndroid Build Coastguard Worker parser.add_argument('--secondary_mem_per_link', type=int, default=0) 130*8975f5c5SAndroid Build Coastguard Worker parser.add_argument('--override-ram-in-gb-for-testing', type=float, default=0) 131*8975f5c5SAndroid Build Coastguard Worker parser.add_argument('--thin-lto') 132*8975f5c5SAndroid Build Coastguard Worker options = parser.parse_args() 133*8975f5c5SAndroid Build Coastguard Worker 134*8975f5c5SAndroid Build Coastguard Worker primary_pool_size, secondary_pool_size, explanation = ( 135*8975f5c5SAndroid Build Coastguard Worker _GetDefaultConcurrentLinks(options.mem_per_link_gb, 136*8975f5c5SAndroid Build Coastguard Worker options.reserve_mem_gb, options.thin_lto, 137*8975f5c5SAndroid Build Coastguard Worker options.secondary_mem_per_link, 138*8975f5c5SAndroid Build Coastguard Worker options.override_ram_in_gb_for_testing)) 139*8975f5c5SAndroid Build Coastguard Worker if options.override_ram_in_gb_for_testing: 140*8975f5c5SAndroid Build Coastguard Worker print('primary={} secondary={} explanation={}'.format( 141*8975f5c5SAndroid Build Coastguard Worker primary_pool_size, secondary_pool_size, explanation)) 142*8975f5c5SAndroid Build Coastguard Worker else: 143*8975f5c5SAndroid Build Coastguard Worker sys.stdout.write( 144*8975f5c5SAndroid Build Coastguard Worker gn_helpers.ToGNString({ 145*8975f5c5SAndroid Build Coastguard Worker 'primary_pool_size': primary_pool_size, 146*8975f5c5SAndroid Build Coastguard Worker 'secondary_pool_size': secondary_pool_size, 147*8975f5c5SAndroid Build Coastguard Worker 'explanation': explanation, 148*8975f5c5SAndroid Build Coastguard Worker })) 149*8975f5c5SAndroid Build Coastguard Worker return 0 150*8975f5c5SAndroid Build Coastguard Worker 151*8975f5c5SAndroid Build Coastguard Worker 152*8975f5c5SAndroid Build Coastguard Workerif __name__ == '__main__': 153*8975f5c5SAndroid Build Coastguard Worker sys.exit(main()) 154