[Lldb-commits] [lldb] r290895 - Improve the performance of jModulesInfo in lldb-server

Tamas Berghammer via lldb-commits lldb-commits at lists.llvm.org
Tue Jan 3 08:29:43 PST 2017


Author: tberghammer
Date: Tue Jan  3 10:29:43 2017
New Revision: 290895

URL: http://llvm.org/viewvc/llvm-project?rev=290895&view=rev
Log:
Improve the performance of jModulesInfo in lldb-server

Previously it parsed /proc/<pid>/maps for every module separately
resulting in a very slow response time. This CL add some caching and
optimizes the implementation to improve the code from O(n*m) to O(n+m)
where n is the number of modules requested and m is the number of
files mapped into memory.

Differential revision: https://reviews.llvm.org/D28233

Modified:
    lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
    lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp?rev=290895&r1=290894&r2=290895&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp Tue Jan  3 10:29:43 2017
@@ -1689,68 +1689,14 @@ Error NativeProcessLinux::GetMemoryRegio
   // Assume proc maps entries are in ascending order.
   // FIXME assert if we find differently.
 
-  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
-  Error error;
-
   if (m_supports_mem_region == LazyBool::eLazyBoolNo) {
     // We're done.
-    error.SetErrorString("unsupported");
-    return error;
+    return Error("unsupported");
   }
 
-  // If our cache is empty, pull the latest.  There should always be at least
-  // one memory region
-  // if memory region handling is supported.
-  if (m_mem_region_cache.empty()) {
-    error = ProcFileReader::ProcessLineByLine(
-        GetID(), "maps", [&](const std::string &line) -> bool {
-          MemoryRegionInfo info;
-          const Error parse_error =
-              ParseMemoryRegionInfoFromProcMapsLine(line, info);
-          if (parse_error.Success()) {
-            m_mem_region_cache.push_back(info);
-            return true;
-          } else {
-            if (log)
-              log->Printf("NativeProcessLinux::%s failed to parse proc maps "
-                          "line '%s': %s",
-                          __FUNCTION__, line.c_str(), error.AsCString());
-            return false;
-          }
-        });
-
-    // If we had an error, we'll mark unsupported.
-    if (error.Fail()) {
-      m_supports_mem_region = LazyBool::eLazyBoolNo;
-      return error;
-    } else if (m_mem_region_cache.empty()) {
-      // No entries after attempting to read them.  This shouldn't happen if
-      // /proc/{pid}/maps
-      // is supported.  Assume we don't support map entries via procfs.
-      if (log)
-        log->Printf("NativeProcessLinux::%s failed to find any procfs maps "
-                    "entries, assuming no support for memory region metadata "
-                    "retrieval",
-                    __FUNCTION__);
-      m_supports_mem_region = LazyBool::eLazyBoolNo;
-      error.SetErrorString("not supported");
-      return error;
-    }
-
-    if (log)
-      log->Printf("NativeProcessLinux::%s read %" PRIu64
-                  " memory region entries from /proc/%" PRIu64 "/maps",
-                  __FUNCTION__,
-                  static_cast<uint64_t>(m_mem_region_cache.size()), GetID());
-
-    // We support memory retrieval, remember that.
-    m_supports_mem_region = LazyBool::eLazyBoolYes;
-  } else {
-    if (log)
-      log->Printf("NativeProcessLinux::%s reusing %" PRIu64
-                  " cached memory region entries",
-                  __FUNCTION__,
-                  static_cast<uint64_t>(m_mem_region_cache.size()));
+  Error error = PopulateMemoryRegionCache();
+  if (error.Fail()) {
+    return error;
   }
 
   lldb::addr_t prev_base_address = 0;
@@ -1760,7 +1706,7 @@ Error NativeProcessLinux::GetMemoryRegio
   // There can be a ton of regions on pthreads apps with lots of threads.
   for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end();
        ++it) {
-    MemoryRegionInfo &proc_entry_info = *it;
+    MemoryRegionInfo &proc_entry_info = it->first;
 
     // Sanity check assumption that /proc/{pid}/maps entries are ascending.
     assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) &&
@@ -1803,6 +1749,67 @@ Error NativeProcessLinux::GetMemoryRegio
   return error;
 }
 
+Error NativeProcessLinux::PopulateMemoryRegionCache() {
+  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+  // If our cache is empty, pull the latest.  There should always be at least
+  // one memory region if memory region handling is supported.
+  if (!m_mem_region_cache.empty()) {
+    if (log)
+      log->Printf("NativeProcessLinux::%s reusing %" PRIu64
+                  " cached memory region entries",
+                  __FUNCTION__,
+                  static_cast<uint64_t>(m_mem_region_cache.size()));
+    return Error();
+  }
+
+  Error error = ProcFileReader::ProcessLineByLine(
+      GetID(), "maps", [&](const std::string &line) -> bool {
+        MemoryRegionInfo info;
+        const Error parse_error =
+            ParseMemoryRegionInfoFromProcMapsLine(line, info);
+        if (parse_error.Success()) {
+          m_mem_region_cache.emplace_back(
+              info, FileSpec(info.GetName().GetCString(), true));
+          return true;
+        } else {
+          if (log)
+            log->Printf("NativeProcessLinux::%s failed to parse proc maps "
+                        "line '%s': %s",
+                        __FUNCTION__, line.c_str(), parse_error.AsCString());
+          return false;
+        }
+      });
+
+  // If we had an error, we'll mark unsupported.
+  if (error.Fail()) {
+    m_supports_mem_region = LazyBool::eLazyBoolNo;
+    return error;
+  } else if (m_mem_region_cache.empty()) {
+    // No entries after attempting to read them.  This shouldn't happen if
+    // /proc/{pid}/maps is supported. Assume we don't support map entries
+    // via procfs.
+    if (log)
+      log->Printf("NativeProcessLinux::%s failed to find any procfs maps "
+                  "entries, assuming no support for memory region metadata "
+                  "retrieval",
+                  __FUNCTION__);
+    m_supports_mem_region = LazyBool::eLazyBoolNo;
+    error.SetErrorString("not supported");
+    return error;
+  }
+
+  if (log)
+    log->Printf("NativeProcessLinux::%s read %" PRIu64
+                " memory region entries from /proc/%" PRIu64 "/maps",
+                __FUNCTION__, static_cast<uint64_t>(m_mem_region_cache.size()),
+                GetID());
+
+  // We support memory retrieval, remember that.
+  m_supports_mem_region = LazyBool::eLazyBoolYes;
+  return Error();
+}
+
 void NativeProcessLinux::DoStopIDBumped(uint32_t newBumpId) {
   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
   if (log)
@@ -2463,60 +2470,38 @@ Error NativeProcessLinux::FixupBreakpoin
 
 Error NativeProcessLinux::GetLoadedModuleFileSpec(const char *module_path,
                                                   FileSpec &file_spec) {
+  Error error = PopulateMemoryRegionCache();
+  if (error.Fail())
+    return error;
+
   FileSpec module_file_spec(module_path, true);
 
-  bool found = false;
   file_spec.Clear();
-  ProcFileReader::ProcessLineByLine(
-      GetID(), "maps", [&](const std::string &line) {
-        SmallVector<StringRef, 16> columns;
-        StringRef(line).split(columns, " ", -1, false);
-        if (columns.size() < 6)
-          return true; // continue searching
-
-        FileSpec this_file_spec(columns[5].str(), false);
-        if (this_file_spec.GetFilename() != module_file_spec.GetFilename())
-          return true; // continue searching
-
-        file_spec = this_file_spec;
-        found = true;
-        return false; // we are done
-      });
-
-  if (!found)
-    return Error("Module file (%s) not found in /proc/%" PRIu64 "/maps file!",
-                 module_file_spec.GetFilename().AsCString(), GetID());
-
-  return Error();
+  for (const auto &it : m_mem_region_cache) {
+    if (it.second.GetFilename() == module_file_spec.GetFilename()) {
+      file_spec = it.second;
+      return Error();
+    }
+  }
+  return Error("Module file (%s) not found in /proc/%" PRIu64 "/maps file!",
+               module_file_spec.GetFilename().AsCString(), GetID());
 }
 
 Error NativeProcessLinux::GetFileLoadAddress(const llvm::StringRef &file_name,
                                              lldb::addr_t &load_addr) {
   load_addr = LLDB_INVALID_ADDRESS;
-  Error error = ProcFileReader::ProcessLineByLine(
-      GetID(), "maps", [&](const std::string &line) -> bool {
-        StringRef maps_row(line);
-
-        SmallVector<StringRef, 16> maps_columns;
-        maps_row.split(maps_columns, StringRef(" "), -1, false);
-
-        if (maps_columns.size() < 6) {
-          // Return true to continue reading the proc file
-          return true;
-        }
-
-        if (maps_columns[5] == file_name) {
-          StringExtractor addr_extractor(maps_columns[0].str().c_str());
-          load_addr = addr_extractor.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
-
-          // Return false to stop reading the proc file further
-          return false;
-        }
+  Error error = PopulateMemoryRegionCache();
+  if (error.Fail())
+    return error;
 
-        // Return true to continue reading the proc file
-        return true;
-      });
-  return error;
+  FileSpec file(file_name, false);
+  for (const auto &it : m_mem_region_cache) {
+    if (it.second == file) {
+      load_addr = it.first.GetRange().GetRangeBase();
+      return Error();
+    }
+  }
+  return Error("No load address found for specified file.");
 }
 
 NativeThreadLinuxSP NativeProcessLinux::GetThreadByID(lldb::tid_t tid) {

Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h?rev=290895&r1=290894&r2=290895&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h Tue Jan  3 10:29:43 2017
@@ -119,7 +119,7 @@ private:
   ArchSpec m_arch;
 
   LazyBool m_supports_mem_region;
-  std::vector<MemoryRegionInfo> m_mem_region_cache;
+  std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;
 
   lldb::tid_t m_pending_notification_tid;
 
@@ -217,6 +217,8 @@ private:
   void ThreadWasCreated(NativeThreadLinux &thread);
 
   void SigchldHandler();
+
+  Error PopulateMemoryRegionCache();
 };
 
 } // namespace process_linux




More information about the lldb-commits mailing list