xref: /llvm-project/clang/utils/analyzer/SATest.py (revision dd3c26a045c081620375a878159f536758baba6e)
1d9944da2SValeriy Savchenko#!/usr/bin/env python
2d9944da2SValeriy Savchenko
3d9944da2SValeriy Savchenkoimport argparse
4d9944da2SValeriy Savchenkoimport sys
53770f5c9SValeriy Savchenkoimport os
63770f5c9SValeriy Savchenko
7e30706afSValeriy Savchenkofrom subprocess import call
83770f5c9SValeriy Savchenko
93770f5c9SValeriy SavchenkoSCRIPTS_DIR = os.path.dirname(os.path.realpath(__file__))
103770f5c9SValeriy SavchenkoPROJECTS_DIR = os.path.join(SCRIPTS_DIR, "projects")
11*dd3c26a0STobias HietaDEFAULT_LLVM_DIR = os.path.realpath(
12*dd3c26a0STobias Hieta    os.path.join(SCRIPTS_DIR, os.path.pardir, os.path.pardir, os.path.pardir)
13*dd3c26a0STobias Hieta)
14d9944da2SValeriy Savchenko
15d9944da2SValeriy Savchenko
16d9944da2SValeriy Savchenkodef add(parser, args):
1794f0eb83SValeriy Savchenko    import SATestAdd
1894f0eb83SValeriy Savchenko    from ProjectMap import ProjectInfo
1994f0eb83SValeriy Savchenko
20d9944da2SValeriy Savchenko    if args.source == "git" and (args.origin == "" or args.commit == ""):
21*dd3c26a0STobias Hieta        parser.error("Please provide both --origin and --commit if source is 'git'")
22d9944da2SValeriy Savchenko
23d9944da2SValeriy Savchenko    if args.source != "git" and (args.origin != "" or args.commit != ""):
24*dd3c26a0STobias Hieta        parser.error(
25*dd3c26a0STobias Hieta            "Options --origin and --commit don't make sense when " "source is not 'git'"
26*dd3c26a0STobias Hieta        )
27d9944da2SValeriy Savchenko
28*dd3c26a0STobias Hieta    project = ProjectInfo(
29*dd3c26a0STobias Hieta        args.name[0], args.mode, args.source, args.origin, args.commit
30*dd3c26a0STobias Hieta    )
31d9944da2SValeriy Savchenko
32d9944da2SValeriy Savchenko    SATestAdd.add_new_project(project)
33d9944da2SValeriy Savchenko
34d9944da2SValeriy Savchenko
35d9944da2SValeriy Savchenkodef build(parser, args):
3694f0eb83SValeriy Savchenko    import SATestBuild
3794f0eb83SValeriy Savchenko
38d9944da2SValeriy Savchenko    SATestBuild.VERBOSE = args.verbose
3938b455e9SValeriy Savchenko
40aec12c12SValeriy Savchenko    projects = get_projects(parser, args)
41*dd3c26a0STobias Hieta    tester = SATestBuild.RegressionTester(
42*dd3c26a0STobias Hieta        args.jobs,
4338b455e9SValeriy Savchenko        projects,
4438b455e9SValeriy Savchenko        args.override_compiler,
45d9944da2SValeriy Savchenko        args.extra_analyzer_config,
46198e6771SDeep Majumder        args.extra_checkers,
47d9944da2SValeriy Savchenko        args.regenerate,
48*dd3c26a0STobias Hieta        args.strictness,
49*dd3c26a0STobias Hieta    )
50d9944da2SValeriy Savchenko    tests_passed = tester.test_all()
51d9944da2SValeriy Savchenko
52d9944da2SValeriy Savchenko    if not tests_passed:
53d9944da2SValeriy Savchenko        sys.stderr.write("ERROR: Tests failed.\n")
54d9944da2SValeriy Savchenko        sys.exit(42)
55d9944da2SValeriy Savchenko
56d9944da2SValeriy Savchenko
57d9944da2SValeriy Savchenkodef compare(parser, args):
5894f0eb83SValeriy Savchenko    import CmpRuns
5994f0eb83SValeriy Savchenko
60*dd3c26a0STobias Hieta    choices = [
61*dd3c26a0STobias Hieta        CmpRuns.HistogramType.RELATIVE.value,
6294f0eb83SValeriy Savchenko        CmpRuns.HistogramType.LOG_RELATIVE.value,
63*dd3c26a0STobias Hieta        CmpRuns.HistogramType.ABSOLUTE.value,
64*dd3c26a0STobias Hieta    ]
6594f0eb83SValeriy Savchenko
6694f0eb83SValeriy Savchenko    if args.histogram is not None and args.histogram not in choices:
67*dd3c26a0STobias Hieta        parser.error(
68*dd3c26a0STobias Hieta            "Incorrect histogram type, available choices are {}".format(choices)
69*dd3c26a0STobias Hieta        )
7094f0eb83SValeriy Savchenko
71d9944da2SValeriy Savchenko    dir_old = CmpRuns.ResultsDirectory(args.old[0], args.root_old)
72d9944da2SValeriy Savchenko    dir_new = CmpRuns.ResultsDirectory(args.new[0], args.root_new)
73d9944da2SValeriy Savchenko
74*dd3c26a0STobias Hieta    CmpRuns.dump_scan_build_results_diff(
75*dd3c26a0STobias Hieta        dir_old,
76*dd3c26a0STobias Hieta        dir_new,
77d9944da2SValeriy Savchenko        show_stats=args.show_stats,
78d9944da2SValeriy Savchenko        stats_only=args.stats_only,
79d9944da2SValeriy Savchenko        histogram=args.histogram,
80*dd3c26a0STobias Hieta        verbose_log=args.verbose_log,
81*dd3c26a0STobias Hieta    )
82d9944da2SValeriy Savchenko
83d9944da2SValeriy Savchenko
84d9944da2SValeriy Savchenkodef update(parser, args):
8594f0eb83SValeriy Savchenko    import SATestUpdateDiffs
8694f0eb83SValeriy Savchenko    from ProjectMap import ProjectMap
8794f0eb83SValeriy Savchenko
88d9944da2SValeriy Savchenko    project_map = ProjectMap()
89d9944da2SValeriy Savchenko    for project in project_map.projects:
9010851f9dSValeriy Savchenko        SATestUpdateDiffs.update_reference_results(project, args.git)
91d9944da2SValeriy Savchenko
92d9944da2SValeriy Savchenko
935b4f1435SValeriy Savchenkodef benchmark(parser, args):
945b4f1435SValeriy Savchenko    from SATestBenchmark import Benchmark
955b4f1435SValeriy Savchenko
96aec12c12SValeriy Savchenko    projects = get_projects(parser, args)
975b4f1435SValeriy Savchenko    benchmark = Benchmark(projects, args.iterations, args.output)
985b4f1435SValeriy Savchenko    benchmark.run()
995b4f1435SValeriy Savchenko
1005b4f1435SValeriy Savchenko
1015b4f1435SValeriy Savchenkodef benchmark_compare(parser, args):
1025b4f1435SValeriy Savchenko    import SATestBenchmark
103*dd3c26a0STobias Hieta
1045b4f1435SValeriy Savchenko    SATestBenchmark.compare(args.old, args.new, args.output)
1055b4f1435SValeriy Savchenko
1065b4f1435SValeriy Savchenko
107aec12c12SValeriy Savchenkodef get_projects(parser, args):
108aec12c12SValeriy Savchenko    from ProjectMap import ProjectMap, Size
1095b4f1435SValeriy Savchenko
1105b4f1435SValeriy Savchenko    project_map = ProjectMap()
1115b4f1435SValeriy Savchenko    projects = project_map.projects
1125b4f1435SValeriy Savchenko
113aec12c12SValeriy Savchenko    def filter_projects(projects, predicate, force=False):
114*dd3c26a0STobias Hieta        return [
115*dd3c26a0STobias Hieta            project.with_fields(
116*dd3c26a0STobias Hieta                enabled=(force or project.enabled) and predicate(project)
117*dd3c26a0STobias Hieta            )
118*dd3c26a0STobias Hieta            for project in projects
119*dd3c26a0STobias Hieta        ]
120aec12c12SValeriy Savchenko
121aec12c12SValeriy Savchenko    if args.projects:
122aec12c12SValeriy Savchenko        projects_arg = args.projects.split(",")
123*dd3c26a0STobias Hieta        available_projects = [project.name for project in projects]
1245b4f1435SValeriy Savchenko
1255b4f1435SValeriy Savchenko        # validate that given projects are present in the project map file
1265b4f1435SValeriy Savchenko        for manual_project in projects_arg:
1275b4f1435SValeriy Savchenko            if manual_project not in available_projects:
128*dd3c26a0STobias Hieta                parser.error(
129*dd3c26a0STobias Hieta                    "Project '{project}' is not found in "
1305b4f1435SValeriy Savchenko                    "the project map file. Available projects are "
131*dd3c26a0STobias Hieta                    "{all}.".format(project=manual_project, all=available_projects)
132*dd3c26a0STobias Hieta                )
1335b4f1435SValeriy Savchenko
134*dd3c26a0STobias Hieta        projects = filter_projects(
135*dd3c26a0STobias Hieta            projects, lambda project: project.name in projects_arg, force=True
136*dd3c26a0STobias Hieta        )
137aec12c12SValeriy Savchenko
138aec12c12SValeriy Savchenko    try:
139aec12c12SValeriy Savchenko        max_size = Size.from_str(args.max_size)
140aec12c12SValeriy Savchenko    except ValueError as e:
141aec12c12SValeriy Savchenko        parser.error("{}".format(e))
142aec12c12SValeriy Savchenko
143*dd3c26a0STobias Hieta    projects = filter_projects(projects, lambda project: project.size <= max_size)
1445b4f1435SValeriy Savchenko
1455b4f1435SValeriy Savchenko    return projects
1465b4f1435SValeriy Savchenko
1475b4f1435SValeriy Savchenko
1483770f5c9SValeriy Savchenkodef docker(parser, args):
1493770f5c9SValeriy Savchenko    if len(args.rest) > 0:
1503770f5c9SValeriy Savchenko        if args.rest[0] != "--":
1513770f5c9SValeriy Savchenko            parser.error("REST arguments should start with '--'")
1523770f5c9SValeriy Savchenko        args.rest = args.rest[1:]
1533770f5c9SValeriy Savchenko
1543770f5c9SValeriy Savchenko    if args.build_image:
1553770f5c9SValeriy Savchenko        docker_build_image()
15611f28782SValeriy Savchenko    elif args.shell:
15711f28782SValeriy Savchenko        docker_shell(args)
1583770f5c9SValeriy Savchenko    else:
159*dd3c26a0STobias Hieta        sys.exit(docker_run(args, " ".join(args.rest)))
1603770f5c9SValeriy Savchenko
1613770f5c9SValeriy Savchenko
1623770f5c9SValeriy Savchenkodef docker_build_image():
163*dd3c26a0STobias Hieta    sys.exit(call("docker build --tag satest-image {}".format(SCRIPTS_DIR), shell=True))
1643770f5c9SValeriy Savchenko
1653770f5c9SValeriy Savchenko
16611f28782SValeriy Savchenkodef docker_shell(args):
16711f28782SValeriy Savchenko    try:
16811f28782SValeriy Savchenko        # First we need to start the docker container in a waiting mode,
16911f28782SValeriy Savchenko        # so it doesn't do anything, but most importantly keeps working
17011f28782SValeriy Savchenko        # while the shell session is in progress.
17111f28782SValeriy Savchenko        docker_run(args, "--wait", "--detach")
17211f28782SValeriy Savchenko        # Since the docker container is running, we can actually connect to it
17311f28782SValeriy Savchenko        call("docker exec -it satest bash", shell=True)
17411f28782SValeriy Savchenko
17511f28782SValeriy Savchenko    except KeyboardInterrupt:
17611f28782SValeriy Savchenko        pass
17711f28782SValeriy Savchenko
17811f28782SValeriy Savchenko    finally:
1799c7ff0a4SValeriy Savchenko        docker_cleanup()
18011f28782SValeriy Savchenko
18111f28782SValeriy Savchenko
18211f28782SValeriy Savchenkodef docker_run(args, command, docker_args=""):
1839c7ff0a4SValeriy Savchenko    try:
184*dd3c26a0STobias Hieta        return call(
185*dd3c26a0STobias Hieta            "docker run --rm --name satest "
1863770f5c9SValeriy Savchenko            "-v {llvm}:/llvm-project "
1873770f5c9SValeriy Savchenko            "-v {build}:/build "
1883770f5c9SValeriy Savchenko            "-v {clang}:/analyzer "
1893770f5c9SValeriy Savchenko            "-v {scripts}:/scripts "
1903770f5c9SValeriy Savchenko            "-v {projects}:/projects "
19111f28782SValeriy Savchenko            "{docker_args} "
192*dd3c26a0STobias Hieta            "satest-image:latest {command}".format(
193*dd3c26a0STobias Hieta                llvm=args.llvm_project_dir,
194e30706afSValeriy Savchenko                build=args.build_dir,
195e30706afSValeriy Savchenko                clang=args.clang_dir,
196e30706afSValeriy Savchenko                scripts=SCRIPTS_DIR,
197e30706afSValeriy Savchenko                projects=PROJECTS_DIR,
19811f28782SValeriy Savchenko                docker_args=docker_args,
199*dd3c26a0STobias Hieta                command=command,
200*dd3c26a0STobias Hieta            ),
201*dd3c26a0STobias Hieta            shell=True,
202*dd3c26a0STobias Hieta        )
2033770f5c9SValeriy Savchenko
2049c7ff0a4SValeriy Savchenko    except KeyboardInterrupt:
2059c7ff0a4SValeriy Savchenko        docker_cleanup()
2069c7ff0a4SValeriy Savchenko
2079c7ff0a4SValeriy Savchenko
2089c7ff0a4SValeriy Savchenkodef docker_cleanup():
2099c7ff0a4SValeriy Savchenko    print("Please wait for docker to clean up")
2109c7ff0a4SValeriy Savchenko    call("docker stop satest", shell=True)
2119c7ff0a4SValeriy Savchenko
2123770f5c9SValeriy Savchenko
213d9944da2SValeriy Savchenkodef main():
214d9944da2SValeriy Savchenko    parser = argparse.ArgumentParser()
215d9944da2SValeriy Savchenko    subparsers = parser.add_subparsers()
216d9944da2SValeriy Savchenko
217d9944da2SValeriy Savchenko    # add subcommand
218d9944da2SValeriy Savchenko    add_parser = subparsers.add_parser(
219*dd3c26a0STobias Hieta        "add", help="Add a new project for the analyzer testing."
220*dd3c26a0STobias Hieta    )
221d9944da2SValeriy Savchenko    # TODO: Add an option not to build.
222d9944da2SValeriy Savchenko    # TODO: Set the path to the Repository directory.
223d9944da2SValeriy Savchenko    add_parser.add_argument("name", nargs=1, help="Name of the new project")
224*dd3c26a0STobias Hieta    add_parser.add_argument(
225*dd3c26a0STobias Hieta        "--mode",
226*dd3c26a0STobias Hieta        action="store",
227*dd3c26a0STobias Hieta        default=1,
228*dd3c26a0STobias Hieta        type=int,
229d9944da2SValeriy Savchenko        choices=[0, 1, 2],
230d9944da2SValeriy Savchenko        help="Build mode: 0 for single file project, "
231d9944da2SValeriy Savchenko        "1 for scan_build, "
232*dd3c26a0STobias Hieta        "2 for single file c++11 project",
233*dd3c26a0STobias Hieta    )
234*dd3c26a0STobias Hieta    add_parser.add_argument(
235*dd3c26a0STobias Hieta        "--source",
236*dd3c26a0STobias Hieta        action="store",
237*dd3c26a0STobias Hieta        default="script",
238d9944da2SValeriy Savchenko        choices=["script", "git", "zip"],
239d9944da2SValeriy Savchenko        help="Source type of the new project: "
240d9944da2SValeriy Savchenko        "'git' for getting from git "
241d9944da2SValeriy Savchenko        "(please provide --origin and --commit), "
242d9944da2SValeriy Savchenko        "'zip' for unpacking source from a zip file, "
243d9944da2SValeriy Savchenko        "'script' for downloading source by running "
244*dd3c26a0STobias Hieta        "a custom script",
245*dd3c26a0STobias Hieta    )
246*dd3c26a0STobias Hieta    add_parser.add_argument(
247*dd3c26a0STobias Hieta        "--origin", action="store", default="", help="Origin link for a git repository"
248*dd3c26a0STobias Hieta    )
249*dd3c26a0STobias Hieta    add_parser.add_argument(
250*dd3c26a0STobias Hieta        "--commit", action="store", default="", help="Git hash for a commit to checkout"
251*dd3c26a0STobias Hieta    )
252d9944da2SValeriy Savchenko    add_parser.set_defaults(func=add)
253d9944da2SValeriy Savchenko
254d9944da2SValeriy Savchenko    # build subcommand
255d9944da2SValeriy Savchenko    build_parser = subparsers.add_parser(
256d9944da2SValeriy Savchenko        "build",
257d9944da2SValeriy Savchenko        help="Build projects from the project map and compare results with "
258*dd3c26a0STobias Hieta        "the reference.",
259*dd3c26a0STobias Hieta    )
260*dd3c26a0STobias Hieta    build_parser.add_argument(
261*dd3c26a0STobias Hieta        "--strictness",
262*dd3c26a0STobias Hieta        dest="strictness",
263*dd3c26a0STobias Hieta        type=int,
264*dd3c26a0STobias Hieta        default=0,
265d9944da2SValeriy Savchenko        help="0 to fail on runtime errors, 1 to fail "
266d9944da2SValeriy Savchenko        "when the number of found bugs are different "
267d9944da2SValeriy Savchenko        "from the reference, 2 to fail on any "
268*dd3c26a0STobias Hieta        "difference from the reference. Default is 0.",
269*dd3c26a0STobias Hieta    )
270*dd3c26a0STobias Hieta    build_parser.add_argument(
271*dd3c26a0STobias Hieta        "-r",
272*dd3c26a0STobias Hieta        dest="regenerate",
273*dd3c26a0STobias Hieta        action="store_true",
274d9944da2SValeriy Savchenko        default=False,
275*dd3c26a0STobias Hieta        help="Regenerate reference output.",
276*dd3c26a0STobias Hieta    )
277*dd3c26a0STobias Hieta    build_parser.add_argument(
278*dd3c26a0STobias Hieta        "--override-compiler",
279*dd3c26a0STobias Hieta        action="store_true",
280*dd3c26a0STobias Hieta        default=False,
281*dd3c26a0STobias Hieta        help="Call scan-build with " "--override-compiler option.",
282*dd3c26a0STobias Hieta    )
283*dd3c26a0STobias Hieta    build_parser.add_argument(
284*dd3c26a0STobias Hieta        "-j",
285*dd3c26a0STobias Hieta        "--jobs",
286*dd3c26a0STobias Hieta        dest="jobs",
287*dd3c26a0STobias Hieta        type=int,
288*dd3c26a0STobias Hieta        default=0,
289*dd3c26a0STobias Hieta        help="Number of projects to test concurrently",
290*dd3c26a0STobias Hieta    )
291*dd3c26a0STobias Hieta    build_parser.add_argument(
292*dd3c26a0STobias Hieta        "--extra-analyzer-config",
293*dd3c26a0STobias Hieta        dest="extra_analyzer_config",
294*dd3c26a0STobias Hieta        type=str,
295d9944da2SValeriy Savchenko        default="",
296*dd3c26a0STobias Hieta        help="Arguments passed to to -analyzer-config",
297*dd3c26a0STobias Hieta    )
298*dd3c26a0STobias Hieta    build_parser.add_argument(
299*dd3c26a0STobias Hieta        "--extra-checkers",
300*dd3c26a0STobias Hieta        dest="extra_checkers",
301*dd3c26a0STobias Hieta        type=str,
302198e6771SDeep Majumder        default="",
303*dd3c26a0STobias Hieta        help="Extra checkers to enable",
304*dd3c26a0STobias Hieta    )
305*dd3c26a0STobias Hieta    build_parser.add_argument(
306*dd3c26a0STobias Hieta        "--projects",
307*dd3c26a0STobias Hieta        action="store",
308*dd3c26a0STobias Hieta        default="",
309*dd3c26a0STobias Hieta        help="Comma-separated list of projects to test",
310*dd3c26a0STobias Hieta    )
311*dd3c26a0STobias Hieta    build_parser.add_argument(
312*dd3c26a0STobias Hieta        "--max-size",
313*dd3c26a0STobias Hieta        action="store",
314*dd3c26a0STobias Hieta        default=None,
315*dd3c26a0STobias Hieta        help="Maximum size for the projects to test",
316*dd3c26a0STobias Hieta    )
317d9944da2SValeriy Savchenko    build_parser.add_argument("-v", "--verbose", action="count", default=0)
318d9944da2SValeriy Savchenko    build_parser.set_defaults(func=build)
319d9944da2SValeriy Savchenko
320d9944da2SValeriy Savchenko    # compare subcommand
321d9944da2SValeriy Savchenko    cmp_parser = subparsers.add_parser(
322d9944da2SValeriy Savchenko        "compare",
323d9944da2SValeriy Savchenko        help="Comparing two static analyzer runs in terms of "
324*dd3c26a0STobias Hieta        "reported warnings and execution time statistics.",
325*dd3c26a0STobias Hieta    )
326*dd3c26a0STobias Hieta    cmp_parser.add_argument(
327*dd3c26a0STobias Hieta        "--root-old",
328*dd3c26a0STobias Hieta        dest="root_old",
329*dd3c26a0STobias Hieta        help="Prefix to ignore on source files for " "OLD directory",
330*dd3c26a0STobias Hieta        action="store",
331*dd3c26a0STobias Hieta        type=str,
332*dd3c26a0STobias Hieta        default="",
333*dd3c26a0STobias Hieta    )
334*dd3c26a0STobias Hieta    cmp_parser.add_argument(
335*dd3c26a0STobias Hieta        "--root-new",
336*dd3c26a0STobias Hieta        dest="root_new",
337*dd3c26a0STobias Hieta        help="Prefix to ignore on source files for " "NEW directory",
338*dd3c26a0STobias Hieta        action="store",
339*dd3c26a0STobias Hieta        type=str,
340*dd3c26a0STobias Hieta        default="",
341*dd3c26a0STobias Hieta    )
342*dd3c26a0STobias Hieta    cmp_parser.add_argument(
343*dd3c26a0STobias Hieta        "--verbose-log",
344*dd3c26a0STobias Hieta        dest="verbose_log",
345*dd3c26a0STobias Hieta        help="Write additional information to LOG " "[default=None]",
346*dd3c26a0STobias Hieta        action="store",
347*dd3c26a0STobias Hieta        type=str,
348*dd3c26a0STobias Hieta        default=None,
349*dd3c26a0STobias Hieta        metavar="LOG",
350*dd3c26a0STobias Hieta    )
351*dd3c26a0STobias Hieta    cmp_parser.add_argument(
352*dd3c26a0STobias Hieta        "--stats-only",
353*dd3c26a0STobias Hieta        action="store_true",
354*dd3c26a0STobias Hieta        dest="stats_only",
355*dd3c26a0STobias Hieta        default=False,
356*dd3c26a0STobias Hieta        help="Only show statistics on reports",
357*dd3c26a0STobias Hieta    )
358*dd3c26a0STobias Hieta    cmp_parser.add_argument(
359*dd3c26a0STobias Hieta        "--show-stats",
360*dd3c26a0STobias Hieta        action="store_true",
361*dd3c26a0STobias Hieta        dest="show_stats",
362*dd3c26a0STobias Hieta        default=False,
363*dd3c26a0STobias Hieta        help="Show change in statistics",
364*dd3c26a0STobias Hieta    )
365*dd3c26a0STobias Hieta    cmp_parser.add_argument(
366*dd3c26a0STobias Hieta        "--histogram",
367*dd3c26a0STobias Hieta        action="store",
368*dd3c26a0STobias Hieta        default=None,
369*dd3c26a0STobias Hieta        help="Show histogram of paths differences. " "Requires matplotlib",
370*dd3c26a0STobias Hieta    )
371d9944da2SValeriy Savchenko    cmp_parser.add_argument("old", nargs=1, help="Directory with old results")
372d9944da2SValeriy Savchenko    cmp_parser.add_argument("new", nargs=1, help="Directory with new results")
373d9944da2SValeriy Savchenko    cmp_parser.set_defaults(func=compare)
374d9944da2SValeriy Savchenko
375d9944da2SValeriy Savchenko    # update subcommand
376d9944da2SValeriy Savchenko    upd_parser = subparsers.add_parser(
377d9944da2SValeriy Savchenko        "update",
378d9944da2SValeriy Savchenko        help="Update static analyzer reference results based on the previous "
379*dd3c26a0STobias Hieta        "run of SATest build. Assumes that SATest build was just run.",
380*dd3c26a0STobias Hieta    )
381*dd3c26a0STobias Hieta    upd_parser.add_argument(
382*dd3c26a0STobias Hieta        "--git", action="store_true", help="Stage updated results using git."
383*dd3c26a0STobias Hieta    )
384d9944da2SValeriy Savchenko    upd_parser.set_defaults(func=update)
385d9944da2SValeriy Savchenko
3863770f5c9SValeriy Savchenko    # docker subcommand
3873770f5c9SValeriy Savchenko    dock_parser = subparsers.add_parser(
388*dd3c26a0STobias Hieta        "docker", help="Run regression system in the docker."
389*dd3c26a0STobias Hieta    )
3903770f5c9SValeriy Savchenko
391*dd3c26a0STobias Hieta    dock_parser.add_argument(
392*dd3c26a0STobias Hieta        "--build-image",
393*dd3c26a0STobias Hieta        action="store_true",
394*dd3c26a0STobias Hieta        help="Build docker image for running tests.",
395*dd3c26a0STobias Hieta    )
396*dd3c26a0STobias Hieta    dock_parser.add_argument(
397*dd3c26a0STobias Hieta        "--shell", action="store_true", help="Start a shell on docker."
398*dd3c26a0STobias Hieta    )
399*dd3c26a0STobias Hieta    dock_parser.add_argument(
400*dd3c26a0STobias Hieta        "--llvm-project-dir",
401*dd3c26a0STobias Hieta        action="store",
4023770f5c9SValeriy Savchenko        default=DEFAULT_LLVM_DIR,
4033770f5c9SValeriy Savchenko        help="Path to LLVM source code. Defaults "
404*dd3c26a0STobias Hieta        "to the repo where this script is located. ",
405*dd3c26a0STobias Hieta    )
406*dd3c26a0STobias Hieta    dock_parser.add_argument(
407*dd3c26a0STobias Hieta        "--build-dir",
408*dd3c26a0STobias Hieta        action="store",
409*dd3c26a0STobias Hieta        default="",
410*dd3c26a0STobias Hieta        help="Path to a directory where docker should " "build LLVM code.",
411*dd3c26a0STobias Hieta    )
412*dd3c26a0STobias Hieta    dock_parser.add_argument(
413*dd3c26a0STobias Hieta        "--clang-dir",
414*dd3c26a0STobias Hieta        action="store",
415*dd3c26a0STobias Hieta        default="",
416*dd3c26a0STobias Hieta        help="Path to find/install LLVM installation.",
417*dd3c26a0STobias Hieta    )
418*dd3c26a0STobias Hieta    dock_parser.add_argument(
419*dd3c26a0STobias Hieta        "rest",
420*dd3c26a0STobias Hieta        nargs=argparse.REMAINDER,
421*dd3c26a0STobias Hieta        default=[],
422*dd3c26a0STobias Hieta        help="Additional args that will be forwarded " "to the docker's entrypoint.",
423*dd3c26a0STobias Hieta    )
4243770f5c9SValeriy Savchenko    dock_parser.set_defaults(func=docker)
4253770f5c9SValeriy Savchenko
4265b4f1435SValeriy Savchenko    # benchmark subcommand
4275b4f1435SValeriy Savchenko    bench_parser = subparsers.add_parser(
428*dd3c26a0STobias Hieta        "benchmark", help="Run benchmarks by building a set of projects multiple times."
429*dd3c26a0STobias Hieta    )
4305b4f1435SValeriy Savchenko
431*dd3c26a0STobias Hieta    bench_parser.add_argument(
432*dd3c26a0STobias Hieta        "-i",
433*dd3c26a0STobias Hieta        "--iterations",
434*dd3c26a0STobias Hieta        action="store",
435*dd3c26a0STobias Hieta        type=int,
436*dd3c26a0STobias Hieta        default=20,
437*dd3c26a0STobias Hieta        help="Number of iterations for building each " "project.",
438*dd3c26a0STobias Hieta    )
439*dd3c26a0STobias Hieta    bench_parser.add_argument(
440*dd3c26a0STobias Hieta        "-o",
441*dd3c26a0STobias Hieta        "--output",
442*dd3c26a0STobias Hieta        action="store",
4435b4f1435SValeriy Savchenko        default="benchmark.csv",
444*dd3c26a0STobias Hieta        help="Output csv file for the benchmark results",
445*dd3c26a0STobias Hieta    )
446*dd3c26a0STobias Hieta    bench_parser.add_argument(
447*dd3c26a0STobias Hieta        "--projects",
448*dd3c26a0STobias Hieta        action="store",
449*dd3c26a0STobias Hieta        default="",
450*dd3c26a0STobias Hieta        help="Comma-separated list of projects to test",
451*dd3c26a0STobias Hieta    )
452*dd3c26a0STobias Hieta    bench_parser.add_argument(
453*dd3c26a0STobias Hieta        "--max-size",
454*dd3c26a0STobias Hieta        action="store",
455*dd3c26a0STobias Hieta        default=None,
456*dd3c26a0STobias Hieta        help="Maximum size for the projects to test",
457*dd3c26a0STobias Hieta    )
4585b4f1435SValeriy Savchenko    bench_parser.set_defaults(func=benchmark)
4595b4f1435SValeriy Savchenko
4605b4f1435SValeriy Savchenko    bench_subparsers = bench_parser.add_subparsers()
4615b4f1435SValeriy Savchenko    bench_compare_parser = bench_subparsers.add_parser(
462*dd3c26a0STobias Hieta        "compare", help="Compare benchmark runs."
463*dd3c26a0STobias Hieta    )
464*dd3c26a0STobias Hieta    bench_compare_parser.add_argument(
465*dd3c26a0STobias Hieta        "--old",
466*dd3c26a0STobias Hieta        action="store",
467*dd3c26a0STobias Hieta        required=True,
468*dd3c26a0STobias Hieta        help="Benchmark reference results to " "compare agains.",
469*dd3c26a0STobias Hieta    )
470*dd3c26a0STobias Hieta    bench_compare_parser.add_argument(
471*dd3c26a0STobias Hieta        "--new", action="store", required=True, help="New benchmark results to check."
472*dd3c26a0STobias Hieta    )
473*dd3c26a0STobias Hieta    bench_compare_parser.add_argument(
474*dd3c26a0STobias Hieta        "-o", "--output", action="store", required=True, help="Output file for plots."
475*dd3c26a0STobias Hieta    )
4765b4f1435SValeriy Savchenko    bench_compare_parser.set_defaults(func=benchmark_compare)
4775b4f1435SValeriy Savchenko
478d9944da2SValeriy Savchenko    args = parser.parse_args()
479d9944da2SValeriy Savchenko    args.func(parser, args)
480d9944da2SValeriy Savchenko
481d9944da2SValeriy Savchenko
482d9944da2SValeriy Savchenkoif __name__ == "__main__":
483d9944da2SValeriy Savchenko    main()
484