blob: a928c8cf4bab407ca1c33ecee4b24c6b6926351d [file] [log] [blame]
Srikrishna Iyer09a81e92019-12-30 10:47:57 -08001# Copyright lowRISC contributors.
2# Licensed under the Apache License, Version 2.0, see LICENSE for details.
3# SPDX-License-Identifier: Apache-2.0
Srikrishna Iyer09a81e92019-12-30 10:47:57 -08004
5import logging as log
6import pprint
Srikrishna Iyer7cf7cad2020-01-08 11:32:53 -08007import random
Srikrishna Iyer37b0c992021-03-23 16:27:26 -07008import shlex
Srikrishna Iyer956b3f82021-04-15 15:14:56 -07009from pathlib import Path
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080010
Srikrishna Iyer9d9d86f2021-03-02 00:15:51 -080011from LauncherFactory import get_launcher
Rupert Swarbrick6cc20112020-04-24 09:44:35 +010012from sim_utils import get_cov_summary_table
Srikrishna Iyere4662af2020-08-10 13:19:42 -070013from tabulate import tabulate
Srikrishna Iyercaa0d892021-03-01 13:15:52 -080014from utils import (VERBOSE, clean_odirs, find_and_substitute_wildcards,
15 rm_path, subst_wildcards)
Rupert Swarbricka2892a52020-10-12 08:50:08 +010016
17
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080018class Deploy():
19 """
Srikrishna Iyer65783742021-02-10 21:42:12 -080020 Abstraction to create and maintain a runnable job (builds, runs, etc.).
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080021 """
22
Srikrishna Iyer65783742021-02-10 21:42:12 -080023 # Indicate the target for each sub-class.
24 target = None
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080025
Srikrishna Iyer6c531b02020-11-23 18:41:16 -080026 # List of variable names that are to be treated as "list of commands".
Srikrishna Iyer65783742021-02-10 21:42:12 -080027 # This tells '_construct_cmd' that these vars are lists that need to
Srikrishna Iyer6c531b02020-11-23 18:41:16 -080028 # be joined with '&&' instead of a space.
29 cmds_list_vars = []
30
Srikrishna Iyer1d2899f2021-02-11 18:23:15 -080031 # Represents the weight with which a job of this target is scheduled. These
32 # initial weights set for each of the targets below are roughly inversely
33 # proportional to their average runtimes. These are subject to change in
34 # future. Lower the runtime, the higher chance the it gets scheduled. It is
35 # useful to customize this only in case of targets that may coexist at a
36 # time.
37 # TODO: Allow these to be set in the HJson.
38 weight = 1
39
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080040 def __str__(self):
Rupert Swarbrick381770d2020-10-12 08:50:08 +010041 return (pprint.pformat(self.__dict__)
Srikrishna Iyer65783742021-02-10 21:42:12 -080042 if log.getLogger().isEnabledFor(VERBOSE) else self.full_name)
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080043
Srikrishna Iyer7cf7cad2020-01-08 11:32:53 -080044 def __init__(self, sim_cfg):
Srikrishna Iyer65783742021-02-10 21:42:12 -080045 assert self.target is not None
Srikrishna Iyere4662af2020-08-10 13:19:42 -070046
Srikrishna Iyer7cf7cad2020-01-08 11:32:53 -080047 # Cross ref the whole cfg object for ease.
48 self.sim_cfg = sim_cfg
49
Srikrishna Iyer65783742021-02-10 21:42:12 -080050 # A list of jobs on which this job depends.
Rupert Swarbrick381770d2020-10-12 08:50:08 +010051 self.dependencies = []
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080052
Cindy Chen924c6062021-01-27 14:27:50 -080053 # Indicates whether running this job requires all dependencies to pass.
54 # If this flag is set to False, any passing dependency will trigger
55 # this current job to run
56 self.needs_all_dependencies_passing = True
57
Srikrishna Iyer65783742021-02-10 21:42:12 -080058 # Declare attributes that need to be extracted from the HJSon cfg.
59 self._define_attrs()
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080060
Srikrishna Iyer65783742021-02-10 21:42:12 -080061 # Set class instance attributes.
62 self._set_attrs()
63
64 # Check if all attributes that are needed are set.
65 self._check_attrs()
66
67 # Do variable substitutions.
68 self._subst_vars()
69
70 # List of vars required to be exported to sub-shell, as a dict.
71 self.exports = self._process_exports()
72
73 # Construct the job's command.
74 self.cmd = self._construct_cmd()
75
76 # Create the launcher object. Launcher retains the handle to self for
77 # lookup & callbacks.
Srikrishna Iyer9d9d86f2021-03-02 00:15:51 -080078 self.launcher = get_launcher(self)
Srikrishna Iyer65783742021-02-10 21:42:12 -080079
80 def _define_attrs(self):
81 """Defines the attributes this instance needs to have.
82
83 These attributes are extracted from the Mode object / HJson config with
84 which this instance is created. There are two types of attributes -
85 one contributes to the generation of the command directly; the other
86 provides supplementary information pertaining to the job, such as
87 patterns that determine whether it passed or failed. These are
88 represented as dicts, whose values indicate in boolean whether the
89 extraction was successful.
90 """
91 # These attributes are explicitly used to construct the job command.
Srikrishna Iyere4662af2020-08-10 13:19:42 -070092 self.mandatory_cmd_attrs = {}
93
Srikrishna Iyer65783742021-02-10 21:42:12 -080094 # These attributes may indirectly contribute to the construction of the
95 # command (through substitution vars) or other things such as pass /
96 # fail patterns.
Srikrishna Iyere4662af2020-08-10 13:19:42 -070097 self.mandatory_misc_attrs = {
Srikrishna Iyer09a81e92019-12-30 10:47:57 -080098 "name": False,
99 "build_mode": False,
100 "flow_makefile": False,
101 "exports": False,
102 "dry_run": False
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700103 }
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800104
Srikrishna Iyer7cf7cad2020-01-08 11:32:53 -0800105 # Function to parse a dict and extract the mandatory cmd and misc attrs.
Srikrishna Iyer65783742021-02-10 21:42:12 -0800106 def _extract_attrs(self, ddict):
107 """Extracts the attributes from the supplied dict.
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800108
Srikrishna Iyer65783742021-02-10 21:42:12 -0800109 'ddict' is typically either the Mode object or the entire config
110 object's dict. It is used to retrieve the instance attributes defined
111 in 'mandatory_cmd_attrs' and 'mandatory_misc_attrs'.
112 """
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800113 ddict_keys = ddict.keys()
114 for key in self.mandatory_cmd_attrs.keys():
Rupert Swarbrick6cc20112020-04-24 09:44:35 +0100115 if self.mandatory_cmd_attrs[key] is False:
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800116 if key in ddict_keys:
117 setattr(self, key, ddict[key])
118 self.mandatory_cmd_attrs[key] = True
119
120 for key in self.mandatory_misc_attrs.keys():
Rupert Swarbrick6cc20112020-04-24 09:44:35 +0100121 if self.mandatory_misc_attrs[key] is False:
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800122 if key in ddict_keys:
123 setattr(self, key, ddict[key])
124 self.mandatory_misc_attrs[key] = True
125
Srikrishna Iyer65783742021-02-10 21:42:12 -0800126 def _set_attrs(self):
127 """Sets additional attributes.
128
129 Invokes '_extract_attrs()' to read in all the necessary instance
130 attributes. Based on those, some additional instance attributes may
131 be derived. Those are set by this method.
132 """
133 self._extract_attrs(self.sim_cfg.__dict__)
134
135 # Output directory where the artifacts go (used by the launcher).
136 self.odir = getattr(self, self.target + "_dir")
137
138 # Qualified name disambiguates the instance name with other instances
139 # of the same class (example: 'uart_smoke' reseeded multiple times
140 # needs to be disambiguated using the index -> '0.uart_smoke'.
141 self.qual_name = self.name
142
143 # Full name disambiguates across multiple cfg being run (example:
144 # 'aes:default', 'uart:default' builds.
145 self.full_name = self.sim_cfg.name + ":" + self.qual_name
146
Srikrishna Iyer956b3f82021-04-15 15:14:56 -0700147 # Job name is used to group the job by cfg and target. The scratch path
148 # directory name is assumed to be uniquified, in case there are more
149 # than one sim_cfgs with the same name.
150 self.job_name = "{}_{}".format(
151 Path(self.sim_cfg.scratch_path).name, self.target)
Srikrishna Iyer9d9d86f2021-03-02 00:15:51 -0800152
Srikrishna Iyer37b0c992021-03-23 16:27:26 -0700153 # Input directories (other than self) this job depends on.
154 self.input_dirs = []
155
156 # Directories touched by this job. These directories are marked
157 # becuase they are used by dependent jobs as input.
158 self.output_dirs = [self.odir]
159
Srikrishna Iyer65783742021-02-10 21:42:12 -0800160 # Pass and fail patterns.
161 self.pass_patterns = []
162 self.fail_patterns = []
163
164 def _check_attrs(self):
165 """Checks if all required class attributes are set.
166
167 Invoked in __init__() after all attributes are extracted and set.
168 """
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800169 for attr in self.mandatory_cmd_attrs.keys():
170 if self.mandatory_cmd_attrs[attr] is False:
Srikrishna Iyer08ccc232021-03-31 00:01:54 -0700171 raise AttributeError("Attribute {!r} not found for "
172 "{!r}.".format(attr, self.name))
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800173
174 for attr in self.mandatory_misc_attrs.keys():
175 if self.mandatory_misc_attrs[attr] is False:
Srikrishna Iyer08ccc232021-03-31 00:01:54 -0700176 raise AttributeError("Attribute {!r} not found for "
177 "{!r}.".format(attr, self.name))
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800178
Srikrishna Iyer65783742021-02-10 21:42:12 -0800179 def _subst_vars(self, ignored_subst_vars=[]):
180 """Recursively search and replace substitution variables.
181
182 First pass: search within self dict. We ignore errors since some
183 substitions may be available in the second pass. Second pass: search
184 the entire sim_cfg object."""
185
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700186 self.__dict__ = find_and_substitute_wildcards(self.__dict__,
Srikrishna Iyer65783742021-02-10 21:42:12 -0800187 self.__dict__,
188 ignored_subst_vars, True)
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700189 self.__dict__ = find_and_substitute_wildcards(self.__dict__,
190 self.sim_cfg.__dict__,
Srikrishna Iyer65783742021-02-10 21:42:12 -0800191 ignored_subst_vars,
192 False)
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800193
Srikrishna Iyer6333b7c2020-10-17 21:14:25 -0700194 def _process_exports(self):
Srikrishna Iyer65783742021-02-10 21:42:12 -0800195 """Convert 'exports' as a list of dicts in the HJson to a dict.
Srikrishna Iyer6333b7c2020-10-17 21:14:25 -0700196
197 Exports is a list of key-value pairs that are to be exported to the
198 subprocess' environment so that the tools can lookup those options.
199 DVSim limits how the data is presented in the HJson (the value of a
200 HJson member cannot be an object). This method converts a list of dicts
201 into a dict variable, which makes it easy to merge the list of exports
202 with the subprocess' env where the ASIC tool is invoked.
Srikrishna Iyer65783742021-02-10 21:42:12 -0800203 """
Srikrishna Iyer6333b7c2020-10-17 21:14:25 -0700204
Srikrishna Iyer65783742021-02-10 21:42:12 -0800205 return {k: str(v) for item in self.exports for k, v in item.items()}
206
207 def _construct_cmd(self):
208 """Construct the command that will eventually be launched."""
209
Srikrishna Iyer9bff8ea2021-04-02 15:14:04 -0700210 cmd = "make -f {} {}".format(self.flow_makefile, self.target)
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800211 if self.dry_run is True:
Srikrishna Iyer9bff8ea2021-04-02 15:14:04 -0700212 cmd += " -n"
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700213 for attr in sorted(self.mandatory_cmd_attrs.keys()):
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800214 value = getattr(self, attr)
215 if type(value) is list:
Srikrishna Iyer6c531b02020-11-23 18:41:16 -0800216 # Join attributes that are list of commands with '&&' to chain
217 # them together when executed as a Make target's recipe.
218 separator = " && " if attr in self.cmds_list_vars else " "
Srikrishna Iyer08ccc232021-03-31 00:01:54 -0700219 value = separator.join(item.strip() for item in value)
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800220 if type(value) is bool:
221 value = int(value)
222 if type(value) is str:
223 value = value.strip()
Srikrishna Iyer9bff8ea2021-04-02 15:14:04 -0700224 cmd += " {}={}".format(attr, shlex.quote(value))
225 return cmd
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800226
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700227 def is_equivalent_job(self, item):
Srikrishna Iyer65783742021-02-10 21:42:12 -0800228 """Checks if job that would be dispatched with 'item' is equivalent to
229 'self'.
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700230
Srikrishna Iyer65783742021-02-10 21:42:12 -0800231 Determines if 'item' and 'self' would behave exactly the same way when
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700232 deployed. If so, then there is no point in keeping both. The caller can
Srikrishna Iyer65783742021-02-10 21:42:12 -0800233 choose to discard 'item' and pick 'self' instead. To do so, we check
234 the final resolved 'cmd' & the exports. The 'name' field will be unique
235 to 'item' and 'self', so we take that out of the comparison.
236 """
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700237 if type(self) != type(item):
238 return False
239
240 # Check if the cmd field is identical.
241 item_cmd = item.cmd.replace(item.name, self.name)
242 if self.cmd != item_cmd:
243 return False
244
245 # Check if exports have identical set of keys.
246 if self.exports.keys() != item.exports.keys():
247 return False
248
249 # Check if exports have identical values.
250 for key, val in self.exports.items():
251 item_val = item.exports[key]
252 if type(item_val) is str:
253 item_val = item_val.replace(item.name, self.name)
254 if val != item_val:
255 return False
256
257 log.log(VERBOSE, "Deploy job \"%s\" is equivalent to \"%s\"",
258 item.name, self.name)
259 return True
260
Srikrishna Iyer65783742021-02-10 21:42:12 -0800261 def pre_launch(self):
262 """Callback to perform additional pre-launch activities.
Srikrishna Iyer6333b7c2020-10-17 21:14:25 -0700263
Srikrishna Iyer65783742021-02-10 21:42:12 -0800264 This is invoked by launcher::_pre_launch().
Srikrishna Iyer2d151192021-02-10 16:56:16 -0800265 """
Srikrishna Iyer65783742021-02-10 21:42:12 -0800266 pass
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800267
Srikrishna Iyer65783742021-02-10 21:42:12 -0800268 def post_finish(self, status):
269 """Callback to perform additional post-finish activities.
Srikrishna Iyer2d151192021-02-10 16:56:16 -0800270
Srikrishna Iyer65783742021-02-10 21:42:12 -0800271 This is invoked by launcher::_post_finish().
Srikrishna Iyer2d151192021-02-10 16:56:16 -0800272 """
Srikrishna Iyer65783742021-02-10 21:42:12 -0800273 pass
Srikrishna Iyer2d151192021-02-10 16:56:16 -0800274
Srikrishna Iyer65783742021-02-10 21:42:12 -0800275 def get_log_path(self):
276 """Returns the log file path."""
Srikrishna Iyer2d151192021-02-10 16:56:16 -0800277
Srikrishna Iyer65783742021-02-10 21:42:12 -0800278 return "{}/{}.log".format(self.odir, self.target)
Weicai Yangfc2ff3b2020-03-19 18:05:14 -0700279
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800280
281class CompileSim(Deploy):
Srikrishna Iyer65783742021-02-10 21:42:12 -0800282 """Abstraction for building the simulation executable."""
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800283
Srikrishna Iyer65783742021-02-10 21:42:12 -0800284 target = "build"
Srikrishna Iyer6c531b02020-11-23 18:41:16 -0800285 cmds_list_vars = ["pre_build_cmds", "post_build_cmds"]
Srikrishna Iyer1d2899f2021-02-11 18:23:15 -0800286 weight = 5
Srikrishna Iyer6c531b02020-11-23 18:41:16 -0800287
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800288 def __init__(self, build_mode, sim_cfg):
Srikrishna Iyer65783742021-02-10 21:42:12 -0800289 self.build_mode_obj = build_mode
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700290 super().__init__(sim_cfg)
291
Srikrishna Iyer65783742021-02-10 21:42:12 -0800292 def _define_attrs(self):
293 super()._define_attrs()
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700294 self.mandatory_cmd_attrs.update({
Srikrishna Iyer8ce80d02020-02-05 10:53:19 -0800295 # tool srcs
Srikrishna Iyer981c36b2020-12-12 12:20:35 -0800296 "proj_root": False,
Srikrishna Iyer8ce80d02020-02-05 10:53:19 -0800297
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800298 # Flist gen
299 "sv_flist_gen_cmd": False,
300 "sv_flist_gen_dir": False,
301 "sv_flist_gen_opts": False,
302
303 # Build
304 "build_dir": False,
Srikrishna Iyer6c531b02020-11-23 18:41:16 -0800305 "pre_build_cmds": False,
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800306 "build_cmd": False,
Srikrishna Iyer6c531b02020-11-23 18:41:16 -0800307 "build_opts": False,
308 "post_build_cmds": False,
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700309 })
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800310
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700311 self.mandatory_misc_attrs.update({
Weicai Yang31029d22020-03-24 11:14:56 -0700312 "cov_db_dir": False,
313 "build_pass_patterns": False,
314 "build_fail_patterns": False
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700315 })
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800316
Srikrishna Iyer65783742021-02-10 21:42:12 -0800317 def _set_attrs(self):
318 super()._extract_attrs(self.build_mode_obj.__dict__)
319 super()._set_attrs()
320
321 # 'build_mode' is used as a substitution variable in the HJson.
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800322 self.build_mode = self.name
Srikrishna Iyer956b3f82021-04-15 15:14:56 -0700323 self.job_name += f"_{self.build_mode}"
Srikrishna Iyer08ccc232021-03-31 00:01:54 -0700324 if self.sim_cfg.cov:
325 self.output_dirs += [self.cov_db_dir]
Weicai Yang31029d22020-03-24 11:14:56 -0700326 self.pass_patterns = self.build_pass_patterns
327 self.fail_patterns = self.build_fail_patterns
Srikrishna Iyer4f0b0902020-01-25 02:28:47 -0800328
Srikrishna Iyer65783742021-02-10 21:42:12 -0800329 def pre_launch(self):
Srikrishna Iyer2d151192021-02-10 16:56:16 -0800330 # Delete old coverage database directories before building again. We
Srikrishna Iyer08ccc232021-03-31 00:01:54 -0700331 # need to do this because the build directory is not 'renewed'.
Srikrishna Iyer2d151192021-02-10 16:56:16 -0800332 rm_path(self.cov_db_dir)
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800333
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800334
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -0800335class CompileOneShot(Deploy):
Srikrishna Iyer65783742021-02-10 21:42:12 -0800336 """Abstraction for building the design (used by non-DV flows)."""
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -0800337
Srikrishna Iyer65783742021-02-10 21:42:12 -0800338 target = "build"
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -0800339
340 def __init__(self, build_mode, sim_cfg):
Srikrishna Iyer65783742021-02-10 21:42:12 -0800341 self.build_mode_obj = build_mode
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700342 super().__init__(sim_cfg)
343
Srikrishna Iyer65783742021-02-10 21:42:12 -0800344 def _define_attrs(self):
345 super()._define_attrs()
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700346 self.mandatory_cmd_attrs.update({
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -0800347 # tool srcs
Srikrishna Iyer981c36b2020-12-12 12:20:35 -0800348 "proj_root": False,
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -0800349
Michael Schaffner3d160992020-03-31 18:37:53 -0700350 # Flist gen
351 "sv_flist_gen_cmd": False,
352 "sv_flist_gen_dir": False,
353 "sv_flist_gen_opts": False,
354
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -0800355 # Build
356 "build_dir": False,
Srikrishna Iyer981c36b2020-12-12 12:20:35 -0800357 "pre_build_cmds": False,
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -0800358 "build_cmd": False,
359 "build_opts": False,
Srikrishna Iyer981c36b2020-12-12 12:20:35 -0800360 "post_build_cmds": False,
Michael Schaffner3d160992020-03-31 18:37:53 -0700361 "build_log": False,
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -0800362
363 # Report processing
364 "report_cmd": False,
365 "report_opts": False
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700366 })
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -0800367
Srikrishna Iyer9bff8ea2021-04-02 15:14:04 -0700368 self.mandatory_misc_attrs.update({"build_fail_patterns": False})
Srikrishna Iyer5b6f9d62021-04-02 02:12:49 -0700369
Srikrishna Iyer65783742021-02-10 21:42:12 -0800370 def _set_attrs(self):
371 super()._extract_attrs(self.build_mode_obj.__dict__)
372 super()._set_attrs()
373
374 # 'build_mode' is used as a substitution variable in the HJson.
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -0800375 self.build_mode = self.name
Srikrishna Iyer956b3f82021-04-15 15:14:56 -0700376 self.job_name += f"_{self.build_mode}"
Srikrishna Iyer5b6f9d62021-04-02 02:12:49 -0700377 self.fail_patterns = self.build_fail_patterns
Michael Schaffner8ac6c4c2020-03-03 15:00:20 -0800378
379
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800380class RunTest(Deploy):
Srikrishna Iyer65783742021-02-10 21:42:12 -0800381 """Abstraction for running tests. This is one per seed for each test."""
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800382
Srikrishna Iyer7cf7cad2020-01-08 11:32:53 -0800383 # Initial seed values when running tests (if available).
Srikrishna Iyer65783742021-02-10 21:42:12 -0800384 target = "run"
Srikrishna Iyer7cf7cad2020-01-08 11:32:53 -0800385 seeds = []
Srikrishna Iyer96e54102020-03-12 22:46:50 -0700386 fixed_seed = None
Srikrishna Iyer6c531b02020-11-23 18:41:16 -0800387 cmds_list_vars = ["pre_run_cmds", "post_run_cmds"]
388
Rupert Swarbrick381770d2020-10-12 08:50:08 +0100389 def __init__(self, index, test, build_job, sim_cfg):
Srikrishna Iyer65783742021-02-10 21:42:12 -0800390 self.test_obj = test
391 self.index = index
392 self.seed = RunTest.get_seed()
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700393 super().__init__(sim_cfg)
394
Srikrishna Iyer65783742021-02-10 21:42:12 -0800395 if build_job is not None:
396 self.dependencies.append(build_job)
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800397
Srikrishna Iyer9d9d86f2021-03-02 00:15:51 -0800398 # We did something wrong if build_mode is not the same as the build_job
399 # arg's name.
400 assert self.build_mode == build_job.name
401
Srikrishna Iyer65783742021-02-10 21:42:12 -0800402 self.launcher.renew_odir = True
403
404 def _define_attrs(self):
405 super()._define_attrs()
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700406 self.mandatory_cmd_attrs.update({
Srikrishna Iyere9879ca2020-11-17 01:34:49 -0800407 # tool srcs
Srikrishna Iyer42d032f2020-03-04 23:55:44 -0800408 "proj_root": False,
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800409 "uvm_test": False,
410 "uvm_test_seq": False,
Srikrishna Iyerde5efa02020-11-20 23:17:11 -0800411 "sw_images": False,
Srikrishna Iyer7702be52020-03-07 01:00:28 -0800412 "sw_build_device": False,
413 "sw_build_dir": False,
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800414 "run_dir": False,
Srikrishna Iyer6c531b02020-11-23 18:41:16 -0800415 "pre_run_cmds": False,
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800416 "run_cmd": False,
Srikrishna Iyer6c531b02020-11-23 18:41:16 -0800417 "run_opts": False,
418 "post_run_cmds": False,
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700419 })
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800420
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700421 self.mandatory_misc_attrs.update({
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800422 "run_dir_name": False,
Srikrishna Iyer1f5fae92021-02-18 21:57:25 -0800423 "cov_db_dir": False,
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800424 "cov_db_test_dir": False,
Weicai Yang31029d22020-03-24 11:14:56 -0700425 "run_pass_patterns": False,
426 "run_fail_patterns": False
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700427 })
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800428
Srikrishna Iyer65783742021-02-10 21:42:12 -0800429 def _set_attrs(self):
430 super()._extract_attrs(self.test_obj.__dict__)
431 super()._set_attrs()
Rupert Swarbrick381770d2020-10-12 08:50:08 +0100432
Srikrishna Iyer65783742021-02-10 21:42:12 -0800433 # 'test' is used as a substitution variable in the HJson.
Srikrishna Iyer09a81e92019-12-30 10:47:57 -0800434 self.test = self.name
Srikrishna Iyer65783742021-02-10 21:42:12 -0800435 self.build_mode = self.test_obj.build_mode.name
436 self.qual_name = self.run_dir_name + "." + str(self.seed)
437 self.full_name = self.sim_cfg.name + ":" + self.qual_name
Srikrishna Iyer956b3f82021-04-15 15:14:56 -0700438 self.job_name += f"_{self.build_mode}"
Srikrishna Iyer08ccc232021-03-31 00:01:54 -0700439 if self.sim_cfg.cov:
Cindy Chend5977582021-06-05 12:49:10 -0700440 self.output_dirs += [self.cov_db_dir]
Srikrishna Iyerd37d10d2021-03-25 18:35:36 -0700441
442 # In GUI mode, the log file is not updated; hence, nothing to check.
443 if not self.sim_cfg.gui:
444 self.pass_patterns = self.run_pass_patterns
445 self.fail_patterns = self.run_fail_patterns
Srikrishna Iyer4f0b0902020-01-25 02:28:47 -0800446
Srikrishna Iyer65783742021-02-10 21:42:12 -0800447 def post_finish(self, status):
Rupert Swarbricka2892a52020-10-12 08:50:08 +0100448 if status != 'P':
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800449 # Delete the coverage data if available.
Srikrishna Iyer2d151192021-02-10 16:56:16 -0800450 rm_path(self.cov_db_test_dir)
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800451
Srikrishna Iyer7cf7cad2020-01-08 11:32:53 -0800452 @staticmethod
453 def get_seed():
Srikrishna Iyer96e54102020-03-12 22:46:50 -0700454 # If --seeds option is passed, then those custom seeds are consumed
455 # first. If --fixed-seed <val> is also passed, the subsequent tests
456 # (once the custom seeds are consumed) will be run with the fixed seed.
Philipp Wagner9a521782020-02-25 11:49:53 +0000457 if not RunTest.seeds:
Rupert Swarbrick6cc20112020-04-24 09:44:35 +0100458 if RunTest.fixed_seed:
459 return RunTest.fixed_seed
Srikrishna Iyera821bbc2020-01-31 00:28:02 -0800460 for i in range(1000):
Philipp Wagner75fd6c72020-02-25 11:47:41 +0000461 seed = random.getrandbits(32)
Srikrishna Iyera821bbc2020-01-31 00:28:02 -0800462 RunTest.seeds.append(seed)
Srikrishna Iyer7cf7cad2020-01-08 11:32:53 -0800463 return RunTest.seeds.pop(0)
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800464
465
Weicai Yang080632d2020-10-16 17:52:14 -0700466class CovUnr(Deploy):
Srikrishna Iyer65783742021-02-10 21:42:12 -0800467 """Abstraction for coverage UNR flow."""
Weicai Yang080632d2020-10-16 17:52:14 -0700468
Srikrishna Iyer65783742021-02-10 21:42:12 -0800469 target = "cov_unr"
Weicai Yang080632d2020-10-16 17:52:14 -0700470
471 def __init__(self, sim_cfg):
Weicai Yang080632d2020-10-16 17:52:14 -0700472 super().__init__(sim_cfg)
473
Srikrishna Iyer65783742021-02-10 21:42:12 -0800474 def _define_attrs(self):
475 super()._define_attrs()
Weicai Yang080632d2020-10-16 17:52:14 -0700476 self.mandatory_cmd_attrs.update({
477 # tool srcs
Srikrishna Iyer981c36b2020-12-12 12:20:35 -0800478 "proj_root": False,
Weicai Yang080632d2020-10-16 17:52:14 -0700479
480 # Need to generate filelist based on build mode
481 "sv_flist_gen_cmd": False,
482 "sv_flist_gen_dir": False,
483 "sv_flist_gen_opts": False,
484 "build_dir": False,
485 "cov_unr_build_cmd": False,
486 "cov_unr_build_opts": False,
487 "cov_unr_run_cmd": False,
488 "cov_unr_run_opts": False
489 })
490
491 self.mandatory_misc_attrs.update({
492 "cov_unr_dir": False,
Srikrishna Iyer8e21e512021-04-02 01:55:47 -0700493 "cov_merge_db_dir": False,
Weicai Yang080632d2020-10-16 17:52:14 -0700494 "build_fail_patterns": False
495 })
496
Srikrishna Iyer65783742021-02-10 21:42:12 -0800497 def _set_attrs(self):
498 super()._set_attrs()
499 self.qual_name = self.target
500 self.full_name = self.sim_cfg.name + ":" + self.qual_name
Srikrishna Iyer8e21e512021-04-02 01:55:47 -0700501 self.input_dirs += [self.cov_merge_db_dir]
Weicai Yang080632d2020-10-16 17:52:14 -0700502
Srikrishna Iyer65783742021-02-10 21:42:12 -0800503 # Reuse the build_fail_patterns set in the HJson.
Weicai Yang080632d2020-10-16 17:52:14 -0700504 self.fail_patterns = self.build_fail_patterns
505
Weicai Yang080632d2020-10-16 17:52:14 -0700506
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800507class CovMerge(Deploy):
Srikrishna Iyer65783742021-02-10 21:42:12 -0800508 """Abstraction for merging coverage databases."""
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800509
Srikrishna Iyer65783742021-02-10 21:42:12 -0800510 target = "cov_merge"
Srikrishna Iyer1d2899f2021-02-11 18:23:15 -0800511 weight = 10
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800512
Rupert Swarbrickf2bf3702020-10-12 17:04:46 +0100513 def __init__(self, run_items, sim_cfg):
Srikrishna Iyer65783742021-02-10 21:42:12 -0800514 # Construct the cov_db_dirs right away from the run_items. This is a
515 # special variable used in the HJson.
516 self.cov_db_dirs = []
517 for run in run_items:
518 if run.cov_db_dir not in self.cov_db_dirs:
519 self.cov_db_dirs.append(run.cov_db_dir)
520
Srikrishna Iyercaa0d892021-03-01 13:15:52 -0800521 # Early lookup the cov_merge_db_dir, which is a mandatory misc
522 # attribute anyway. We need it to compute additional cov db dirs.
523 self.cov_merge_db_dir = subst_wildcards("{cov_merge_db_dir}",
524 sim_cfg.__dict__)
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700525
Srikrishna Iyercaa0d892021-03-01 13:15:52 -0800526 # Prune previous merged cov directories, keeping past 7 dbs.
527 prev_cov_db_dirs = clean_odirs(odir=self.cov_merge_db_dir, max_odirs=7)
528
529 # If the --cov-merge-previous command line switch is passed, then
530 # merge coverage with the previous runs.
531 if sim_cfg.cov_merge_previous:
532 self.cov_db_dirs += [str(item) for item in prev_cov_db_dirs]
533
534 super().__init__(sim_cfg)
Rupert Swarbrickf2bf3702020-10-12 17:04:46 +0100535 self.dependencies += run_items
Srikrishna Iyer65783742021-02-10 21:42:12 -0800536 # Run coverage merge even if one test passes.
Cindy Chen924c6062021-01-27 14:27:50 -0800537 self.needs_all_dependencies_passing = False
Rupert Swarbrickf2bf3702020-10-12 17:04:46 +0100538
Srikrishna Iyer65783742021-02-10 21:42:12 -0800539 # Append cov_db_dirs to the list of exports.
Srikrishna Iyer37b0c992021-03-23 16:27:26 -0700540 self.exports["cov_db_dirs"] = shlex.quote(" ".join(self.cov_db_dirs))
Srikrishna Iyer65783742021-02-10 21:42:12 -0800541
542 def _define_attrs(self):
543 super()._define_attrs()
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700544 self.mandatory_cmd_attrs.update({
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800545 "cov_merge_cmd": False,
546 "cov_merge_opts": False
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700547 })
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800548
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700549 self.mandatory_misc_attrs.update({
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800550 "cov_merge_dir": False,
551 "cov_merge_db_dir": False
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700552 })
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800553
Srikrishna Iyer65783742021-02-10 21:42:12 -0800554 def _set_attrs(self):
555 super()._set_attrs()
556 self.qual_name = self.target
557 self.full_name = self.sim_cfg.name + ":" + self.qual_name
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800558
Srikrishna Iyer65783742021-02-10 21:42:12 -0800559 # For merging coverage db, the precise output dir is set in the HJson.
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800560 self.odir = self.cov_merge_db_dir
Srikrishna Iyer37b0c992021-03-23 16:27:26 -0700561 self.input_dirs += self.cov_db_dirs
Srikrishna Iyer08ccc232021-03-31 00:01:54 -0700562 self.output_dirs = [self.odir]
Srikrishna Iyer37b0c992021-03-23 16:27:26 -0700563
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800564
565class CovReport(Deploy):
Srikrishna Iyer65783742021-02-10 21:42:12 -0800566 """Abstraction for coverage report generation. """
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800567
Srikrishna Iyer65783742021-02-10 21:42:12 -0800568 target = "cov_report"
Srikrishna Iyer1d2899f2021-02-11 18:23:15 -0800569 weight = 10
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800570
Rupert Swarbrick381770d2020-10-12 08:50:08 +0100571 def __init__(self, merge_job, sim_cfg):
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700572 super().__init__(sim_cfg)
Rupert Swarbrick381770d2020-10-12 08:50:08 +0100573 self.dependencies.append(merge_job)
574
Srikrishna Iyer65783742021-02-10 21:42:12 -0800575 def _define_attrs(self):
576 super()._define_attrs()
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700577 self.mandatory_cmd_attrs.update({
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800578 "cov_report_cmd": False,
579 "cov_report_opts": False
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700580 })
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800581
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700582 self.mandatory_misc_attrs.update({
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800583 "cov_report_dir": False,
584 "cov_merge_db_dir": False,
Srikrishna Iyer39ffebd2020-03-30 11:53:12 -0700585 "cov_report_txt": False
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700586 })
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800587
Srikrishna Iyer65783742021-02-10 21:42:12 -0800588 def _set_attrs(self):
589 super()._set_attrs()
590 self.qual_name = self.target
591 self.full_name = self.sim_cfg.name + ":" + self.qual_name
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800592
Srikrishna Iyer65783742021-02-10 21:42:12 -0800593 # Keep track of coverage results, once the job is finished.
594 self.cov_total = ""
595 self.cov_results = ""
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800596
Srikrishna Iyer65783742021-02-10 21:42:12 -0800597 def post_finish(self, status):
598 """Extract the coverage results summary for the dashboard.
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800599
Srikrishna Iyer65783742021-02-10 21:42:12 -0800600 If that fails for some reason, report the job as a failure.
601 """
602
603 if self.dry_run or status != 'P':
604 return
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800605
Rupert Swarbricka2892a52020-10-12 08:50:08 +0100606 results, self.cov_total, ex_msg = get_cov_summary_table(
607 self.cov_report_txt, self.sim_cfg.tool)
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800608
Rupert Swarbricka2892a52020-10-12 08:50:08 +0100609 if ex_msg:
Srikrishna Iyer65783742021-02-10 21:42:12 -0800610 self.launcher.fail_msg += ex_msg
Rupert Swarbricka2892a52020-10-12 08:50:08 +0100611 log.error(ex_msg)
Srikrishna Iyer65783742021-02-10 21:42:12 -0800612 return
Rupert Swarbricka2892a52020-10-12 08:50:08 +0100613
614 # Succeeded in obtaining the coverage data.
615 colalign = (("center", ) * len(results[0]))
616 self.cov_results = tabulate(results,
617 headers="firstrow",
618 tablefmt="pipe",
619 colalign=colalign)
620
621 # Delete the cov report - not needed.
Srikrishna Iyer65783742021-02-10 21:42:12 -0800622 rm_path(self.get_log_path())
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800623
624
625class CovAnalyze(Deploy):
Srikrishna Iyer65783742021-02-10 21:42:12 -0800626 """Abstraction for running the coverage analysis tool."""
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800627
Srikrishna Iyer65783742021-02-10 21:42:12 -0800628 target = "cov_analyze"
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800629
630 def __init__(self, sim_cfg):
Srikrishna Iyer8e21e512021-04-02 01:55:47 -0700631 # Enforce GUI mode for coverage analysis.
632 sim_cfg.gui = True
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700633 super().__init__(sim_cfg)
634
Srikrishna Iyer65783742021-02-10 21:42:12 -0800635 def _define_attrs(self):
636 super()._define_attrs()
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700637 self.mandatory_cmd_attrs.update({
Srikrishna Iyer39ffebd2020-03-30 11:53:12 -0700638 # tool srcs
Srikrishna Iyer981c36b2020-12-12 12:20:35 -0800639 "proj_root": False,
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800640 "cov_analyze_cmd": False,
641 "cov_analyze_opts": False
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700642 })
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800643
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700644 self.mandatory_misc_attrs.update({
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800645 "cov_analyze_dir": False,
646 "cov_merge_db_dir": False
Srikrishna Iyere4662af2020-08-10 13:19:42 -0700647 })
Srikrishna Iyer2a710a42020-02-10 10:39:15 -0800648
Srikrishna Iyer65783742021-02-10 21:42:12 -0800649 def _set_attrs(self):
650 super()._set_attrs()
651 self.qual_name = self.target
652 self.full_name = self.sim_cfg.name + ":" + self.qual_name
Srikrishna Iyer8e21e512021-04-02 01:55:47 -0700653 self.input_dirs += [self.cov_merge_db_dir]