llvm.org GIT mirror llvm / 128ce31
[lit] Rename lit.{TestFormats,Util} to their aliased names {formats,util}. - With compatibility hack in lit.__init__, so this hopefully shouldn't break anything. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188040 91177308-0d34-0410-b5e6-96231b3b80d8 Daniel Dunbar 6 years ago
9 changed file(s) with 392 addition(s) and 388 deletion(s). Raw diff Collapse all Expand all
33 import sys
44
55 import lit.Test
6 import lit.TestFormats
6 import lit.formats
77 import lit.TestingConfig
8 import lit.Util
8 import lit.util
99
1010 class LitConfig:
1111 """LitConfig - Configuration data for a 'lit' test runner instance, shared
2121 Test = lit.Test
2222
2323 # Provide access to built-in formats.
24 formats = lit.TestFormats
24 formats = lit.formats
2525
2626 # Provide access to built-in utility functions.
27 util = lit.Util
27 util = lit.util
2828
2929 def __init__(self, progname, path, quiet,
3030 useValgrind, valgrindLeakCheck, valgrindArgs,
7979 if self.bashPath is not None:
8080 return self.bashPath
8181
82 self.bashPath = lit.Util.which('bash', os.pathsep.join(self.path))
82 self.bashPath = lit.util.which('bash', os.pathsep.join(self.path))
8383 if self.bashPath is None:
8484 # Check some known paths.
8585 for path in ('/bin/bash', '/usr/bin/bash', '/usr/local/bin/bash'):
9595
9696 def getToolsPath(self, dir, paths, tools):
9797 if dir is not None and os.path.isabs(dir) and os.path.isdir(dir):
98 if not lit.Util.checkToolsPath(dir, tools):
98 if not lit.util.checkToolsPath(dir, tools):
9999 return None
100100 else:
101 dir = lit.Util.whichTools(tools, paths)
101 dir = lit.util.whichTools(tools, paths)
102102
103103 # bash
104 self.bashPath = lit.Util.which('bash', dir)
104 self.bashPath = lit.util.which('bash', dir)
105105 if self.bashPath is None:
106106 self.note("Unable to find 'bash.exe'.")
107107 self.bashPath = ''
0 from __future__ import absolute_import
11 import itertools
22
3 import lit.Util
3 import lit.util
44 from lit.ShCommands import Command, Pipeline, Seq
55
66 class ShLexer:
7474 # Outside of a string, '\\' escapes everything.
7575 self.eat()
7676 if self.pos == self.end:
77 lit.Util.warning(
77 lit.util.warning(
7878 "escape at end of quoted argument in: %r" % self.data)
7979 return str
8080 str += self.eat()
9292 # Inside a '"' quoted string, '\\' only escapes the quote
9393 # character and backslash, otherwise it is preserved.
9494 if self.pos == self.end:
95 lit.Util.warning(
95 lit.util.warning(
9696 "escape at end of quoted argument in: %r" % self.data)
9797 return str
9898 c = self.eat()
104104 str += '\\' + c
105105 else:
106106 str += c
107 lit.Util.warning("missing quote character in %r" % self.data)
107 lit.util.warning("missing quote character in %r" % self.data)
108108 return str
109109
110110 def lex_arg_checked(self, c):
+0
-230
utils/lit/lit/TestFormats.py less more
None from __future__ import absolute_import
1 import os
2 import sys
3
4 import lit.Test
5 import lit.TestRunner
6 import lit.Util
7
8 kIsWindows = sys.platform in ['win32', 'cygwin']
9
10 class GoogleTest(object):
11 def __init__(self, test_sub_dir, test_suffix):
12 self.test_sub_dir = os.path.normcase(str(test_sub_dir)).split(';')
13 self.test_suffix = str(test_suffix)
14
15 # On Windows, assume tests will also end in '.exe'.
16 if kIsWindows:
17 self.test_suffix += '.exe'
18
19 def getGTestTests(self, path, litConfig, localConfig):
20 """getGTestTests(path) - [name]
21
22 Return the tests available in gtest executable.
23
24 Args:
25 path: String path to a gtest executable
26 litConfig: LitConfig instance
27 localConfig: TestingConfig instance"""
28
29 try:
30 lines = lit.Util.capture([path, '--gtest_list_tests'],
31 env=localConfig.environment)
32 lines = lines.decode('ascii')
33 if kIsWindows:
34 lines = lines.replace('\r', '')
35 lines = lines.split('\n')
36 except:
37 litConfig.error("unable to discover google-tests in %r" % path)
38 raise StopIteration
39
40 nested_tests = []
41 for ln in lines:
42 if not ln.strip():
43 continue
44
45 prefix = ''
46 index = 0
47 while ln[index*2:index*2+2] == ' ':
48 index += 1
49 while len(nested_tests) > index:
50 nested_tests.pop()
51
52 ln = ln[index*2:]
53 if ln.endswith('.'):
54 nested_tests.append(ln)
55 else:
56 yield ''.join(nested_tests) + ln
57
58 # Note: path_in_suite should not include the executable name.
59 def getTestsInExecutable(self, testSuite, path_in_suite, execpath,
60 litConfig, localConfig):
61 if not execpath.endswith(self.test_suffix):
62 return
63 (dirname, basename) = os.path.split(execpath)
64 # Discover the tests in this executable.
65 for testname in self.getGTestTests(execpath, litConfig, localConfig):
66 testPath = path_in_suite + (basename, testname)
67 yield lit.Test.Test(testSuite, testPath, localConfig)
68
69 def getTestsInDirectory(self, testSuite, path_in_suite,
70 litConfig, localConfig):
71 source_path = testSuite.getSourcePath(path_in_suite)
72 for filename in os.listdir(source_path):
73 filepath = os.path.join(source_path, filename)
74 if os.path.isdir(filepath):
75 # Iterate over executables in a directory.
76 if not os.path.normcase(filename) in self.test_sub_dir:
77 continue
78 dirpath_in_suite = path_in_suite + (filename, )
79 for subfilename in os.listdir(filepath):
80 execpath = os.path.join(filepath, subfilename)
81 for test in self.getTestsInExecutable(
82 testSuite, dirpath_in_suite, execpath,
83 litConfig, localConfig):
84 yield test
85 elif ('.' in self.test_sub_dir):
86 for test in self.getTestsInExecutable(
87 testSuite, path_in_suite, filepath,
88 litConfig, localConfig):
89 yield test
90
91 def execute(self, test, litConfig):
92 testPath,testName = os.path.split(test.getSourcePath())
93 while not os.path.exists(testPath):
94 # Handle GTest parametrized and typed tests, whose name includes
95 # some '/'s.
96 testPath, namePrefix = os.path.split(testPath)
97 testName = os.path.join(namePrefix, testName)
98
99 cmd = [testPath, '--gtest_filter=' + testName]
100 if litConfig.useValgrind:
101 cmd = litConfig.valgrindArgs + cmd
102
103 if litConfig.noExecute:
104 return lit.Test.PASS, ''
105
106 out, err, exitCode = lit.TestRunner.executeCommand(
107 cmd, env=test.config.environment)
108
109 if not exitCode:
110 return lit.Test.PASS,''
111
112 return lit.Test.FAIL, out + err
113
114 ###
115
116 class FileBasedTest(object):
117 def getTestsInDirectory(self, testSuite, path_in_suite,
118 litConfig, localConfig):
119 source_path = testSuite.getSourcePath(path_in_suite)
120 for filename in os.listdir(source_path):
121 # Ignore dot files and excluded tests.
122 if (filename.startswith('.') or
123 filename in localConfig.excludes):
124 continue
125
126 filepath = os.path.join(source_path, filename)
127 if not os.path.isdir(filepath):
128 base,ext = os.path.splitext(filename)
129 if ext in localConfig.suffixes:
130 yield lit.Test.Test(testSuite, path_in_suite + (filename,),
131 localConfig)
132
133 class ShTest(FileBasedTest):
134 def __init__(self, execute_external = False):
135 self.execute_external = execute_external
136
137 def execute(self, test, litConfig):
138 return lit.TestRunner.executeShTest(test, litConfig,
139 self.execute_external)
140
141 ###
142
143 import re
144 import tempfile
145
146 class OneCommandPerFileTest:
147 # FIXME: Refactor into generic test for running some command on a directory
148 # of inputs.
149
150 def __init__(self, command, dir, recursive=False,
151 pattern=".*", useTempInput=False):
152 if isinstance(command, str):
153 self.command = [command]
154 else:
155 self.command = list(command)
156 if dir is not None:
157 dir = str(dir)
158 self.dir = dir
159 self.recursive = bool(recursive)
160 self.pattern = re.compile(pattern)
161 self.useTempInput = useTempInput
162
163 def getTestsInDirectory(self, testSuite, path_in_suite,
164 litConfig, localConfig):
165 dir = self.dir
166 if dir is None:
167 dir = testSuite.getSourcePath(path_in_suite)
168
169 for dirname,subdirs,filenames in os.walk(dir):
170 if not self.recursive:
171 subdirs[:] = []
172
173 subdirs[:] = [d for d in subdirs
174 if (d != '.svn' and
175 d not in localConfig.excludes)]
176
177 for filename in filenames:
178 if (filename.startswith('.') or
179 not self.pattern.match(filename) or
180 filename in localConfig.excludes):
181 continue
182
183 path = os.path.join(dirname,filename)
184 suffix = path[len(dir):]
185 if suffix.startswith(os.sep):
186 suffix = suffix[1:]
187 test = lit.Test.Test(
188 testSuite, path_in_suite + tuple(suffix.split(os.sep)),
189 localConfig)
190 # FIXME: Hack?
191 test.source_path = path
192 yield test
193
194 def createTempInput(self, tmp, test):
195 abstract
196
197 def execute(self, test, litConfig):
198 if test.config.unsupported:
199 return (lit.Test.UNSUPPORTED, 'Test is unsupported')
200
201 cmd = list(self.command)
202
203 # If using temp input, create a temporary file and hand it to the
204 # subclass.
205 if self.useTempInput:
206 tmp = tempfile.NamedTemporaryFile(suffix='.cpp')
207 self.createTempInput(tmp, test)
208 tmp.flush()
209 cmd.append(tmp.name)
210 elif hasattr(test, 'source_path'):
211 cmd.append(test.source_path)
212 else:
213 cmd.append(test.getSourcePath())
214
215 out, err, exitCode = lit.TestRunner.executeCommand(cmd)
216
217 diags = out + err
218 if not exitCode and not diags.strip():
219 return lit.Test.PASS,''
220
221 # Try to include some useful information.
222 report = """Command: %s\n""" % ' '.join(["'%s'" % a
223 for a in cmd])
224 if self.useTempInput:
225 report += """Temporary File: %s\n""" % tmp.name
226 report += "--\n%s--\n""" % open(tmp.name).read()
227 report += """Output:\n--\n%s--""" % diags
228
229 return lit.Test.FAIL, report
99
1010 import lit.ShUtil as ShUtil
1111 import lit.Test as Test
12 import lit.Util as Util
12 import lit.util
1313
1414 class InternalShellError(Exception):
1515 def __init__(self, command, message):
153153
154154 # Resolve the executable path ourselves.
155155 args = list(j.args)
156 args[0] = Util.which(args[0], cfg.environment['PATH'])
156 args[0] = lit.util.which(args[0], cfg.environment['PATH'])
157157 if not args[0]:
158158 raise InternalShellError(j, '%r: command not found' % j.args[0])
159159
471471 return (Test.PASS, '')
472472
473473 # Create the output directory if it does not already exist.
474 Util.mkdir_p(os.path.dirname(tmpBase))
474 lit.util.mkdir_p(os.path.dirname(tmpBase))
475475
476476 if useExternalSh:
477477 res = executeScript(test, litConfig, tmpBase, script, execdir)
+0
-140
utils/lit/lit/Util.py less more
None import errno
1 import itertools
2 import math
3 import os
4 import subprocess
5 import sys
6
7 def detectCPUs():
8 """
9 Detects the number of CPUs on a system. Cribbed from pp.
10 """
11 # Linux, Unix and MacOS:
12 if hasattr(os, "sysconf"):
13 if "SC_NPROCESSORS_ONLN" in os.sysconf_names:
14 # Linux & Unix:
15 ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
16 if isinstance(ncpus, int) and ncpus > 0:
17 return ncpus
18 else: # OSX:
19 return int(capture(['sysctl', '-n', 'hw.ncpu']))
20 # Windows:
21 if "NUMBER_OF_PROCESSORS" in os.environ:
22 ncpus = int(os.environ["NUMBER_OF_PROCESSORS"])
23 if ncpus > 0:
24 return ncpus
25 return 1 # Default
26
27 def mkdir_p(path):
28 """mkdir_p(path) - Make the "path" directory, if it does not exist; this
29 will also make directories for any missing parent directories."""
30 if not path or os.path.exists(path):
31 return
32
33 parent = os.path.dirname(path)
34 if parent != path:
35 mkdir_p(parent)
36
37 try:
38 os.mkdir(path)
39 except OSError:
40 e = sys.exc_info()[1]
41 # Ignore EEXIST, which may occur during a race condition.
42 if e.errno != errno.EEXIST:
43 raise
44
45 def capture(args, env=None):
46 """capture(command) - Run the given command (or argv list) in a shell and
47 return the standard output."""
48 p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
49 env=env)
50 out,_ = p.communicate()
51 return out
52
53 def which(command, paths = None):
54 """which(command, [paths]) - Look up the given command in the paths string
55 (or the PATH environment variable, if unspecified)."""
56
57 if paths is None:
58 paths = os.environ.get('PATH','')
59
60 # Check for absolute match first.
61 if os.path.isfile(command):
62 return command
63
64 # Would be nice if Python had a lib function for this.
65 if not paths:
66 paths = os.defpath
67
68 # Get suffixes to search.
69 # On Cygwin, 'PATHEXT' may exist but it should not be used.
70 if os.pathsep == ';':
71 pathext = os.environ.get('PATHEXT', '').split(';')
72 else:
73 pathext = ['']
74
75 # Search the paths...
76 for path in paths.split(os.pathsep):
77 for ext in pathext:
78 p = os.path.join(path, command + ext)
79 if os.path.exists(p):
80 return p
81
82 return None
83
84 def checkToolsPath(dir, tools):
85 for tool in tools:
86 if not os.path.exists(os.path.join(dir, tool)):
87 return False;
88 return True;
89
90 def whichTools(tools, paths):
91 for path in paths.split(os.pathsep):
92 if checkToolsPath(path, tools):
93 return path
94 return None
95
96 def printHistogram(items, title = 'Items'):
97 items.sort(key = lambda item: item[1])
98
99 maxValue = max([v for _,v in items])
100
101 # Select first "nice" bar height that produces more than 10 bars.
102 power = int(math.ceil(math.log(maxValue, 10)))
103 for inc in itertools.cycle((5, 2, 2.5, 1)):
104 barH = inc * 10**power
105 N = int(math.ceil(maxValue / barH))
106 if N > 10:
107 break
108 elif inc == 1:
109 power -= 1
110
111 histo = [set() for i in range(N)]
112 for name,v in items:
113 bin = min(int(N * v/maxValue), N-1)
114 histo[bin].add(name)
115
116 barW = 40
117 hr = '-' * (barW + 34)
118 print('\nSlowest %s:' % title)
119 print(hr)
120 for name,value in items[-20:]:
121 print('%.2fs: %s' % (value, name))
122 print('\n%s Times:' % title)
123 print(hr)
124 pDigits = int(math.ceil(math.log(maxValue, 10)))
125 pfDigits = max(0, 3-pDigits)
126 if pfDigits:
127 pDigits += pfDigits + 1
128 cDigits = int(math.ceil(math.log(len(items), 10)))
129 print("[%s] :: [%s] :: [%s]" % ('Range'.center((pDigits+1)*2 + 3),
130 'Percentage'.center(barW),
131 'Count'.center(cDigits*2 + 1)))
132 print(hr)
133 for i,row in enumerate(histo):
134 pct = float(len(row)) / len(items)
135 w = int(barW * pct)
136 print("[%*.*fs,%*.*fs) :: [%s%s] :: [%*d/%*d]" % (
137 pDigits, pfDigits, i*barH, pDigits, pfDigits, (i+1)*barH,
138 '*'*w, ' '*(barW-w), cDigits, len(row), cDigits, len(items)))
139
88 __version__ = '.'.join(str(v) for v in __versioninfo__) + 'dev'
99
1010 __all__ = []
11
12 # Compatibility hacks for old names.
13 from . import util as Util
14 from . import formats as TestFormats
0 from __future__ import absolute_import
1 import os
2 import sys
3
4 import lit.Test
5 import lit.TestRunner
6 import lit.util
7
8 kIsWindows = sys.platform in ['win32', 'cygwin']
9
10 class GoogleTest(object):
11 def __init__(self, test_sub_dir, test_suffix):
12 self.test_sub_dir = os.path.normcase(str(test_sub_dir)).split(';')
13 self.test_suffix = str(test_suffix)
14
15 # On Windows, assume tests will also end in '.exe'.
16 if kIsWindows:
17 self.test_suffix += '.exe'
18
19 def getGTestTests(self, path, litConfig, localConfig):
20 """getGTestTests(path) - [name]
21
22 Return the tests available in gtest executable.
23
24 Args:
25 path: String path to a gtest executable
26 litConfig: LitConfig instance
27 localConfig: TestingConfig instance"""
28
29 try:
30 lines = lit.util.capture([path, '--gtest_list_tests'],
31 env=localConfig.environment)
32 lines = lines.decode('ascii')
33 if kIsWindows:
34 lines = lines.replace('\r', '')
35 lines = lines.split('\n')
36 except:
37 litConfig.error("unable to discover google-tests in %r" % path)
38 raise StopIteration
39
40 nested_tests = []
41 for ln in lines:
42 if not ln.strip():
43 continue
44
45 prefix = ''
46 index = 0
47 while ln[index*2:index*2+2] == ' ':
48 index += 1
49 while len(nested_tests) > index:
50 nested_tests.pop()
51
52 ln = ln[index*2:]
53 if ln.endswith('.'):
54 nested_tests.append(ln)
55 else:
56 yield ''.join(nested_tests) + ln
57
58 # Note: path_in_suite should not include the executable name.
59 def getTestsInExecutable(self, testSuite, path_in_suite, execpath,
60 litConfig, localConfig):
61 if not execpath.endswith(self.test_suffix):
62 return
63 (dirname, basename) = os.path.split(execpath)
64 # Discover the tests in this executable.
65 for testname in self.getGTestTests(execpath, litConfig, localConfig):
66 testPath = path_in_suite + (basename, testname)
67 yield lit.Test.Test(testSuite, testPath, localConfig)
68
69 def getTestsInDirectory(self, testSuite, path_in_suite,
70 litConfig, localConfig):
71 source_path = testSuite.getSourcePath(path_in_suite)
72 for filename in os.listdir(source_path):
73 filepath = os.path.join(source_path, filename)
74 if os.path.isdir(filepath):
75 # Iterate over executables in a directory.
76 if not os.path.normcase(filename) in self.test_sub_dir:
77 continue
78 dirpath_in_suite = path_in_suite + (filename, )
79 for subfilename in os.listdir(filepath):
80 execpath = os.path.join(filepath, subfilename)
81 for test in self.getTestsInExecutable(
82 testSuite, dirpath_in_suite, execpath,
83 litConfig, localConfig):
84 yield test
85 elif ('.' in self.test_sub_dir):
86 for test in self.getTestsInExecutable(
87 testSuite, path_in_suite, filepath,
88 litConfig, localConfig):
89 yield test
90
91 def execute(self, test, litConfig):
92 testPath,testName = os.path.split(test.getSourcePath())
93 while not os.path.exists(testPath):
94 # Handle GTest parametrized and typed tests, whose name includes
95 # some '/'s.
96 testPath, namePrefix = os.path.split(testPath)
97 testName = os.path.join(namePrefix, testName)
98
99 cmd = [testPath, '--gtest_filter=' + testName]
100 if litConfig.useValgrind:
101 cmd = litConfig.valgrindArgs + cmd
102
103 if litConfig.noExecute:
104 return lit.Test.PASS, ''
105
106 out, err, exitCode = lit.TestRunner.executeCommand(
107 cmd, env=test.config.environment)
108
109 if not exitCode:
110 return lit.Test.PASS,''
111
112 return lit.Test.FAIL, out + err
113
114 ###
115
116 class FileBasedTest(object):
117 def getTestsInDirectory(self, testSuite, path_in_suite,
118 litConfig, localConfig):
119 source_path = testSuite.getSourcePath(path_in_suite)
120 for filename in os.listdir(source_path):
121 # Ignore dot files and excluded tests.
122 if (filename.startswith('.') or
123 filename in localConfig.excludes):
124 continue
125
126 filepath = os.path.join(source_path, filename)
127 if not os.path.isdir(filepath):
128 base,ext = os.path.splitext(filename)
129 if ext in localConfig.suffixes:
130 yield lit.Test.Test(testSuite, path_in_suite + (filename,),
131 localConfig)
132
133 class ShTest(FileBasedTest):
134 def __init__(self, execute_external = False):
135 self.execute_external = execute_external
136
137 def execute(self, test, litConfig):
138 return lit.TestRunner.executeShTest(test, litConfig,
139 self.execute_external)
140
141 ###
142
143 import re
144 import tempfile
145
146 class OneCommandPerFileTest:
147 # FIXME: Refactor into generic test for running some command on a directory
148 # of inputs.
149
150 def __init__(self, command, dir, recursive=False,
151 pattern=".*", useTempInput=False):
152 if isinstance(command, str):
153 self.command = [command]
154 else:
155 self.command = list(command)
156 if dir is not None:
157 dir = str(dir)
158 self.dir = dir
159 self.recursive = bool(recursive)
160 self.pattern = re.compile(pattern)
161 self.useTempInput = useTempInput
162
163 def getTestsInDirectory(self, testSuite, path_in_suite,
164 litConfig, localConfig):
165 dir = self.dir
166 if dir is None:
167 dir = testSuite.getSourcePath(path_in_suite)
168
169 for dirname,subdirs,filenames in os.walk(dir):
170 if not self.recursive:
171 subdirs[:] = []
172
173 subdirs[:] = [d for d in subdirs
174 if (d != '.svn' and
175 d not in localConfig.excludes)]
176
177 for filename in filenames:
178 if (filename.startswith('.') or
179 not self.pattern.match(filename) or
180 filename in localConfig.excludes):
181 continue
182
183 path = os.path.join(dirname,filename)
184 suffix = path[len(dir):]
185 if suffix.startswith(os.sep):
186 suffix = suffix[1:]
187 test = lit.Test.Test(
188 testSuite, path_in_suite + tuple(suffix.split(os.sep)),
189 localConfig)
190 # FIXME: Hack?
191 test.source_path = path
192 yield test
193
194 def createTempInput(self, tmp, test):
195 abstract
196
197 def execute(self, test, litConfig):
198 if test.config.unsupported:
199 return (lit.Test.UNSUPPORTED, 'Test is unsupported')
200
201 cmd = list(self.command)
202
203 # If using temp input, create a temporary file and hand it to the
204 # subclass.
205 if self.useTempInput:
206 tmp = tempfile.NamedTemporaryFile(suffix='.cpp')
207 self.createTempInput(tmp, test)
208 tmp.flush()
209 cmd.append(tmp.name)
210 elif hasattr(test, 'source_path'):
211 cmd.append(test.source_path)
212 else:
213 cmd.append(test.getSourcePath())
214
215 out, err, exitCode = lit.TestRunner.executeCommand(cmd)
216
217 diags = out + err
218 if not exitCode and not diags.strip():
219 return lit.Test.PASS,''
220
221 # Try to include some useful information.
222 report = """Command: %s\n""" % ' '.join(["'%s'" % a
223 for a in cmd])
224 if self.useTempInput:
225 report += """Temporary File: %s\n""" % tmp.name
226 report += "--\n%s--\n""" % open(tmp.name).read()
227 report += """Output:\n--\n%s--""" % diags
228
229 return lit.Test.FAIL, report
1111 import lit.ProgressBar
1212 import lit.LitConfig
1313 import lit.Test
14 import lit.Util
14 import lit.util
1515
1616 import lit.discovery
1717
254254 # I haven't seen this bug occur with 2.5.2 and later, so only enable multiple
255255 # threads by default there.
256256 if sys.hexversion >= 0x2050200:
257 opts.numThreads = lit.Util.detectCPUs()
257 opts.numThreads = lit.util.detectCPUs()
258258 else:
259259 opts.numThreads = 1
260260
416416 byTime = list(times.items())
417417 byTime.sort(key = lambda item: item[1])
418418 if byTime:
419 lit.Util.printHistogram(byTime, title='Tests')
419 lit.util.printHistogram(byTime, title='Tests')
420420
421421 for name,code in (('Expected Passes ', lit.Test.PASS),
422422 ('Expected Failures ', lit.Test.XFAIL),
0 import errno
1 import itertools
2 import math
3 import os
4 import subprocess
5 import sys
6
7 def detectCPUs():
8 """
9 Detects the number of CPUs on a system. Cribbed from pp.
10 """
11 # Linux, Unix and MacOS:
12 if hasattr(os, "sysconf"):
13 if "SC_NPROCESSORS_ONLN" in os.sysconf_names:
14 # Linux & Unix:
15 ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
16 if isinstance(ncpus, int) and ncpus > 0:
17 return ncpus
18 else: # OSX:
19 return int(capture(['sysctl', '-n', 'hw.ncpu']))
20 # Windows:
21 if "NUMBER_OF_PROCESSORS" in os.environ:
22 ncpus = int(os.environ["NUMBER_OF_PROCESSORS"])
23 if ncpus > 0:
24 return ncpus
25 return 1 # Default
26
27 def mkdir_p(path):
28 """mkdir_p(path) - Make the "path" directory, if it does not exist; this
29 will also make directories for any missing parent directories."""
30 if not path or os.path.exists(path):
31 return
32
33 parent = os.path.dirname(path)
34 if parent != path:
35 mkdir_p(parent)
36
37 try:
38 os.mkdir(path)
39 except OSError:
40 e = sys.exc_info()[1]
41 # Ignore EEXIST, which may occur during a race condition.
42 if e.errno != errno.EEXIST:
43 raise
44
45 def capture(args, env=None):
46 """capture(command) - Run the given command (or argv list) in a shell and
47 return the standard output."""
48 p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
49 env=env)
50 out,_ = p.communicate()
51 return out
52
53 def which(command, paths = None):
54 """which(command, [paths]) - Look up the given command in the paths string
55 (or the PATH environment variable, if unspecified)."""
56
57 if paths is None:
58 paths = os.environ.get('PATH','')
59
60 # Check for absolute match first.
61 if os.path.isfile(command):
62 return command
63
64 # Would be nice if Python had a lib function for this.
65 if not paths:
66 paths = os.defpath
67
68 # Get suffixes to search.
69 # On Cygwin, 'PATHEXT' may exist but it should not be used.
70 if os.pathsep == ';':
71 pathext = os.environ.get('PATHEXT', '').split(';')
72 else:
73 pathext = ['']
74
75 # Search the paths...
76 for path in paths.split(os.pathsep):
77 for ext in pathext:
78 p = os.path.join(path, command + ext)
79 if os.path.exists(p):
80 return p
81
82 return None
83
84 def checkToolsPath(dir, tools):
85 for tool in tools:
86 if not os.path.exists(os.path.join(dir, tool)):
87 return False;
88 return True;
89
90 def whichTools(tools, paths):
91 for path in paths.split(os.pathsep):
92 if checkToolsPath(path, tools):
93 return path
94 return None
95
96 def printHistogram(items, title = 'Items'):
97 items.sort(key = lambda item: item[1])
98
99 maxValue = max([v for _,v in items])
100
101 # Select first "nice" bar height that produces more than 10 bars.
102 power = int(math.ceil(math.log(maxValue, 10)))
103 for inc in itertools.cycle((5, 2, 2.5, 1)):
104 barH = inc * 10**power
105 N = int(math.ceil(maxValue / barH))
106 if N > 10:
107 break
108 elif inc == 1:
109 power -= 1
110
111 histo = [set() for i in range(N)]
112 for name,v in items:
113 bin = min(int(N * v/maxValue), N-1)
114 histo[bin].add(name)
115
116 barW = 40
117 hr = '-' * (barW + 34)
118 print('\nSlowest %s:' % title)
119 print(hr)
120 for name,value in items[-20:]:
121 print('%.2fs: %s' % (value, name))
122 print('\n%s Times:' % title)
123 print(hr)
124 pDigits = int(math.ceil(math.log(maxValue, 10)))
125 pfDigits = max(0, 3-pDigits)
126 if pfDigits:
127 pDigits += pfDigits + 1
128 cDigits = int(math.ceil(math.log(len(items), 10)))
129 print("[%s] :: [%s] :: [%s]" % ('Range'.center((pDigits+1)*2 + 3),
130 'Percentage'.center(barW),
131 'Count'.center(cDigits*2 + 1)))
132 print(hr)
133 for i,row in enumerate(histo):
134 pct = float(len(row)) / len(items)
135 w = int(barW * pct)
136 print("[%*.*fs,%*.*fs) :: [%s%s] :: [%*d/%*d]" % (
137 pDigits, pfDigits, i*barH, pDigits, pfDigits, (i+1)*barH,
138 '*'*w, ' '*(barW-w), cDigits, len(row), cDigits, len(items)))
139