Loading proto/load_generator.proto +16 −13 Original line number Diff line number Diff line Loading @@ -48,22 +48,25 @@ message ScalarOrRange { message Parameters { uint64 num_requests = 1; // if == 0, generate infinite requests repeated RequestTypeEnum request_types = 2; float offered_load = 3; float holding_time = 4; float inter_arrival_time = 5; repeated ScalarOrRange availability = 6; // one from the list is selected repeated ScalarOrRange capacity_gbps = 7; // one from the list is selected repeated ScalarOrRange e2e_latency_ms = 8; // one from the list is selected uint32 max_workers = 9; bool do_teardown = 10; bool dry_mode = 11; bool record_to_dlt = 12; string dlt_domain_id = 13; string device_regex = 3; // Only devices and endpoints matching the regex expression will be considered as string endpoint_regex = 4; // source-destination candidates for the requests generated. float offered_load = 5; float holding_time = 6; float inter_arrival_time = 7; repeated ScalarOrRange availability = 8; // One from the list is selected to populate the constraint repeated ScalarOrRange capacity_gbps = 9; // One from the list is selected to populate the constraint repeated ScalarOrRange e2e_latency_ms = 10; // One from the list is selected to populate the constraint uint32 max_workers = 11; bool do_teardown = 12; bool dry_mode = 13; bool record_to_dlt = 14; string dlt_domain_id = 15; } message Status { Parameters parameters = 1; uint64 num_generated = 2; bool infinite_loop = 3; bool running = 4; uint64 num_released = 3; bool infinite_loop = 4; bool running = 5; } src/load_generator/command/__main__.py +2 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,8 @@ def main(): RequestType.SLICE_L2NM, RequestType.SLICE_L3NM, ], device_regex=r'.+', endpoint_regex=r'.+', offered_load = 50, holding_time = 10, availability_ranges = [[0.0, 99.9999]], Loading src/load_generator/load_gen/Parameters.py +21 −4 Original line number Diff line number Diff line Loading @@ -20,16 +20,27 @@ from load_generator.tools.ListScalarRange import Type_ListScalarRange class Parameters: def __init__( self, num_requests : int, request_types : List[str], offered_load : Optional[float] = None, inter_arrival_time : Optional[float] = None, holding_time : Optional[float] = None, self, num_requests : int, request_types : List[str], device_regex : Optional[str] = None, endpoint_regex : Optional[str] = None, offered_load : Optional[float] = None, inter_arrival_time : Optional[float] = None, holding_time : Optional[float] = None, availability_ranges : Type_ListScalarRange = DEFAULT_AVAILABILITY_RANGES, capacity_gbps_ranges : Type_ListScalarRange = DEFAULT_CAPACITY_GBPS_RANGES, e2e_latency_ms_ranges : Type_ListScalarRange = DEFAULT_E2E_LATENCY_MS_RANGES, max_workers : int = DEFAULT_MAX_WORKERS, do_teardown : bool = True, dry_mode : bool = False, record_to_dlt : bool = False, dlt_domain_id : Optional[str] = None max_workers : int = DEFAULT_MAX_WORKERS, do_teardown : bool = True, dry_mode : bool = False, record_to_dlt : bool = False, dlt_domain_id : Optional[str] = None ) -> None: self._num_requests = num_requests self._request_types = request_types self._device_regex = r'.*' if (device_regex is None or len(device_regex) == 0) else device_regex self._endpoint_regex = r'.*' if (endpoint_regex is None or len(endpoint_regex) == 0) else endpoint_regex self._offered_load = offered_load self._inter_arrival_time = inter_arrival_time self._holding_time = holding_time Loading Loading @@ -62,6 +73,12 @@ class Parameters: @property def request_types(self): return self._request_types @property def device_regex(self): return self._device_regex @property def endpoint_regex(self): return self._endpoint_regex @property def offered_load(self): return self._offered_load Loading src/load_generator/load_gen/RequestGenerator.py +36 −17 Original line number Diff line number Diff line Loading @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import logging, json, random, re, threading import logging, json, random, re, threading, uuid from typing import Dict, Optional, Set, Tuple from common.proto.context_pb2 import Empty, IsolationLevelEnum, TopologyId from common.tools.grpc.Tools import grpc_message_to_json Loading Loading @@ -54,6 +54,7 @@ class RequestGenerator: self._parameters = parameters self._lock = threading.Lock() self._num_generated = 0 self._num_released = 0 self._available_device_endpoints : Dict[str, Set[str]] = dict() self._used_device_endpoints : Dict[str, Dict[str, str]] = dict() self._endpoint_ids_to_types : Dict[Tuple[str, str], str] = dict() Loading @@ -65,6 +66,9 @@ class RequestGenerator: @property def num_generated(self): return self._num_generated @property def num_released(self): return self._num_released @property def infinite_loop(self): return self._parameters.num_requests == 0 Loading @@ -79,13 +83,21 @@ class RequestGenerator: if self._parameters.record_to_dlt: dlt_domain_id = TopologyId(**json_topology_id('dlt-perf-eval')) re_device = re.compile(r'^{:s}$'.format(self._parameters.device_regex)) re_endpoint = re.compile(r'^{:s}$'.format(self._parameters.endpoint_regex)) devices = context_client.ListDevices(Empty()) for device in devices.devices: if self._parameters.record_to_dlt: record_device_to_dlt(dlt_connector_client, dlt_domain_id, device.device_id) if re_device.match(device.name) is None: continue device_uuid = device.device_id.device_uuid.uuid self._device_data[device_uuid] = grpc_message_to_json(device) _endpoints = self._available_device_endpoints.setdefault(device_uuid, set()) for endpoint in device.device_endpoints: if re_endpoint.match(endpoint.name) is None: continue endpoint_uuid = endpoint.endpoint_id.endpoint_uuid.uuid endpoints = self._device_endpoint_data.setdefault(device_uuid, dict()) endpoints[endpoint_uuid] = grpc_message_to_json(endpoint) Loading @@ -95,11 +107,11 @@ class RequestGenerator: self._endpoint_ids_to_types.setdefault((device_uuid, endpoint_uuid), endpoint_type) self._endpoint_types_to_ids.setdefault(endpoint_type, set()).add((device_uuid, endpoint_uuid)) if self._parameters.record_to_dlt: record_device_to_dlt(dlt_connector_client, dlt_domain_id, device.device_id) links = context_client.ListLinks(Empty()) for link in links.links: if self._parameters.record_to_dlt: record_link_to_dlt(dlt_connector_client, dlt_domain_id, link.link_id) for endpoint_id in link.link_endpoint_ids: device_uuid = endpoint_id.device_id.device_uuid.uuid endpoint_uuid = endpoint_id.endpoint_uuid.uuid Loading @@ -116,9 +128,6 @@ class RequestGenerator: if endpoint_key not in endpoints_for_type: continue endpoints_for_type.discard(endpoint_key) if self._parameters.record_to_dlt: record_link_to_dlt(dlt_connector_client, dlt_domain_id, link.link_id) def dump_state(self) -> None: with self._lock: _endpoints = { Loading Loading @@ -192,23 +201,18 @@ class RequestGenerator: if not self.infinite_loop and (self._num_generated >= self._parameters.num_requests): LOGGER.info('Generation Done!') return True, None, None # completed self._num_generated += 1 num_request = self._num_generated #request_uuid = str(uuid.uuid4()) request_uuid = 'svc_{:d}'.format(num_request) # choose request type request_uuid = str(uuid.uuid4()) request_type = random.choice(self._parameters.request_types) if request_type in { RequestType.SERVICE_L2NM, RequestType.SERVICE_L3NM, RequestType.SERVICE_TAPI, RequestType.SERVICE_MW }: return False, self._compose_service(num_request, request_uuid, request_type), request_type return False, self._compose_service(request_uuid, request_type), request_type elif request_type in {RequestType.SLICE_L2NM, RequestType.SLICE_L3NM}: return False, self._compose_slice(num_request, request_uuid, request_type), request_type return False, self._compose_slice(request_uuid, request_type), request_type def _compose_service(self, num_request : int, request_uuid : str, request_type : str) -> Optional[Dict]: def _compose_service(self, request_uuid : str, request_type : str) -> Optional[Dict]: # choose source endpoint src_endpoint_types = set(ENDPOINT_COMPATIBILITY.keys()) if request_type in {RequestType.SERVICE_TAPI} else None src = self._use_device_endpoint(request_uuid, request_type, endpoint_types=src_endpoint_types) Loading Loading @@ -237,6 +241,10 @@ class RequestGenerator: self._release_device_endpoint(src_device_uuid, src_endpoint_uuid) return None with self._lock: self._num_generated += 1 num_request = self._num_generated # compose endpoints dst_device_uuid,dst_endpoint_uuid = dst endpoint_ids = [ Loading Loading @@ -383,7 +391,7 @@ class RequestGenerator: return json_service_l2nm_planned( request_uuid, endpoint_ids=endpoint_ids, constraints=[], config_rules=config_rules) def _compose_slice(self, num_request : int, request_uuid : str, request_type : str) -> Optional[Dict]: def _compose_slice(self, request_uuid : str, request_type : str) -> Optional[Dict]: # choose source endpoint src = self._use_device_endpoint(request_uuid, request_type) if src is None: Loading @@ -404,6 +412,10 @@ class RequestGenerator: self._release_device_endpoint(src_device_uuid, src_endpoint_uuid) return None with self._lock: self._num_generated += 1 num_request = self._num_generated # compose endpoints dst_device_uuid,dst_endpoint_uuid = dst endpoint_ids = [ Loading Loading @@ -505,8 +517,15 @@ class RequestGenerator: device_uuid = endpoint_id['device_id']['device_uuid']['uuid'] endpoint_uuid = endpoint_id['endpoint_uuid']['uuid'] self._release_device_endpoint(device_uuid, endpoint_uuid) with self._lock: self._num_released += 1 elif 'slice_id' in json_request: for endpoint_id in json_request['slice_endpoint_ids']: device_uuid = endpoint_id['device_id']['device_uuid']['uuid'] endpoint_uuid = endpoint_id['endpoint_uuid']['uuid'] self._release_device_endpoint(device_uuid, endpoint_uuid) with self._lock: self._num_released += 1 src/load_generator/load_gen/RequestScheduler.py +3 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,9 @@ class RequestScheduler: @property def num_generated(self): return min(self._generator.num_generated, self._parameters.num_requests) @property def num_released(self): return min(self._generator.num_released, self._parameters.num_requests) @property def infinite_loop(self): return self._generator.infinite_loop Loading Loading
proto/load_generator.proto +16 −13 Original line number Diff line number Diff line Loading @@ -48,22 +48,25 @@ message ScalarOrRange { message Parameters { uint64 num_requests = 1; // if == 0, generate infinite requests repeated RequestTypeEnum request_types = 2; float offered_load = 3; float holding_time = 4; float inter_arrival_time = 5; repeated ScalarOrRange availability = 6; // one from the list is selected repeated ScalarOrRange capacity_gbps = 7; // one from the list is selected repeated ScalarOrRange e2e_latency_ms = 8; // one from the list is selected uint32 max_workers = 9; bool do_teardown = 10; bool dry_mode = 11; bool record_to_dlt = 12; string dlt_domain_id = 13; string device_regex = 3; // Only devices and endpoints matching the regex expression will be considered as string endpoint_regex = 4; // source-destination candidates for the requests generated. float offered_load = 5; float holding_time = 6; float inter_arrival_time = 7; repeated ScalarOrRange availability = 8; // One from the list is selected to populate the constraint repeated ScalarOrRange capacity_gbps = 9; // One from the list is selected to populate the constraint repeated ScalarOrRange e2e_latency_ms = 10; // One from the list is selected to populate the constraint uint32 max_workers = 11; bool do_teardown = 12; bool dry_mode = 13; bool record_to_dlt = 14; string dlt_domain_id = 15; } message Status { Parameters parameters = 1; uint64 num_generated = 2; bool infinite_loop = 3; bool running = 4; uint64 num_released = 3; bool infinite_loop = 4; bool running = 5; }
src/load_generator/command/__main__.py +2 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,8 @@ def main(): RequestType.SLICE_L2NM, RequestType.SLICE_L3NM, ], device_regex=r'.+', endpoint_regex=r'.+', offered_load = 50, holding_time = 10, availability_ranges = [[0.0, 99.9999]], Loading
src/load_generator/load_gen/Parameters.py +21 −4 Original line number Diff line number Diff line Loading @@ -20,16 +20,27 @@ from load_generator.tools.ListScalarRange import Type_ListScalarRange class Parameters: def __init__( self, num_requests : int, request_types : List[str], offered_load : Optional[float] = None, inter_arrival_time : Optional[float] = None, holding_time : Optional[float] = None, self, num_requests : int, request_types : List[str], device_regex : Optional[str] = None, endpoint_regex : Optional[str] = None, offered_load : Optional[float] = None, inter_arrival_time : Optional[float] = None, holding_time : Optional[float] = None, availability_ranges : Type_ListScalarRange = DEFAULT_AVAILABILITY_RANGES, capacity_gbps_ranges : Type_ListScalarRange = DEFAULT_CAPACITY_GBPS_RANGES, e2e_latency_ms_ranges : Type_ListScalarRange = DEFAULT_E2E_LATENCY_MS_RANGES, max_workers : int = DEFAULT_MAX_WORKERS, do_teardown : bool = True, dry_mode : bool = False, record_to_dlt : bool = False, dlt_domain_id : Optional[str] = None max_workers : int = DEFAULT_MAX_WORKERS, do_teardown : bool = True, dry_mode : bool = False, record_to_dlt : bool = False, dlt_domain_id : Optional[str] = None ) -> None: self._num_requests = num_requests self._request_types = request_types self._device_regex = r'.*' if (device_regex is None or len(device_regex) == 0) else device_regex self._endpoint_regex = r'.*' if (endpoint_regex is None or len(endpoint_regex) == 0) else endpoint_regex self._offered_load = offered_load self._inter_arrival_time = inter_arrival_time self._holding_time = holding_time Loading Loading @@ -62,6 +73,12 @@ class Parameters: @property def request_types(self): return self._request_types @property def device_regex(self): return self._device_regex @property def endpoint_regex(self): return self._endpoint_regex @property def offered_load(self): return self._offered_load Loading
src/load_generator/load_gen/RequestGenerator.py +36 −17 Original line number Diff line number Diff line Loading @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import logging, json, random, re, threading import logging, json, random, re, threading, uuid from typing import Dict, Optional, Set, Tuple from common.proto.context_pb2 import Empty, IsolationLevelEnum, TopologyId from common.tools.grpc.Tools import grpc_message_to_json Loading Loading @@ -54,6 +54,7 @@ class RequestGenerator: self._parameters = parameters self._lock = threading.Lock() self._num_generated = 0 self._num_released = 0 self._available_device_endpoints : Dict[str, Set[str]] = dict() self._used_device_endpoints : Dict[str, Dict[str, str]] = dict() self._endpoint_ids_to_types : Dict[Tuple[str, str], str] = dict() Loading @@ -65,6 +66,9 @@ class RequestGenerator: @property def num_generated(self): return self._num_generated @property def num_released(self): return self._num_released @property def infinite_loop(self): return self._parameters.num_requests == 0 Loading @@ -79,13 +83,21 @@ class RequestGenerator: if self._parameters.record_to_dlt: dlt_domain_id = TopologyId(**json_topology_id('dlt-perf-eval')) re_device = re.compile(r'^{:s}$'.format(self._parameters.device_regex)) re_endpoint = re.compile(r'^{:s}$'.format(self._parameters.endpoint_regex)) devices = context_client.ListDevices(Empty()) for device in devices.devices: if self._parameters.record_to_dlt: record_device_to_dlt(dlt_connector_client, dlt_domain_id, device.device_id) if re_device.match(device.name) is None: continue device_uuid = device.device_id.device_uuid.uuid self._device_data[device_uuid] = grpc_message_to_json(device) _endpoints = self._available_device_endpoints.setdefault(device_uuid, set()) for endpoint in device.device_endpoints: if re_endpoint.match(endpoint.name) is None: continue endpoint_uuid = endpoint.endpoint_id.endpoint_uuid.uuid endpoints = self._device_endpoint_data.setdefault(device_uuid, dict()) endpoints[endpoint_uuid] = grpc_message_to_json(endpoint) Loading @@ -95,11 +107,11 @@ class RequestGenerator: self._endpoint_ids_to_types.setdefault((device_uuid, endpoint_uuid), endpoint_type) self._endpoint_types_to_ids.setdefault(endpoint_type, set()).add((device_uuid, endpoint_uuid)) if self._parameters.record_to_dlt: record_device_to_dlt(dlt_connector_client, dlt_domain_id, device.device_id) links = context_client.ListLinks(Empty()) for link in links.links: if self._parameters.record_to_dlt: record_link_to_dlt(dlt_connector_client, dlt_domain_id, link.link_id) for endpoint_id in link.link_endpoint_ids: device_uuid = endpoint_id.device_id.device_uuid.uuid endpoint_uuid = endpoint_id.endpoint_uuid.uuid Loading @@ -116,9 +128,6 @@ class RequestGenerator: if endpoint_key not in endpoints_for_type: continue endpoints_for_type.discard(endpoint_key) if self._parameters.record_to_dlt: record_link_to_dlt(dlt_connector_client, dlt_domain_id, link.link_id) def dump_state(self) -> None: with self._lock: _endpoints = { Loading Loading @@ -192,23 +201,18 @@ class RequestGenerator: if not self.infinite_loop and (self._num_generated >= self._parameters.num_requests): LOGGER.info('Generation Done!') return True, None, None # completed self._num_generated += 1 num_request = self._num_generated #request_uuid = str(uuid.uuid4()) request_uuid = 'svc_{:d}'.format(num_request) # choose request type request_uuid = str(uuid.uuid4()) request_type = random.choice(self._parameters.request_types) if request_type in { RequestType.SERVICE_L2NM, RequestType.SERVICE_L3NM, RequestType.SERVICE_TAPI, RequestType.SERVICE_MW }: return False, self._compose_service(num_request, request_uuid, request_type), request_type return False, self._compose_service(request_uuid, request_type), request_type elif request_type in {RequestType.SLICE_L2NM, RequestType.SLICE_L3NM}: return False, self._compose_slice(num_request, request_uuid, request_type), request_type return False, self._compose_slice(request_uuid, request_type), request_type def _compose_service(self, num_request : int, request_uuid : str, request_type : str) -> Optional[Dict]: def _compose_service(self, request_uuid : str, request_type : str) -> Optional[Dict]: # choose source endpoint src_endpoint_types = set(ENDPOINT_COMPATIBILITY.keys()) if request_type in {RequestType.SERVICE_TAPI} else None src = self._use_device_endpoint(request_uuid, request_type, endpoint_types=src_endpoint_types) Loading Loading @@ -237,6 +241,10 @@ class RequestGenerator: self._release_device_endpoint(src_device_uuid, src_endpoint_uuid) return None with self._lock: self._num_generated += 1 num_request = self._num_generated # compose endpoints dst_device_uuid,dst_endpoint_uuid = dst endpoint_ids = [ Loading Loading @@ -383,7 +391,7 @@ class RequestGenerator: return json_service_l2nm_planned( request_uuid, endpoint_ids=endpoint_ids, constraints=[], config_rules=config_rules) def _compose_slice(self, num_request : int, request_uuid : str, request_type : str) -> Optional[Dict]: def _compose_slice(self, request_uuid : str, request_type : str) -> Optional[Dict]: # choose source endpoint src = self._use_device_endpoint(request_uuid, request_type) if src is None: Loading @@ -404,6 +412,10 @@ class RequestGenerator: self._release_device_endpoint(src_device_uuid, src_endpoint_uuid) return None with self._lock: self._num_generated += 1 num_request = self._num_generated # compose endpoints dst_device_uuid,dst_endpoint_uuid = dst endpoint_ids = [ Loading Loading @@ -505,8 +517,15 @@ class RequestGenerator: device_uuid = endpoint_id['device_id']['device_uuid']['uuid'] endpoint_uuid = endpoint_id['endpoint_uuid']['uuid'] self._release_device_endpoint(device_uuid, endpoint_uuid) with self._lock: self._num_released += 1 elif 'slice_id' in json_request: for endpoint_id in json_request['slice_endpoint_ids']: device_uuid = endpoint_id['device_id']['device_uuid']['uuid'] endpoint_uuid = endpoint_id['endpoint_uuid']['uuid'] self._release_device_endpoint(device_uuid, endpoint_uuid) with self._lock: self._num_released += 1
src/load_generator/load_gen/RequestScheduler.py +3 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,9 @@ class RequestScheduler: @property def num_generated(self): return min(self._generator.num_generated, self._parameters.num_requests) @property def num_released(self): return min(self._generator.num_released, self._parameters.num_requests) @property def infinite_loop(self): return self._generator.infinite_loop Loading