Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/firecracker
Path: blob/main/tests/integration_tests/functional/test_topology.py
1958 views
1
# Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
# SPDX-License-Identifier: Apache-2.0
3
"""Tests for ensuring correctness of CPU and cache topology in the guest."""
4
5
import os
6
import platform
7
import pytest
8
import framework.utils_cpuid as utils
9
10
TOPOLOGY_STR = {1: "0", 2: "0,1", 16: "0-15"}
11
PLATFORM = platform.machine()
12
13
14
def _check_cpu_topology(test_microvm, expected_cpu_count,
15
expected_threads_per_core,
16
expected_cpus_list):
17
expected_cpu_topology = {
18
"CPU(s)": str(expected_cpu_count),
19
"On-line CPU(s) list": expected_cpus_list,
20
"Thread(s) per core": str(expected_threads_per_core),
21
"Core(s) per socket": str(
22
int(expected_cpu_count / expected_threads_per_core)),
23
"Socket(s)": "1",
24
"NUMA node(s)": "1"
25
}
26
27
utils.check_guest_cpuid_output(test_microvm, "lscpu", None, ':',
28
expected_cpu_topology)
29
30
31
def _check_cache_topology_x86(test_microvm, num_vcpus_on_lvl_1_cache,
32
num_vcpus_on_lvl_3_cache):
33
vm = test_microvm
34
expected_lvl_1_str = '{} ({})'.format(hex(num_vcpus_on_lvl_1_cache),
35
num_vcpus_on_lvl_1_cache)
36
expected_lvl_3_str = '{} ({})'.format(hex(num_vcpus_on_lvl_3_cache),
37
num_vcpus_on_lvl_3_cache)
38
39
cpu_vendor = utils.get_cpu_vendor()
40
if cpu_vendor == utils.CpuVendor.AMD:
41
expected_level_1_topology = {
42
"level": '0x1 (1)',
43
"extra cores sharing this cache": expected_lvl_1_str
44
}
45
expected_level_3_topology = {
46
"level": '0x3 (3)',
47
"extra cores sharing this cache": expected_lvl_3_str
48
}
49
elif cpu_vendor == utils.CpuVendor.INTEL:
50
expected_level_1_topology = {
51
"cache level": '0x1 (1)',
52
"extra threads sharing this cache": expected_lvl_1_str,
53
}
54
expected_level_3_topology = {
55
"cache level": '0x3 (3)',
56
"extra threads sharing this cache": expected_lvl_3_str,
57
}
58
59
utils.check_guest_cpuid_output(vm, "cpuid -1", "--- cache 0 ---", '=',
60
expected_level_1_topology)
61
utils.check_guest_cpuid_output(vm, "cpuid -1", "--- cache 1 ---", '=',
62
expected_level_1_topology)
63
utils.check_guest_cpuid_output(vm, "cpuid -1", "--- cache 2 ---", '=',
64
expected_level_1_topology)
65
utils.check_guest_cpuid_output(vm, "cpuid -1", "--- cache 3 ---", '=',
66
expected_level_3_topology)
67
68
69
def _check_cache_topology_arm(test_microvm, no_cpus):
70
# We will check the cache topology by looking at what each cpu
71
# contains as far as cache info.
72
# For that we are iterating through the hierarchy of folders inside:
73
# /sys/devices/system/cpu/cpuX/cache/indexY/type - the type of the cache
74
# (i.e Instruction, Data, Unified)
75
# /sys/devices/system/cpu/cpuX/cache/indexY/size - size of the cache
76
# /sys/devices/system/cpu/cpuX/cache/indexY/level - L1, L2 or L3 cache.
77
# There are 2 types of L1 cache (instruction and data) that is why the
78
# "cache_info" variable below has 4 items.
79
80
path = "/sys/devices/system/cpu/"
81
82
cache_files = ["level", "type", "size",
83
"coherency_line_size", "number_of_sets"]
84
85
for i in range(no_cpus):
86
cpu_path = os.path.join(os.path.join(path, 'cpu{}'.format(i)), "cache")
87
dirs = os.listdir(cpu_path)
88
for cache_level in dirs:
89
if "index" not in os.path.basename(cache_level):
90
continue
91
cache_path = os.path.join(cpu_path, cache_level)
92
93
for cache_file in cache_files:
94
absolute_cache_file = os.path.join(cache_path, cache_file)
95
with open(absolute_cache_file, 'r') as file:
96
host_val = file.readline().strip()
97
guest_val = utils.read_guest_file(
98
test_microvm, absolute_cache_file
99
)
100
assert host_val == guest_val
101
102
103
@pytest.mark.skipif(
104
PLATFORM != "x86_64",
105
reason="Firecracker supports CPU topology only on x86_64."
106
)
107
@pytest.mark.parametrize(
108
"num_vcpus",
109
[1, 2, 16],
110
)
111
@pytest.mark.parametrize(
112
"htt",
113
[True, False],
114
)
115
def test_cpu_topology(test_microvm_with_ssh, network_config, num_vcpus, htt):
116
"""Check the CPU topology for a microvm with the specified config."""
117
vm = test_microvm_with_ssh
118
vm.spawn()
119
vm.basic_config(vcpu_count=num_vcpus, ht_enabled=htt)
120
_tap, _, _ = vm.ssh_network_config(network_config, '1')
121
vm.start()
122
123
_check_cpu_topology(vm, num_vcpus, 2 if htt and num_vcpus > 1 else 1,
124
TOPOLOGY_STR[num_vcpus])
125
126
127
@pytest.mark.parametrize(
128
"num_vcpus",
129
[1, 2, 16],
130
)
131
@pytest.mark.parametrize(
132
"htt",
133
[True, False],
134
)
135
def test_cache_topology(test_microvm_with_ssh, network_config, num_vcpus, htt):
136
"""Check the cache topology for a microvm with the specified config."""
137
vm = test_microvm_with_ssh
138
vm.spawn()
139
vm.basic_config(vcpu_count=num_vcpus, ht_enabled=htt)
140
_tap, _, _ = vm.ssh_network_config(network_config, '1')
141
vm.start()
142
if PLATFORM == "x86_64":
143
_check_cache_topology_x86(vm, 1 if htt and num_vcpus > 1 else 0,
144
num_vcpus - 1)
145
elif PLATFORM == "aarch64":
146
_check_cache_topology_arm(vm, num_vcpus)
147
else:
148
raise Exception("This test is not run on this platform!")
149
150