11
11
from framework .builder import MicrovmBuilder , SnapshotBuilder , SnapshotType
12
12
from framework .utils import get_free_mem_ssh , run_cmd
13
13
14
- MB_TO_PAGES = 256
15
14
STATS_POLLING_INTERVAL_S = 1
16
15
17
16
18
17
@retry (delay = 0.5 , tries = 10 )
19
- def get_stable_rss_mem_by_pid (pid , percentage_delta = 0.5 ):
18
+ def get_stable_rss_mem_by_pid (pid , percentage_delta = 1 ):
20
19
"""
21
20
Get the RSS memory that a guest uses, given the pid of the guest.
22
21
23
22
Wait till the fluctuations in RSS drop below percentage_delta. If timeout
24
23
is reached before the fluctuations drop, raise an exception.
25
24
"""
26
25
26
+ # All values are reported as KiB
27
+
27
28
def get_rss_from_pmap ():
28
29
_ , output , _ = run_cmd ("pmap -X {}" .format (pid ))
29
30
return int (output .split ("\n " )[- 2 ].split ()[1 ], 10 )
30
31
31
32
first_rss = get_rss_from_pmap ()
32
33
time .sleep (1 )
33
34
second_rss = get_rss_from_pmap ()
34
-
35
- delta = ( abs (first_rss - second_rss ) / float ( first_rss )) * 100
36
- assert delta < percentage_delta
37
-
35
+ print ( f"RSS readings: { first_rss } , { second_rss } " )
36
+ abs_diff = abs (first_rss - second_rss )
37
+ abs_delta = 100 * abs_diff / first_rss
38
+ assert abs_delta < percentage_delta or abs_diff < 2 ** 10
38
39
return second_rss
39
40
40
41
41
- def make_guest_dirty_memory (ssh_connection , should_oom = False , amount = 8192 ):
42
+ def make_guest_dirty_memory (ssh_connection , should_oom = False , amount_mib = 32 ):
42
43
"""Tell the guest, over ssh, to dirty `amount` pages of memory."""
43
44
logger = logging .getLogger ("make_guest_dirty_memory" )
44
45
45
- amount_in_mbytes = amount / MB_TO_PAGES
46
-
47
- cmd = f"/sbin/fillmem { amount_in_mbytes } "
46
+ cmd = f"/sbin/fillmem { amount_mib } "
48
47
exit_code , stdout , stderr = ssh_connection .execute_command (cmd )
49
48
# add something to the logs for troubleshooting
50
49
if exit_code != 0 :
@@ -53,18 +52,23 @@ def make_guest_dirty_memory(ssh_connection, should_oom=False, amount=8192):
53
52
logger .error ("stderr: %s" , stderr )
54
53
55
54
cmd = "cat /tmp/fillmem_output.txt"
56
- _ , stdout , _ = ssh_connection .execute_command (cmd )
55
+ tries = 3
56
+ while tries > 0 :
57
+ # it may take a bit of time to dirty the memory and the OOM to kick-in
58
+ time .sleep (0.5 )
59
+ _ , stdout , _ = ssh_connection .execute_command (cmd )
60
+ if stdout != "" :
61
+ break
62
+ tries -= 1
63
+
57
64
if should_oom :
58
- assert (
59
- "OOM Killer stopped the program with "
60
- "signal 9, exit code 0" in stdout
61
- )
65
+ assert "OOM Killer stopped the program with signal 9, exit code 0" in stdout
62
66
else :
63
67
assert exit_code == 0 , stderr
64
68
assert "Memory filling was successful" in stdout , stdout
65
69
66
70
67
- def _test_rss_memory_lower (test_microvm ):
71
+ def _test_rss_memory_lower (test_microvm , stable_delta = 1 ):
68
72
"""Check inflating the balloon makes guest use less rss memory."""
69
73
# Get the firecracker pid, and open an ssh connection.
70
74
firecracker_pid = test_microvm .jailer_clone_pid
@@ -75,20 +79,22 @@ def _test_rss_memory_lower(test_microvm):
75
79
assert test_microvm .api_session .is_status_no_content (response .status_code )
76
80
77
81
# Get initial rss consumption.
78
- init_rss = get_stable_rss_mem_by_pid (firecracker_pid )
82
+ init_rss = get_stable_rss_mem_by_pid (firecracker_pid , percentage_delta = stable_delta )
79
83
80
84
# Get the balloon back to 0.
81
85
response = test_microvm .balloon .patch (amount_mib = 0 )
82
86
assert test_microvm .api_session .is_status_no_content (response .status_code )
83
87
# This call will internally wait for rss to become stable.
84
- _ = get_stable_rss_mem_by_pid (firecracker_pid )
88
+ _ = get_stable_rss_mem_by_pid (firecracker_pid , percentage_delta = stable_delta )
85
89
86
90
# Dirty memory, then inflate balloon and get ballooned rss consumption.
87
91
make_guest_dirty_memory (ssh_connection )
88
92
89
93
response = test_microvm .balloon .patch (amount_mib = 200 )
90
94
assert test_microvm .api_session .is_status_no_content (response .status_code )
91
- balloon_rss = get_stable_rss_mem_by_pid (firecracker_pid )
95
+ balloon_rss = get_stable_rss_mem_by_pid (
96
+ firecracker_pid , percentage_delta = stable_delta
97
+ )
92
98
93
99
# Check that the ballooning reclaimed the memory.
94
100
assert balloon_rss - init_rss <= 15000
@@ -236,7 +242,7 @@ def test_reinflate_balloon(test_microvm_with_api):
236
242
_ = get_stable_rss_mem_by_pid (firecracker_pid )
237
243
238
244
# Get the guest to dirty memory.
239
- make_guest_dirty_memory (test_microvm .ssh )
245
+ make_guest_dirty_memory (test_microvm .ssh , amount_mib = 32 )
240
246
first_reading = get_stable_rss_mem_by_pid (firecracker_pid )
241
247
242
248
# Now inflate the balloon.
@@ -251,7 +257,7 @@ def test_reinflate_balloon(test_microvm_with_api):
251
257
_ = get_stable_rss_mem_by_pid (firecracker_pid )
252
258
253
259
# Now have the guest dirty memory again.
254
- make_guest_dirty_memory (test_microvm .ssh )
260
+ make_guest_dirty_memory (test_microvm .ssh , amount_mib = 32 )
255
261
third_reading = get_stable_rss_mem_by_pid (firecracker_pid )
256
262
257
263
# Now inflate the balloon again.
@@ -335,7 +341,7 @@ def test_stats(test_microvm_with_api):
335
341
initial_stats = test_microvm .balloon .get_stats ().json ()
336
342
337
343
# Dirty 10MB of pages.
338
- make_guest_dirty_memory (test_microvm .ssh , amount = 10 * MB_TO_PAGES )
344
+ make_guest_dirty_memory (test_microvm .ssh , amount_mib = 10 )
339
345
time .sleep (1 )
340
346
# This call will internally wait for rss to become stable.
341
347
_ = get_stable_rss_mem_by_pid (firecracker_pid )
@@ -395,7 +401,7 @@ def test_stats_update(test_microvm_with_api):
395
401
firecracker_pid = test_microvm .jailer_clone_pid
396
402
397
403
# Dirty 30MB of pages.
398
- make_guest_dirty_memory (test_microvm .ssh , amount = 30 * MB_TO_PAGES )
404
+ make_guest_dirty_memory (test_microvm .ssh , amount_mib = 30 )
399
405
400
406
# This call will internally wait for rss to become stable.
401
407
_ = get_stable_rss_mem_by_pid (firecracker_pid )
@@ -453,7 +459,7 @@ def test_balloon_snapshot(bin_cloner_path, microvm_factory, guest_kernel, rootfs
453
459
vm .start ()
454
460
455
461
# Dirty 60MB of pages.
456
- make_guest_dirty_memory (vm .ssh , amount = 60 * MB_TO_PAGES )
462
+ make_guest_dirty_memory (vm .ssh , amount_mib = 60 )
457
463
time .sleep (1 )
458
464
459
465
# Get the firecracker pid, and open an ssh connection.
@@ -502,7 +508,7 @@ def test_balloon_snapshot(bin_cloner_path, microvm_factory, guest_kernel, rootfs
502
508
third_reading = get_stable_rss_mem_by_pid (firecracker_pid )
503
509
504
510
# Dirty 60MB of pages.
505
- make_guest_dirty_memory (microvm .ssh , amount = 60 * MB_TO_PAGES )
511
+ make_guest_dirty_memory (microvm .ssh , amount_mib = 60 )
506
512
507
513
# Check memory usage.
508
514
fourth_reading = get_stable_rss_mem_by_pid (firecracker_pid )
@@ -583,7 +589,7 @@ def test_memory_scrub(microvm_factory, guest_kernel, rootfs):
583
589
microvm .start ()
584
590
585
591
# Dirty 60MB of pages.
586
- make_guest_dirty_memory (microvm .ssh , amount = 60 * MB_TO_PAGES )
592
+ make_guest_dirty_memory (microvm .ssh , amount_mib = 60 )
587
593
588
594
# Now inflate the balloon with 60MB of pages.
589
595
response = microvm .balloon .patch (amount_mib = 60 )
0 commit comments