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