1import errno 2import itertools 3import math 4import os 5import platform 6import signal 7import subprocess 8import sys 9 10def to_bytes(str): 11 # Encode to UTF-8 to get binary data. 12 return str.encode('utf-8') 13 14def to_string(bytes): 15 if isinstance(bytes, str): 16 return bytes 17 return to_bytes(bytes) 18 19def convert_string(bytes): 20 try: 21 return to_string(bytes.decode('utf-8')) 22 except UnicodeError: 23 return str(bytes) 24 25def detectCPUs(): 26 """ 27 Detects the number of CPUs on a system. Cribbed from pp. 28 """ 29 # Linux, Unix and MacOS: 30 if hasattr(os, "sysconf"): 31 if "SC_NPROCESSORS_ONLN" in os.sysconf_names: 32 # Linux & Unix: 33 ncpus = os.sysconf("SC_NPROCESSORS_ONLN") 34 if isinstance(ncpus, int) and ncpus > 0: 35 return ncpus 36 else: # OSX: 37 return int(capture(['sysctl', '-n', 'hw.ncpu'])) 38 # Windows: 39 if "NUMBER_OF_PROCESSORS" in os.environ: 40 ncpus = int(os.environ["NUMBER_OF_PROCESSORS"]) 41 if ncpus > 0: 42 return ncpus 43 return 1 # Default 44 45def mkdir_p(path): 46 """mkdir_p(path) - Make the "path" directory, if it does not exist; this 47 will also make directories for any missing parent directories.""" 48 if not path or os.path.exists(path): 49 return 50 51 parent = os.path.dirname(path) 52 if parent != path: 53 mkdir_p(parent) 54 55 try: 56 os.mkdir(path) 57 except OSError: 58 e = sys.exc_info()[1] 59 # Ignore EEXIST, which may occur during a race condition. 60 if e.errno != errno.EEXIST: 61 raise 62 63def capture(args, env=None): 64 """capture(command) - Run the given command (or argv list) in a shell and 65 return the standard output.""" 66 p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, 67 env=env) 68 out,_ = p.communicate() 69 return convert_string(out) 70 71def which(command, paths = None): 72 """which(command, [paths]) - Look up the given command in the paths string 73 (or the PATH environment variable, if unspecified).""" 74 75 if paths is None: 76 paths = os.environ.get('PATH','') 77 78 # Check for absolute match first. 79 if os.path.isfile(command): 80 return command 81 82 # Would be nice if Python had a lib function for this. 83 if not paths: 84 paths = os.defpath 85 86 # Get suffixes to search. 87 # On Cygwin, 'PATHEXT' may exist but it should not be used. 88 if os.pathsep == ';': 89 pathext = os.environ.get('PATHEXT', '').split(';') 90 else: 91 pathext = [''] 92 93 # Search the paths... 94 for path in paths.split(os.pathsep): 95 for ext in pathext: 96 p = os.path.join(path, command + ext) 97 if os.path.exists(p): 98 return p 99 100 return None 101 102def checkToolsPath(dir, tools): 103 for tool in tools: 104 if not os.path.exists(os.path.join(dir, tool)): 105 return False; 106 return True; 107 108def whichTools(tools, paths): 109 for path in paths.split(os.pathsep): 110 if checkToolsPath(path, tools): 111 return path 112 return None 113 114def printHistogram(items, title = 'Items'): 115 items.sort(key = lambda item: item[1]) 116 117 maxValue = max([v for _,v in items]) 118 119 # Select first "nice" bar height that produces more than 10 bars. 120 power = int(math.ceil(math.log(maxValue, 10))) 121 for inc in itertools.cycle((5, 2, 2.5, 1)): 122 barH = inc * 10**power 123 N = int(math.ceil(maxValue / barH)) 124 if N > 10: 125 break 126 elif inc == 1: 127 power -= 1 128 129 histo = [set() for i in range(N)] 130 for name,v in items: 131 bin = min(int(N * v/maxValue), N-1) 132 histo[bin].add(name) 133 134 barW = 40 135 hr = '-' * (barW + 34) 136 print('\nSlowest %s:' % title) 137 print(hr) 138 for name,value in items[-20:]: 139 print('%.2fs: %s' % (value, name)) 140 print('\n%s Times:' % title) 141 print(hr) 142 pDigits = int(math.ceil(math.log(maxValue, 10))) 143 pfDigits = max(0, 3-pDigits) 144 if pfDigits: 145 pDigits += pfDigits + 1 146 cDigits = int(math.ceil(math.log(len(items), 10))) 147 print("[%s] :: [%s] :: [%s]" % ('Range'.center((pDigits+1)*2 + 3), 148 'Percentage'.center(barW), 149 'Count'.center(cDigits*2 + 1))) 150 print(hr) 151 for i,row in enumerate(histo): 152 pct = float(len(row)) / len(items) 153 w = int(barW * pct) 154 print("[%*.*fs,%*.*fs) :: [%s%s] :: [%*d/%*d]" % ( 155 pDigits, pfDigits, i*barH, pDigits, pfDigits, (i+1)*barH, 156 '*'*w, ' '*(barW-w), cDigits, len(row), cDigits, len(items))) 157 158# Close extra file handles on UNIX (on Windows this cannot be done while 159# also redirecting input). 160kUseCloseFDs = not (platform.system() == 'Windows') 161def executeCommand(command, cwd=None, env=None): 162 p = subprocess.Popen(command, cwd=cwd, 163 stdin=subprocess.PIPE, 164 stdout=subprocess.PIPE, 165 stderr=subprocess.PIPE, 166 env=env, close_fds=kUseCloseFDs) 167 out,err = p.communicate() 168 exitCode = p.wait() 169 170 # Detect Ctrl-C in subprocess. 171 if exitCode == -signal.SIGINT: 172 raise KeyboardInterrupt 173 174 # Ensure the resulting output is always of string type. 175 out = convert_string(out) 176 err = convert_string(err) 177 178 return out, err, exitCode 179 180def usePlatformSdkOnDarwin(config, lit_config): 181 # On Darwin, support relocatable SDKs by providing Clang with a 182 # default system root path. 183 if 'darwin' in config.target_triple: 184 try: 185 cmd = subprocess.Popen(['xcrun', '--show-sdk-path'], 186 stdout=subprocess.PIPE, stderr=subprocess.PIPE) 187 out, err = cmd.communicate() 188 out = out.strip() 189 res = cmd.wait() 190 except OSError: 191 res = -1 192 if res == 0 and out: 193 sdk_path = out 194 lit_config.note('using SDKROOT: %r' % sdk_path) 195 config.environment['SDKROOT'] = sdk_path 196