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