summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/Support/Host.h5
-rw-r--r--llvm/include/llvm/Support/MemoryBuffer.h6
-rw-r--r--llvm/lib/Support/Host.cpp58
-rw-r--r--llvm/lib/Support/MemoryBuffer.cpp12
-rw-r--r--llvm/unittests/Support/CMakeLists.txt1
-rw-r--r--llvm/unittests/Support/Host.cpp47
6 files changed, 128 insertions, 1 deletions
diff --git a/llvm/include/llvm/Support/Host.h b/llvm/include/llvm/Support/Host.h
index 9e59a9428da..9df584c68c0 100644
--- a/llvm/include/llvm/Support/Host.h
+++ b/llvm/include/llvm/Support/Host.h
@@ -70,6 +70,11 @@ namespace sys {
///
/// \return - True on success.
bool getHostCPUFeatures(StringMap<bool> &Features);
+
+ /// Get the number of physical cores (as opposed to logical cores returned
+ /// from thread::hardware_concurrency(), which includes hyperthreads).
+ /// Returns -1 if unknown for the current host system.
+ int getHostNumPhysicalCores();
}
}
diff --git a/llvm/include/llvm/Support/MemoryBuffer.h b/llvm/include/llvm/Support/MemoryBuffer.h
index 70d91bdc26a..062672c8e57 100644
--- a/llvm/include/llvm/Support/MemoryBuffer.h
+++ b/llvm/include/llvm/Support/MemoryBuffer.h
@@ -70,6 +70,12 @@ public:
getFile(const Twine &Filename, int64_t FileSize = -1,
bool RequiresNullTerminator = true, bool IsVolatileSize = false);
+ /// Read all of the specified file into a MemoryBuffer as a stream
+ /// (i.e. until EOF reached). This is useful for special files that
+ /// look like a regular file but have 0 size (e.g. /proc/cpuinfo on Linux).
+ static ErrorOr<std::unique_ptr<MemoryBuffer>>
+ getFileAsStream(const Twine &Filename);
+
/// Given an already-open file descriptor, map some slice of it into a
/// MemoryBuffer. The slice is specified by an \p Offset and \p MapSize.
/// Since this is in the middle of a file, the buffer is not null terminated.
diff --git a/llvm/lib/Support/Host.cpp b/llvm/lib/Support/Host.cpp
index cf61e0487a5..fa3cd9a0966 100644
--- a/llvm/lib/Support/Host.cpp
+++ b/llvm/lib/Support/Host.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Host.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
@@ -19,9 +20,10 @@
#include "llvm/Config/config.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
-#include <string.h>
#include <assert.h>
+#include <string.h>
// Include the platform-specific parts of this class.
#ifdef LLVM_ON_UNIX
@@ -1188,6 +1190,60 @@ StringRef sys::getHostCPUName() {
StringRef sys::getHostCPUName() { return "generic"; }
#endif
+#if defined(__linux__) && defined(__x86_64__)
+// On Linux, the number of physical cores can be computed from /proc/cpuinfo,
+// using the number of unique physical/core id pairs. The following
+// implementation reads the /proc/cpuinfo format on an x86_64 system.
+int computeHostNumPhysicalCores() {
+ // Read /proc/cpuinfo as a stream (until EOF reached). It cannot be
+ // mmapped because it appears to have 0 size.
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
+ llvm::MemoryBuffer::getFileAsStream("/proc/cpuinfo");
+ if (std::error_code EC = Text.getError()) {
+ llvm::errs() << "Can't read "
+ << "/proc/cpuinfo: " << EC.message() << "\n";
+ }
+ SmallVector<StringRef, 8> strs;
+ (*Text)->getBuffer().split(strs, "\n", /*MaxSplit=*/-1,
+ /*KeepEmpty=*/false);
+ int CurPhysicalId = -1;
+ int CurCoreId = -1;
+ SmallSet<std::pair<int, int>, 32> UniqueItems;
+ for (auto &Line : strs) {
+ Line = Line.trim();
+ if (!Line.startswith("physical id") && !Line.startswith("core id"))
+ continue;
+ std::pair<StringRef, StringRef> Data = Line.split(':');
+ auto Name = Data.first.trim();
+ auto Val = Data.second.trim();
+ if (Name == "physical id") {
+ assert(CurPhysicalId == -1 &&
+ "Expected a core id before seeing another physical id");
+ Val.getAsInteger(10, CurPhysicalId);
+ }
+ if (Name == "core id") {
+ assert(CurCoreId == -1 &&
+ "Expected a physical id before seeing another core id");
+ Val.getAsInteger(10, CurCoreId);
+ }
+ if (CurPhysicalId != -1 && CurCoreId != -1) {
+ UniqueItems.insert(std::make_pair(CurPhysicalId, CurCoreId));
+ CurPhysicalId = -1;
+ CurCoreId = -1;
+ }
+ }
+ return UniqueItems.size();
+}
+#else
+// On other systems, return -1 to indicate unknown.
+int computeHostNumPhysicalCores() { return -1; }
+#endif
+
+int sys::getHostNumPhysicalCores() {
+ static int NumCores = computeHostNumPhysicalCores();
+ return NumCores;
+}
+
#if defined(__i386__) || defined(_M_IX86) || \
defined(__x86_64__) || defined(_M_X64)
bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
diff --git a/llvm/lib/Support/MemoryBuffer.cpp b/llvm/lib/Support/MemoryBuffer.cpp
index 689343206c5..a3a18c9283c 100644
--- a/llvm/lib/Support/MemoryBuffer.cpp
+++ b/llvm/lib/Support/MemoryBuffer.cpp
@@ -438,6 +438,18 @@ ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getSTDIN() {
return getMemoryBufferForStream(0, "<stdin>");
}
+ErrorOr<std::unique_ptr<MemoryBuffer>>
+MemoryBuffer::getFileAsStream(const Twine &Filename) {
+ int FD;
+ std::error_code EC = sys::fs::openFileForRead(Filename, FD);
+ if (EC)
+ return EC;
+ ErrorOr<std::unique_ptr<MemoryBuffer>> Ret =
+ getMemoryBufferForStream(FD, Filename);
+ close(FD);
+ return Ret;
+}
+
MemoryBufferRef MemoryBuffer::getMemBufferRef() const {
StringRef Data = getBuffer();
StringRef Identifier = getBufferIdentifier();
diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt
index 25c5dec80c1..9aef7210b1f 100644
--- a/llvm/unittests/Support/CMakeLists.txt
+++ b/llvm/unittests/Support/CMakeLists.txt
@@ -19,6 +19,7 @@ add_llvm_unittest(SupportTests
ErrorTest.cpp
ErrorOrTest.cpp
FileOutputBufferTest.cpp
+ Host.cpp
LEB128Test.cpp
LineIteratorTest.cpp
LockFileManagerTest.cpp
diff --git a/llvm/unittests/Support/Host.cpp b/llvm/unittests/Support/Host.cpp
new file mode 100644
index 00000000000..1fb0bc73314
--- /dev/null
+++ b/llvm/unittests/Support/Host.cpp
@@ -0,0 +1,47 @@
+//========- unittests/Support/Host.cpp - Host.cpp tests --------------========//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Host.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+class HostTest : public testing::Test {
+ Triple Host;
+ SmallVector<std::pair<Triple::ArchType, Triple::OSType>, 4> SupportedArchAndOSs;
+
+protected:
+ bool isSupportedArchAndOS() {
+ if (is_contained(SupportedArchAndOSs, std::make_pair(Host.getArch(), Host.getOS())))
+ return true;
+
+ return false;
+ }
+
+ HostTest() {
+ Host.setTriple(Triple::normalize(sys::getProcessTriple()));
+
+ // Initially this is only testing detection of the number of
+ // physical cores, which is currently only supported for
+ // x86_64 Linux.
+ SupportedArchAndOSs.push_back(std::make_pair(Triple::x86_64, Triple::Linux));
+ }
+};
+
+TEST_F(HostTest, NumPhysicalCores) {
+ int Num = sys::getHostNumPhysicalCores();
+
+ if (isSupportedArchAndOS())
+ ASSERT_GT(Num, 0);
+ else
+ ASSERT_EQ(Num, -1);
+}
OpenPOWER on IntegriCloud