• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# -*- coding: utf-8 -*-
2# Copyright 2013 The ChromiumOS Authors
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""A module to generate experiments."""
7
8
9import os
10import re
11import socket
12import sys
13
14from benchmark import Benchmark
15from cros_utils import command_executer
16from cros_utils import logger
17from experiment import Experiment
18import file_lock_machine
19from label import Label
20from label import MockLabel
21from results_cache import CacheConditions
22import test_flag
23
24import config
25
26
27# Users may want to run Telemetry tests either individually, or in
28# specified sets.  Here we define sets of tests that users may want
29# to run together.
30
31telemetry_perfv2_tests = [
32    "kraken",
33    "octane",
34]
35
36telemetry_pagecycler_tests = [
37    "page_cycler_v2.intl_ar_fa_he",
38    "page_cycler_v2.intl_es_fr_pt-BR",
39    "page_cycler_v2.intl_hi_ru",
40    "page_cycler_v2.intl_ja_zh",
41    "page_cycler_v2.intl_ko_th_vi",
42    "page_cycler_v2.typical_25",
43]
44
45telemetry_toolchain_old_perf_tests = [
46    "page_cycler_v2.intl_es_fr_pt-BR",
47    "page_cycler_v2.intl_hi_ru",
48    "page_cycler_v2.intl_ja_zh",
49    "page_cycler_v2.intl_ko_th_vi",
50    "page_cycler_v2.netsim.top_10",
51    "page_cycler_v2.typical_25",
52    "spaceport",
53    "tab_switching.top_10",
54]
55telemetry_toolchain_perf_tests = [
56    "octane",
57    "kraken",
58    "speedometer",
59    "speedometer2",
60    "jetstream2",
61]
62graphics_perf_tests = [
63    "graphics_GLBench",
64    "graphics_GLMark2",
65    "graphics_SanAngeles",
66    "graphics_WebGLAquarium",
67    "graphics_WebGLPerformance",
68]
69# TODO: disable rendering.desktop by default as the benchmark is
70# currently in a bad state
71# page_cycler_v2.typical_25 is deprecated and the recommend replacement is
72# loading.desktop@@typical (crbug.com/916340)
73telemetry_crosbolt_perf_tests = [
74    "octane",
75    "kraken",
76    "speedometer2",
77    "jetstream",
78    "loading.desktop",
79    # 'rendering.desktop',
80]
81
82crosbolt_perf_tests = [
83    "graphics_WebGLAquarium",
84    "tast.video.PlaybackPerfVP91080P30FPS",
85]
86
87#    'cheets_AntutuTest',
88#    'cheets_PerfBootServer',
89#    'cheets_CandyCrushTest',
90#    'cheets_LinpackTest',
91# ]
92
93dso_list = [
94    "all",
95    "chrome",
96    "kallsyms",
97]
98
99
100class ExperimentFactory(object):
101    """Factory class for building an Experiment, given an ExperimentFile as input.
102
103    This factory is currently hardcoded to produce an experiment for running
104    ChromeOS benchmarks, but the idea is that in the future, other types
105    of experiments could be produced.
106    """
107
108    def AppendBenchmarkSet(
109        self,
110        benchmarks,
111        benchmark_list,
112        test_args,
113        iterations,
114        rm_chroot_tmp,
115        perf_args,
116        suite,
117        show_all_results,
118        retries,
119        run_local,
120        cwp_dso,
121        weight,
122    ):
123        """Add all the tests in a set to the benchmarks list."""
124        for test_name in benchmark_list:
125            telemetry_benchmark = Benchmark(
126                test_name,
127                test_name,
128                test_args,
129                iterations,
130                rm_chroot_tmp,
131                perf_args,
132                suite,
133                show_all_results,
134                retries,
135                run_local,
136                cwp_dso,
137                weight,
138            )
139            benchmarks.append(telemetry_benchmark)
140
141    def GetExperiment(self, experiment_file, working_directory, log_dir):
142        """Construct an experiment from an experiment file."""
143        global_settings = experiment_file.GetGlobalSettings()
144        experiment_name = global_settings.GetField("name")
145        board = global_settings.GetField("board")
146        chromeos_root = global_settings.GetField("chromeos_root")
147        log_level = global_settings.GetField("logging_level")
148        if log_level not in ("quiet", "average", "verbose"):
149            log_level = "verbose"
150
151        crosfleet = global_settings.GetField("crosfleet")
152        no_lock = bool(global_settings.GetField("no_lock"))
153        # Check whether crosfleet tool is installed correctly for crosfleet mode.
154        if crosfleet and not self.CheckCrosfleetTool(chromeos_root, log_level):
155            sys.exit(0)
156
157        remote = global_settings.GetField("remote")
158        # This is used to remove the ",' from the remote if user
159        # add them to the remote string.
160        new_remote = []
161        if remote:
162            for i in remote:
163                c = re.sub("[\"']", "", i)
164                new_remote.append(c)
165        remote = new_remote
166        rm_chroot_tmp = global_settings.GetField("rm_chroot_tmp")
167        perf_args = global_settings.GetField("perf_args")
168        download_debug = global_settings.GetField("download_debug")
169        # Do not download debug symbols when perf_args is not specified.
170        if not perf_args and download_debug:
171            download_debug = False
172        acquire_timeout = global_settings.GetField("acquire_timeout")
173        cache_dir = global_settings.GetField("cache_dir")
174        cache_only = global_settings.GetField("cache_only")
175        config.AddConfig("no_email", global_settings.GetField("no_email"))
176        share_cache = global_settings.GetField("share_cache")
177        results_dir = global_settings.GetField("results_dir")
178        compress_results = global_settings.GetField("compress_results")
179        # Warn user that option use_file_locks is deprecated.
180        use_file_locks = global_settings.GetField("use_file_locks")
181        if use_file_locks:
182            l = logger.GetLogger()
183            l.LogWarning(
184                "Option use_file_locks is deprecated, please remove it "
185                "from your experiment settings."
186            )
187        locks_dir = global_settings.GetField("locks_dir")
188        # If not specified, set the locks dir to the default locks dir in
189        # file_lock_machine.
190        if not locks_dir:
191            locks_dir = file_lock_machine.Machine.LOCKS_DIR
192        if not os.path.exists(locks_dir):
193            raise RuntimeError(
194                "Cannot access default lock directory. "
195                "Please run prodaccess or specify a local directory"
196            )
197        chrome_src = global_settings.GetField("chrome_src")
198        show_all_results = global_settings.GetField("show_all_results")
199        cwp_dso = global_settings.GetField("cwp_dso")
200        if cwp_dso and not cwp_dso in dso_list:
201            raise RuntimeError("The DSO specified is not supported")
202        ignore_min_max = global_settings.GetField("ignore_min_max")
203        dut_config = {
204            "enable_aslr": global_settings.GetField("enable_aslr"),
205            "intel_pstate": global_settings.GetField("intel_pstate"),
206            "cooldown_time": global_settings.GetField("cooldown_time"),
207            "cooldown_temp": global_settings.GetField("cooldown_temp"),
208            "governor": global_settings.GetField("governor"),
209            "cpu_usage": global_settings.GetField("cpu_usage"),
210            "cpu_freq_pct": global_settings.GetField("cpu_freq_pct"),
211            "turbostat": global_settings.GetField("turbostat"),
212            "top_interval": global_settings.GetField("top_interval"),
213        }
214
215        # Default cache hit conditions. The image checksum in the cache and the
216        # computed checksum of the image must match. Also a cache file must exist.
217        cache_conditions = [
218            CacheConditions.CACHE_FILE_EXISTS,
219            CacheConditions.CHECKSUMS_MATCH,
220        ]
221        if global_settings.GetField("rerun_if_failed"):
222            cache_conditions.append(CacheConditions.RUN_SUCCEEDED)
223        if global_settings.GetField("rerun"):
224            cache_conditions.append(CacheConditions.FALSE)
225        if global_settings.GetField("same_machine"):
226            cache_conditions.append(CacheConditions.SAME_MACHINE_MATCH)
227        if global_settings.GetField("same_specs"):
228            cache_conditions.append(CacheConditions.MACHINES_MATCH)
229
230        # Construct benchmarks.
231        # Some fields are common with global settings. The values are
232        # inherited and/or merged with the global settings values.
233        benchmarks = []
234        all_benchmark_settings = experiment_file.GetSettings("benchmark")
235
236        # Check if there is duplicated benchmark name
237        benchmark_names = {}
238        # Check if in cwp_dso mode, all benchmarks should have same iterations
239        cwp_dso_iterations = 0
240
241        for benchmark_settings in all_benchmark_settings:
242            benchmark_name = benchmark_settings.name
243            test_name = benchmark_settings.GetField("test_name")
244            if not test_name:
245                test_name = benchmark_name
246            test_args = benchmark_settings.GetField("test_args")
247
248            # Rename benchmark name if 'story-filter' or 'story-tag-filter' specified
249            # in test_args. Make sure these two tags only appear once.
250            story_count = 0
251            for arg in test_args.split():
252                if "--story-filter=" in arg or "--story-tag-filter=" in arg:
253                    story_count += 1
254                    if story_count > 1:
255                        raise RuntimeError(
256                            "Only one story or story-tag filter allowed in "
257                            "a single benchmark run"
258                        )
259                    # Rename benchmark name with an extension of 'story'-option
260                    benchmark_name = "%s@@%s" % (
261                        benchmark_name,
262                        arg.split("=")[-1],
263                    )
264
265            # Check for duplicated benchmark name after renaming
266            if not benchmark_name in benchmark_names:
267                benchmark_names[benchmark_name] = True
268            else:
269                raise SyntaxError(
270                    "Duplicate benchmark name: '%s'." % benchmark_name
271                )
272
273            iterations = benchmark_settings.GetField("iterations")
274            if cwp_dso:
275                if cwp_dso_iterations not in (0, iterations):
276                    raise RuntimeError(
277                        "Iterations of each benchmark run are not the " "same"
278                    )
279                cwp_dso_iterations = iterations
280
281            suite = benchmark_settings.GetField("suite")
282            retries = benchmark_settings.GetField("retries")
283            run_local = benchmark_settings.GetField("run_local")
284            weight = benchmark_settings.GetField("weight")
285            if weight:
286                if not cwp_dso:
287                    raise RuntimeError(
288                        "Weight can only be set when DSO specified"
289                    )
290                if suite != "telemetry_Crosperf":
291                    raise RuntimeError(
292                        "CWP approximation weight only works with "
293                        "telemetry_Crosperf suite"
294                    )
295                if run_local:
296                    raise RuntimeError(
297                        "run_local must be set to False to use CWP "
298                        "approximation"
299                    )
300                if weight < 0:
301                    raise RuntimeError("Weight should be a float >=0")
302            elif cwp_dso:
303                raise RuntimeError(
304                    "With DSO specified, each benchmark should have a " "weight"
305                )
306
307            if suite == "telemetry_Crosperf":
308                if test_name == "all_perfv2":
309                    self.AppendBenchmarkSet(
310                        benchmarks,
311                        telemetry_perfv2_tests,
312                        test_args,
313                        iterations,
314                        rm_chroot_tmp,
315                        perf_args,
316                        suite,
317                        show_all_results,
318                        retries,
319                        run_local,
320                        cwp_dso,
321                        weight,
322                    )
323                elif test_name == "all_pagecyclers":
324                    self.AppendBenchmarkSet(
325                        benchmarks,
326                        telemetry_pagecycler_tests,
327                        test_args,
328                        iterations,
329                        rm_chroot_tmp,
330                        perf_args,
331                        suite,
332                        show_all_results,
333                        retries,
334                        run_local,
335                        cwp_dso,
336                        weight,
337                    )
338                elif test_name == "all_crosbolt_perf":
339                    self.AppendBenchmarkSet(
340                        benchmarks,
341                        telemetry_crosbolt_perf_tests,
342                        test_args,
343                        iterations,
344                        rm_chroot_tmp,
345                        perf_args,
346                        "telemetry_Crosperf",
347                        show_all_results,
348                        retries,
349                        run_local,
350                        cwp_dso,
351                        weight,
352                    )
353                    self.AppendBenchmarkSet(
354                        benchmarks,
355                        crosbolt_perf_tests,
356                        "",
357                        iterations,
358                        rm_chroot_tmp,
359                        perf_args,
360                        "",
361                        show_all_results,
362                        retries,
363                        run_local=False,
364                        cwp_dso=cwp_dso,
365                        weight=weight,
366                    )
367                elif test_name == "all_toolchain_perf":
368                    self.AppendBenchmarkSet(
369                        benchmarks,
370                        telemetry_toolchain_perf_tests,
371                        test_args,
372                        iterations,
373                        rm_chroot_tmp,
374                        perf_args,
375                        suite,
376                        show_all_results,
377                        retries,
378                        run_local,
379                        cwp_dso,
380                        weight,
381                    )
382                    # Add non-telemetry toolchain-perf benchmarks:
383
384                    # Tast test platform.ReportDiskUsage for image size.
385                    benchmarks.append(
386                        Benchmark(
387                            "platform.ReportDiskUsage",
388                            "platform.ReportDiskUsage",
389                            "",
390                            1,  # This is not a performance benchmark, only run once.
391                            rm_chroot_tmp,
392                            "",
393                            "tast",  # Specify the suite to be 'tast'
394                            show_all_results,
395                            retries,
396                        )
397                    )
398
399                    # TODO: crbug.com/1057755 Do not enable graphics_WebGLAquarium until
400                    # it gets fixed.
401                    #
402                    # benchmarks.append(
403                    #     Benchmark(
404                    #         'graphics_WebGLAquarium',
405                    #         'graphics_WebGLAquarium',
406                    #         '',
407                    #         iterations,
408                    #         rm_chroot_tmp,
409                    #         perf_args,
410                    #         'crosperf_Wrapper',  # Use client wrapper in Autotest
411                    #         show_all_results,
412                    #         retries,
413                    #         run_local=False,
414                    #         cwp_dso=cwp_dso,
415                    #         weight=weight))
416                elif test_name == "all_toolchain_perf_old":
417                    self.AppendBenchmarkSet(
418                        benchmarks,
419                        telemetry_toolchain_old_perf_tests,
420                        test_args,
421                        iterations,
422                        rm_chroot_tmp,
423                        perf_args,
424                        suite,
425                        show_all_results,
426                        retries,
427                        run_local,
428                        cwp_dso,
429                        weight,
430                    )
431                else:
432                    benchmark = Benchmark(
433                        benchmark_name,
434                        test_name,
435                        test_args,
436                        iterations,
437                        rm_chroot_tmp,
438                        perf_args,
439                        suite,
440                        show_all_results,
441                        retries,
442                        run_local,
443                        cwp_dso,
444                        weight,
445                    )
446                    benchmarks.append(benchmark)
447            else:
448                if test_name == "all_graphics_perf":
449                    self.AppendBenchmarkSet(
450                        benchmarks,
451                        graphics_perf_tests,
452                        "",
453                        iterations,
454                        rm_chroot_tmp,
455                        perf_args,
456                        "",
457                        show_all_results,
458                        retries,
459                        run_local=False,
460                        cwp_dso=cwp_dso,
461                        weight=weight,
462                    )
463                else:
464                    # Add the single benchmark.
465                    benchmark = Benchmark(
466                        benchmark_name,
467                        test_name,
468                        test_args,
469                        iterations,
470                        rm_chroot_tmp,
471                        perf_args,
472                        suite,
473                        show_all_results,
474                        retries,
475                        run_local=False,
476                        cwp_dso=cwp_dso,
477                        weight=weight,
478                    )
479                    benchmarks.append(benchmark)
480
481        if not benchmarks:
482            raise RuntimeError("No benchmarks specified")
483
484        # Construct labels.
485        # Some fields are common with global settings. The values are
486        # inherited and/or merged with the global settings values.
487        labels = []
488        all_label_settings = experiment_file.GetSettings("label")
489        all_remote = list(remote)
490        for label_settings in all_label_settings:
491            label_name = label_settings.name
492            image = label_settings.GetField("chromeos_image")
493            build = label_settings.GetField("build")
494            autotest_path = label_settings.GetField("autotest_path")
495            debug_path = label_settings.GetField("debug_path")
496            chromeos_root = label_settings.GetField("chromeos_root")
497            my_remote = label_settings.GetField("remote")
498            compiler = label_settings.GetField("compiler")
499            new_remote = []
500            if my_remote:
501                for i in my_remote:
502                    c = re.sub("[\"']", "", i)
503                    new_remote.append(c)
504            my_remote = new_remote
505
506            if image:
507                if crosfleet:
508                    raise RuntimeError(
509                        "In crosfleet mode, local image should not be used."
510                    )
511                if build:
512                    raise RuntimeError(
513                        "Image path and build are provided at the same "
514                        "time, please use only one of them."
515                    )
516            else:
517                if not build:
518                    raise RuntimeError("Can not have empty 'build' field!")
519                image, autotest_path, debug_path = label_settings.GetXbuddyPath(
520                    build,
521                    autotest_path,
522                    debug_path,
523                    board,
524                    chromeos_root,
525                    log_level,
526                    download_debug,
527                )
528
529            cache_dir = label_settings.GetField("cache_dir")
530            chrome_src = label_settings.GetField("chrome_src")
531
532            # TODO(yunlian): We should consolidate code in machine_manager.py
533            # to derermine whether we are running from within google or not
534            if (
535                "corp.google.com" in socket.gethostname()
536                and not my_remote
537                and not crosfleet
538            ):
539                my_remote = self.GetDefaultRemotes(board)
540            if global_settings.GetField("same_machine") and len(my_remote) > 1:
541                raise RuntimeError(
542                    "Only one remote is allowed when same_machine "
543                    "is turned on"
544                )
545            all_remote += my_remote
546            image_args = label_settings.GetField("image_args")
547            if test_flag.GetTestMode():
548                # pylint: disable=too-many-function-args
549                label = MockLabel(
550                    label_name,
551                    build,
552                    image,
553                    autotest_path,
554                    debug_path,
555                    chromeos_root,
556                    board,
557                    my_remote,
558                    image_args,
559                    cache_dir,
560                    cache_only,
561                    log_level,
562                    compiler,
563                    crosfleet,
564                    chrome_src,
565                )
566            else:
567                label = Label(
568                    label_name,
569                    build,
570                    image,
571                    autotest_path,
572                    debug_path,
573                    chromeos_root,
574                    board,
575                    my_remote,
576                    image_args,
577                    cache_dir,
578                    cache_only,
579                    log_level,
580                    compiler,
581                    crosfleet,
582                    chrome_src,
583                )
584            labels.append(label)
585
586        if not labels:
587            raise RuntimeError("No labels specified")
588
589        email = global_settings.GetField("email")
590        all_remote += list(set(my_remote))
591        all_remote = list(set(all_remote))
592        if crosfleet:
593            for remote in all_remote:
594                self.CheckRemotesInCrosfleet(remote)
595        experiment = Experiment(
596            experiment_name,
597            all_remote,
598            working_directory,
599            chromeos_root,
600            cache_conditions,
601            labels,
602            benchmarks,
603            experiment_file.Canonicalize(),
604            email,
605            acquire_timeout,
606            log_dir,
607            log_level,
608            share_cache,
609            results_dir,
610            compress_results,
611            locks_dir,
612            cwp_dso,
613            ignore_min_max,
614            crosfleet,
615            dut_config,
616            no_lock=no_lock,
617        )
618
619        return experiment
620
621    def GetDefaultRemotes(self, board):
622        default_remotes_file = os.path.join(
623            os.path.dirname(__file__), "default_remotes"
624        )
625        try:
626            with open(default_remotes_file) as f:
627                for line in f:
628                    key, v = line.split(":")
629                    if key.strip() == board:
630                        remotes = v.strip().split()
631                        if remotes:
632                            return remotes
633                        else:
634                            raise RuntimeError(
635                                "There is no remote for {0}".format(board)
636                            )
637        except IOError:
638            # TODO: rethrow instead of throwing different exception.
639            raise RuntimeError(
640                "IOError while reading file {0}".format(default_remotes_file)
641            )
642        else:
643            raise RuntimeError("There is no remote for {0}".format(board))
644
645    def CheckRemotesInCrosfleet(self, remote):
646        # TODO: (AI:zhizhouy) need to check whether a remote is a local or lab
647        # machine. If not lab machine, raise an error.
648        pass
649
650    def CheckCrosfleetTool(self, chromeos_root, log_level):
651        CROSFLEET_PATH = "crosfleet"
652        if os.path.exists(CROSFLEET_PATH):
653            return True
654        l = logger.GetLogger()
655        l.LogOutput("Crosfleet tool not installed, trying to install it.")
656        ce = command_executer.GetCommandExecuter(l, log_level=log_level)
657        setup_lab_tools = os.path.join(
658            chromeos_root, "chromeos-admin", "lab-tools", "setup_lab_tools"
659        )
660        cmd = "%s" % setup_lab_tools
661        status = ce.RunCommand(cmd)
662        if status != 0:
663            raise RuntimeError(
664                "Crosfleet tool not installed correctly, please try to "
665                "manually install it from %s" % setup_lab_tools
666            )
667        l.LogOutput(
668            "Crosfleet is installed at %s, please login before first use. "
669            'Login by running "crosfleet login" and follow instructions.'
670            % CROSFLEET_PATH
671        )
672        return False
673