Fix performance of stack tracing.
authorRuben Ayrapetyan <r.ayrapetyan@samsung.com>
Fri, 15 Sep 2017 18:14:01 +0000 (21:14 +0300)
committerRuben Ayrapetyan <r.ayrapetyan@samsung.com>
Fri, 15 Sep 2017 18:11:24 +0000 (21:11 +0300)
profiler/profiler/src/stackentry.h
src/track/libheaptrack.cpp
src/track/trace.h
src/track/tracetree.h

index 5680283..3833e94 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef STACKENTRY_H
 #define STACKENTRY_H
 
+#include <string.h>
+
 static constexpr size_t MAX_NAME_LENGTH = 512;
 
 class StackEntry {
index b2fe6fc..3e5d449 100644 (file)
 
 using namespace std;
 
+unordered_set<Trace::ip_t> TraceTree::knownNames;
+
 thread_local bool RecursionGuard::isActive = false;
 
+// CoreCLR profiler will fill this up with the current managed stack.
+__thread StackEntry* g_shadowStack = nullptr;
+
 namespace {
 
 /**
@@ -232,6 +237,10 @@ public:
 
         s_data = new LockedData(out, stopCallback);
 
+       fprintf(out,
+                "n %" PRIxPTR " [Unmanaged->Managed]\n",
+                (uintptr_t) -1);
+
         if (initAfterCallback) {
             debugLog<MinimalOutput>("%s", "calling initAfterCallback");
             initAfterCallback(out);
index 4540c4a..f99064e 100644 (file)
 
 #include <execinfo.h>
 #include <string>
-#include <unordered_map>
-#include "../profiler/src/stackentry.h"
-
-// CoreCLR profiler will fill this up with the current managed stack.
-__thread StackEntry * g_shadowStack = nullptr;
 
 /**
  * @brief A libunwind based backtrace.
@@ -60,26 +55,15 @@ struct Trace
         return m_data[m_skip + i];
     }
 
-    std::string getManagedName(int i) const
-    {
-        return m_managed_names[m_skip + i];
-    }
-
     int size() const
     {
         return m_size - m_skip;
     }
 
-    bool is_managed(int i) const 
-    {
-        assert(i < size());
-        return (i >= m_size - m_skip - m_managed_size);
-    }
-
     __attribute__((noinline))
     bool fill(int skip)
     {
-        int size = backtrace(m_data + m_managed_size, MAX_SIZE);
+        int size = backtrace(m_data, MAX_SIZE);
         // filter bogus frames at the end, which sometimes get returned by libunwind
         // cf.: https://bugs.kde.org/show_bug.cgi?id=379082
         while (size > 0 && !m_data[size - 1]) {
@@ -87,8 +71,6 @@ struct Trace
         }
         m_size = size;
         m_skip = skip;
-        m_managed_size = managed_backtrace(m_size, MAX_SIZE);
-        m_size += m_managed_size;
         return m_size > 0;
     }
 
@@ -99,35 +81,11 @@ struct Trace
         m_data[0] = addr;
         m_data[1] = addr;
     }
+
 private:
     int m_size = 0;
     int m_skip = 0;
-    int m_managed_size = 0;
-    ip_t m_data[MAX_SIZE * 2];
-    std::string m_managed_names[MAX_SIZE * 2];
-
-    int managed_backtrace(int start_index, int max_size) {
-        StackEntry *stackIter = g_shadowStack;
-        int i = start_index;
-
-        if (stackIter != nullptr && max_size > 0) {
-            m_data[i] = (void*) 0xffffffff;
-            m_managed_names[i] = "[Unmanaged->Managed]";
-            ++i;
-            --max_size;
-            while (stackIter != nullptr && max_size > 0) {
-                ip_t key = reinterpret_cast<ip_t>(stackIter->m_funcId);
-                m_managed_names[i] = stackIter->m_className;
-                m_managed_names[i].append("::");
-                m_managed_names[i].append(stackIter->m_methodName);
-                --max_size;
-                m_data[i] = key;
-                ++i;
-                stackIter = stackIter->m_next;
-            }
-        }
-        return i - start_index;
-    }
+    ip_t m_data[MAX_SIZE];
 };
 
 #endif // TRACE_H
index 947373b..1aacd82 100644 (file)
@@ -32,7 +32,9 @@
 
 #include "trace.h"
 
-static std::unordered_set<Trace::ip_t> knownNames;
+#include "../profiler/src/stackentry.h"
+
+extern __thread StackEntry* g_shadowStack;
 
 struct TraceEdge
 {
@@ -70,30 +72,66 @@ public:
     {
         uint32_t index = 0;
         TraceEdge* parent = &m_root;
-        for (int i = trace.size() - 1; i >= 0; --i) {
-            const auto ip = trace[i];
-            if (!ip) {
-                continue;
-            }
+
+        auto handleIP = [this, out, &parent, &index] (void *ip, bool isManaged) {
             auto it =
                 std::lower_bound(parent->children.begin(), parent->children.end(), ip,
                                  [](const TraceEdge& l, const Trace::ip_t ip) { return l.instructionPointer < ip; });
             if (it == parent->children.end() || it->instructionPointer != ip) {
                 index = m_index++;
-                if (trace.is_managed(i) && knownNames.find(ip) == knownNames.end()) {
-                    std::string managed_name = trace.getManagedName(i);
-                    fprintf(out, "n %" PRIxPTR " %s\n", reinterpret_cast<uintptr_t>(ip), managed_name.c_str());
-                    knownNames.insert(ip);
-                }
                 it = parent->children.insert(it, {ip, index, {}});
-                fprintf(out, "t %" PRIxPTR " %x %x\n", reinterpret_cast<uintptr_t>(ip), parent->index, trace.is_managed(i) ? 1 : 0);
+                fprintf(out, "t %" PRIxPTR " %x %x\n", reinterpret_cast<uintptr_t>(ip), parent->index, isManaged ? 1 : 0);
             }
             index = it->index;
             parent = &(*it);
+        };
+
+        // process managed stack
+        StackEntry *stackIter = g_shadowStack;
+
+        if (stackIter != nullptr) {
+           void* managedStack[Trace::MAX_SIZE];
+           int managedStackSize = 0;
+
+            managedStack[managedStackSize++] = (void *) (uintptr_t) -1;
+
+            while (stackIter != nullptr && managedStackSize < Trace::MAX_SIZE) {
+                void *ip = reinterpret_cast<void *>(stackIter->m_funcId);
+
+                if (knownNames.find(ip) == knownNames.end()) {
+                    std::string managed_name = stackIter->m_className;
+                    managed_name.append("::");
+                    managed_name.append(stackIter->m_methodName);
+
+                    fprintf(out, "n %" PRIxPTR " %s\n", reinterpret_cast<uintptr_t>(ip), managed_name.c_str());
+
+                   knownNames.insert(ip);
+                }
+
+               managedStack[managedStackSize++] = ip;
+
+                stackIter = stackIter->m_next;
+            }
+
+            for (int i = managedStackSize - 1; i >= 0; --i) {
+                handleIP(managedStack[i], true);
+            }
+        }
+
+        // process unmanaged stack
+        for (int i = trace.size() - 1; i >= 0; --i) {
+            const auto ip = trace[i];
+            if (!ip) {
+                continue;
+            }
+
+            handleIP(ip, false);
         }
         return index;
     }
 
+    static std::unordered_set<Trace::ip_t> knownNames;
+
 private:
     TraceEdge m_root = {0, 0, {}};
     uint32_t m_index = 1;