Skip to content
This repository has been archived by the owner on Apr 7, 2022. It is now read-only.

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
zigen committed Dec 30, 2021
1 parent 470c21d commit 274e4f3
Show file tree
Hide file tree
Showing 14 changed files with 146 additions and 77 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
old/
results/
*.pickle
*.pkl

# OMNeT++
.cmdenv-log
.qtenvrc
Expand Down
65 changes: 19 additions & 46 deletions quisp_run/commands/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from quisp_run.workers import Executor, Writer, job_display
from quisp_run.config import parse_config

from quisp_run.utils import console
from quisp_run.utils import console, error_console


@click.command()
Expand All @@ -22,70 +22,43 @@
default="./modules:./channels:./networks",
help="colon separated path list to NED files",
)
@click.option(
"--config-file", "-c", default="./benchmark.ini", help="configuration file to use"
)
@click.option(
"--sim-name",
"-s",
default=None,
help="configuration name to run",
)
@click.option("--quisp-root", "-r", default="../quisp", help="QuISP root directory")
@click.option(
"--dryrun",
"-d",
is_flag=True,
default=False,
help="dry run, show the command without running QuISP",
)
def run(ui, ned_path, config_file, sim_name, quisp_root, dryrun):
def run(ui, ned_path, quisp_root):
if not os.path.exists(quisp_root):
print(f"quisp_root: {quisp_root} not found", file=sys.stderr)
error_console.print(f"quisp_root: {quisp_root} not found")
exit(1)

quisp_workdir = os.path.join(quisp_root, "quisp")
exe_path = "./quisp"

if not os.path.exists(os.path.join(quisp_root, exe_path)):
print(f"quisp executable not found", file=sys.stderr)
error_console.print(f"quisp executable not found")
exit(1)

config_file = os.path.abspath(os.path.join(os.getcwd(), config_file))
asyncio.run(start_simulations(exe_path, ui, ned_path, quisp_workdir))

# add config dir to ned path
ned_path += ":" + os.path.abspath(os.path.join(os.getcwd(), "config/topology"))

asyncio.run(
start_simulations(
exe_path, ui, config_file, sim_name, ned_path, [], dryrun, quisp_workdir
)
)


async def start_simulations(
exe_path, ui, config_file, sim_name, ned_path, opts, dryrun, quisp_workdir
):
# if dryrun:
# print(cmd.to_str())
# exit(0)

async def start_simulations(exe_path, ui, ned_path, quisp_workdir):
console.print(f"Working dir: {quisp_workdir}")
pool_size = 8
sim_settings: List[SimSetting] = []
plan = None

# populate simulation settings from simulation plan
with open("simulation.plan", "r") as f:
source = f.read()
plan = parse_config(source)
sim_settings = plan.populate()
plan.populate()
plan.create_result_dir()
plan.write_config()
ned_path += ":" + plan.ned_path
sim_context = SimContext(exe_path, ui, ned_path, quisp_workdir, pool_size, plan)

sim_context = SimContext(
exe_path, ui, ned_path, quisp_workdir, pool_size, sim_settings
)

workers = [Executor(i, sim_context) for i in range(pool_size)]
worker_tasks = [asyncio.create_task(worker.run()) for worker in workers]
display_task = asyncio.create_task(job_display(workers, sim_context, console))
# setup workers
executors = [Executor(i, sim_context) for i in range(pool_size)]
worker_tasks = [asyncio.create_task(worker.run()) for worker in executors]
display_task = asyncio.create_task(job_display(executors, sim_context, console))
writer = Writer(sim_context)
writer_task = asyncio.create_task(writer.run())

# run workers
await asyncio.gather(display_task, writer_task, *worker_tasks)
30 changes: 17 additions & 13 deletions quisp_run/config/parser.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
import sys
from quisp_run.simulation import SimPlan, new_config_vars
from quisp_run.utils import console, error_console

CONFIG_EVAL_ENV_GLOBALS = {
"__builtins__": {
"range": range,
"list": list,
"filter": filter,
"map": map,
}
}


def parse_config(plan_source: str) -> SimPlan:
config_vars = new_config_vars()
try:
exec(
plan_source,
{
"__builtins__": {
"range": range,
"list": list,
"filter": filter,
"map": map,
}
},
CONFIG_EVAL_ENV_GLOBALS,
config_vars,
)
except IndentationError as e:
print(e, file=sys.stderr)
config_vars["error"] = e

