Hi Zinovy, I have reverted this change in r356630 in order to get the build bots back to green.
I was able to reproduce the issue locally on my machine, it appears that your use of “import yaml” is not part of the standard python distribution and so is not found. Douglas Yung From: cfe-commits <cfe-commits-boun...@lists.llvm.org> On Behalf Of Galina Kistanova via cfe-commits Sent: Wednesday, March 20, 2019 14:03 To: Zinovy Nis <zinovy....@gmail.com> Cc: cfe-commits <cfe-commits@lists.llvm.org> Subject: Re: [clang-tools-extra] r356565 - Reland r356547 after fixing the tests for Linux. Hello Zinovy, This commit broke test on the next builder: http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-ubuntu-fast/builds/45557 . . . Failing Tests (1): Clang Tools :: clang-tidy/clang-tidy-diff.cpp Please have a look? Thanks Galina On Wed, Mar 20, 2019 at 8:49 AM Zinovy Nis via cfe-commits <cfe-commits@lists.llvm.org<mailto:cfe-commits@lists.llvm.org>> wrote: Author: zinovy.nis Date: Wed Mar 20 08:50:26 2019 New Revision: 356565 URL: http://llvm.org/viewvc/llvm-project?rev=356565&view=rev Log: Reland r356547 after fixing the tests for Linux. [clang-tidy] Parallelize clang-tidy-diff.py This patch has 2 rationales: - large patches lead to long command lines and often cause max command line length restrictions imposed by OS; - clang-tidy runs on modified files are independent and can be done in parallel, the same as done for run-clang-tidy. Differential Revision: https://reviews.llvm.org/D57662 Modified: clang-tools-extra/trunk/clang-tidy/tool/clang-tidy-diff.py Modified: clang-tools-extra/trunk/clang-tidy/tool/clang-tidy-diff.py URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/tool/clang-tidy-diff.py?rev=356565&r1=356564&r2=356565&view=diff ============================================================================== --- clang-tools-extra/trunk/clang-tidy/tool/clang-tidy-diff.py (original) +++ clang-tools-extra/trunk/clang-tidy/tool/clang-tidy-diff.py Wed Mar 20 08:50:26 2019 @@ -24,10 +24,90 @@ Example usage for git/svn users: """ import argparse +import glob import json +import multiprocessing +import os import re +import shutil import subprocess import sys +import tempfile +import threading +import traceback +import yaml + +is_py2 = sys.version[0] == '2' + +if is_py2: + import Queue as queue +else: + import queue as queue + + +def run_tidy(task_queue, lock, timeout): + watchdog = None + while True: + command = task_queue.get() + try: + proc = subprocess.Popen(command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + + if timeout is not None: + watchdog = threading.Timer(timeout, proc.kill) + watchdog.start() + + stdout, stderr = proc.communicate() + + with lock: + sys.stdout.write(stdout.decode('utf-8') + '\n') + sys.stdout.flush() + if stderr: + sys.stderr.write(stderr.decode('utf-8') + '\n') + sys.stderr.flush() + except Exception as e: + with lock: + sys.stderr.write('Failed: ' + str(e) + ': '.join(command) + '\n') + finally: + with lock: + if (not timeout is None) and (not watchdog is None): + if not watchdog.is_alive(): + sys.stderr.write('Terminated by timeout: ' + + ' '.join(command) + '\n') + watchdog.cancel() + task_queue.task_done() + + +def start_workers(max_tasks, tidy_caller, task_queue, lock, timeout): + for _ in range(max_tasks): + t = threading.Thread(target=tidy_caller, args=(task_queue, lock, timeout)) + t.daemon = True + t.start() + +def merge_replacement_files(tmpdir, mergefile): + """Merge all replacement files in a directory into a single file""" + # The fixes suggested by clang-tidy >= 4.0.0 are given under + # the top level key 'Diagnostics' in the output yaml files + mergekey = "Diagnostics" + merged = [] + for replacefile in glob.iglob(os.path.join(tmpdir, '*.yaml')): + content = yaml.safe_load(open(replacefile, 'r')) + if not content: + continue # Skip empty files. + merged.extend(content.get(mergekey, [])) + + if merged: + # MainSourceFile: The key is required by the definition inside + # include/clang/Tooling/ReplacementsYaml.h, but the value + # is actually never used inside clang-apply-replacements, + # so we set it to '' here. + output = { 'MainSourceFile': '', mergekey: merged } + with open(mergefile, 'w') as out: + yaml.safe_dump(output, out) + else: + # Empty the file: + open(mergefile, 'w').close() def main(): @@ -47,7 +127,10 @@ def main(): r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc)', help='custom pattern selecting file paths to check ' '(case insensitive, overridden by -regex)') - + parser.add_argument('-j', type=int, default=1, + help='number of tidy instances to be run in parallel.') + parser.add_argument('-timeout', type=int, default=None, + help='timeout per each file in seconds.') parser.add_argument('-fix', action='store_true', default=False, help='apply suggested fixes') parser.add_argument('-checks', @@ -84,7 +167,7 @@ def main(): match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % args.p, line) if match: filename = match.group(2) - if filename == None: + if filename is None: continue if args.regex is not None: @@ -102,44 +185,79 @@ def main(): line_count = int(match.group(3)) if line_count == 0: continue - end_line = start_line + line_count - 1; + end_line = start_line + line_count - 1 lines_by_file.setdefault(filename, []).append([start_line, end_line]) - if len(lines_by_file) == 0: + if not any(lines_by_file): print("No relevant changes found.") sys.exit(0) - line_filter_json = json.dumps( - [{"name" : name, "lines" : lines_by_file[name]} for name in lines_by_file], - separators = (',', ':')) - - quote = ""; - if sys.platform == 'win32': - line_filter_json=re.sub(r'"', r'"""', line_filter_json) - else: - quote = "'"; + max_task_count = args.j + if max_task_count == 0: + max_task_count = multiprocessing.cpu_count() + max_task_count = min(len(lines_by_file), max_task_count) - # Run clang-tidy on files containing changes. - command = [args.clang_tidy_binary] - command.append('-line-filter=' + quote + line_filter_json + quote) - if args.fix: - command.append('-fix') + tmpdir = None if args.export_fixes: - command.append('-export-fixes=' + args.export_fixes) + tmpdir = tempfile.mkdtemp() + + # Tasks for clang-tidy. + task_queue = queue.Queue(max_task_count) + # A lock for console output. + lock = threading.Lock() + + # Run a pool of clang-tidy workers. + start_workers(max_task_count, run_tidy, task_queue, lock, args.timeout) + + # Form the common args list. + common_clang_tidy_args = [] + if args.fix: + common_clang_tidy_args.append('-fix') if args.checks != '': - command.append('-checks=' + quote + args.checks + quote) + common_clang_tidy_args.append('-checks=' + args.checks) if args.quiet: - command.append('-quiet') + common_clang_tidy_args.append('-quiet') if args.build_path is not None: - command.append('-p=%s' % args.build_path) - command.extend(lines_by_file.keys()) + common_clang_tidy_args.append('-p=%s' % args.build_path) for arg in args.extra_arg: - command.append('-extra-arg=%s' % arg) + common_clang_tidy_args.append('-extra-arg=%s' % arg) for arg in args.extra_arg_before: - command.append('-extra-arg-before=%s' % arg) - command.extend(clang_tidy_args) + common_clang_tidy_args.append('-extra-arg-before=%s' % arg) + + for name in lines_by_file: + line_filter_json = json.dumps( + [{"name": name, "lines": lines_by_file[name]}], + separators=(',', ':')) + + # Run clang-tidy on files containing changes. + command = [args.clang_tidy_binary] + command.append('-line-filter=' + line_filter_json) + if args.export_fixes: + # Get a temporary file. We immediately close the handle so clang-tidy can + # overwrite it. + (handle, tmp_name) = tempfile.mkstemp(suffix='.yaml', dir=tmpdir) + os.close(handle) + command.append('-export-fixes=' + tmp_name) + command.extend(common_clang_tidy_args) + command.append(name) + command.extend(clang_tidy_args) + + task_queue.put(command) + + # Wait for all threads to be done. + task_queue.join() + + if args.export_fixes: + print('Writing fixes to ' + args.export_fixes + ' ...') + try: + merge_replacement_files(tmpdir, args.export_fixes) + except: + sys.stderr.write('Error exporting fixes.\n') + traceback.print_exc() + + if tmpdir: + shutil.rmtree(tmpdir) - sys.exit(subprocess.call(' '.join(command), shell=True)) if __name__ == '__main__': main() _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org<mailto:cfe-commits@lists.llvm.org> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits