def apply(self, actions: SimulatorAction): self.writer.write_action_result(self.env, actions) # increase performance when debug logging is disabled if logger.isEnabledFor(logging.DEBUG): logger.debug(f"SimulatorAction: %s", repr(actions)) # Get the new placement from the action passed by the RL agent # Modify and set the placement parameter of the instantiated simulator object. self.simulator.params.sf_placement = actions.placement # Update which sf is available at which node for node_id, placed_sf_list in actions.placement.items(): available = {} # Keep only SFs which still process for sf, sf_data in self.simulator.params.network.nodes[node_id][ 'available_sf'].items(): if sf_data['load'] != 0: available[sf] = sf_data # Add all SFs which are in the placement for sf in placed_sf_list: available[sf] = available.get(sf, {'load': 0.0}) self.simulator.params.network.nodes[node_id][ 'available_sf'] = available # Get the new schedule from the SimulatorAction # Set it in the params of the instantiated simulator object. self.simulator.params.schedule = actions.scheduling # reset metrics for steps metrics.reset_run() # Run the simulation again with the new params for the set duration. # Due to SimPy restraints, we multiply the duration by the run times because SimPy does not reset when run() # stops and we must increase the value of "until=" to accomodate for this. e.g.: 1st run call runs for 100 time # uniits (1 run time), 2nd run call will also run for 100 more time units but value of "until=" is now 200. runtime_steps = self.duration * self.run_times logger.debug("Running simulator until time step %s", runtime_steps) self.env.run(until=runtime_steps) # Parse the NetworkX object into a dict format specified in SimulatorState. This is done to account # for changing node remaining capacities. # Also, parse the network stats and prepare it in SimulatorState format. self.parse_network() self.network_metrics() # Increment the run times variable self.run_times += 1 # Record end time of the apply round, doesn't change start time to show the running time of the entire # simulation at the end of the simulation. self.end_time = time.time() metrics.running_time(self.start_time, self.end_time) # Create a new SimulatorState object to pass to the RL Agent simulator_state = SimulatorState(self.network_dict, self.simulator.params.sf_placement, self.sfc_list, self.sf_list, self.traffic, self.network_stats) self.writer.write_state_results(self.env, simulator_state) return simulator_state
def main(): args = parse_args() metrics.reset() start_time = time.time() logging.basicConfig(level=logging.INFO) # Create a SimPy environment env = simpy.Environment() # Seed the random generator random.seed(args.seed) numpy.random.seed(args.seed) # Parse network and get NetworkX object and ingress network list network, ing_nodes = reader.read_network(args.network, node_cap=10, link_cap=10) # Getting current SFC list, and the SF list of each SFC, and config # use dummy placement and schedule for running simulator without algorithm # TODO: make configurable via CLI sf_placement = dummy_data.triangle_placement schedule = dummy_data.triangle_schedule # Getting current SFC list, and the SF list of each SFC, and config sfc_list = reader.get_sfc(args.sf) sf_list = reader.get_sf(args.sf, args.sfr) config = reader.get_config(args.config) # Create the simulator parameters object with the provided args params = SimulatorParams(network, ing_nodes, sfc_list, sf_list, config, args.seed, sf_placement=sf_placement, schedule=schedule) log.info(params) if args.trace: trace = reader.get_trace(args.trace) TraceProcessor(params, env, trace) # Create a FlowSimulator object, pass the SimPy environment and params objects simulator = FlowSimulator(env, params) # Start the simulation simulator.start() # Run the simpy environment for the specified duration env.run(until=args.duration) # Record endtime and running_time metrics end_time = time.time() metrics.running_time(start_time, end_time) # dump all metrics log.info(metrics.metrics)
def init(self, network_file, service_functions_file, config_file, seed, trace=None, resource_functions_path=""): # Initialize metrics, record start time metrics.reset() self.run_times = int(1) self.start_time = time.time() # Parse network and SFC + SF file self.network, self.ing_nodes = reader.read_network(network_file, node_cap=10, link_cap=10) self.sfc_list = reader.get_sfc(service_functions_file) self.sf_list = reader.get_sf(service_functions_file, resource_functions_path) self.config = reader.get_config(config_file) # Generate SimPy simulation environment self.env = simpy.Environment() # Instantiate the parameter object for the simulator. self.params = SimulatorParams(self.network, self.ing_nodes, self.sfc_list, self.sf_list, self.config, seed) # Trace handling if trace: trace = reader.get_trace(trace) TraceProcessor(self.params, self.env, trace) self.duration = self.params.run_duration # Get and plant random seed self.seed = seed random.seed(self.seed) numpy.random.seed(self.seed) # Instantiate a simulator object, pass the environment and params self.simulator = FlowSimulator(self.env, self.params) # Start the simulator self.simulator.start() # Run the environment for one step to get initial stats. self.env.step() # Parse the NetworkX object into a dict format specified in SimulatorState. This is done to account # for changing node remaining capacities. # Also, parse the network stats and prepare it in SimulatorState format. self.parse_network() self.network_metrics() # Record end time and running time metrics self.end_time = time.time() metrics.running_time(self.start_time, self.end_time) simulator_state = SimulatorState(self.network_dict, self.simulator.params.sf_placement, self.sfc_list, self.sf_list, self.traffic, self.network_stats) # self.writer.write_state_results(self.env, simulator_state) return simulator_state
def init(self, seed): # reset network caps and available SFs: reader.reset_cap(self.network) # Initialize metrics, record start time metrics.reset_metrics() self.run_times = int(1) self.start_time = time.time() # Parse network and SFC + SF file # Generate SimPy simulation environment self.env = simpy.Environment() self.params = SimulatorParams(self.network, self.ing_nodes, self.sfc_list, self.sf_list, self.config) # Instantiate the parameter object for the simulator. if self.params.use_states and 'trace_path' in self.config: logger.warning( 'Two state model and traces are both activated, thi will cause unexpected behaviour!' ) if self.params.use_states: if self.params.in_init_state: self.params.in_init_state = False else: self.params.update_state() self.duration = self.params.run_duration # Get and plant random seed self.seed = seed random.seed(self.seed) numpy.random.seed(self.seed) # Instantiate a simulator object, pass the environment and params self.simulator = FlowSimulator(self.env, self.params) # Start the simulator self.simulator.start() # Trace handling if 'trace_path' in self.config: trace_path = os.path.join(os.getcwd(), self.config['trace_path']) trace = reader.get_trace(trace_path) TraceProcessor(self.params, self.env, trace, self.simulator) # Run the environment for one step to get initial stats. self.env.step() # Parse the NetworkX object into a dict format specified in SimulatorState. This is done to account # for changing node remaining capacities. # Also, parse the network stats and prepare it in SimulatorState format. self.parse_network() self.network_metrics() # Record end time and running time metrics self.end_time = time.time() metrics.running_time(self.start_time, self.end_time) simulator_state = SimulatorState(self.network_dict, self.simulator.params.sf_placement, self.sfc_list, self.sf_list, self.traffic, self.network_stats) logger.debug(f"t={self.env.now}: {simulator_state}") return simulator_state