except Exception as e:
print("Unexpected error:", e, file=sys.stderr)
error_console.print("\n[red]Failed to parse the config file")
error_console.print_exception(max_frames=0)
config_vars["error"] = e
exit(1)

# console.print(config_vars)

plan = SimPlan(config_vars)
return plan
4 changes: 4 additions & 0 deletions quisp_run/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
from rich.theme import Theme

QUISP_RUN_ROOT_DIR = os.path.dirname(os.path.abspath(os.path.dirname(__file__)))
QUISP_TEMPALTE_OMNETPP_INI = os.path.join(
QUISP_RUN_ROOT_DIR, "templates", "omnetpp.ini"
)
QUISP_TEMPALTE_TOPOLOGY_DIR = os.path.join(QUISP_RUN_ROOT_DIR, "templates", "topology")

DEFAULT_RICH_CONSOLE_THEME = Theme(
{
Expand Down
21 changes: 18 additions & 3 deletions quisp_run/simulation/context.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import asyncio
from typing import TYPE_CHECKING
from rich.live import Live
from enum import Enum
from typing import Optional, List
from .setting import SimSetting
from .result import Result

if TYPE_CHECKING:
from .plan import SimPlan


class OmnetppEnv(Enum):
Cmdenv = "Cmdenv"
Expand All @@ -21,6 +26,7 @@ class SimContext:
simulations: asyncio.Queue[Optional[SimSetting]]
results: asyncio.Queue[Optional[Result]]
done: asyncio.Queue[None]
live: Optional[Live]

def __init__(
self,
Expand All @@ -29,19 +35,28 @@ def __init__(
ned_path: str,
working_dir: str,
pool_size: int,
simulations: List[SimSetting],
plan: "SimPlan",
):
self.exe_path = exe_path
self.ui = ui
self.ned_path = ned_path
self.working_dir = working_dir
self.pool_size = pool_size
num_simulations = len(simulations)
num_simulations = len(plan.settings)
self.simulations = asyncio.Queue(num_simulations + pool_size)
for setting in simulations:
for setting in plan.settings:
self.simulations.put_nowait(setting)
setting.context = self
for _ in range(pool_size):
self.simulations.put_nowait(None)
self.results = asyncio.Queue(num_simulations)
self.done = asyncio.Queue(num_simulations)
self.live = None

def log(self, *args, **kwargs):
if self.live is not None:
self.live.console.log(*args, **kwargs)

def print(self, *args, **kwargs):
if self.live is not None:
self.live.console.print(*args, **kwargs)
45 changes: 44 additions & 1 deletion quisp_run/simulation/plan.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
from typing import List, Optional, TypedDict, Dict
import itertools
import itertools, os, time, shutil
from quisp_run.simulation import SimSetting
from quisp_run.constants import (
QUISP_RUN_ROOT_DIR,
QUISP_TEMPALTE_OMNETPP_INI,
QUISP_TEMPALTE_TOPOLOGY_DIR,
)

DEFAULT_SIM_TARGET_PARAMETERS: List[str] = [
"num_bufs",
Expand All @@ -9,6 +14,7 @@
"connection_types",
"config_ini_file",
]

DEFAULT_SETTING_KEY_DICT: Dict[str, str] = {
"num_bufs": "num_buf",
"num_nodes": "num_node",
Expand All @@ -31,6 +37,9 @@ class ConfigVars(TypedDict):

class SimPlan:
config_vars: ConfigVars
settings: List[SimSetting] = []
result_dir: str = ""
ned_path: str = ""

def __init__(self, config_vars: ConfigVars):
self.config_vars = config_vars
Expand All @@ -56,8 +65,42 @@ def populate(self) -> List[SimSetting]:
assert len(params) == len(keys)
setting_keys = [self.config_vars["setting_key_dict"][k] for k in keys]
settings.append(SimSetting(**dict(zip(setting_keys, params))))
self.settings = settings
return settings

def generate_ini_config(self) -> str:
return ""

def create_result_dir(self):
root = os.path.join(QUISP_RUN_ROOT_DIR, "results")
result_dir = os.path.join(root, self.get_result_dir_name())
os.makedirs(result_dir)
self.result_dir = result_dir
shutil.copy(QUISP_TEMPALTE_OMNETPP_INI, os.path.join(result_dir, "omnetpp.ini"))
topology_path = os.path.join(result_dir, "topology")
shutil.copytree(QUISP_TEMPALTE_TOPOLOGY_DIR, topology_path)
self.ned_path = topology_path

def write_config(self):
assert (
self.result_dir != ""
), "SimPlan.result_dir is empty, call SimPlan.create_result_dir() first"
config_file_path = os.path.join(self.result_dir, "omnetpp.ini")
with open(config_file_path, "a") as f:
for setting in self.settings:
setting.config_ini_file = config_file_path
config_str = setting.generate_config()
f.write(f"[Config {setting.sim_name}]\n")
f.write(config_str)
f.write("\n\n")

def get_result_dir_name(self) -> str:
return (
time.strftime("%Y-%m-%d_%H-%M-%S")
+ "-"
+ self.config_vars["title"].replace(" ", "_").replace("/", "_")
)


def new_config_vars():
return ConfigVars(
Expand Down
3 changes: 3 additions & 0 deletions quisp_run/simulation/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ def to_dict(self) -> Dict:
"real": self.real_time_str,
"error": self.error_message,
}

def to_log_str(self) -> str:
return f"{self.setting.sim_name} {self.num_total_events} events, {self.final_events_per_sec} ev/s"
31 changes: 25 additions & 6 deletions quisp_run/simulation/setting.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,47 @@ class SimSetting:
def to_command_list(self) -> List[str]:
assert self.context is not None, "SimSetting.context is None"

opt_str = "--**.buffers={} ".format(self.num_buf)
opt_str += "--network=topology.{}_network ".format(self.network_type)
# opt_str += "--{}_network.connectionType=\"{}\" ".format(self.network_type, self.connection_type)

cmd = [
self.context.exe_path,
"-u",
self.context.ui,
replace_path_placeholder(self.config_ini_file),
"-c",
self.sim_name,
"-n",
self.context.ned_path,
opt_str,
]
return cmd

def generate_config(self) -> str:
config_str = ""
config_str += "network=topology.{}_network\n".format(self.network_type)
config_str += "**.buffers={}\n".format(self.num_buf)
config_str += '{}_network.connectionType="{}"\n'.format(
self.network_type, self.connection_type
)

traffic_pattern_index: int = 1
num_purification: int = 1
lone_initiator_addr: int = 0
link_tomography_enabled: bool = False
purification_type: str = "1001"
config_str += "**.app.TrafficPattern={}\n".format(traffic_pattern_index)
config_str += "**.app.LoneInitiatorAddress={}\n".format(lone_initiator_addr)
config_str += "**.qrsa.hm.link_tomography={}\n".format(
str(link_tomography_enabled).lower()
)
config_str += "**.qrsa.hm.initial_purification={}\n".format(num_purification)
config_str += "**.qrsa.hm.Purification_type={}\n".format(purification_type)
return config_str

@property
def config_name(self) -> str:
return "{}{}_mm_pur_es".format(self.network_type, self.num_node)

@property
def sim_name(self) -> str:
return f"{self.config_name}-buf{self.num_buf}"
return f"buf{self.num_buf}-nodes-{self.num_node}-{self.network_type}-{self.connection_type}-"

def to_command_str(self) -> str:
return " ".join(self.to_command_list())
Expand Down
2 changes: 2 additions & 0 deletions quisp_run/utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from sys import stderr
from rich.console import Console
from quisp_run.constants import QUISP_RUN_ROOT_DIR, DEFAULT_RICH_CONSOLE_THEME

Expand All @@ -12,3 +13,4 @@ def replace_path_placeholder(path_str: str) -> str:


console = Console(theme=DEFAULT_RICH_CONSOLE_THEME)
error_console = Console(theme=DEFAULT_RICH_CONSOLE_THEME, stderr=True)
3 changes: 1 addition & 2 deletions quisp_run/workers/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ async def run(self):

await self.switch_simulation(setting)
cmd_list = setting.to_command_list()
self.console.log(cmd_list)
await self.run_quisp(cmd_list)
result = self.get_result()
await ctx.results.put(result)
Expand Down Expand Up @@ -155,7 +154,7 @@ async def run_quisp(self, cmd: List[str]):
elif buf.startswith("user"):
self.user_time_str = buf.split("\t")[1]
elif buf:
print("Err: ", buf)
self.context.log("[red]Err: ", buf)
self.error_messages += buf + "\n"
await self.set_status(WorkerStatus.ERROR)
await asyncio.sleep(1)
Expand Down
Loading

0 comments on commit 274e4f3

Please sign in to comment.