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