Changeset 92538ab for tests/pybin/tools.py
- Timestamp:
- Apr 10, 2022, 2:53:18 PM (3 years ago)
- Branches:
- ADT, ast-experimental, enum, master, pthread-emulation, qualifiedEnum
- Children:
- d8e2a09
- Parents:
- 4559b34 (diff), 6256891 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
tests/pybin/tools.py
r4559b34 r92538ab 23 23 24 24 # helper functions to run terminal commands 25 def sh(*cmd, timeout = False, output_file = None, input_file = None, input_text = None, error = subprocess.STDOUT, ignore_dry_run = False ):25 def sh(*cmd, timeout = False, output_file = None, input_file = None, input_text = None, error = subprocess.STDOUT, ignore_dry_run = False, pass_fds = []): 26 26 try: 27 27 cmd = list(cmd) … … 65 65 **({'input' : bytes(input_text, encoding='utf-8')} if input_text else {'stdin' : input_file}), 66 66 stdout = output_file, 67 stderr = error 67 stderr = error, 68 pass_fds = pass_fds 68 69 ) as proc: 69 70 70 71 try: 71 out, _= proc.communicate(72 out, errout = proc.communicate( 72 73 timeout = settings.timeout.single if timeout else None 73 74 ) 74 75 75 return proc.returncode, out.decode("latin-1") if out else None 76 return proc.returncode, out.decode("latin-1") if out else None, errout.decode("latin-1") if errout else None 76 77 except subprocess.TimeoutExpired: 77 78 if settings.timeout2gdb: 78 79 print("Process {} timeout".format(proc.pid)) 79 80 proc.communicate() 80 return 124, str(None) 81 return 124, str(None), "Subprocess Timeout 2 gdb" 81 82 else: 82 83 proc.send_signal(signal.SIGABRT) 83 84 proc.communicate() 84 return 124, str(None) 85 return 124, str(None), "Subprocess Timeout 2 gdb" 85 86 86 87 except Exception as ex: … … 105 106 return (False, "No file") 106 107 107 code, out = sh("file", fname, output_file=subprocess.PIPE)108 code, out, err = sh("file", fname, output_file=subprocess.PIPE) 108 109 if code != 0: 109 return (False, "'file EXPECT' failed with code {} ".format(code))110 return (False, "'file EXPECT' failed with code {} '{}'".format(code, err)) 110 111 111 112 match = re.search(".*: (.*)", out) … … 190 191 ] 191 192 cmd = [s for s in cmd if s] 192 return sh(*cmd, output_file=output_file, error=error )193 return sh(*cmd, output_file=output_file, error=error, pass_fds=settings.make_jobfds) 193 194 194 195 def make_recon(target): … … 241 242 # move a file 242 243 def mv(source, dest): 243 ret, _ = sh("mv", source, dest)244 ret, _, _ = sh("mv", source, dest) 244 245 return ret 245 246 246 247 # cat one file into the other 247 248 def cat(source, dest): 248 ret, _ = sh("cat", source, output_file=dest)249 ret, _, _ = sh("cat", source, output_file=dest) 249 250 return ret 250 251 … … 289 290 # system 290 291 ################################################################################ 292 def jobserver_version(): 293 make_ret, out, err = sh('make', '.test_makeflags', '-j2', output_file=subprocess.PIPE, error=subprocess.PIPE) 294 if make_ret != 0: 295 print("ERROR: cannot find Makefile jobserver version", file=sys.stderr) 296 print(" test returned : {} '{}'".format(make_ret, err), file=sys.stderr) 297 sys.exit(1) 298 299 re_jobs = re.search("--jobserver-(auth|fds)", out) 300 if not re_jobs: 301 print("ERROR: cannot find Makefile jobserver version", file=sys.stderr) 302 print(" MAKEFLAGS are : '{}'".format(out), file=sys.stderr) 303 sys.exit(1) 304 305 return "--jobserver-{}".format(re_jobs.group(1)) 306 307 def prep_recursive_make(N): 308 if N < 2: 309 return [] 310 311 # create the pipe 312 (r, w) = os.pipe() 313 314 # feel it with N-1 tokens, (Why N-1 and not N, I don't know it's in the manpage for make) 315 os.write(w, b'+' * (N - 1)); 316 317 # prep the flags for make 318 make_flags = ["-j{}".format(N), "--jobserver-auth={},{}".format(r, w)] 319 320 # tell make about the pipes 321 os.environ["MAKEFLAGS"] = os.environ["MFLAGS"] = " ".join(make_flags) 322 323 # make sure pass the pipes to our children 324 settings.update_make_fds(r, w) 325 326 return make_flags 327 328 def prep_unlimited_recursive_make(): 329 # prep the flags for make 330 make_flags = ["-j"] 331 332 # tell make about the pipes 333 os.environ["MAKEFLAGS"] = os.environ["MFLAGS"] = "-j" 334 335 return make_flags 336 337 338 def eval_hardware(): 339 # we can create as many things as we want 340 # how much hardware do we have? 341 if settings.distribute: 342 # remote hardware is allowed 343 # how much do we have? 344 ret, jstr, _ = sh("distcc", "-j", output_file=subprocess.PIPE, ignore_dry_run=True) 345 return int(jstr.strip()) if ret == 0 else multiprocessing.cpu_count() 346 else: 347 # remote isn't allowed, use local cpus 348 return multiprocessing.cpu_count() 349 291 350 # count number of jobs to create 292 def job_count( options , tests):351 def job_count( options ): 293 352 # check if the user already passed in a number of jobs for multi-threading 294 if not options.jobs: 295 make_flags = os.environ.get('MAKEFLAGS') 296 force = bool(make_flags) 297 make_jobs_fds = re.search("--jobserver-(auth|fds)=\s*([0-9]+),([0-9]+)", make_flags) if make_flags else None 298 if make_jobs_fds : 299 tokens = os.read(int(make_jobs_fds.group(2)), 1024) 300 options.jobs = len(tokens) 301 os.write(int(make_jobs_fds.group(3)), tokens) 302 else : 303 if settings.distribute: 304 ret, jstr = sh("distcc", "-j", output_file=subprocess.PIPE, ignore_dry_run=True) 305 if ret == 0: 306 options.jobs = int(jstr.strip()) 307 else : 308 options.jobs = multiprocessing.cpu_count() 309 else: 310 options.jobs = multiprocessing.cpu_count() 353 make_env = os.environ.get('MAKEFLAGS') 354 make_flags = make_env.split() if make_env else None 355 jobstr = jobserver_version() 356 357 if options.jobs and make_flags: 358 print('WARNING: -j options should not be specified when called form Make', file=sys.stderr) 359 360 # Top level make is calling the shots, just follow 361 if make_flags: 362 # do we have -j and --jobserver-... 363 jobopt = None 364 exists_fds = None 365 for f in make_flags: 366 jobopt = f if f.startswith("-j") else jobopt 367 exists_fds = f if f.startswith(jobstr) else exists_fds 368 369 # do we have limited parallelism? 370 if exists_fds : 371 try: 372 rfd, wfd = tuple(exists_fds.split('=')[1].split(',')) 373 except: 374 print("ERROR: jobserver has unrecoginzable format, was '{}'".format(exists_fds), file=sys.stderr) 375 sys.exit(1) 376 377 # read the token pipe to count number of available tokens and restore the pipe 378 # this assumes the test suite script isn't invoked in parellel with something else 379 tokens = os.read(int(rfd), 65536) 380 os.write(int(wfd), tokens) 381 382 # the number of tokens is off by one for obscure but well documented reason 383 # see man make for more details 384 options.jobs = len(tokens) + 1 385 386 # do we have unlimited parallelism? 387 elif jobopt and jobopt != "-j1": 388 # check that this actually make sense 389 if jobopt != "-j": 390 print("ERROR: -j option passed by make but no {}, was '{}'".format(jobstr, jobopt), file=sys.stderr) 391 sys.exit(1) 392 393 options.jobs = eval_hardware() 394 flags = prep_unlimited_recursive_make() 395 396 397 # then no parallelism 398 else: 399 options.jobs = 1 400 401 # keep all flags make passed along, except the weird 'w' which is about subdirectories 402 flags = [f for f in make_flags if f != 'w'] 403 404 # Arguments are calling the shots, fake the top level make 405 elif options.jobs : 406 407 # make sure we have a valid number of jobs that corresponds to user input 408 if options.jobs < 0 : 409 print('ERROR: Invalid number of jobs', file=sys.stderr) 410 sys.exit(1) 411 412 flags = prep_recursive_make(options.jobs) 413 414 # Arguments are calling the shots, fake the top level make, but 0 is a special case 415 elif options.jobs == 0: 416 options.jobs = eval_hardware() 417 flags = prep_unlimited_recursive_make() 418 419 # No one says to run in parallel, then don't 311 420 else : 312 force = True313 314 # make sure we have a valid number of jobs that corresponds to user input 315 if options.jobs <= 0 :316 print('ERROR: Invalid number of jobs', file=sys.stderr)317 sys.exit(1) 318 319 return min( options.jobs, len(tests) ), force421 options.jobs = 1 422 flags = [] 423 424 # Make sure we call make as expected 425 settings.update_make_cmd( flags ) 426 427 # return the job count 428 return options.jobs 320 429 321 430 # enable core dumps for all the test children … … 334 443 distcc_hash = os.path.join(settings.SRCDIR, '../tools/build/distcc_hash') 335 444 config = "%s-%s" % (settings.arch.target, settings.debug.path) 336 _, out = sh(distcc_hash, config, output_file=subprocess.PIPE, ignore_dry_run=True)445 _, out, _ = sh(distcc_hash, config, output_file=subprocess.PIPE, ignore_dry_run=True) 337 446 return out.strip() 338 447 … … 374 483 375 484 if not os.path.isfile(core): 376 return 1, "ERR No core dump (limit soft: {} hard: {})".format(*resource.getrlimit(resource.RLIMIT_CORE))485 return 1, "ERR No core dump, expected '{}' (limit soft: {} hard: {})".format(core, *resource.getrlimit(resource.RLIMIT_CORE)) 377 486 378 487 try: 379 return sh('gdb', '-n', path, core, '-batch', '-x', cmd, output_file=subprocess.PIPE) 488 ret, out, err = sh('gdb', '-n', path, core, '-batch', '-x', cmd, output_file=subprocess.PIPE) 489 if ret == 0: 490 return 0, out 491 else: 492 return 1, err 380 493 except: 381 494 return 1, "ERR Could not read core with gdb"
Note:
See TracChangeset
for help on using the changeset viewer.