service-capacity-modeling 0.3.73__py3-none-any.whl → 0.3.79__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of service-capacity-modeling might be problematic. Click here for more details.

Files changed (40) hide show
  1. service_capacity_modeling/capacity_planner.py +46 -40
  2. service_capacity_modeling/hardware/__init__.py +11 -7
  3. service_capacity_modeling/hardware/profiles/shapes/aws/auto_i3en.json +172 -0
  4. service_capacity_modeling/hardware/profiles/shapes/aws/auto_i4i.json +220 -0
  5. service_capacity_modeling/hardware/profiles/shapes/aws/manual_instances.json +0 -184
  6. service_capacity_modeling/interface.py +48 -22
  7. service_capacity_modeling/models/__init__.py +21 -2
  8. service_capacity_modeling/models/common.py +268 -190
  9. service_capacity_modeling/models/headroom_strategy.py +2 -1
  10. service_capacity_modeling/models/org/netflix/__init__.py +4 -1
  11. service_capacity_modeling/models/org/netflix/aurora.py +12 -7
  12. service_capacity_modeling/models/org/netflix/cassandra.py +39 -24
  13. service_capacity_modeling/models/org/netflix/counter.py +44 -20
  14. service_capacity_modeling/models/org/netflix/crdb.py +7 -4
  15. service_capacity_modeling/models/org/netflix/ddb.py +9 -5
  16. service_capacity_modeling/models/org/netflix/elasticsearch.py +8 -6
  17. service_capacity_modeling/models/org/netflix/entity.py +5 -3
  18. service_capacity_modeling/models/org/netflix/evcache.py +21 -25
  19. service_capacity_modeling/models/org/netflix/graphkv.py +5 -3
  20. service_capacity_modeling/models/org/netflix/iso_date_math.py +12 -9
  21. service_capacity_modeling/models/org/netflix/kafka.py +13 -7
  22. service_capacity_modeling/models/org/netflix/key_value.py +4 -2
  23. service_capacity_modeling/models/org/netflix/postgres.py +4 -2
  24. service_capacity_modeling/models/org/netflix/rds.py +10 -5
  25. service_capacity_modeling/models/org/netflix/stateless_java.py +4 -2
  26. service_capacity_modeling/models/org/netflix/time_series.py +4 -2
  27. service_capacity_modeling/models/org/netflix/time_series_config.py +3 -3
  28. service_capacity_modeling/models/org/netflix/wal.py +4 -2
  29. service_capacity_modeling/models/org/netflix/zookeeper.py +5 -3
  30. service_capacity_modeling/stats.py +14 -11
  31. service_capacity_modeling/tools/auto_shape.py +10 -6
  32. service_capacity_modeling/tools/fetch_pricing.py +13 -6
  33. service_capacity_modeling/tools/generate_missing.py +4 -3
  34. service_capacity_modeling/tools/instance_families.py +18 -7
  35. {service_capacity_modeling-0.3.73.dist-info → service_capacity_modeling-0.3.79.dist-info}/METADATA +9 -5
  36. {service_capacity_modeling-0.3.73.dist-info → service_capacity_modeling-0.3.79.dist-info}/RECORD +40 -38
  37. {service_capacity_modeling-0.3.73.dist-info → service_capacity_modeling-0.3.79.dist-info}/WHEEL +0 -0
  38. {service_capacity_modeling-0.3.73.dist-info → service_capacity_modeling-0.3.79.dist-info}/entry_points.txt +0 -0
  39. {service_capacity_modeling-0.3.73.dist-info → service_capacity_modeling-0.3.79.dist-info}/licenses/LICENSE +0 -0
  40. {service_capacity_modeling-0.3.73.dist-info → service_capacity_modeling-0.3.79.dist-info}/top_level.txt +0 -0
@@ -190,7 +190,7 @@ def model_desires_percentiles(
190
190
  def _set_instance_objects(
191
191
  desires: CapacityDesires,
192
192
  hardware: Hardware,
193
- ):
193
+ ) -> None:
194
194
  if desires.current_clusters:
195
195
  for zonal_cluster_capacity in desires.current_clusters.zonal:
196
196
  if zonal_cluster_capacity.cluster_instance_name in hardware.instances:
@@ -290,7 +290,9 @@ def _regret(
290
290
  return plans_by_regret
291
291
 
292
292
 
293
- def _add_requirement(requirement, accum):
293
+ def _add_requirement(
294
+ requirement: CapacityRequirement, accum: Dict[str, Dict[str, List[Interval]]]
295
+ ) -> None:
294
296
  if requirement.requirement_type not in accum:
295
297
  accum[requirement.requirement_type] = {}
296
298
 
@@ -305,7 +307,11 @@ def _add_requirement(requirement, accum):
305
307
  requirements[field].append(d)
306
308
 
307
309
 
308
- def _merge_models(plans_by_model, zonal_requirements, regional_requirements):
310
+ def _merge_models(
311
+ plans_by_model: List[List[CapacityPlan]],
312
+ zonal_requirements: Dict[str, Dict[str, List[Interval]]],
313
+ regional_requirements: Dict[str, Dict[str, List[Interval]]],
314
+ ) -> List[CapacityPlan]:
309
315
  capacity_plans = []
310
316
  for composed in zip(*filter(lambda x: x, plans_by_model)):
311
317
  merged_plans = [functools.reduce(merge_plan, composed)]
@@ -331,10 +337,10 @@ def _in_allowed(inp: str, allowed: Sequence[str]) -> bool:
331
337
  class CapacityPlanner:
332
338
  def __init__(
333
339
  self,
334
- default_num_simulations=128,
335
- default_num_results=2,
336
- default_lifecycles=(Lifecycle.stable, Lifecycle.beta),
337
- ):
340
+ default_num_simulations: int = 128,
341
+ default_num_results: int = 2,
342
+ default_lifecycles: Tuple[Lifecycle, ...] = (Lifecycle.stable, Lifecycle.beta),
343
+ ) -> None:
338
344
  self._shapes: HardwareShapes = shapes
339
345
  self._models: Dict[str, CapacityModel] = {}
340
346
 
@@ -343,11 +349,11 @@ class CapacityPlanner:
343
349
  self._default_regret_params = CapacityRegretParameters()
344
350
  self._default_lifecycles = default_lifecycles
345
351
 
346
- def register_group(self, group: Callable[[], Dict[str, CapacityModel]]):
352
+ def register_group(self, group: Callable[[], Dict[str, CapacityModel]]) -> None:
347
353
  for name, model in group().items():
348
354
  self.register_model(name, model)
349
355
 
350
- def register_model(self, name: str, capacity_model: CapacityModel):
356
+ def register_model(self, name: str, capacity_model: CapacityModel) -> None:
351
357
  self._models[name] = capacity_model
352
358
 
353
359
  @property
@@ -429,16 +435,16 @@ class CapacityPlanner:
429
435
 
430
436
  def _group_plans_by_percentile( # pylint: disable=too-many-positional-arguments
431
437
  self,
432
- drives,
433
- extra_model_arguments,
434
- instance_families,
435
- lifecycles,
436
- num_regions,
437
- num_results,
438
- region,
439
- model_percentile_desires,
440
- sorted_percentiles,
441
- ):
438
+ drives: Optional[Sequence[str]],
439
+ extra_model_arguments: Dict[str, Any],
440
+ instance_families: Optional[Sequence[str]],
441
+ lifecycles: Sequence[Lifecycle],
442
+ num_regions: int,
443
+ num_results: Optional[int],
444
+ region: str,
445
+ model_percentile_desires: Any,
446
+ sorted_percentiles: List[int],
447
+ ) -> Dict[int, Sequence[CapacityPlan]]:
442
448
  percentile_plans = {}
443
449
  for index, percentile in enumerate(sorted_percentiles):
444
450
  percentile_plan = []
@@ -470,15 +476,15 @@ class CapacityPlanner:
470
476
 
471
477
  def _mean_plan( # pylint: disable=too-many-positional-arguments
472
478
  self,
473
- drives,
474
- extra_model_arguments,
475
- instance_families,
476
- lifecycles,
477
- num_regions,
478
- num_results,
479
- region,
480
- model_mean_desires,
481
- ):
479
+ drives: Optional[Sequence[str]],
480
+ extra_model_arguments: Dict[str, Any],
481
+ instance_families: Optional[Sequence[str]],
482
+ lifecycles: Sequence[Lifecycle],
483
+ num_regions: int,
484
+ num_results: Optional[int],
485
+ region: str,
486
+ model_mean_desires: Dict[str, CapacityDesires],
487
+ ) -> Sequence[CapacityPlan]:
482
488
  mean_plans = []
483
489
  for mean_sub_model, mean_sub_desire in model_mean_desires.items():
484
490
  mean_sub_plan = self._plan_certain(
@@ -585,7 +591,7 @@ class CapacityPlanner:
585
591
  ]
586
592
 
587
593
  # Calculates the minimum cpu, memory, and network requirements based on desires.
588
- def _per_instance_requirements(self, desires) -> Tuple[int, float]:
594
+ def _per_instance_requirements(self, desires: CapacityDesires) -> Tuple[int, float]:
589
595
  # Applications often set fixed reservations of heap or OS memory
590
596
  per_instance_mem = (
591
597
  desires.data_shape.reserved_instance_app_mem_gib
@@ -621,14 +627,14 @@ class CapacityPlanner:
621
627
 
622
628
  def generate_scenarios( # pylint: disable=too-many-positional-arguments
623
629
  self,
624
- model,
625
- region,
626
- desires,
627
- num_regions,
628
- lifecycles,
629
- instance_families,
630
- drives,
631
- ):
630
+ model: CapacityModel,
631
+ region: str,
632
+ desires: CapacityDesires,
633
+ num_regions: int,
634
+ lifecycles: Optional[Sequence[Lifecycle]],
635
+ instance_families: Optional[Sequence[str]],
636
+ drives: Optional[Sequence[str]],
637
+ ) -> Generator[Tuple[Instance, Drive, RegionContext], None, None]:
632
638
  lifecycles = lifecycles or self._default_lifecycles
633
639
  instance_families = instance_families or []
634
640
  drives = drives or []
@@ -718,8 +724,8 @@ class CapacityPlanner:
718
724
  lifecycles = lifecycles or self._default_lifecycles
719
725
 
720
726
  # requirement types -> values
721
- zonal_requirements: Dict[str, Dict] = {}
722
- regional_requirements: Dict[str, Dict] = {}
727
+ zonal_requirements: Dict[str, Dict[str, List[Interval]]] = {}
728
+ regional_requirements: Dict[str, Dict[str, List[Interval]]] = {}
723
729
 
724
730
  regret_clusters_by_model: Dict[
725
731
  str, Sequence[Tuple[CapacityPlan, CapacityDesires, float]]
@@ -836,7 +842,7 @@ class CapacityPlanner:
836
842
  model_name: str,
837
843
  desires: CapacityDesires,
838
844
  extra_model_arguments: Dict[str, Any],
839
- ):
845
+ ) -> Generator[Tuple[str, CapacityDesires], None, None]:
840
846
  queue: List[Tuple[CapacityDesires, str]] = [(desires, model_name)]
841
847
  models_used = []
842
848
 
@@ -5,6 +5,8 @@ import logging
5
5
  import os
6
6
  from functools import reduce
7
7
  from pathlib import Path
8
+ from typing import Any
9
+ from typing import cast
8
10
  from typing import Dict
9
11
  from typing import List
10
12
  from typing import Optional
@@ -20,11 +22,11 @@ from service_capacity_modeling.interface import Service
20
22
  logger = logging.getLogger(__name__)
21
23
 
22
24
 
23
- def load_pricing(pricing: Dict) -> Pricing:
25
+ def load_pricing(pricing: Dict[str, Any]) -> Pricing:
24
26
  return Pricing(regions=pricing)
25
27
 
26
28
 
27
- def load_hardware(hardware: Dict) -> Hardware:
29
+ def load_hardware(hardware: Dict[str, Any]) -> Hardware:
28
30
  return Hardware(**hardware)
29
31
 
30
32
 
@@ -103,7 +105,9 @@ def merge_hardware(existing: Hardware, override: Hardware) -> Hardware:
103
105
  merged[key] = override_obj.get(key)
104
106
  elif isinstance(existing_field, Dict):
105
107
  override_field = override_obj.get(key)
106
- merged_field = merged.setdefault(key, {})
108
+ if override_field is None:
109
+ override_field = {}
110
+ merged_field = cast(Dict[str, Any], merged.setdefault(key, {}))
107
111
 
108
112
  existing_keys = existing_field.keys()
109
113
  override_keys = override_obj.get(key, {}).keys()
@@ -119,7 +123,7 @@ def merge_hardware(existing: Hardware, override: Hardware) -> Hardware:
119
123
  return Hardware(**merged)
120
124
 
121
125
 
122
- def merge_pricing(existing: Dict, override: Dict) -> Dict:
126
+ def merge_pricing(existing: Dict[str, Any], override: Dict[str, Any]) -> Dict[str, Any]:
123
127
  merged = existing.copy()
124
128
  for region, override_pricing in override.items():
125
129
  if region not in merged:
@@ -165,7 +169,7 @@ def load_hardware_from_disk(
165
169
  if shape_paths is None:
166
170
  shape_paths = []
167
171
 
168
- combined_pricing: Dict = {}
172
+ combined_pricing: Dict[str, Any] = {}
169
173
 
170
174
  logger.debug("Loading pricing from: %s", price_paths)
171
175
  for price_path in price_paths:
@@ -185,7 +189,7 @@ def load_hardware_from_disk(
185
189
  return price_hardware(hardware=hardware, pricing=pricing)
186
190
 
187
191
 
188
- def load_hardware_from_s3(bucket, path) -> GlobalHardware:
192
+ def load_hardware_from_s3(bucket: str, path: str) -> GlobalHardware:
189
193
  try:
190
194
  # boto is a heavy dependency so we only want to take it if
191
195
  # someone will be using it ...
@@ -205,7 +209,7 @@ def load_hardware_from_s3(bucket, path) -> GlobalHardware:
205
209
 
206
210
 
207
211
  class HardwareShapes:
208
- def __init__(self):
212
+ def __init__(self) -> None:
209
213
  self._hardware: Optional[GlobalHardware] = None
210
214
 
211
215
  def load(self, new_hardware: GlobalHardware) -> None:
@@ -0,0 +1,172 @@
1
+ {
2
+ "instances": {
3
+ "i3en.large": {
4
+ "name": "i3en.large",
5
+ "cpu": 2,
6
+ "cpu_cores": 1,
7
+ "cpu_ghz": 3.1,
8
+ "cpu_ipc_scale": 1.0,
9
+ "ram_gib": 15.26,
10
+ "net_mbps": 2100.0,
11
+ "drive": {
12
+ "name": "ephem",
13
+ "size_gib": 1164,
14
+ "read_io_per_s": 42500,
15
+ "write_io_per_s": 32500,
16
+ "single_tenant": false,
17
+ "read_io_latency_ms": {
18
+ "low": 0.08,
19
+ "mid": 0.125,
20
+ "high": 0.2,
21
+ "confidence": 0.9,
22
+ "minimum_value": 0.07,
23
+ "maximum_value": 2.0
24
+ }
25
+ }
26
+ },
27
+ "i3en.xlarge": {
28
+ "name": "i3en.xlarge",
29
+ "cpu": 4,
30
+ "cpu_cores": 2,
31
+ "cpu_ghz": 3.1,
32
+ "cpu_ipc_scale": 1.0,
33
+ "ram_gib": 30.52,
34
+ "net_mbps": 4200.0,
35
+ "drive": {
36
+ "name": "ephem",
37
+ "size_gib": 2328,
38
+ "read_io_per_s": 85000,
39
+ "write_io_per_s": 65000,
40
+ "single_tenant": false,
41
+ "read_io_latency_ms": {
42
+ "low": 0.08,
43
+ "mid": 0.125,
44
+ "high": 0.2,
45
+ "confidence": 0.9,
46
+ "minimum_value": 0.07,
47
+ "maximum_value": 2.0
48
+ }
49
+ }
50
+ },
51
+ "i3en.2xlarge": {
52
+ "name": "i3en.2xlarge",
53
+ "cpu": 8,
54
+ "cpu_cores": 4,
55
+ "cpu_ghz": 3.1,
56
+ "cpu_ipc_scale": 1.0,
57
+ "ram_gib": 61.04,
58
+ "net_mbps": 8400.0,
59
+ "drive": {
60
+ "name": "ephem",
61
+ "size_gib": 4657,
62
+ "read_io_per_s": 170000,
63
+ "write_io_per_s": 130000,
64
+ "single_tenant": false,
65
+ "read_io_latency_ms": {
66
+ "low": 0.08,
67
+ "mid": 0.125,
68
+ "high": 0.2,
69
+ "confidence": 0.9,
70
+ "minimum_value": 0.07,
71
+ "maximum_value": 2.0
72
+ }
73
+ }
74
+ },
75
+ "i3en.3xlarge": {
76
+ "name": "i3en.3xlarge",
77
+ "cpu": 12,
78
+ "cpu_cores": 6,
79
+ "cpu_ghz": 3.1,
80
+ "cpu_ipc_scale": 1.0,
81
+ "ram_gib": 91.55,
82
+ "net_mbps": 12500.0,
83
+ "drive": {
84
+ "name": "ephem",
85
+ "size_gib": 6985,
86
+ "read_io_per_s": 255000,
87
+ "write_io_per_s": 195000,
88
+ "single_tenant": true,
89
+ "read_io_latency_ms": {
90
+ "low": 0.08,
91
+ "mid": 0.125,
92
+ "high": 0.2,
93
+ "confidence": 0.9,
94
+ "minimum_value": 0.07,
95
+ "maximum_value": 2.0
96
+ }
97
+ }
98
+ },
99
+ "i3en.6xlarge": {
100
+ "name": "i3en.6xlarge",
101
+ "cpu": 24,
102
+ "cpu_cores": 12,
103
+ "cpu_ghz": 3.1,
104
+ "cpu_ipc_scale": 1.0,
105
+ "ram_gib": 183.11,
106
+ "net_mbps": 25000.0,
107
+ "drive": {
108
+ "name": "ephem",
109
+ "size_gib": 13970,
110
+ "read_io_per_s": 510000,
111
+ "write_io_per_s": 390000,
112
+ "single_tenant": true,
113
+ "read_io_latency_ms": {
114
+ "low": 0.08,
115
+ "mid": 0.125,
116
+ "high": 0.2,
117
+ "confidence": 0.9,
118
+ "minimum_value": 0.07,
119
+ "maximum_value": 2.0
120
+ }
121
+ }
122
+ },
123
+ "i3en.12xlarge": {
124
+ "name": "i3en.12xlarge",
125
+ "cpu": 48,
126
+ "cpu_cores": 24,
127
+ "cpu_ghz": 3.1,
128
+ "cpu_ipc_scale": 1.0,
129
+ "ram_gib": 366.21,
130
+ "net_mbps": 50000.0,
131
+ "drive": {
132
+ "name": "ephem",
133
+ "size_gib": 27940,
134
+ "read_io_per_s": 1020000,
135
+ "write_io_per_s": 780000,
136
+ "single_tenant": true,
137
+ "read_io_latency_ms": {
138
+ "low": 0.08,
139
+ "mid": 0.125,
140
+ "high": 0.2,
141
+ "confidence": 0.9,
142
+ "minimum_value": 0.07,
143
+ "maximum_value": 2.0
144
+ }
145
+ }
146
+ },
147
+ "i3en.24xlarge": {
148
+ "name": "i3en.24xlarge",
149
+ "cpu": 96,
150
+ "cpu_cores": 48,
151
+ "cpu_ghz": 3.1,
152
+ "cpu_ipc_scale": 1.0,
153
+ "ram_gib": 732.42,
154
+ "net_mbps": 100000.0,
155
+ "drive": {
156
+ "name": "ephem",
157
+ "size_gib": 55879,
158
+ "read_io_per_s": 2040000,
159
+ "write_io_per_s": 1560000,
160
+ "single_tenant": true,
161
+ "read_io_latency_ms": {
162
+ "low": 0.08,
163
+ "mid": 0.125,
164
+ "high": 0.2,
165
+ "confidence": 0.9,
166
+ "minimum_value": 0.07,
167
+ "maximum_value": 2.0
168
+ }
169
+ }
170
+ }
171
+ }
172
+ }
@@ -0,0 +1,220 @@
1
+ {
2
+ "instances": {
3
+ "i4i.large": {
4
+ "name": "i4i.large",
5
+ "cpu": 2,
6
+ "cpu_cores": 1,
7
+ "cpu_ghz": 3.5,
8
+ "cpu_ipc_scale": 1.15,
9
+ "ram_gib": 15.26,
10
+ "net_mbps": 781.0,
11
+ "drive": {
12
+ "name": "ephem",
13
+ "size_gib": 436,
14
+ "read_io_per_s": 50000,
15
+ "write_io_per_s": 27500,
16
+ "single_tenant": false,
17
+ "read_io_latency_ms": {
18
+ "low": 0.1,
19
+ "mid": 0.125,
20
+ "high": 0.17,
21
+ "confidence": 0.9,
22
+ "minimum_value": 0.05,
23
+ "maximum_value": 2.0
24
+ }
25
+ }
26
+ },
27
+ "i4i.xlarge": {
28
+ "name": "i4i.xlarge",
29
+ "cpu": 4,
30
+ "cpu_cores": 2,
31
+ "cpu_ghz": 3.5,
32
+ "cpu_ipc_scale": 1.15,
33
+ "ram_gib": 30.52,
34
+ "net_mbps": 1875.0,
35
+ "drive": {
36
+ "name": "ephem",
37
+ "size_gib": 873,
38
+ "read_io_per_s": 100000,
39
+ "write_io_per_s": 55000,
40
+ "single_tenant": false,
41
+ "read_io_latency_ms": {
42
+ "low": 0.1,
43
+ "mid": 0.125,
44
+ "high": 0.17,
45
+ "confidence": 0.9,
46
+ "minimum_value": 0.05,
47
+ "maximum_value": 2.0
48
+ }
49
+ }
50
+ },
51
+ "i4i.2xlarge": {
52
+ "name": "i4i.2xlarge",
53
+ "cpu": 8,
54
+ "cpu_cores": 4,
55
+ "cpu_ghz": 3.5,
56
+ "cpu_ipc_scale": 1.15,
57
+ "ram_gib": 61.04,
58
+ "net_mbps": 4687.0,
59
+ "drive": {
60
+ "name": "ephem",
61
+ "size_gib": 1746,
62
+ "read_io_per_s": 200000,
63
+ "write_io_per_s": 110000,
64
+ "single_tenant": false,
65
+ "read_io_latency_ms": {
66
+ "low": 0.1,
67
+ "mid": 0.125,
68
+ "high": 0.17,
69
+ "confidence": 0.9,
70
+ "minimum_value": 0.05,
71
+ "maximum_value": 2.0
72
+ }
73
+ }
74
+ },
75
+ "i4i.4xlarge": {
76
+ "name": "i4i.4xlarge",
77
+ "cpu": 16,
78
+ "cpu_cores": 8,
79
+ "cpu_ghz": 3.5,
80
+ "cpu_ipc_scale": 1.15,
81
+ "ram_gib": 122.07,
82
+ "net_mbps": 9375.0,
83
+ "drive": {
84
+ "name": "ephem",
85
+ "size_gib": 3492,
86
+ "read_io_per_s": 400000,
87
+ "write_io_per_s": 220000,
88
+ "single_tenant": true,
89
+ "read_io_latency_ms": {
90
+ "low": 0.1,
91
+ "mid": 0.125,
92
+ "high": 0.17,
93
+ "confidence": 0.9,
94
+ "minimum_value": 0.05,
95
+ "maximum_value": 2.0
96
+ }
97
+ }
98
+ },
99
+ "i4i.8xlarge": {
100
+ "name": "i4i.8xlarge",
101
+ "cpu": 32,
102
+ "cpu_cores": 16,
103
+ "cpu_ghz": 3.5,
104
+ "cpu_ipc_scale": 1.15,
105
+ "ram_gib": 244.14,
106
+ "net_mbps": 18750.0,
107
+ "drive": {
108
+ "name": "ephem",
109
+ "size_gib": 6985,
110
+ "read_io_per_s": 800000,
111
+ "write_io_per_s": 440000,
112
+ "single_tenant": true,
113
+ "read_io_latency_ms": {
114
+ "low": 0.1,
115
+ "mid": 0.125,
116
+ "high": 0.17,
117
+ "confidence": 0.9,
118
+ "minimum_value": 0.05,
119
+ "maximum_value": 2.0
120
+ }
121
+ }
122
+ },
123
+ "i4i.12xlarge": {
124
+ "name": "i4i.12xlarge",
125
+ "cpu": 48,
126
+ "cpu_cores": 24,
127
+ "cpu_ghz": 3.5,
128
+ "cpu_ipc_scale": 1.15,
129
+ "ram_gib": 366.21,
130
+ "net_mbps": 28125.0,
131
+ "drive": {
132
+ "name": "ephem",
133
+ "size_gib": 10477,
134
+ "read_io_per_s": 1200000,
135
+ "write_io_per_s": 660000,
136
+ "single_tenant": true,
137
+ "read_io_latency_ms": {
138
+ "low": 0.1,
139
+ "mid": 0.125,
140
+ "high": 0.17,
141
+ "confidence": 0.9,
142
+ "minimum_value": 0.05,
143
+ "maximum_value": 2.0
144
+ }
145
+ }
146
+ },
147
+ "i4i.16xlarge": {
148
+ "name": "i4i.16xlarge",
149
+ "cpu": 64,
150
+ "cpu_cores": 32,
151
+ "cpu_ghz": 3.5,
152
+ "cpu_ipc_scale": 1.15,
153
+ "ram_gib": 488.28,
154
+ "net_mbps": 37500.0,
155
+ "drive": {
156
+ "name": "ephem",
157
+ "size_gib": 13970,
158
+ "read_io_per_s": 1600000,
159
+ "write_io_per_s": 880000,
160
+ "single_tenant": true,
161
+ "read_io_latency_ms": {
162
+ "low": 0.1,
163
+ "mid": 0.125,
164
+ "high": 0.17,
165
+ "confidence": 0.9,
166
+ "minimum_value": 0.05,
167
+ "maximum_value": 2.0
168
+ }
169
+ }
170
+ },
171
+ "i4i.24xlarge": {
172
+ "name": "i4i.24xlarge",
173
+ "cpu": 96,
174
+ "cpu_cores": 48,
175
+ "cpu_ghz": 3.5,
176
+ "cpu_ipc_scale": 1.15,
177
+ "ram_gib": 732.42,
178
+ "net_mbps": 56250.0,
179
+ "drive": {
180
+ "name": "ephem",
181
+ "size_gib": 20955,
182
+ "read_io_per_s": 2400000,
183
+ "write_io_per_s": 1320000,
184
+ "single_tenant": true,
185
+ "read_io_latency_ms": {
186
+ "low": 0.1,
187
+ "mid": 0.125,
188
+ "high": 0.17,
189
+ "confidence": 0.9,
190
+ "minimum_value": 0.05,
191
+ "maximum_value": 2.0
192
+ }
193
+ }
194
+ },
195
+ "i4i.32xlarge": {
196
+ "name": "i4i.32xlarge",
197
+ "cpu": 128,
198
+ "cpu_cores": 64,
199
+ "cpu_ghz": 3.5,
200
+ "cpu_ipc_scale": 1.15,
201
+ "ram_gib": 976.56,
202
+ "net_mbps": 75000.0,
203
+ "drive": {
204
+ "name": "ephem",
205
+ "size_gib": 27940,
206
+ "read_io_per_s": 3200000,
207
+ "write_io_per_s": 1760000,
208
+ "single_tenant": true,
209
+ "read_io_latency_ms": {
210
+ "low": 0.1,
211
+ "mid": 0.125,
212
+ "high": 0.17,
213
+ "confidence": 0.9,
214
+ "minimum_value": 0.05,
215
+ "maximum_value": 2.0
216
+ }
217
+ }
218
+ }
219
+ }
220
+ }