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 #include "llvm/Support/Threading.h"
17
18 #include "gtest/gtest.h"
19
20 #define ASSERT_NO_ERROR(x) \
21 if (std::error_code ASSERT_NO_ERROR_ec = x) { \
22 SmallString<128> MessageStorage; \
23 raw_svector_ostream Message(MessageStorage); \
24 Message << #x ": did not return errc::success.\n" \
25 << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \
26 << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \
27 GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \
28 } else { \
29 }
30
31 using namespace llvm;
32
33 class HostTest : public testing::Test {
34 Triple Host;
35
36 protected:
isSupportedArchAndOS()37 bool isSupportedArchAndOS() {
38 // Initially this is only testing detection of the number of
39 // physical cores, which is currently only supported/tested on
40 // some systems.
41 return (Host.isOSWindows() && llvm_is_multithreaded()) ||
42 Host.isOSDarwin() || (Host.isX86() && Host.isOSLinux()) ||
43 (Host.isPPC64() && Host.isOSLinux()) ||
44 (Host.isSystemZ() && (Host.isOSLinux() || Host.isOSzOS()));
45 }
46
HostTest()47 HostTest() : Host(Triple::normalize(sys::getProcessTriple())) {}
48 };
49
TEST_F(HostTest,NumPhysicalCores)50 TEST_F(HostTest, NumPhysicalCores) {
51 int Num = sys::getHostNumPhysicalCores();
52
53 if (isSupportedArchAndOS())
54 ASSERT_GT(Num, 0);
55 else
56 ASSERT_EQ(Num, -1);
57 }
58
TEST(getLinuxHostCPUName,ARM)59 TEST(getLinuxHostCPUName, ARM) {
60 StringRef CortexA9ProcCpuinfo = R"(
61 processor : 0
62 model name : ARMv7 Processor rev 10 (v7l)
63 BogoMIPS : 1393.66
64 Features : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32
65 CPU implementer : 0x41
66 CPU architecture: 7
67 CPU variant : 0x2
68 CPU part : 0xc09
69 CPU revision : 10
70
71 processor : 1
72 model name : ARMv7 Processor rev 10 (v7l)
73 BogoMIPS : 1393.66
74 Features : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32
75 CPU implementer : 0x41
76 CPU architecture: 7
77 CPU variant : 0x2
78 CPU part : 0xc09
79 CPU revision : 10
80
81 Hardware : Generic OMAP4 (Flattened Device Tree)
82 Revision : 0000
83 Serial : 0000000000000000
84 )";
85
86 EXPECT_EQ(sys::detail::getHostCPUNameForARM(CortexA9ProcCpuinfo),
87 "cortex-a9");
88 EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x41\n"
89 "CPU part : 0xc0f"),
90 "cortex-a15");
91 // Verify that both CPU implementer and CPU part are checked:
92 EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x40\n"
93 "CPU part : 0xc0f"),
94 "generic");
95 EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
96 "CPU part : 0x06f"),
97 "krait");
98 }
99
TEST(getLinuxHostCPUName,AArch64)100 TEST(getLinuxHostCPUName, AArch64) {
101 EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x41\n"
102 "CPU part : 0xd03"),
103 "cortex-a53");
104
105 EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x41\n"
106 "CPU part : 0xd0c"),
107 "neoverse-n1");
108 // Verify that both CPU implementer and CPU part are checked:
109 EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x40\n"
110 "CPU part : 0xd03"),
111 "generic");
112 EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
113 "CPU part : 0x201"),
114 "kryo");
115 EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
116 "CPU part : 0x800"),
117 "cortex-a73");
118 EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
119 "CPU part : 0x801"),
120 "cortex-a73");
121 EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
122 "CPU part : 0xc00"),
123 "falkor");
124 EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n"
125 "CPU part : 0xc01"),
126 "saphira");
127
128 // MSM8992/4 weirdness
129 StringRef MSM8992ProcCpuInfo = R"(
130 Processor : AArch64 Processor rev 3 (aarch64)
131 processor : 0
132 processor : 1
133 processor : 2
134 processor : 3
135 processor : 4
136 processor : 5
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 CPU revision : 3
143
144 Hardware : Qualcomm Technologies, Inc MSM8992
145 )";
146
147 EXPECT_EQ(sys::detail::getHostCPUNameForARM(MSM8992ProcCpuInfo),
148 "cortex-a53");
149
150 // Exynos big.LITTLE weirdness
151 const std::string ExynosProcCpuInfo = R"(
152 processor : 0
153 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
154 CPU implementer : 0x41
155 CPU architecture: 8
156 CPU variant : 0x0
157 CPU part : 0xd05
158
159 processor : 1
160 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
161 CPU implementer : 0x53
162 CPU architecture: 8
163 )";
164
165 // Verify default for Exynos.
166 EXPECT_EQ(sys::detail::getHostCPUNameForARM(ExynosProcCpuInfo +
167 "CPU variant : 0xc\n"
168 "CPU part : 0xafe"),
169 "exynos-m3");
170 // Verify Exynos M3.
171 EXPECT_EQ(sys::detail::getHostCPUNameForARM(ExynosProcCpuInfo +
172 "CPU variant : 0x1\n"
173 "CPU part : 0x002"),
174 "exynos-m3");
175 // Verify Exynos M4.
176 EXPECT_EQ(sys::detail::getHostCPUNameForARM(ExynosProcCpuInfo +
177 "CPU variant : 0x1\n"
178 "CPU part : 0x003"),
179 "exynos-m4");
180
181 const std::string ThunderX2T99ProcCpuInfo = R"(
182 processor : 0
183 BogoMIPS : 400.00
184 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
185 CPU implementer : 0x43
186 CPU architecture: 8
187 CPU variant : 0x1
188 CPU part : 0x0af
189 )";
190
191 // Verify different versions of ThunderX2T99.
192 EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
193 "CPU implementer : 0x42\n"
194 "CPU part : 0x516"),
195 "thunderx2t99");
196
197 EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
198 "CPU implementer : 0x42\n"
199 "CPU part : 0x0516"),
200 "thunderx2t99");
201
202 EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
203 "CPU implementer : 0x43\n"
204 "CPU part : 0x516"),
205 "thunderx2t99");
206
207 EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
208 "CPU implementer : 0x43\n"
209 "CPU part : 0x0516"),
210 "thunderx2t99");
211
212 EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
213 "CPU implementer : 0x42\n"
214 "CPU part : 0xaf"),
215 "thunderx2t99");
216
217 EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
218 "CPU implementer : 0x42\n"
219 "CPU part : 0x0af"),
220 "thunderx2t99");
221
222 EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
223 "CPU implementer : 0x43\n"
224 "CPU part : 0xaf"),
225 "thunderx2t99");
226
227 EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderX2T99ProcCpuInfo +
228 "CPU implementer : 0x43\n"
229 "CPU part : 0x0af"),
230 "thunderx2t99");
231
232 // Verify ThunderXT88.
233 const std::string ThunderXT88ProcCpuInfo = R"(
234 processor : 0
235 BogoMIPS : 200.00
236 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
237 CPU implementer : 0x43
238 CPU architecture: 8
239 CPU variant : 0x1
240 CPU part : 0x0a1
241 )";
242
243 EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderXT88ProcCpuInfo +
244 "CPU implementer : 0x43\n"
245 "CPU part : 0x0a1"),
246 "thunderxt88");
247
248 EXPECT_EQ(sys::detail::getHostCPUNameForARM(ThunderXT88ProcCpuInfo +
249 "CPU implementer : 0x43\n"
250 "CPU part : 0xa1"),
251 "thunderxt88");
252
253 // Verify HiSilicon processors.
254 EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x48\n"
255 "CPU part : 0xd01"),
256 "tsv110");
257
258 // Verify A64FX.
259 const std::string A64FXProcCpuInfo = R"(
260 processor : 0
261 BogoMIPS : 200.00
262 Features : fp asimd evtstrm sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm fcma dcpop sve
263 CPU implementer : 0x46
264 CPU architecture: 8
265 CPU variant : 0x1
266 CPU part : 0x001
267 )";
268
269 EXPECT_EQ(sys::detail::getHostCPUNameForARM(A64FXProcCpuInfo), "a64fx");
270
271 // Verify Nvidia Carmel.
272 const std::string CarmelProcCpuInfo = R"(
273 processor : 0
274 model name : ARMv8 Processor rev 0 (v8l)
275 BogoMIPS : 62.50
276 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm dcpop
277 CPU implementer : 0x4e
278 CPU architecture: 8
279 CPU variant : 0x0
280 CPU part : 0x004
281 CPU revision : 0
282 )";
283
284 EXPECT_EQ(sys::detail::getHostCPUNameForARM(CarmelProcCpuInfo), "carmel");
285
286 // Snapdragon mixed implementer quirk
287 const std::string Snapdragon865ProcCPUInfo = R"(
288 processor : 0
289 BogoMIPS : 38.40
290 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
291 CPU implementer : 0x51
292 CPU architecture: 8
293 CPU variant : 0xd
294 CPU part : 0x805
295 CPU revision : 14
296 processor : 1
297 processor : 2
298 processor : 3
299 processor : 4
300 processor : 5
301 processor : 6
302 BogoMIPS : 38.40
303 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
304 CPU implementer : 0x41
305 CPU architecture: 8
306 CPU variant : 0x1
307 CPU part : 0xd0d
308 CPU revision : 0
309 )";
310 EXPECT_EQ(sys::detail::getHostCPUNameForARM(Snapdragon865ProcCPUInfo), "cortex-a77");
311 }
312
TEST(getLinuxHostCPUName,s390x)313 TEST(getLinuxHostCPUName, s390x) {
314 SmallVector<std::string> ModelIDs(
315 {"3931", "8561", "3906", "2964", "2827", "2817", "2097", "2064"});
316 SmallVector<std::string> VectorSupport({"", "vx"});
317 SmallVector<StringRef> ExpectedCPUs;
318
319 // Model Id: 3931
320 ExpectedCPUs.push_back("zEC12");
321 ExpectedCPUs.push_back("arch14");
322
323 // Model Id: 8561
324 ExpectedCPUs.push_back("zEC12");
325 ExpectedCPUs.push_back("z15");
326
327 // Model Id: 3906
328 ExpectedCPUs.push_back("zEC12");
329 ExpectedCPUs.push_back("z14");
330
331 // Model Id: 2964
332 ExpectedCPUs.push_back("zEC12");
333 ExpectedCPUs.push_back("z13");
334
335 // Model Id: 2827
336 ExpectedCPUs.push_back("zEC12");
337 ExpectedCPUs.push_back("zEC12");
338
339 // Model Id: 2817
340 ExpectedCPUs.push_back("z196");
341 ExpectedCPUs.push_back("z196");
342
343 // Model Id: 2097
344 ExpectedCPUs.push_back("z10");
345 ExpectedCPUs.push_back("z10");
346
347 // Model Id: 2064
348 ExpectedCPUs.push_back("generic");
349 ExpectedCPUs.push_back("generic");
350
351 const std::string DummyBaseVectorInfo =
352 "features : esan3 zarch stfle msa ldisp eimm dfp edat etf3eh highgprs "
353 "te ";
354 const std::string DummyBaseMachineInfo =
355 "processor 0: version = FF, identification = 059C88, machine = ";
356
357 int CheckIndex = 0;
358 for (size_t I = 0; I < ModelIDs.size(); I++) {
359 for (size_t J = 0; J < VectorSupport.size(); J++) {
360 const std::string DummyCPUInfo = DummyBaseVectorInfo + VectorSupport[J] +
361 "\n" + DummyBaseMachineInfo +
362 ModelIDs[I];
363 EXPECT_EQ(sys::detail::getHostCPUNameForS390x(DummyCPUInfo),
364 ExpectedCPUs[CheckIndex++]);
365 }
366 }
367 }
368
369 #if defined(__APPLE__) || defined(_AIX)
runAndGetCommandOutput(const char * ExePath,ArrayRef<llvm::StringRef> argv,std::unique_ptr<char[]> & Buffer,off_t & Size)370 static bool runAndGetCommandOutput(
371 const char *ExePath, ArrayRef<llvm::StringRef> argv,
372 std::unique_ptr<char[]> &Buffer, off_t &Size) {
373 bool Success = false;
374 [ExePath, argv, &Buffer, &Size, &Success] {
375 using namespace llvm::sys;
376 SmallString<128> TestDirectory;
377 ASSERT_NO_ERROR(fs::createUniqueDirectory("host_test", TestDirectory));
378
379 SmallString<128> OutputFile(TestDirectory);
380 path::append(OutputFile, "out");
381 StringRef OutputPath = OutputFile.str();
382
383 const Optional<StringRef> Redirects[] = {
384 /*STDIN=*/None, /*STDOUT=*/OutputPath, /*STDERR=*/None};
385 int RetCode = ExecuteAndWait(ExePath, argv, /*env=*/llvm::None, Redirects);
386 ASSERT_EQ(0, RetCode);
387
388 int FD = 0;
389 ASSERT_NO_ERROR(fs::openFileForRead(OutputPath, FD));
390 Size = ::lseek(FD, 0, SEEK_END);
391 ASSERT_NE(-1, Size);
392 ::lseek(FD, 0, SEEK_SET);
393 Buffer = std::make_unique<char[]>(Size);
394 ASSERT_EQ(::read(FD, Buffer.get(), Size), Size);
395 ::close(FD);
396
397 ASSERT_NO_ERROR(fs::remove(OutputPath));
398 ASSERT_NO_ERROR(fs::remove(TestDirectory.str()));
399 Success = true;
400 }();
401 return Success;
402 }
403
TEST_F(HostTest,DummyRunAndGetCommandOutputUse)404 TEST_F(HostTest, DummyRunAndGetCommandOutputUse) {
405 // Suppress defined-but-not-used warnings when the tests using the helper are
406 // disabled.
407 (void) runAndGetCommandOutput;
408 }
409 #endif
410
411 #if defined(__APPLE__)
TEST_F(HostTest,getMacOSHostVersion)412 TEST_F(HostTest, getMacOSHostVersion) {
413 using namespace llvm::sys;
414 llvm::Triple HostTriple(getProcessTriple());
415 if (!HostTriple.isMacOSX())
416 return;
417
418 const char *SwVersPath = "/usr/bin/sw_vers";
419 StringRef argv[] = {SwVersPath, "-productVersion"};
420 std::unique_ptr<char[]> Buffer;
421 off_t Size;
422 ASSERT_EQ(runAndGetCommandOutput(SwVersPath, argv, Buffer, Size), true);
423 StringRef SystemVersion(Buffer.get(), Size);
424
425 // Ensure that the two versions match.
426 unsigned SystemMajor, SystemMinor, SystemMicro;
427 ASSERT_EQ(llvm::Triple((Twine("x86_64-apple-macos") + SystemVersion))
428 .getMacOSXVersion(SystemMajor, SystemMinor, SystemMicro),
429 true);
430 unsigned HostMajor, HostMinor, HostMicro;
431 ASSERT_EQ(HostTriple.getMacOSXVersion(HostMajor, HostMinor, HostMicro), true);
432
433 if (SystemMajor > 10) {
434 // Don't compare the 'Minor' and 'Micro' versions, as they're always '0' for
435 // the 'Darwin' triples on 11.x.
436 ASSERT_EQ(SystemMajor, HostMajor);
437 } else {
438 // Don't compare the 'Micro' version, as it's always '0' for the 'Darwin'
439 // triples.
440 ASSERT_EQ(std::tie(SystemMajor, SystemMinor), std::tie(HostMajor, HostMinor));
441 }
442 }
443 #endif
444
445 #if defined(_AIX)
TEST_F(HostTest,AIXVersionDetect)446 TEST_F(HostTest, AIXVersionDetect) {
447 using namespace llvm::sys;
448
449 llvm::Triple HostTriple(getProcessTriple());
450 ASSERT_EQ(HostTriple.getOS(), Triple::AIX);
451
452 llvm::Triple ConfiguredHostTriple(LLVM_HOST_TRIPLE);
453 ASSERT_EQ(ConfiguredHostTriple.getOS(), Triple::AIX);
454
455 const char *ExePath = "/usr/bin/oslevel";
456 StringRef argv[] = {ExePath};
457 std::unique_ptr<char[]> Buffer;
458 off_t Size;
459 ASSERT_EQ(runAndGetCommandOutput(ExePath, argv, Buffer, Size), true);
460 StringRef SystemVersion(Buffer.get(), Size);
461
462 unsigned SystemMajor, SystemMinor, SystemMicro;
463 llvm::Triple((Twine("powerpc-ibm-aix") + SystemVersion))
464 .getOSVersion(SystemMajor, SystemMinor, SystemMicro);
465
466 // Ensure that the host triple version (major) and release (minor) numbers,
467 // unless explicitly configured, match with those of the current system.
468 if (!ConfiguredHostTriple.getOSMajorVersion()) {
469 unsigned HostMajor, HostMinor, HostMicro;
470 HostTriple.getOSVersion(HostMajor, HostMinor, HostMicro);
471 ASSERT_EQ(std::tie(SystemMajor, SystemMinor),
472 std::tie(HostMajor, HostMinor));
473 }
474
475 llvm::Triple TargetTriple(getDefaultTargetTriple());
476 if (TargetTriple.getOS() != Triple::AIX)
477 return;
478
479 // Ensure that the target triple version (major) and release (minor) numbers
480 // match with those of the current system.
481 llvm::Triple ConfiguredTargetTriple(LLVM_DEFAULT_TARGET_TRIPLE);
482 if (ConfiguredTargetTriple.getOSMajorVersion())
483 return; // The version was configured explicitly; skip.
484
485 unsigned TargetMajor, TargetMinor, TargetMicro;
486 TargetTriple.getOSVersion(TargetMajor, TargetMinor, TargetMicro);
487 ASSERT_EQ(std::tie(SystemMajor, SystemMinor),
488 std::tie(TargetMajor, TargetMinor));
489 }
490
TEST_F(HostTest,AIXHostCPUDetect)491 TEST_F(HostTest, AIXHostCPUDetect) {
492 // Return a value based on the current processor implementation mode.
493 const char *ExePath = "/usr/sbin/getsystype";
494 StringRef argv[] = {ExePath, "-i"};
495 std::unique_ptr<char[]> Buffer;
496 off_t Size;
497 ASSERT_EQ(runAndGetCommandOutput(ExePath, argv, Buffer, Size), true);
498 StringRef CPU(Buffer.get(), Size);
499 StringRef MCPU = StringSwitch<const char *>(CPU)
500 .Case("POWER 4\n", "pwr4")
501 .Case("POWER 5\n", "pwr5")
502 .Case("POWER 6\n", "pwr6")
503 .Case("POWER 7\n", "pwr7")
504 .Case("POWER 8\n", "pwr8")
505 .Case("POWER 9\n", "pwr9")
506 .Case("POWER 10\n", "pwr10")
507 .Default("unknown");
508
509 StringRef HostCPU = sys::getHostCPUName();
510
511 // Just do the comparison on the base implementation mode.
512 if (HostCPU == "970")
513 HostCPU = StringRef("pwr4");
514 else
515 HostCPU = HostCPU.rtrim('x');
516
517 EXPECT_EQ(HostCPU, MCPU);
518 }
519 #endif
520