12 # Encode to UTF-8 to get binary data.
13 return str.encode('utf-8')
16 if isinstance(bytes, str):
18 return to_bytes(bytes)
20 def convert_string(bytes):
22 return to_string(bytes.decode('utf-8'))
28 Detects the number of CPUs on a system. Cribbed from pp.
30 # Linux, Unix and MacOS:
31 if hasattr(os, "sysconf"):
32 if "SC_NPROCESSORS_ONLN" in os.sysconf_names:
34 ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
35 if isinstance(ncpus, int) and ncpus > 0:
38 return int(capture(['sysctl', '-n', 'hw.ncpu']))
40 if "NUMBER_OF_PROCESSORS" in os.environ:
41 ncpus = int(os.environ["NUMBER_OF_PROCESSORS"])
43 # With more than 32 processes, process creation often fails with
44 # "Too many open files". FIXME: Check if there's a better fix.
49 """mkdir_p(path) - Make the "path" directory, if it does not exist; this
50 will also make directories for any missing parent directories."""
51 if not path or os.path.exists(path):
54 parent = os.path.dirname(path)
62 # Ignore EEXIST, which may occur during a race condition.
63 if e.errno != errno.EEXIST:
66 def capture(args, env=None):
67 """capture(command) - Run the given command (or argv list) in a shell and
68 return the standard output."""
69 p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
71 out,_ = p.communicate()
72 return convert_string(out)
74 def which(command, paths = None):
75 """which(command, [paths]) - Look up the given command in the paths string
76 (or the PATH environment variable, if unspecified)."""
79 paths = os.environ.get('PATH','')
81 # Check for absolute match first.
82 if os.path.isfile(command):
85 # Would be nice if Python had a lib function for this.
89 # Get suffixes to search.
90 # On Cygwin, 'PATHEXT' may exist but it should not be used.
92 pathext = os.environ.get('PATHEXT', '').split(';')
97 for path in paths.split(os.pathsep):
99 p = os.path.join(path, command + ext)
100 if os.path.exists(p) and not os.path.isdir(p):
105 def checkToolsPath(dir, tools):
107 if not os.path.exists(os.path.join(dir, tool)):
111 def whichTools(tools, paths):
112 for path in paths.split(os.pathsep):
113 if checkToolsPath(path, tools):
117 def printHistogram(items, title = 'Items'):
118 items.sort(key = lambda item: item[1])
120 maxValue = max([v for _,v in items])
122 # Select first "nice" bar height that produces more than 10 bars.
123 power = int(math.ceil(math.log(maxValue, 10)))
124 for inc in itertools.cycle((5, 2, 2.5, 1)):
125 barH = inc * 10**power
126 N = int(math.ceil(maxValue / barH))
132 histo = [set() for i in range(N)]
134 bin = min(int(N * v/maxValue), N-1)
138 hr = '-' * (barW + 34)
139 print('\nSlowest %s:' % title)
141 for name,value in items[-20:]:
142 print('%.2fs: %s' % (value, name))
143 print('\n%s Times:' % title)
145 pDigits = int(math.ceil(math.log(maxValue, 10)))
146 pfDigits = max(0, 3-pDigits)
148 pDigits += pfDigits + 1
149 cDigits = int(math.ceil(math.log(len(items), 10)))
150 print("[%s] :: [%s] :: [%s]" % ('Range'.center((pDigits+1)*2 + 3),
151 'Percentage'.center(barW),
152 'Count'.center(cDigits*2 + 1)))
154 for i,row in enumerate(histo):
155 pct = float(len(row)) / len(items)
157 print("[%*.*fs,%*.*fs) :: [%s%s] :: [%*d/%*d]" % (
158 pDigits, pfDigits, i*barH, pDigits, pfDigits, (i+1)*barH,
159 '*'*w, ' '*(barW-w), cDigits, len(row), cDigits, len(items)))
161 class ExecuteCommandTimeoutException(Exception):
162 def __init__(self, msg, out, err, exitCode):
163 assert isinstance(msg, str)
164 assert isinstance(out, str)
165 assert isinstance(err, str)
166 assert isinstance(exitCode, int)
170 self.exitCode = exitCode
172 # Close extra file handles on UNIX (on Windows this cannot be done while
173 # also redirecting input).
174 kUseCloseFDs = not (platform.system() == 'Windows')
175 def executeCommand(command, cwd=None, env=None, input=None, timeout=0):
177 Execute command ``command`` (list of arguments or string)
179 * working directory ``cwd`` (str), use None to use the current
181 * environment ``env`` (dict), use None for none
182 * Input to the command ``input`` (str), use string to pass
184 * Max execution time ``timeout`` (int) seconds. Use 0 for no timeout.
186 Returns a tuple (out, err, exitCode) where
187 * ``out`` (str) is the standard output of running the command
188 * ``err`` (str) is the standard error of running the command
189 * ``exitCode`` (int) is the exitCode of running the command
191 If the timeout is hit an ``ExecuteCommandTimeoutException``
194 p = subprocess.Popen(command, cwd=cwd,
195 stdin=subprocess.PIPE,
196 stdout=subprocess.PIPE,
197 stderr=subprocess.PIPE,
198 env=env, close_fds=kUseCloseFDs)
200 # FIXME: Because of the way nested function scopes work in Python 2.x we
201 # need to use a reference to a mutable object rather than a plain
202 # bool. In Python 3 we could use the "nonlocal" keyword but we need
203 # to support Python 2 as well.
208 # We may be invoking a shell so we need to kill the
209 # process and all its children.
211 killProcessAndChildren(p.pid)
213 timerObject = threading.Timer(timeout, killProcess)
216 out,err = p.communicate(input=input)
219 if timerObject != None:
222 # Ensure the resulting output is always of string type.
223 out = convert_string(out)
224 err = convert_string(err)
227 raise ExecuteCommandTimeoutException(
228 msg='Reached timeout of {} seconds'.format(timeout),
234 # Detect Ctrl-C in subprocess.
235 if exitCode == -signal.SIGINT:
236 raise KeyboardInterrupt
238 return out, err, exitCode
240 def usePlatformSdkOnDarwin(config, lit_config):
241 # On Darwin, support relocatable SDKs by providing Clang with a
242 # default system root path.
243 if 'darwin' in config.target_triple:
245 cmd = subprocess.Popen(['xcrun', '--show-sdk-path'],
246 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
247 out, err = cmd.communicate()
254 lit_config.note('using SDKROOT: %r' % sdk_path)
255 config.environment['SDKROOT'] = sdk_path
257 def killProcessAndChildren(pid):
259 This function kills a process with ``pid`` and all its
260 running children (recursively). It is currently implemented
261 using the psutil module which provides a simple platform
262 neutral implementation.
264 TODO: Reimplement this without using psutil so we can
265 remove our dependency on it.
269 psutilProc = psutil.Process(pid)
270 for child in psutilProc.children(recursive=True):
273 except psutil.NoSuchProcess:
276 except psutil.NoSuchProcess: