29
29
CONFIG_NAME_ABS = os .path .join (defs .CFG_LOCATION , CONFIG_NAME_REL )
30
30
CONFIG_DICT = json .load (open (CONFIG_NAME_ABS , encoding = "utf-8" ))
31
31
32
+ # Number of seconds to wait for the iperf3 server to start
33
+ SERVER_STARTUP_TIME_SEC = 2
32
34
DEBUG = False
33
35
IPERF3 = "iperf3"
34
36
THROUGHPUT = "throughput"
43
45
DELTA_PERCENTAGE_TAG = "delta_percentage"
44
46
TARGET_TAG = "target"
45
47
48
+ # How many clients/servers should be spawned per vcpu
49
+ LOAD_FACTOR = 1
50
+
51
+ # Time (in seconds) for which iperf "warms up"
52
+ WARMUP_SEC = 5
53
+
54
+ # Time (in seconds) for which iperf runs after warmup is done
55
+ RUNTIME_SEC = 20
56
+
57
+ # Dictionary mapping modes (guest-to-host, host-to-guest, bidirectional) to arguments passed to the iperf3 clients spawned
58
+ MODE_MAP = {"bd" : ["" , "-R" ], "g2h" : ["" ], "h2g" : ["-R" ]}
59
+
46
60
47
61
# pylint: disable=R0903
48
62
class NetTCPThroughputBaselineProvider (BaselineProvider ):
@@ -95,7 +109,7 @@ def produce_iperf_output(
95
109
current_avail_cpu += 1
96
110
97
111
# Wait for iperf3 server to start.
98
- time .sleep (2 )
112
+ time .sleep (SERVER_STARTUP_TIME_SEC )
99
113
100
114
# Start `vcpus` iperf3 clients. We can not use iperf3 parallel streams
101
115
# due to non deterministic results and lack of scaling.
@@ -217,76 +231,73 @@ def consume_iperf_tcp_output(cons, result, vcpus_count):
217
231
cons .consume_custom (fcvcpu_samples_tag , cpu_util_fc_vcpu_samples )
218
232
219
233
220
- def create_pipes_generator (basevm , mode , current_avail_cpu , protocol , host_ip , env_id ):
234
+ def pipe (basevm , mode , payload_length , current_avail_cpu , host_ip , env_id ):
221
235
"""Create producer/consumer pipes."""
222
- for payload_length in protocol ["payload_length" ]:
223
- iperf_guest_cmd_builder = (
224
- CmdBuilder (IPERF3 )
225
- .with_arg ("--verbose" )
226
- .with_arg ("--client" , host_ip )
227
- .with_arg ("--time" , CONFIG_DICT ["time" ])
228
- .with_arg ("--json" )
229
- .with_arg ("--omit" , protocol ["omit" ])
236
+ iperf_guest_cmd_builder = (
237
+ CmdBuilder (IPERF3 )
238
+ .with_arg ("--verbose" )
239
+ .with_arg ("--client" , host_ip )
240
+ .with_arg ("--time" , RUNTIME_SEC )
241
+ .with_arg ("--json" )
242
+ .with_arg ("--omit" , WARMUP_SEC )
243
+ )
244
+
245
+ if payload_length != "DEFAULT" :
246
+ iperf_guest_cmd_builder = iperf_guest_cmd_builder .with_arg (
247
+ "--len" , f"{ payload_length } "
230
248
)
231
249
232
- if payload_length != "DEFAULT" :
233
- iperf_guest_cmd_builder = iperf_guest_cmd_builder .with_arg (
234
- "--len" , f"{ payload_length } "
235
- )
236
-
237
- iperf3_id = f"tcp-p{ payload_length } -wsDEFAULT-{ mode } "
238
-
239
- cons = consumer .LambdaConsumer (
240
- metadata_provider = DictMetadataProvider (
241
- measurements = CONFIG_DICT ["measurements" ],
242
- baseline_provider = NetTCPThroughputBaselineProvider (env_id , iperf3_id ),
243
- ),
244
- func = consume_iperf_tcp_output ,
245
- func_kwargs = {"vcpus_count" : basevm .vcpus_count },
246
- )
247
-
248
- prod_kwargs = {
249
- "guest_cmd_builder" : iperf_guest_cmd_builder ,
250
- "basevm" : basevm ,
251
- "current_avail_cpu" : current_avail_cpu ,
252
- "runtime" : CONFIG_DICT ["time" ],
253
- "omit" : protocol ["omit" ],
254
- "load_factor" : CONFIG_DICT ["load_factor" ],
255
- "modes" : CONFIG_DICT ["modes" ][mode ],
256
- }
257
- prod = producer .LambdaProducer (produce_iperf_output , prod_kwargs )
258
- yield cons , prod , f"{ env_id } /{ iperf3_id } "
259
-
260
-
261
- def pipes (basevm , host_ip , current_avail_cpu , env_id ):
262
- """Pipes generator."""
263
- for mode in CONFIG_DICT ["modes" ]:
264
- # We run bi-directional tests only on uVM with more than 2 vCPus
265
- # because we need to pin one iperf3/direction per vCPU, and since we
266
- # have two directions, we need at least two vCPUs.
267
- if mode == "bd" and basevm .vcpus_count < 2 :
268
- continue
269
-
270
- for protocol in CONFIG_DICT ["protocols" ]:
271
- # Distribute modes evenly between producers and consumers.
272
- pipes_generator = create_pipes_generator (
273
- basevm , mode , current_avail_cpu , protocol , host_ip , env_id
274
- )
275
-
276
- for cons , prod , pipe_tag in pipes_generator :
277
- yield cons , prod , pipe_tag
250
+ iperf3_id = f"tcp-p{ payload_length } -wsDEFAULT-{ mode } "
251
+
252
+ cons = consumer .LambdaConsumer (
253
+ metadata_provider = DictMetadataProvider (
254
+ measurements = CONFIG_DICT ["measurements" ],
255
+ baseline_provider = NetTCPThroughputBaselineProvider (env_id , iperf3_id ),
256
+ ),
257
+ func = consume_iperf_tcp_output ,
258
+ func_kwargs = {"vcpus_count" : basevm .vcpus_count },
259
+ )
260
+
261
+ prod_kwargs = {
262
+ "guest_cmd_builder" : iperf_guest_cmd_builder ,
263
+ "basevm" : basevm ,
264
+ "current_avail_cpu" : current_avail_cpu ,
265
+ "runtime" : RUNTIME_SEC ,
266
+ "omit" : WARMUP_SEC ,
267
+ "load_factor" : LOAD_FACTOR ,
268
+ "modes" : MODE_MAP [mode ],
269
+ }
270
+ prod = producer .LambdaProducer (produce_iperf_output , prod_kwargs )
271
+ return cons , prod , f"{ env_id } /{ iperf3_id } "
278
272
279
273
280
274
@pytest .mark .nonci
281
275
@pytest .mark .timeout (3600 )
282
276
@pytest .mark .parametrize ("vcpus" , [1 , 2 ])
277
+ @pytest .mark .parametrize (
278
+ "payload_length" , ["DEFAULT" , "1024K" ], ids = ["pDEFAULT" , "p1024K" ]
279
+ )
280
+ @pytest .mark .parametrize ("mode" , ["g2h" , "h2g" , "bd" ])
283
281
def test_network_tcp_throughput (
284
- microvm_factory , network_config , guest_kernel , rootfs , vcpus , st_core
282
+ microvm_factory ,
283
+ network_config ,
284
+ guest_kernel ,
285
+ rootfs ,
286
+ vcpus ,
287
+ payload_length ,
288
+ mode ,
289
+ st_core ,
285
290
):
286
291
"""
287
292
Iperf between guest and host in both directions for TCP workload.
288
293
"""
289
294
295
+ # We run bi-directional tests only on uVM with more than 2 vCPus
296
+ # because we need to pin one iperf3/direction per vCPU, and since we
297
+ # have two directions, we need at least two vCPUs.
298
+ if mode == "bd" and vcpus < 2 :
299
+ pytest .skip ("bidrectional test only done with at least 2 vcpus" )
300
+
290
301
guest_mem_mib = 1024
291
302
vm = microvm_factory .build (guest_kernel , rootfs , monitor_memory = False )
292
303
vm .spawn ()
@@ -312,13 +323,15 @@ def test_network_tcp_throughput(
312
323
current_avail_cpu += 1
313
324
assert vm .pin_vcpu (i , current_avail_cpu ), f"Failed to pin fc_vcpu { i } thread."
314
325
315
- for cons , prod , tag in pipes (
326
+ cons , prod , tag = pipe (
316
327
vm ,
317
- DEFAULT_HOST_IP ,
328
+ mode ,
329
+ payload_length ,
318
330
current_avail_cpu + 1 ,
331
+ DEFAULT_HOST_IP ,
319
332
f"{ guest_kernel .name ()} /{ rootfs .name ()} /{ microvm_cfg } " ,
320
- ):
321
- st_core .add_pipe (prod , cons , tag )
333
+ )
334
+ st_core .add_pipe (prod , cons , tag )
322
335
323
336
# Start running the commands on guest, gather results and verify pass
324
337
# criteria.
0 commit comments