Index: third_party/lit/lit/util.py |
diff --git a/third_party/lit/lit/util.py b/third_party/lit/lit/util.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a4233bac7aa5bc43a1e777dcd8495297da335b31 |
--- /dev/null |
+++ b/third_party/lit/lit/util.py |
@@ -0,0 +1,195 @@ |
+import errno |
+import itertools |
+import math |
+import os |
+import platform |
+import signal |
+import subprocess |
+import sys |
+ |
+def to_bytes(str): |
+ # Encode to UTF-8 to get binary data. |
+ return str.encode('utf-8') |
+ |
+def to_string(bytes): |
+ if isinstance(bytes, str): |
+ return bytes |
+ return to_bytes(bytes) |
+ |
+def convert_string(bytes): |
+ try: |
+ return to_string(bytes.decode('utf-8')) |
+ except UnicodeError: |
+ return str(bytes) |
+ |
+def detectCPUs(): |
+ """ |
+ Detects the number of CPUs on a system. Cribbed from pp. |
+ """ |
+ # Linux, Unix and MacOS: |
+ if hasattr(os, "sysconf"): |
+ if "SC_NPROCESSORS_ONLN" in os.sysconf_names: |
+ # Linux & Unix: |
+ ncpus = os.sysconf("SC_NPROCESSORS_ONLN") |
+ if isinstance(ncpus, int) and ncpus > 0: |
+ return ncpus |
+ else: # OSX: |
+ return int(capture(['sysctl', '-n', 'hw.ncpu'])) |
+ # Windows: |
+ if "NUMBER_OF_PROCESSORS" in os.environ: |
+ ncpus = int(os.environ["NUMBER_OF_PROCESSORS"]) |
+ if ncpus > 0: |
+ return ncpus |
+ return 1 # Default |
+ |
+def mkdir_p(path): |
+ """mkdir_p(path) - Make the "path" directory, if it does not exist; this |
+ will also make directories for any missing parent directories.""" |
+ if not path or os.path.exists(path): |
+ return |
+ |
+ parent = os.path.dirname(path) |
+ if parent != path: |
+ mkdir_p(parent) |
+ |
+ try: |
+ os.mkdir(path) |
+ except OSError: |
+ e = sys.exc_info()[1] |
+ # Ignore EEXIST, which may occur during a race condition. |
+ if e.errno != errno.EEXIST: |
+ raise |
+ |
+def capture(args, env=None): |
+ """capture(command) - Run the given command (or argv list) in a shell and |
+ return the standard output.""" |
+ p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, |
+ env=env) |
+ out,_ = p.communicate() |
+ return convert_string(out) |
+ |
+def which(command, paths = None): |
+ """which(command, [paths]) - Look up the given command in the paths string |
+ (or the PATH environment variable, if unspecified).""" |
+ |
+ if paths is None: |
+ paths = os.environ.get('PATH','') |
+ |
+ # Check for absolute match first. |
+ if os.path.isfile(command): |
+ return command |
+ |
+ # Would be nice if Python had a lib function for this. |
+ if not paths: |
+ paths = os.defpath |
+ |
+ # Get suffixes to search. |
+ # On Cygwin, 'PATHEXT' may exist but it should not be used. |
+ if os.pathsep == ';': |
+ pathext = os.environ.get('PATHEXT', '').split(';') |
+ else: |
+ pathext = [''] |
+ |
+ # Search the paths... |
+ for path in paths.split(os.pathsep): |
+ for ext in pathext: |
+ p = os.path.join(path, command + ext) |
+ if os.path.exists(p): |
+ return p |
+ |
+ return None |
+ |
+def checkToolsPath(dir, tools): |
+ for tool in tools: |
+ if not os.path.exists(os.path.join(dir, tool)): |
+ return False; |
+ return True; |
+ |
+def whichTools(tools, paths): |
+ for path in paths.split(os.pathsep): |
+ if checkToolsPath(path, tools): |
+ return path |
+ return None |
+ |
+def printHistogram(items, title = 'Items'): |
+ items.sort(key = lambda item: item[1]) |
+ |
+ maxValue = max([v for _,v in items]) |
+ |
+ # Select first "nice" bar height that produces more than 10 bars. |
+ power = int(math.ceil(math.log(maxValue, 10))) |
+ for inc in itertools.cycle((5, 2, 2.5, 1)): |
+ barH = inc * 10**power |
+ N = int(math.ceil(maxValue / barH)) |
+ if N > 10: |
+ break |
+ elif inc == 1: |
+ power -= 1 |
+ |
+ histo = [set() for i in range(N)] |
+ for name,v in items: |
+ bin = min(int(N * v/maxValue), N-1) |
+ histo[bin].add(name) |
+ |
+ barW = 40 |
+ hr = '-' * (barW + 34) |
+ print('\nSlowest %s:' % title) |
+ print(hr) |
+ for name,value in items[-20:]: |
+ print('%.2fs: %s' % (value, name)) |
+ print('\n%s Times:' % title) |
+ print(hr) |
+ pDigits = int(math.ceil(math.log(maxValue, 10))) |
+ pfDigits = max(0, 3-pDigits) |
+ if pfDigits: |
+ pDigits += pfDigits + 1 |
+ cDigits = int(math.ceil(math.log(len(items), 10))) |
+ print("[%s] :: [%s] :: [%s]" % ('Range'.center((pDigits+1)*2 + 3), |
+ 'Percentage'.center(barW), |
+ 'Count'.center(cDigits*2 + 1))) |
+ print(hr) |
+ for i,row in enumerate(histo): |
+ pct = float(len(row)) / len(items) |
+ w = int(barW * pct) |
+ print("[%*.*fs,%*.*fs) :: [%s%s] :: [%*d/%*d]" % ( |
+ pDigits, pfDigits, i*barH, pDigits, pfDigits, (i+1)*barH, |
+ '*'*w, ' '*(barW-w), cDigits, len(row), cDigits, len(items))) |
+ |
+# Close extra file handles on UNIX (on Windows this cannot be done while |
+# also redirecting input). |
+kUseCloseFDs = not (platform.system() == 'Windows') |
+def executeCommand(command, cwd=None, env=None, input=None): |
+ p = subprocess.Popen(command, cwd=cwd, |
+ stdin=subprocess.PIPE, |
+ stdout=subprocess.PIPE, |
+ stderr=subprocess.PIPE, |
+ env=env, close_fds=kUseCloseFDs) |
+ out,err = p.communicate(input=input) |
+ exitCode = p.wait() |
+ |
+ # Detect Ctrl-C in subprocess. |
+ if exitCode == -signal.SIGINT: |
+ raise KeyboardInterrupt |
+ |
+ # Ensure the resulting output is always of string type. |
+ out = convert_string(out) |
+ err = convert_string(err) |
+ |
+ return out, err, exitCode |
+ |
+def usePlatformSdkOnDarwin(config, lit_config): |
+ # On Darwin, support relocatable SDKs by providing Clang with a |
+ # default system root path. |
+ if 'darwin' in config.target_triple: |
+ try: |
+ cmd = subprocess.Popen(['xcrun', '--show-sdk-path'], |
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
+ out, err = cmd.communicate() |
+ out = out.strip() |
+ res = cmd.wait() |
+ except OSError: |
+ res = -1 |
+ if res == 0 and out: |
+ sdk_path = out |
+ lit_config.note('using SDKROOT: %r' % sdk_path) |
+ config.environment['SDKROOT'] = sdk_path |