1 //========- unittests/Support/Host.cpp - Host.cpp tests --------------========//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/Support/Host.h"
10 #include "llvm/Config/llvm-config.h"
11 #include "llvm/ADT/SmallVector.h"
12 #include "llvm/ADT/Triple.h"
13 #include "llvm/Support/FileSystem.h"
14 #include "llvm/Support/Path.h"
15 #include "llvm/Support/Program.h"
16 
17 #include "gtest/gtest.h"
18 
19 #define ASSERT_NO_ERROR(x) ASSERT_EQ(x, std::error_code())
20 
21 using namespace llvm;
22 
23 class HostTest : public testing::Test {
24   Triple Host;
25 
26 protected:
27   bool isSupportedArchAndOS() {
28     // Initially this is only testing detection of the number of
29     // physical cores, which is currently only supported/tested for
30     // x86_64 Linux and Darwin.
31     return (Host.getArch() == Triple::x86_64 &&
32             (Host.isOSDarwin() || Host.getOS() == Triple::Linux));
33   }
34 
35   HostTest() : Host(Triple::normalize(sys::getProcessTriple())) {}
36 };
37 
38 TEST_F(HostTest, NumPhysicalCores) {
39   int Num = sys::getHostNumPhysicalCores();
40 
41   if (isSupportedArchAndOS())
42     ASSERT_GT(Num, 0);
43   else
44     ASSERT_EQ(Num, -1);
45 }
46 
47 TEST(getLinuxHostCPUName, ARM) {
48   StringRef CortexA9ProcCpuinfo = R"(
49 processor       : 0
50 model name      : ARMv7 Processor rev 10 (v7l)
51 BogoMIPS        : 1393.66
52 Features        : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32
53 CPU implementer : 0x41
54 CPU architecture: 7
55 CPU variant     : 0x2
56 CPU part        : 0xc09
57 CPU revision    : 10
58 
59 processor       : 1
60 model name      : ARMv7 Processor rev 10 (v7l)
61 BogoMIPS        : 1393.66
62 Features        : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32
63 CPU implementer : 0x41
64 CPU architecture: 7
65 CPU variant     : 0x2
66 CPU part        : 0xc09
67 CPU revision    : 10
68 
69 Hardware        : Generic OMAP4 (Flattened Device Tree)
70 Revision        : 0000
71 Serial          : 0000000000000000
72 )";
73 
74   EXPECT_EQ(sys::detail::getHostCPUNameForARM(CortexA9ProcCpuinfo),
75             "cortex-a9");
76   EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x41\n"
77                                               "CPU part        : 0xc0f"),
78             "cortex-a15");
79   // Verify that both CPU implementer and CPU part are checked:
80   EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x40\n"
81                                               "CPU part        : 0xc0f"),
82             "generic");
83   EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
84                                               "CPU part        : 0x06f"),
85             "krait");
86 }
87 
88 TEST(getLinuxHostCPUName, AArch64) {
89   EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x41\n"
90                                               "CPU part        : 0xd03"),
91             "cortex-a53");
92   // Verify that both CPU implementer and CPU part are checked:
93   EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x40\n"
94                                               "CPU part        : 0xd03"),
95             "generic");
96   EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
97                                               "CPU part        : 0x201"),
98             "kryo");
99   EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
100                                               "CPU part        : 0x800"),
101             "cortex-a73");
102   EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
103                                               "CPU part        : 0x801"),
104             "cortex-a73");
105   EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
106                                               "CPU part        : 0xc00"),
107             "falkor");
108   EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
109                                               "CPU part        : 0xc01"),
110             "saphira");
111 
112   // MSM8992/4 weirdness
113   StringRef MSM8992ProcCpuInfo = R"(
114 Processor       : AArch64 Processor rev 3 (aarch64)
115 processor       : 0
116 processor       : 1
117 processor       : 2
118 processor       : 3
119 processor       : 4
120 processor       : 5
121 Features        : fp asimd evtstrm aes pmull sha1 sha2 crc32
122 CPU implementer : 0x41
123 CPU architecture: 8
124 CPU variant     : 0x0
125 CPU part        : 0xd03
126 CPU revision    : 3
127 
128 Hardware        : Qualcomm Technologies, Inc MSM8992
129 )";
130 
131   EXPECT_EQ(sys::detail::getHostCPUNameForARM(MSM8992ProcCpuInfo),
132             "cortex-a53");
133 
134   // Exynos big.LITTLE weirdness
135   const std::string ExynosProcCpuInfo = R"(
136 processor       : 0
137 Features        : fp asimd evtstrm aes pmull sha1 sha2 crc32
138 CPU implementer : 0x41
139 CPU architecture: 8
140 CPU variant     : 0x0
141 CPU part        : 0xd03
142 
143 processor       : 1
144 Features        : fp asimd evtstrm aes pmull sha1 sha2 crc32
145 CPU implementer : 0x53
146 CPU architecture: 8
147 )";
148 
149   // Verify default for Exynos.
150   EXPECT_EQ(sys::detail::getHostCPUNameForARM(ExynosProcCpuInfo +
151                                               "CPU variant     : 0xc\n"
152                                               "CPU part        : 0xafe"),
153             "exynos-m1");
154   // Verify Exynos M1.
155   EXPECT_EQ(sys::detail::getHostCPUNameForARM(ExynosProcCpuInfo +
156                                               "CPU variant     : 0x1\n"
157                                               "CPU part        : 0x001"),
158             "exynos-m1");
159   // Verify Exynos M2.
160   EXPECT_EQ(sys::detail::getHostCPUNameForARM(ExynosProcCpuInfo +
161                                               "CPU variant     : 0x4\n"
162                                               "CPU part        : 0x001"),
163             "exynos-m2");
164 
165   const std::string ThunderX2T99ProcCpuInfo = R"(
166 processor	: 0
167 BogoMIPS	: 400.00
168 Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
169 CPU implementer	: 0x43
170 CPU architecture: 8
171 CPU variant	: 0x1
172 CPU part	: 0x0af
173 )";
174 
175   // Verify different versions of ThunderX2T99.
176   EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
177                                               "CPU implementer	: 0x42\n"
178                                               "CPU part	: 0x516"),
179             "thunderx2t99");
180 
181   EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
182                                               "CPU implementer	: 0x42\n"
183                                               "CPU part	: 0x0516"),
184             "thunderx2t99");
185 
186   EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
187                                               "CPU implementer	: 0x43\n"
188                                               "CPU part	: 0x516"),
189             "thunderx2t99");
190 
191   EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
192                                               "CPU implementer	: 0x43\n"
193                                               "CPU part	: 0x0516"),
194             "thunderx2t99");
195 
196   EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
197                                               "CPU implementer	: 0x42\n"
198                                               "CPU part	: 0xaf"),
199             "thunderx2t99");
200 
201   EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
202                                               "CPU implementer	: 0x42\n"
203                                               "CPU part	: 0x0af"),
204             "thunderx2t99");
205 
206   EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
207                                               "CPU implementer	: 0x43\n"
208                                               "CPU part	: 0xaf"),
209             "thunderx2t99");
210 
211   EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
212                                               "CPU implementer	: 0x43\n"
213                                               "CPU part	: 0x0af"),
214             "thunderx2t99");
215 
216   // Verify ThunderXT88.
217   const std::string ThunderXT88ProcCpuInfo = R"(
218 processor	: 0
219 BogoMIPS	: 200.00
220 Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32
221 CPU implementer	: 0x43
222 CPU architecture: 8
223 CPU variant	: 0x1
224 CPU part	: 0x0a1
225 )";
226 
227   EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderXT88ProcCpuInfo +
228                                               "CPU implementer	: 0x43\n"
229                                               "CPU part	: 0x0a1"),
230             "thunderxt88");
231 
232   EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderXT88ProcCpuInfo +
233                                               "CPU implementer	: 0x43\n"
234                                               "CPU part	: 0xa1"),
235             "thunderxt88");
236 
237   // Verify HiSilicon processors.
238   EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x48\n"
239                                               "CPU part        : 0xd01"),
240             "tsv110");
241 }
242 
243 #if defined(__APPLE__) || defined(_AIX)
244 static bool runAndGetCommandOutput(
245     const char *ExePath, ArrayRef<llvm::StringRef> argv,
246     std::unique_ptr<char[]> &Buffer, off_t &Size) {
247   bool Success = false;
248   [ExePath, argv, &Buffer, &Size, &Success] {
249     using namespace llvm::sys;
250     SmallString<128> TestDirectory;
251     ASSERT_NO_ERROR(fs::createUniqueDirectory("host_test", TestDirectory));
252 
253     SmallString<128> OutputFile(TestDirectory);
254     path::append(OutputFile, "out");
255     StringRef OutputPath = OutputFile.str();
256 
257     const Optional<StringRef> Redirects[] = {
258         /*STDIN=*/None, /*STDOUT=*/OutputPath, /*STDERR=*/None};
259     int RetCode = ExecuteAndWait(ExePath, argv, /*env=*/llvm::None, Redirects);
260     ASSERT_EQ(0, RetCode);
261 
262     int FD = 0;
263     ASSERT_NO_ERROR(fs::openFileForRead(OutputPath, FD));
264     Size = ::lseek(FD, 0, SEEK_END);
265     ASSERT_NE(-1, Size);
266     ::lseek(FD, 0, SEEK_SET);
267     Buffer = llvm::make_unique<char[]>(Size);
268     ASSERT_EQ(::read(FD, Buffer.get(), Size), Size);
269     ::close(FD);
270 
271     ASSERT_NO_ERROR(fs::remove(OutputPath));
272     ASSERT_NO_ERROR(fs::remove(TestDirectory.str()));
273     Success = true;
274   }();
275   return Success;
276 }
277 
278 TEST_F(HostTest, DummyRunAndGetCommandOutputUse) {
279   // Suppress defined-but-not-used warnings when the tests using the helper are
280   // disabled.
281   (void) runAndGetCommandOutput;
282 }
283 #endif
284 
285 #if defined(__APPLE__)
286 TEST_F(HostTest, getMacOSHostVersion) {
287   using namespace llvm::sys;
288   llvm::Triple HostTriple(getProcessTriple());
289   if (!HostTriple.isMacOSX())
290     return;
291 
292   const char *SwVersPath = "/usr/bin/sw_vers";
293   StringRef argv[] = {SwVersPath, "-productVersion"};
294   std::unique_ptr<char[]> Buffer;
295   off_t Size;
296   ASSERT_EQ(runAndGetCommandOutput(SwVersPath, argv, Buffer, Size), true);
297   StringRef SystemVersion(Buffer.get(), Size);
298 
299   // Ensure that the two versions match.
300   unsigned SystemMajor, SystemMinor, SystemMicro;
301   ASSERT_EQ(llvm::Triple((Twine("x86_64-apple-macos") + SystemVersion))
302                 .getMacOSXVersion(SystemMajor, SystemMinor, SystemMicro),
303             true);
304   unsigned HostMajor, HostMinor, HostMicro;
305   ASSERT_EQ(HostTriple.getMacOSXVersion(HostMajor, HostMinor, HostMicro), true);
306 
307   // Don't compare the 'Micro' version, as it's always '0' for the 'Darwin'
308   // triples.
309   ASSERT_EQ(std::tie(SystemMajor, SystemMinor), std::tie(HostMajor, HostMinor));
310 }
311 #endif
312 
313 #if defined(_AIX)
314 TEST_F(HostTest, AIXVersionDetect) {
315   using namespace llvm::sys;
316 
317   llvm::Triple HostTriple(getProcessTriple());
318   ASSERT_EQ(HostTriple.getOS(), Triple::AIX);
319 
320   llvm::Triple ConfiguredHostTriple(LLVM_HOST_TRIPLE);
321   ASSERT_EQ(ConfiguredHostTriple.getOS(), Triple::AIX);
322 
323   const char *ExePath = "/usr/bin/oslevel";
324   StringRef argv[] = {ExePath};
325   std::unique_ptr<char[]> Buffer;
326   off_t Size;
327   ASSERT_EQ(runAndGetCommandOutput(ExePath, argv, Buffer, Size), true);
328   StringRef SystemVersion(Buffer.get(), Size);
329 
330   unsigned SystemMajor, SystemMinor, SystemMicro;
331   llvm::Triple((Twine("powerpc-ibm-aix") + SystemVersion))
332       .getOSVersion(SystemMajor, SystemMinor, SystemMicro);
333 
334   // Ensure that the host triple version (major) and release (minor) numbers,
335   // unless explicitly configured, match with those of the current system.
336   if (!ConfiguredHostTriple.getOSMajorVersion()) {
337     unsigned HostMajor, HostMinor, HostMicro;
338     HostTriple.getOSVersion(HostMajor, HostMinor, HostMicro);
339     ASSERT_EQ(std::tie(SystemMajor, SystemMinor),
340               std::tie(HostMajor, HostMinor));
341   }
342 
343   llvm::Triple TargetTriple(getDefaultTargetTriple());
344   if (TargetTriple.getOS() != Triple::AIX)
345     return;
346 
347   // Ensure that the target triple version (major) and release (minor) numbers
348   // match with those of the current system.
349   llvm::Triple ConfiguredTargetTriple(LLVM_DEFAULT_TARGET_TRIPLE);
350   if (ConfiguredTargetTriple.getOSMajorVersion())
351     return; // The version was configured explicitly; skip.
352 
353   unsigned TargetMajor, TargetMinor, TargetMicro;
354   TargetTriple.getOSVersion(TargetMajor, TargetMinor, TargetMicro);
355   ASSERT_EQ(std::tie(SystemMajor, SystemMinor),
356             std::tie(TargetMajor, TargetMinor));
357 }
358 #endif
359