Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions src/dvsim/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from dvsim.job.deploy import RunTest
from dvsim.launcher.base import Launcher
from dvsim.launcher.factory import set_launcher_type
from dvsim.launcher.fake import FakeLauncher
from dvsim.launcher.local import LocalLauncher
from dvsim.launcher.lsf import LsfLauncher
from dvsim.launcher.nc import NcLauncher
Expand Down Expand Up @@ -785,6 +786,12 @@ def parse_args():
help=("Print dvsim tool messages but don't actually run any command"),
)

dvg.add_argument(
"--fake",
action="store_true",
help=("Use a fake launcher that generates random results"),
)

args = parser.parse_args()

if args.version:
Expand Down Expand Up @@ -843,7 +850,7 @@ def main() -> None:
args.cfg = os.path.join(proj_root, cfg_path)

# Add timestamp to args that all downstream objects can use.
curr_ts = datetime.datetime.utcnow()
curr_ts = datetime.datetime.now(datetime.UTC)
args.timestamp_long = curr_ts.strftime(TS_FORMAT_LONG)
args.timestamp = curr_ts.strftime(TS_FORMAT)

Expand All @@ -863,11 +870,11 @@ def main() -> None:
LsfLauncher.max_parallel = args.max_parallel
NcLauncher.max_parallel = args.max_parallel
Launcher.max_odirs = args.max_odirs
set_launcher_type(args.local)
FakeLauncher.max_parallel = args.max_parallel
set_launcher_type(is_local=args.local, fake=args.fake)

# Build infrastructure from hjson file and create the list of items to
# be deployed.
global cfg
cfg = make_cfg(args.cfg, args, proj_root)

# List items available for run if --list switch is passed, and exit.
Expand Down
10 changes: 5 additions & 5 deletions src/dvsim/flow/sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,7 @@ def create_bucket_report(buckets):
return fail_msgs

deployed_items = self.deploy
results = SimResults(deployed_items, results)
sim_results = SimResults(deployed_items, results)

# Generate results table for runs.
results_str = "## " + self.results_title + "\n"
Expand Down Expand Up @@ -857,13 +857,13 @@ def create_bucket_report(buckets):
if self.build_seed and not self.run_only:
results_str += f"### Build randomization enabled with --build-seed {self.build_seed}\n"

if not results.table:
if not sim_results.table:
results_str += "No results to display.\n"

else:
# Map regr results to the testplan entries.
if not self.testplan.test_results_mapped:
self.testplan.map_test_results(test_results=results.table)
self.testplan.map_test_results(test_results=sim_results.table)

results_str += self.testplan.get_test_results_table(
map_full_testplan=self.map_full_testplan,
Expand All @@ -889,9 +889,9 @@ def create_bucket_report(buckets):
else:
self.results_summary["Coverage"] = "--"

if results.buckets:
if sim_results.buckets:
self.errors_seen = True
results_str += "\n".join(create_bucket_report(results.buckets))
results_str += "\n".join(create_bucket_report(sim_results.buckets))

self.results_md = results_str
return results_str
Expand Down
8 changes: 7 additions & 1 deletion src/dvsim/launcher/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import os

from dvsim.launcher.base import Launcher
from dvsim.launcher.fake import FakeLauncher
from dvsim.launcher.local import LocalLauncher
from dvsim.launcher.lsf import LsfLauncher
from dvsim.launcher.nc import NcLauncher
Expand All @@ -23,7 +24,7 @@
_LAUNCHER_CLS: type[Launcher] | None = None


def set_launcher_type(is_local: bool = False) -> None:
def set_launcher_type(is_local: bool = False, fake: bool = False) -> None:
"""Set the launcher type that will be used to launch the jobs.

The env variable `DVSIM_LAUNCHER` is used to identify what launcher system
Expand All @@ -35,6 +36,8 @@ def set_launcher_type(is_local: bool = False) -> None:
launcher = os.environ.get("DVSIM_LAUNCHER", "local")
if is_local:
launcher = "local"
if fake:
launcher = "fake"
Launcher.variant = launcher

global _LAUNCHER_CLS
Expand All @@ -53,6 +56,9 @@ def set_launcher_type(is_local: bool = False) -> None:
elif launcher == "slurm":
_LAUNCHER_CLS = SlurmLauncher

elif launcher == "fake":
_LAUNCHER_CLS = FakeLauncher

# These custom launchers are site specific. They may not be committed to
# the open source repo.
elif launcher == "edacloud" and EDACLOUD_LAUNCHER_EXISTS:
Expand Down
72 changes: 72 additions & 0 deletions src/dvsim/launcher/fake.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Copyright lowRISC contributors (OpenTitan project).
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0

"""Fake Launcher that returns random results."""

from random import choice, random
from typing import TYPE_CHECKING

from dvsim.launcher.base import ErrorMessage, Launcher

if TYPE_CHECKING:
from dvsim.job.deploy import CovReport, Deploy, RunTest


def _run_test_handler(deploy: "RunTest") -> str:
"""Handle a RunTest deploy job."""
return choice(("P", "F"))


def _cov_report_handler(deploy: "CovReport") -> str:
"""Handle a CompileSim deploy job."""
keys = [
"score",
"line",
"cond",
"toggle",
"fsm",
"branch",
"assert",
"group",
]

deploy.cov_results_dict = {k: f"{random() * 100:.2f} %" for k in keys}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine provided that you never need to recreate a run otherwise the RNG will need seeding

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, in this case I don't think we need to reproduce the results. The random side is just to get some fake data for the report templates while working on those. Specifically test the colourisation with different percentages.

In the future if there are other use cases for this we could add more configuration options. One of those might be seeding the randomness, perhaps also setting the type of randomness.


return "P"


_DEPLOY_HANDLER = {
"RunTest": _run_test_handler,
"CovReport": _cov_report_handler,
}


class FakeLauncher(Launcher):
"""Launch jobs and return fake results."""

# Poll job's completion status every this many seconds
poll_freq = 0
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I presume that this is used elsewhere and that 0 is correctly interpreted as "Don't poll"

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used by the scheduler for the sleep duration between polling. It looks like it's used to rate limit the "are you done yet" polling. This is useful where a launcher is submitting a job to a grid engine for example, where polling an external API with no wait period would lock the system up.

This fake launcher only returns a job completion status. Setting this to 0 means the scheduler will not wait before asking the launcher again about status, as it will be the next set of jobs it asks about and there is no value in waiting between jobs.


def __init__(self, deploy: "Deploy") -> None:
"""Initialize common class members."""
super().__init__(deploy)

def _do_launch(self) -> None:
"""Do the launch."""

def poll(self) -> str | None:
"""Check status of the running process."""
deploy_cls = self.deploy.__class__.__name__
if deploy_cls in _DEPLOY_HANDLER:
return _DEPLOY_HANDLER[deploy_cls](deploy=self.deploy)

# Default result is Pass
return "P"

def kill(self) -> None:
"""Kill the running process."""
self._post_finish(
"K",
ErrorMessage(line_number=None, message="Job killed!", context=[]),
)
Loading