Skip to content

Commit f2a5170

Browse files
committed
Merge branch 'v0.3' into refine_rl_component_bundle
2 parents 5d62151 + 9fd91ff commit f2a5170

22 files changed

+221
-158
lines changed

examples/vm_scheduling/offline_lp/launcher.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from ilp_agent import IlpAgent
1313

1414
from maro.simulator import Env
15-
from maro.simulator.scenarios.vm_scheduling import DecisionPayload
15+
from maro.simulator.scenarios.vm_scheduling import DecisionEvent
1616
from maro.simulator.scenarios.vm_scheduling.common import Action
1717
from maro.utils import LogFormat, Logger, convert_dottable
1818

@@ -46,7 +46,7 @@
4646
env.set_seed(config.env.seed)
4747

4848
metrics: object = None
49-
decision_event: DecisionPayload = None
49+
decision_event: DecisionEvent = None
5050
is_done: bool = False
5151
action: Action = None
5252

examples/vm_scheduling/rl/env_sampler.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from maro.rl.policy import AbsPolicy
1414
from maro.rl.rollout import AbsAgentWrapper, AbsEnvSampler, CacheElement, SimpleAgentWrapper
1515
from maro.simulator import Env
16-
from maro.simulator.scenarios.vm_scheduling import AllocateAction, DecisionPayload, PostponeAction
16+
from maro.simulator.scenarios.vm_scheduling import AllocateAction, DecisionEvent, PostponeAction
1717

