]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | import errno |
2 | import itertools | |
3 | import math | |
4 | import os | |
5 | import platform | |
6 | import signal | |
7 | import subprocess | |
8 | import sys | |
223e47cc | 9 | |
85aaf69f SL |
10 | def to_bytes(str): |
11 | # Encode to UTF-8 to get binary data. | |
12 | return str.encode('utf-8') | |
13 | ||
14 | def to_string(bytes): | |
15 | if isinstance(bytes, str): | |
16 | return bytes | |
17 | return to_bytes(bytes) | |
18 | ||
19 | def convert_string(bytes): | |
20 | try: | |
21 | return to_string(bytes.decode('utf-8')) | |
22 | except UnicodeError: | |
23 | return str(bytes) | |
24 | ||
223e47cc LB |
25 | def 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"): | |
1a4d82fc | 31 | if "SC_NPROCESSORS_ONLN" in os.sysconf_names: |
223e47cc LB |
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: | |
1a4d82fc | 39 | if "NUMBER_OF_PROCESSORS" in os.environ: |
223e47cc LB |
40 | ncpus = int(os.environ["NUMBER_OF_PROCESSORS"]) |
41 | if ncpus > 0: | |
42 | return ncpus | |
43 | return 1 # Default | |
44 | ||
45 | def 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.""" | |
223e47cc LB |
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) | |
1a4d82fc JJ |
57 | except OSError: |
58 | e = sys.exc_info()[1] | |
223e47cc LB |
59 | # Ignore EEXIST, which may occur during a race condition. |
60 | if e.errno != errno.EEXIST: | |
61 | raise | |
62 | ||
63 | def capture(args, env=None): | |
223e47cc LB |
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() | |
85aaf69f | 69 | return convert_string(out) |
223e47cc LB |
70 | |
71 | def 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 | ||
102 | def 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 | ||
108 | def whichTools(tools, paths): | |
109 | for path in paths.split(os.pathsep): | |
110 | if checkToolsPath(path, tools): | |
111 | return path | |
112 | return None | |
113 | ||
114 | def printHistogram(items, title = 'Items'): | |
1a4d82fc | 115 | items.sort(key = lambda item: item[1]) |
223e47cc LB |
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) | |
1a4d82fc JJ |
136 | print('\nSlowest %s:' % title) |
137 | print(hr) | |
223e47cc | 138 | for name,value in items[-20:]: |
1a4d82fc JJ |
139 | print('%.2fs: %s' % (value, name)) |
140 | print('\n%s Times:' % title) | |
141 | print(hr) | |
223e47cc LB |
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))) | |
1a4d82fc | 147 | print("[%s] :: [%s] :: [%s]" % ('Range'.center((pDigits+1)*2 + 3), |
223e47cc | 148 | 'Percentage'.center(barW), |
1a4d82fc JJ |
149 | 'Count'.center(cDigits*2 + 1))) |
150 | print(hr) | |
223e47cc LB |
151 | for i,row in enumerate(histo): |
152 | pct = float(len(row)) / len(items) | |
153 | w = int(barW * pct) | |
1a4d82fc JJ |
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). | |
160 | kUseCloseFDs = not (platform.system() == 'Windows') | |
161 | def 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 | ||
1a4d82fc | 174 | # Ensure the resulting output is always of string type. |
85aaf69f SL |
175 | out = convert_string(out) |
176 | err = convert_string(err) | |
1a4d82fc JJ |
177 | |
178 | return out, err, exitCode | |
179 | ||
180 | def 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 |