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