1818
from .config import (
1919
num_features,
@@ -62,7 +62,7 @@ def __init__(
6262

6363
def _get_global_and_agent_state_impl(
6464
self,
65-
event: DecisionPayload,
65+
event: DecisionEvent,
6666
tick: int = None,
6767
) -> Tuple[Union[None, np.ndarray, List[object]], Dict[Any, Union[np.ndarray, List[object]]]]:
6868
pm_state, vm_state = self._get_pm_state(), self._get_vm_state(event)
@@ -89,14 +89,14 @@ def _get_global_and_agent_state_impl(
8989
def _translate_to_env_action(
9090
self,
9191
action_dict: Dict[Any, Union[np.ndarray, List[object]]],
92-
event: DecisionPayload,
92+
event: DecisionEvent,
9393
) -> Dict[Any, object]:
9494
if action_dict["AGENT"] == self.num_pms:
9595
return {"AGENT": PostponeAction(vm_id=event.vm_id, postpone_step=1)}
9696
else:
9797
return {"AGENT": AllocateAction(vm_id=event.vm_id, pm_id=action_dict["AGENT"][0])}
9898

99-
def _get_reward(self, env_action_dict: Dict[Any, object], event: DecisionPayload, tick: int) -> Dict[Any, float]:
99+
def _get_reward(self, env_action_dict: Dict[Any, object], event: DecisionEvent, tick: int) -> Dict[Any, float]:
100100
action = env_action_dict["AGENT"]
101101
conf = reward_shaping_conf if self._env == self._learn_env else test_reward_shaping_conf
102102
if isinstance(action, PostponeAction): # postponement
@@ -139,7 +139,7 @@ def _get_vm_state(self, event):
139139
],
140140
)
141141

142-
def _get_allocation_reward(self, event: DecisionPayload, alpha: float, beta: float):
142+
def _get_allocation_reward(self, event: DecisionEvent, alpha: float, beta: float):
143143
vm_unit_price = self._env.business_engine._get_unit_price(
144144
event.vm_cpu_cores_requirement,
145145
event.vm_memory_requirement,

examples/vm_scheduling/rule_based_algorithm/agent.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
# Licensed under the MIT license.
33

44
from maro.simulator import Env
5-
from maro.simulator.scenarios.vm_scheduling import AllocateAction, DecisionPayload, PostponeAction
5+
from maro.simulator.scenarios.vm_scheduling import AllocateAction, DecisionEvent, PostponeAction
66
from maro.simulator.scenarios.vm_scheduling.common import Action
77

88

99
class VMSchedulingAgent(object):
1010
def __init__(self, algorithm):
1111
self._algorithm = algorithm
1212

13-
def choose_action(self, decision_event: DecisionPayload, env: Env) -> Action:
13+
def choose_action(self, decision_event: DecisionEvent, env: Env) -> Action:
1414
"""This method will determine whether to postpone the current VM or allocate a PM to the current VM."""
1515
valid_pm_num: int = len(decision_event.valid_pms)
1616

examples/vm_scheduling/rule_based_algorithm/best_fit.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
from rule_based_algorithm import RuleBasedAlgorithm
66

77
from maro.simulator import Env
8-
from maro.simulator.scenarios.vm_scheduling import AllocateAction, DecisionPayload
8+
from maro.simulator.scenarios.vm_scheduling import AllocateAction, DecisionEvent
99

1010

1111
class BestFit(RuleBasedAlgorithm):
1212
def __init__(self, **kwargs):
1313
super().__init__()
1414
self._metric_type: str = kwargs["metric_type"]
1515

16-
def allocate_vm(self, decision_event: DecisionPayload, env: Env) -> AllocateAction:
16+
def allocate_vm(self, decision_event: DecisionEvent, env: Env) -> AllocateAction:
1717
# Use a rule to choose a valid PM.
1818
chosen_idx: int = self._pick_pm_func(decision_event, env)
1919
# Take action to allocate on the chose PM.

examples/vm_scheduling/rule_based_algorithm/bin_packing.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from rule_based_algorithm import RuleBasedAlgorithm
88

99
from maro.simulator import Env
10-
from maro.simulator.scenarios.vm_scheduling import AllocateAction, DecisionPayload
10+
from maro.simulator.scenarios.vm_scheduling import AllocateAction, DecisionEvent
1111

1212

1313
class BinPacking(RuleBasedAlgorithm):
@@ -24,7 +24,7 @@ def _init_bin(self):
2424
self._bins = [[] for _ in range(self._pm_cpu_core_num + 1)]
2525
self._bin_size = [0] * (self._pm_cpu_core_num + 1)
2626

27-
def allocate_vm(self, decision_event: DecisionPayload, env: Env) -> AllocateAction:
27+
def allocate_vm(self, decision_event: DecisionEvent, env: Env) -> AllocateAction:
2828
# Initialize the bin.
2929
self._init_bin()
3030

examples/vm_scheduling/rule_based_algorithm/first_fit.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
from rule_based_algorithm import RuleBasedAlgorithm
55

66
from maro.simulator import Env
7-
from maro.simulator.scenarios.vm_scheduling import AllocateAction, DecisionPayload
7+
from maro.simulator.scenarios.vm_scheduling import AllocateAction, DecisionEvent
88

99

1010
class FirstFit(RuleBasedAlgorithm):
1111
def __init__(self, **kwargs):
1212
super().__init__()
1313

14-
def allocate_vm(self, decision_event: DecisionPayload, env: Env) -> AllocateAction:
14+
def allocate_vm(self, decision_event: DecisionEvent, env: Env) -> AllocateAction:
1515
# Use a valid PM based on its order.
1616
chosen_idx: int = decision_event.valid_pms[0]
1717
# Take action to allocate on the chose PM.

examples/vm_scheduling/rule_based_algorithm/random_pick.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
from rule_based_algorithm import RuleBasedAlgorithm
77

88
from maro.simulator import Env
9-
from maro.simulator.scenarios.vm_scheduling import AllocateAction, DecisionPayload
9+
from maro.simulator.scenarios.vm_scheduling import AllocateAction, DecisionEvent
1010

1111

1212
class RandomPick(RuleBasedAlgorithm):
1313
def __init__(self, **kwargs):
1414
super().__init__()
1515

16-
def allocate_vm(self, decision_event: DecisionPayload, env: Env) -> AllocateAction:
16+
def allocate_vm(self, decision_event: DecisionEvent, env: Env) -> AllocateAction:
1717
valid_pm_num: int = len(decision_event.valid_pms)
1818
# Random choose a valid PM.
1919
chosen_idx: int = random.randint(0, valid_pm_num - 1)

examples/vm_scheduling/rule_based_algorithm/round_robin.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from rule_based_algorithm import RuleBasedAlgorithm
55

66
from maro.simulator import Env
7-
from maro.simulator.scenarios.vm_scheduling import AllocateAction, DecisionPayload
7+
from maro.simulator.scenarios.vm_scheduling import AllocateAction, DecisionEvent
88

99

1010
class RoundRobin(RuleBasedAlgorithm):
@@ -15,7 +15,7 @@ def __init__(self, **kwargs):
1515
kwargs["env"].snapshot_list["pms"][kwargs["env"].frame_index :: ["cpu_cores_capacity"]].shape[0]
1616
)
1717

18-
def allocate_vm(self, decision_event: DecisionPayload, env: Env) -> AllocateAction:
18+
def allocate_vm(self, decision_event: DecisionEvent, env: Env) -> AllocateAction:
1919
# Choose the valid PM which index is next to the previous chose PM's index
2020
chosen_idx: int = (self._prev_idx + 1) % self._pm_num
2121
while chosen_idx not in decision_event.valid_pms:

examples/vm_scheduling/rule_based_algorithm/rule_based_algorithm.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
import abc
55

66
from maro.simulator import Env
7-
from maro.simulator.scenarios.vm_scheduling import AllocateAction, DecisionPayload
7+
from maro.simulator.scenarios.vm_scheduling import AllocateAction, DecisionEvent
88

99

1010
class RuleBasedAlgorithm(object):
1111
__metaclass__ = abc.ABCMeta
1212

1313
@abc.abstractmethod
14-
def allocate_vm(self, decision_event: DecisionPayload, env: Env) -> AllocateAction:
14+
def allocate_vm(self, decision_event: DecisionEvent, env: Env) -> AllocateAction:
1515
"""This method will determine allocate which PM to the current VM."""
1616
raise NotImplementedError

maro/common.py

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
4+
5+
class BaseDecisionEvent:
6+
"""Base class for all decision events.
7+
8+
We made this design for the convenience of users. As a summary, there are two types of events in MARO:
9+
- CascadeEvent & AtomEvent: used to drive the MARO Env / business engine.
10+
- DecisionEvent: exposed to users as a means of communication.
11+
12+
The latter one serves as the `payload` of the former ones inside of MARO Env.
13+
14+
Therefore, the related namings might be a little bit tricky.
15+
- Inside MARO Env: `decision_event` is actually a CascadeEvent. DecisionEvent is the payload of them.
16+
- Outside MARO Env (for users): `decision_event` is a DecisionEvent.
17+
"""
18+
19+
20+
class BaseAction:
21+
"""Base class for all action payloads"""

maro/event_buffer/event_buffer.py

+12-12
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
import csv
66
from collections import defaultdict
7-
from typing import Callable, List, Optional
7+
from typing import Callable, List, Optional, cast
88

9+
from ..common import BaseAction, BaseDecisionEvent
910
from .event import ActualEvent, AtomEvent, CascadeEvent
1011
from .event_linked_list import EventLinkedList
1112
from .event_pool import EventPool
@@ -122,9 +123,7 @@ def gen_atom_event(self, tick: int, event_type: object, payload: object = None)
122123
Returns:
123124
AtomEvent: Atom event object
124125
"""
125-
event = self._event_pool.gen(tick, event_type, payload, False)
126-
assert isinstance(event, AtomEvent)
127-
return event
126+
return cast(AtomEvent, self._event_pool.gen(tick, event_type, payload, is_cascade=False))
128127

129128
def gen_cascade_event(self, tick: int, event_type: object, payload: object) -> CascadeEvent:
130129
"""Generate an cascade event that used to hold immediate events that
@@ -138,31 +137,32 @@ def gen_cascade_event(self, tick: int, event_type: object, payload: object) -> C
138137
Returns:
139138
CascadeEvent: Cascade event object.
140139
"""
141-
event = self._event_pool.gen(tick, event_type, payload, True)
142-
assert isinstance(event, CascadeEvent)
143-
return event
140+
return cast(CascadeEvent, self._event_pool.gen(tick, event_type, payload, is_cascade=True))
144141

145-
def gen_decision_event(self, tick: int, payload: object) -> CascadeEvent:
142+
def gen_decision_event(self, tick: int, payload: BaseDecisionEvent) -> CascadeEvent:
146143
"""Generate a decision event that will stop current simulation, and ask agent for action.
147144
148145
Args:
149146
tick (int): Tick that the event will be processed.
150-
payload (object): Payload of event, used to pass data to handlers.
147+
payload (BaseDecisionEvent): Payload of event, used to pass data to handlers.
151148
Returns:
152149
CascadeEvent: Event object
153150
"""
151+
assert isinstance(payload, BaseDecisionEvent)
154152
return self.gen_cascade_event(tick, MaroEvents.PENDING_DECISION, payload)
155153

156-
def gen_action_event(self, tick: int, payload: object) -> CascadeEvent:
154+
def gen_action_event(self, tick: int, payloads: List[BaseAction]) -> CascadeEvent:
157155
"""Generate an event that used to dispatch action to business engine.
158156
159157
Args:
160158
tick (int): Tick that the event will be processed.
161-
payload (object): Payload of event, used to pass data to handlers.
159+
payloads (List[BaseAction]): Payloads of event, used to pass data to handlers.
162160
Returns:
163161
CascadeEvent: Event object
164162
"""
165-
return self.gen_cascade_event(tick, MaroEvents.TAKE_ACTION, payload)
163+
assert isinstance(payloads, list)
164+
assert all(isinstance(p, BaseAction) for p in payloads)
165+
return self.gen_cascade_event(tick, MaroEvents.TAKE_ACTION, payloads)
166166

167167
def register_event_handler(self, event_type: object, handler: Callable) -> None:
168168
"""Register an event with handler, when there is an event need to be processed,

0 commit comments

Comments
 (0)