[Lldb-commits] [lldb] 5de0a3e - [trace][intelpt] Support system-wide tracing [1] - Add a method for accessing the list of logical core ids

Walter Erquinigo via lldb-commits lldb-commits at lists.llvm.org
Mon May 2 08:49:01 PDT 2022


Author: Walter Erquinigo
Date: 2022-05-02T08:48:49-07:00
New Revision: 5de0a3e9da721189dd648a90e87829d375c5d17f

URL: https://github.com/llvm/llvm-project/commit/5de0a3e9da721189dd648a90e87829d375c5d17f
DIFF: https://github.com/llvm/llvm-project/commit/5de0a3e9da721189dd648a90e87829d375c5d17f.diff

LOG: [trace][intelpt] Support system-wide tracing [1] - Add a method for accessing the list of logical core ids

In order to open perf events per core, we need to first get the list of
core ids available in the system. So I'm adding a function that does
that by parsing /proc/cpuinfo. That seems to be the simplest and most
portable way to do that.

Besides that, I made a few refactors and renames to reflect better that
the cpu info that we use in lldb-server comes from procfs.

Differential Revision: https://reviews.llvm.org/D124573

Added: 
    lldb/source/Plugins/Process/Linux/Procfs.cpp
    lldb/unittests/Process/Linux/ProcfsTests.cpp

Modified: 
    lldb/docs/lldb-gdb-remote.txt
    lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
    lldb/source/Plugins/Process/Linux/CMakeLists.txt
    lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
    lldb/source/Plugins/Process/Linux/Perf.cpp
    lldb/source/Plugins/Process/Linux/Procfs.h
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionSaver.cpp
    lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
    lldb/unittests/Process/Linux/CMakeLists.txt
    lldb/unittests/Process/Linux/PerfTests.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/docs/lldb-gdb-remote.txt b/lldb/docs/lldb-gdb-remote.txt
index 2ddc3183b80e7..545fbb46ae242 100644
--- a/lldb/docs/lldb-gdb-remote.txt
+++ b/lldb/docs/lldb-gdb-remote.txt
@@ -467,7 +467,7 @@ read packet: OK/E<error code>;AAAAAAAAA
 //
 //  Binary data kinds:
 //    - threadTraceBuffer: trace buffer for a thread.
-//    - cpuInfo: contents of the /proc/cpuinfo file.
+//    - procfsCpuInfo: contents of the /proc/cpuinfo file.
 //
 //  Counter info kinds:
 //    tsc-perf-zero-conversion:
@@ -522,7 +522,7 @@ read packet: {...object}/E<error code>;AAAAAAAAA
 //
 //  Binary data kinds:
 //    - threadTraceBuffer: trace buffer for a thread.
-//    - cpuInfo: contents of the /proc/cpuinfo file.
+//    - procfsCpuInfo: contents of the /proc/cpuinfo file.
 //----------------------------------------------------------------------
 
 send packet: jLLDBTraceGetBinaryData:{"type":<type>,"kind":<query>,"tid":<tid>,"offset":<offset>,"size":<size>}]

