Changeset fc01219


Ignore:
Timestamp:
Mar 7, 2022, 5:08:03 PM (3 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, ast-experimental, enum, master, pthread-emulation, qualifiedEnum
Children:
ef56087
Parents:
d529ad0
Message:

fixed -j option in the test suite to behave like make's -j.
-j unlimited not supported yet.

Location:
tests
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • tests/Makefile.am

    rd529ad0 rfc01219  
    6666PRETTY_PATH=mkdir -p $(dir $(abspath ${@})) && cd ${srcdir} &&
    6767
    68 .PHONY: list .validate
    69 .INTERMEDIATE: .validate .validate.cfa
     68.PHONY: list .validate .test_makeflags
     69.INTERMEDIATE: .validate .validate.cfa .test_makeflags
    7070EXTRA_PROGRAMS = avl_test linkonce .dummy_hack # build but do not install
    7171EXTRA_DIST = test.py \
     
    123123        @+${TEST_PY} --list ${concurrent}
    124124
     125.test_makeflags:
     126        @echo "${MAKEFLAGS}"
     127
    125128.validate: .validate.cfa
    126129        $(CFACOMPILE) .validate.cfa -fsyntax-only -Wall -Wextra -Werror
  • tests/pybin/settings.py

    rd529ad0 rfc01219  
    155155        global generating
    156156        global make
     157        global make_jobfds
    157158        global output_width
    158159        global timeout
     
    168169        generating   = options.regenerate_expected
    169170        make         = ['make']
     171        make_jobfds  = []
    170172        output_width = 24
    171173        timeout      = Timeouts(options.timeout, options.global_timeout)
     
    177179                os.putenv('DISTCC_LOG', os.path.join(BUILDDIR, 'distcc_error.log'))
    178180
    179 def update_make_cmd(force, jobs):
     181def update_make_cmd(flags):
    180182        global make
    181 
    182         make = ['make'] if not force else ['make', "-j%i" % jobs]
     183        make = ['make', *flags]
     184
     185def update_make_fds(r, w):
     186        global make_jobfds
     187        make_jobfds = (r, w)
    183188
    184189def validate():
  • tests/pybin/tools.py

    rd529ad0 rfc01219  
    2323
    2424# 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):
     25def sh(*cmd, timeout = False, output_file = None, input_file = None, input_text = None, error = subprocess.STDOUT, ignore_dry_run = False, pass_fds = []):
    2626        try:
    2727                cmd = list(cmd)
     
    6565                                **({'input' : bytes(input_text, encoding='utf-8')} if input_text else {'stdin' : input_file}),
    6666                                stdout  = output_file,
    67                                 stderr  = error
     67                                stderr  = error,
     68                                pass_fds = pass_fds
    6869                        ) as proc:
    6970
     
    190191        ]
    191192        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)
    193194
    194195def make_recon(target):
     
    289290#               system
    290291################################################################################
     292def jobserver_version():
     293        make_ret, out = sh('make', '.test_makeflags', '-j2', output_file=subprocess.PIPE)
     294        if make_ret != 0:
     295                with open (errf, "r") as myfile:
     296                        error=myfile.read()
     297                print("ERROR: cannot find Makefile jobserver version", file=sys.stderr)
     298                print("       test returned : \n%s" % out, file=sys.stderr)
     299                sys.exit(1)
     300
     301        re_jobs = re.search("--jobserver-(auth|fds)", out)
     302        if not re_jobs:
     303                print("ERROR: cannot find Makefile jobserver version", file=sys.stderr)
     304                print("       MAKEFLAGS are : \n%s" % out, file=sys.stderr)
     305                sys.exit(1)
     306
     307        return "--jobserver-{}".format(re_jobs.group(1))
     308
     309def prep_recursive_make(N):
     310        if N < 2:
     311                return []
     312
     313        # create the pipe
     314        (r, w) = os.pipe()
     315
     316        # feel it with N-1 tokens, (Why N-1 and not N, I don't know it's in the manpage for make)
     317        os.write(w, b'+' * (N - 1));
     318
     319        # prep the flags for make
     320        make_flags = ["-j{}".format(N), "--jobserver-auth={},{}".format(r, w)]
     321
     322        # tell make about the pipes
     323        os.environ["MAKEFLAGS"] = os.environ["MFLAGS"] = " ".join(make_flags)
     324        print(os.environ["MFLAGS"])
     325
     326        # make sure pass the pipes to our children
     327        settings.update_make_fds(r, w)
     328
     329        return make_flags
     330
    291331# count number of jobs to create
    292332def job_count( options ):
    293333        # 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 :
     334        make_env = os.environ.get('MAKEFLAGS')
     335        make_flags = make_env.split() if make_env else None
     336        jobstr = jobserver_version()
     337
     338        if options.jobs and make_flags:
     339                print('WARNING: -j options should not be specified when called form Make', file=sys.stderr)
     340
     341        # Top level make is calling the shots, just follow
     342        if make_flags:
     343                # do we have -j and --jobserver-...
     344                jobopt = None
     345                exists_fds = None
     346                for f in make_flags:
     347                        jobopt = f if f.startswith("-j") else jobopt
     348                        exists_fds = f if f.startswith(jobstr) else exists_fds
     349
     350                # do we have limited parallelism?
     351                if exists_fds :
     352                        print("limited {}".format(exists_fds))
     353                        try:
     354                                rfd, wfd = tuple(exists_fds.split('=')[1].split(','))
     355                        except:
     356                                print("ERROR: jobserver has unrecoginzable format, was '{}'".format(exists_fds), file=sys.stderr)
     357                                sys.exit(1)
     358
     359                        print("{} {}".format(rfd, wfd))
     360
     361                        # read the token pipe to count number of available tokens and restore the pipe
     362                        # this assumes the test suite script isn't invoked in parellel with something else
     363                        tokens = os.read(int(rfd), 65536)
     364                        os.write(int(wfd), tokens)
     365
     366                        # the number of tokens is off by one for obscure but well documented reason
     367                        # see man make for more details
     368                        options.jobs = len(tokens) + 1
     369
     370                # do we have unlimited parallelism?
     371                elif jobopt and jobopt != "-j1":
     372                        # check that this actually make sense
     373                        if jobopt != "-j":
     374                                print("ERROR: -j option passed by make but no {}, was '{}'".format(jobstr, jobopt), file=sys.stderr)
     375                                sys.exit(1)
     376
     377                        # we can create as many things as we want
     378                        # how much hardware do we have?
    303379                        if settings.distribute:
     380                                # remote hardware is allowed
     381                                # how much do we have?
    304382                                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()
     383                                options.jobs = int(jstr.strip()) if ret == 0 else multiprocessing.cpu_count()
    309384                        else:
     385                                # remote isn't allowed, use local cpus
    310386                                options.jobs = multiprocessing.cpu_count()
     387
     388                        make_flags = prep_recursive_make(options.jobs)
     389
     390
     391                # then no parallelism
     392                else:
     393                        options.jobs = 1
     394
     395                # keep all flags make passed along
     396                flags = make_flags
     397
     398        # Arguments are calling the shots, fake the top level make
     399        elif options.jobs:
     400                # make sure we have a valid number of jobs that corresponds to user input
     401                if options.jobs <= 0 :
     402                        print('ERROR: Invalid number of jobs', file=sys.stderr)
     403                        sys.exit(1)
     404
     405                flags = prep_recursive_make(options.jobs)
     406
     407        # No one says to run in parallel, then don't
    311408        else :
    312                 force = True
    313 
    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 options.jobs, force
     409                options.jobs = 1
     410                flags = []
     411
     412        # Make sure we call make as expected
     413        settings.update_make_cmd( flags )
     414
     415        # return the job count
     416        return options.jobs
    320417
    321418# enable core dumps for all the test children
  • tests/test.py

    rd529ad0 rfc01219  
    418418                                print('WARNING: test "{}" has empty .expect file'.format(t.target()), file=sys.stderr)
    419419
    420         options.jobs, forceJobs = job_count( options )
    421         settings.update_make_cmd(forceJobs, options.jobs)
     420        options.jobs = job_count( options )
    422421
    423422        # for each build configurations, run the test
Note: See TracChangeset for help on using the changeset viewer.