diff  --git a/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h b/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
index 8960949f2039f..294b0205af452 100644
--- a/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
+++ b/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
@@ -18,6 +18,12 @@
 /// See docs/lldb-gdb-remote.txt for more information.
 namespace lldb_private {
 
+// List of data kinds used by jLLDBGetState and jLLDBGetBinaryData.
+struct IntelPTDataKinds {
+  static const char *kProcFsCpuInfo;
+  static const char *kThreadTraceBuffer;
+};
+
 /// jLLDBTraceStart gdb-remote packet
 /// \{
 struct TraceIntelPTStartRequest : TraceStartRequest {

diff  --git a/lldb/source/Plugins/Process/Linux/CMakeLists.txt b/lldb/source/Plugins/Process/Linux/CMakeLists.txt
index cc70edba3483e..125cc0e38ca21 100644
--- a/lldb/source/Plugins/Process/Linux/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/Linux/CMakeLists.txt
@@ -9,6 +9,7 @@ add_lldb_library(lldbPluginProcessLinux
   NativeRegisterContextLinux_x86_64.cpp
   NativeThreadLinux.cpp
   Perf.cpp
+  Procfs.cpp
   SingleStepCheck.cpp
 
   LINK_LIBS

diff  --git a/lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp b/lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
index 8c10828627971..e2303b37eb883 100644
--- a/lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
+++ b/lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
@@ -9,6 +9,7 @@
 #include "IntelPTCollector.h"
 
 #include "Perf.h"
+#include "Procfs.h"
 
 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
 #include "lldb/Host/linux/Support.h"
@@ -57,21 +58,6 @@ enum IntelPTConfigFileType {
   BitOffset
 };
 
-/// Get the content of /proc/cpuinfo that can be later used to decode traces.
-static Expected<ArrayRef<uint8_t>> GetCPUInfo() {
-  static llvm::Optional<std::vector<uint8_t>> cpu_info;
-  if (!cpu_info) {
-    auto buffer_or_error = errorOrToExpected(getProcFile("cpuinfo"));
-    if (!buffer_or_error)
-      return buffer_or_error.takeError();
-    MemoryBuffer &buffer = **buffer_or_error;
-    cpu_info = std::vector<uint8_t>(
-        reinterpret_cast<const uint8_t *>(buffer.getBufferStart()),
-        reinterpret_cast<const uint8_t *>(buffer.getBufferEnd()));
-  }
-  return *cpu_info;
-}
-
 static Expected<uint32_t> ReadIntelPTConfigFile(const char *file,
                                                 IntelPTConfigFileType type) {
   ErrorOr<std::unique_ptr<MemoryBuffer>> stream =
@@ -430,7 +416,7 @@ void IntelPTThreadTrace::ReadCyclicBuffer(llvm::MutableArrayRef<uint8_t> &dst,
 
 TraceThreadState IntelPTThreadTrace::GetState() const {
   return {static_cast<int64_t>(m_tid),
-          {TraceBinaryData{"threadTraceBuffer",
+          {TraceBinaryData{IntelPTDataKinds::kThreadTraceBuffer,
                            static_cast<int64_t>(GetTraceBufferSize())}}};
 }
 
@@ -592,13 +578,13 @@ Error IntelPTCollector::OnThreadDestroyed(lldb::tid_t tid) {
 }
 
 Expected<json::Value> IntelPTCollector::GetState() const {
-  Expected<ArrayRef<uint8_t>> cpu_info = GetCPUInfo();
+  Expected<ArrayRef<uint8_t>> cpu_info = GetProcfsCpuInfo();
   if (!cpu_info)
     return cpu_info.takeError();
 
   TraceGetStateResponse state;
-  state.processBinaryData.push_back(
-      {"cpuInfo", static_cast<int64_t>(cpu_info->size())});
+  state.processBinaryData.push_back({IntelPTDataKinds::kProcFsCpuInfo,
+                                     static_cast<int64_t>(cpu_info->size())});
 
   std::vector<TraceThreadState> thread_states =
       m_thread_traces.GetThreadStates();
@@ -622,14 +608,14 @@ IntelPTCollector::GetTracedThread(lldb::tid_t tid) const {
 
 Expected<std::vector<uint8_t>>
 IntelPTCollector::GetBinaryData(const TraceGetBinaryDataRequest &request) const {
-  if (request.kind == "threadTraceBuffer") {
+  if (request.kind == IntelPTDataKinds::kThreadTraceBuffer) {
     if (Expected<const IntelPTThreadTrace &> trace =
             GetTracedThread(*request.tid))
       return trace->GetIntelPTBuffer(request.offset, request.size);
     else
       return trace.takeError();
-  } else if (request.kind == "cpuInfo") {
-    return GetCPUInfo();
+  } else if (request.kind == IntelPTDataKinds::kProcFsCpuInfo) {
+    return GetProcfsCpuInfo();
   }
   return createStringError(inconvertibleErrorCode(),
                            "Unsuported trace binary data kind: %s",

diff  --git a/lldb/source/Plugins/Process/Linux/Perf.cpp b/lldb/source/Plugins/Process/Linux/Perf.cpp
index ed65c61dc4829..d43cd121eb126 100644
--- a/lldb/source/Plugins/Process/Linux/Perf.cpp
+++ b/lldb/source/Plugins/Process/Linux/Perf.cpp
@@ -8,8 +8,11 @@
 
 #include "Perf.h"
 
+#include "lldb/Host/linux/Support.h"
+
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
 
 #include <sys/mman.h>
 #include <sys/syscall.h>

diff  --git a/lldb/source/Plugins/Process/Linux/Procfs.cpp b/lldb/source/Plugins/Process/Linux/Procfs.cpp
new file mode 100644
index 0000000000000..1ff7c568d891f
--- /dev/null
+++ b/lldb/source/Plugins/Process/Linux/Procfs.cpp
@@ -0,0 +1,71 @@
+//===-- Procfs.cpp --------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Procfs.h"
+
+#include "lldb/Host/linux/Support.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace lldb_private;
+using namespace process_linux;
+using namespace llvm;
+
+Expected<ArrayRef<uint8_t>> lldb_private::process_linux::GetProcfsCpuInfo() {
+  static Optional<std::vector<uint8_t>> cpu_info;
+  if (!cpu_info) {
+    auto buffer_or_error = errorOrToExpected(getProcFile("cpuinfo"));
+    if (!buffer_or_error)
+      return buffer_or_error.takeError();
+    MemoryBuffer &buffer = **buffer_or_error;
+    cpu_info = std::vector<uint8_t>(
+        reinterpret_cast<const uint8_t *>(buffer.getBufferStart()),
+        reinterpret_cast<const uint8_t *>(buffer.getBufferEnd()));
+  }
+  return *cpu_info;
+}
+
+Expected<std::vector<int>>
+lldb_private::process_linux::GetAvailableLogicalCoreIDs(StringRef cpuinfo) {
+  SmallVector<StringRef, 8> lines;
+  cpuinfo.split(lines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+  std::vector<int> logical_cores;
+
+  for (StringRef line : lines) {
+    std::pair<StringRef, StringRef> key_value = line.split(':');
+    auto key = key_value.first.trim();
+    auto val = key_value.second.trim();
+    if (key == "processor") {
+      int processor;
+      if (val.getAsInteger(10, processor))
+        return createStringError(
+            inconvertibleErrorCode(),
+            "Failed parsing the /proc/cpuinfo line entry: %s", line.data());
+      logical_cores.push_back(processor);
+    }
+  }
+  return logical_cores;
+}
+
+llvm::Expected<llvm::ArrayRef<int>>
+lldb_private::process_linux::GetAvailableLogicalCoreIDs() {
+  static Optional<std::vector<int>> logical_cores_ids;
+  if (!logical_cores_ids) {
+    // We find the actual list of core ids by parsing /proc/cpuinfo
+    Expected<ArrayRef<uint8_t>> cpuinfo = GetProcfsCpuInfo();
+    if (!cpuinfo)
+      return cpuinfo.takeError();
+
+    Expected<std::vector<int>> core_ids = GetAvailableLogicalCoreIDs(
+        StringRef(reinterpret_cast<const char *>(cpuinfo->data())));
+    if (!core_ids)
+      return core_ids.takeError();
+
+    logical_cores_ids.emplace(std::move(*core_ids));
+  }
+  return *logical_cores_ids;
+}

diff  --git a/lldb/source/Plugins/Process/Linux/Procfs.h b/lldb/source/Plugins/Process/Linux/Procfs.h
index 59dd76a2584c3..297fafe7ccd5e 100644
--- a/lldb/source/Plugins/Process/Linux/Procfs.h
+++ b/lldb/source/Plugins/Process/Linux/Procfs.h
@@ -11,6 +11,10 @@
 
 #include <sys/ptrace.h>
 
+#include "llvm/Support/Error.h"
+
+#include <vector>
+
 #ifdef __ANDROID__
 #if defined(__arm64__) || defined(__aarch64__)
 typedef unsigned long elf_greg_t;
@@ -28,3 +32,24 @@ typedef struct user_fpsimd_state elf_fpregset_t;
 #else // __ANDROID__
 #include <sys/procfs.h>
 #endif // __ANDROID__
+
+namespace lldb_private {
+namespace process_linux {
+
+/// \return
+///     The content of /proc/cpuinfo and cache it if errors didn't happen.
+llvm::Expected<llvm::ArrayRef<uint8_t>> GetProcfsCpuInfo();
+
+/// \return
+///     A list of available logical core ids given the contents of
+///     /proc/cpuinfo.
+llvm::Expected<std::vector<int>>
+GetAvailableLogicalCoreIDs(llvm::StringRef cpuinfo);
+
+/// \return
+///     A list with all the logical cores available in the system and cache it
+///     if errors didn't happen.
+llvm::Expected<llvm::ArrayRef<int>> GetAvailableLogicalCoreIDs();
+
+} // namespace process_linux
+} // namespace lldb_private

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
index a5def7906dc95..394963a263084 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
@@ -81,7 +81,8 @@ TraceIntelPT::TraceIntelPT(
   for (const ThreadPostMortemTraceSP &thread : traced_threads) {
     m_thread_decoders.emplace(thread->GetID(),
                               std::make_unique<ThreadDecoder>(thread, *this));
-    SetPostMortemThreadDataFile(thread->GetID(), "threadTraceBuffer",
+    SetPostMortemThreadDataFile(thread->GetID(),
+                                IntelPTDataKinds::kThreadTraceBuffer,
                                 thread->GetTraceFile());
   }
 }
@@ -179,7 +180,8 @@ llvm::Expected<size_t> TraceIntelPT::GetRawTraceSize(Thread &thread) {
 }
 
 Expected<pt_cpu> TraceIntelPT::GetCPUInfoForLiveProcess() {
-  Expected<std::vector<uint8_t>> cpu_info = GetLiveProcessBinaryData("cpuInfo");
+  Expected<std::vector<uint8_t>> cpu_info =
+      GetLiveProcessBinaryData(IntelPTDataKinds::kProcFsCpuInfo);
   if (!cpu_info)
     return cpu_info.takeError();
 
@@ -393,7 +395,8 @@ Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
 
 Error TraceIntelPT::OnThreadBufferRead(lldb::tid_t tid,
                                        OnBinaryDataReadCallback callback) {
-  return OnThreadBinaryDataRead(tid, "threadTraceBuffer", callback);
+  return OnThreadBinaryDataRead(tid, IntelPTDataKinds::kThreadTraceBuffer,
+                                callback);
 }
 
 TaskTimer &TraceIntelPT::GetTimer() { return m_task_timer; }

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionSaver.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionSaver.cpp
index 241d9c52d0627..7ed4292280843 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionSaver.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionSaver.cpp
@@ -48,8 +48,8 @@ llvm::Error TraceIntelPTSessionSaver::SaveToDisk(TraceIntelPT &trace_ipt,
     return json_intel_pt_trace.takeError();
 
   llvm::Expected<JSONTraceSessionBase> json_session_description =
-      TraceSessionSaver::BuildProcessesSection(*live_process,
-                                               "threadTraceBuffer", directory);
+      TraceSessionSaver::BuildProcessesSection(
+          *live_process, IntelPTDataKinds::kThreadTraceBuffer, directory);
 
   if (!json_session_description)
     return json_session_description.takeError();

diff  --git a/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp b/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
index 5dd026141b3e8..bd450bb0721c9 100644
--- a/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
+++ b/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
@@ -13,6 +13,9 @@ using namespace llvm::json;
 
 namespace lldb_private {
 
+const char *IntelPTDataKinds::kProcFsCpuInfo = "procfsCpuInfo";
+const char *IntelPTDataKinds::kThreadTraceBuffer = "threadTraceBuffer";
+
 bool fromJSON(const json::Value &value, TraceIntelPTStartRequest &packet,
               Path path) {
   ObjectMapper o(value, path);

diff  --git a/lldb/unittests/Process/Linux/CMakeLists.txt b/lldb/unittests/Process/Linux/CMakeLists.txt
index 30fa7e4ea57d9..d7ad90e66f611 100644
--- a/lldb/unittests/Process/Linux/CMakeLists.txt
+++ b/lldb/unittests/Process/Linux/CMakeLists.txt
@@ -1,6 +1,7 @@
 add_lldb_unittest(ProcessLinuxTests
   IntelPTCollectorTests.cpp
   PerfTests.cpp
+  ProcfsTests.cpp
 
   LINK_LIBS
     lldbPluginProcessLinux

diff  --git a/lldb/unittests/Process/Linux/PerfTests.cpp b/lldb/unittests/Process/Linux/PerfTests.cpp
index 084b857b908f9..fd9280b30e917 100644
--- a/lldb/unittests/Process/Linux/PerfTests.cpp
+++ b/lldb/unittests/Process/Linux/PerfTests.cpp
@@ -13,6 +13,7 @@
 #include "llvm/Support/Error.h"
 
 #include "gtest/gtest.h"
+
 #include <chrono>
 #include <cstdint>
 

diff  --git a/lldb/unittests/Process/Linux/ProcfsTests.cpp b/lldb/unittests/Process/Linux/ProcfsTests.cpp
new file mode 100644
index 0000000000000..f619234ea5bb0
--- /dev/null
+++ b/lldb/unittests/Process/Linux/ProcfsTests.cpp
@@ -0,0 +1,104 @@
+//===-- ProcfsTests.cpp ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Procfs.h"
+
+#include "lldb/Host/linux/Support.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace lldb_private;
+using namespace process_linux;
+using namespace llvm;
+
+TEST(Perf, HardcodedLogicalCoreIDs) {
+  Expected<std::vector<int>> core_ids =
+      GetAvailableLogicalCoreIDs(R"(processor       : 13
+vendor_id       : GenuineIntel
+cpu family      : 6
+model           : 85
+model name      : Intel(R) Xeon(R) Gold 6138 CPU @ 2.00GHz
+stepping        : 4
+microcode       : 0x2000065
+cpu MHz         : 2886.370
+cache size      : 28160 KB
+physical id     : 1
+siblings        : 40
+core id         : 19
+cpu cores       : 20
+apicid          : 103
+initial apicid  : 103
+fpu             : yes
+fpu_exception   : yes
+cpuid level     : 22
+power management:
+
+processor       : 24
+vendor_id       : GenuineIntel
+cpu family      : 6
+model           : 85
+model name      : Intel(R) Xeon(R) Gold 6138 CPU @ 2.00GHz
+stepping        : 4
+microcode       : 0x2000065
+cpu MHz         : 2768.494
+cache size      : 28160 KB
+physical id     : 1
+siblings        : 40
+core id         : 20
+cpu cores       : 20
+apicid          : 105
+power management:
+
+processor       : 35
+vendor_id       : GenuineIntel
+cpu family      : 6
+model           : 85
+model name      : Intel(R) Xeon(R) Gold 6138 CPU @ 2.00GHz
+stepping        : 4
+microcode       : 0x2000065
+cpu MHz         : 2884.703
+cache size      : 28160 KB
+physical id     : 1
+siblings        : 40
+core id         : 24
+cpu cores       : 20
+apicid          : 113
+
+processor       : 79
+vendor_id       : GenuineIntel
+cpu family      : 6
+model           : 85
+model name      : Intel(R) Xeon(R) Gold 6138 CPU @ 2.00GHz
+stepping        : 4
+microcode       : 0x2000065
+cpu MHz         : 3073.955
+cache size      : 28160 KB
+physical id     : 1
+siblings        : 40
+core id         : 28
+cpu cores       : 20
+apicid          : 121
+power management:
+)");
+
+  ASSERT_TRUE((bool)core_ids);
+  ASSERT_THAT(*core_ids, ::testing::ElementsAre(13, 24, 35, 79));
+}
+
+TEST(Perf, RealLogicalCoreIDs) {
+  // We first check we can read /proc/cpuinfo
+  auto buffer_or_error = errorOrToExpected(getProcFile("cpuinfo"));
+  if (!buffer_or_error)
+    GTEST_SKIP() << toString(buffer_or_error.takeError());
+
+  // At this point we shouldn't fail parsing the core ids
+  Expected<ArrayRef<int>> core_ids = GetAvailableLogicalCoreIDs();
+  ASSERT_TRUE((bool)core_ids);
+  ASSERT_GT((int)core_ids->size(), 0) << "We must see at least one core";
+}


        


More information about the lldb-commits mailing list