Index: base/trace_event/heap_profiler_type_name_deduplicator.cc |
diff --git a/base/trace_event/heap_profiler_type_name_deduplicator.cc b/base/trace_event/heap_profiler_type_name_deduplicator.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..040528f37311beaa77090ec8090ea3fc8e6c6f36 |
--- /dev/null |
+++ b/base/trace_event/heap_profiler_type_name_deduplicator.cc |
@@ -0,0 +1,130 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h" |
+ |
+#include <stdlib.h> |
+#include <string> |
+#include <utility> |
+ |
+#include "base/strings/stringprintf.h" |
+#include "base/trace_event/trace_event_memory_overhead.h" |
+ |
+#if !defined(COMPILER_MSVC) |
+#include <cxxabi.h> |
+#endif |
+ |
+namespace base { |
+namespace trace_event { |
+ |
+namespace { |
+ |
+// Wraps C++ symbol name demangling API for safer memory management. |
+class Demangler { |
+ public: |
+ Demangler() : buffer_(nullptr), buffer_size_(0) {} |
+ |
+ ~Demangler() { |
+ if (buffer_) |
+ free(buffer_); |
+ } |
+ |
+#if defined(COMPILER_MSVC) |
+ |
+ // On MSVC, |typeid(T).name()| returns a human-readable, non-mangled type |
+ // name, so there is no need to demangle anything. |
+ const char* Demangle(const char* mangled_name) { |
+ // Silence unused variable warnings. |
+ static_cast<void>(buffer_); |
+ static_cast<void>(buffer_size_); |
+ return mangled_name; |
+ } |
+ |
+#else // GCC and Clang use the cross-vendor C++ ABI. |
+ |
+ // Demangles a C++ symbol name returned by |typeid(T).name()|. The returned |
+ // pointer is valid until the next call to |Demangle|, or until the the |
+ // |Demangler| instance is destructed. |
+ const char* Demangle(const char* mangled_name) { |
+ // Reuse the buffer across calls. It will automatically be reallocated if |
+ // it is not large enough to fit the demangled name. |
+ int status = 0; |
+ char* result = |
+ abi::__cxa_demangle(mangled_name, buffer_, &buffer_size_, &status); |
+ |
+ if (result) { |
+ buffer_ = result; |
+ return result; |
+ } |
+ |
+ return mangled_name; |
+ } |
+ |
+#endif // defined(COMPILER_MSVC) |
+ |
+ private: |
+ char* buffer_; |
+ size_t buffer_size_; |
+}; |
+ |
+} // namespace |
+ |
+TypeNameDeduplicator::TypeNameDeduplicator() { |
+ // A null pointer has type ID 0 ("unknown type"); |
+ type_ids_.insert(std::make_pair(nullptr, 0)); |
+ next_id_ = 1; |
+} |
+ |
+TypeNameDeduplicator::~TypeNameDeduplicator() {} |
+ |
+int TypeNameDeduplicator::Insert(const char* type_name) { |
+ auto result = type_ids_.insert(std::make_pair(type_name, 0)); |
+ auto& elem = result.first; |
+ bool did_not_exist_before = result.second; |
+ |
+ if (did_not_exist_before) { |
+ elem->second = next_id_; |
+ next_id_++; |
+ } |
+ |
+ return elem->second; |
+} |
+ |
+void TypeNameDeduplicator::AppendAsTraceFormat(std::string* out) const { |
+ out->append("{"); // Begin the type names dictionary. |
+ |
+ auto it = type_ids_.begin(); |
+ std::string stringify_buffer; |
+ Demangler demangler; |
+ |
+ // Write the first entry manually; the null pointer must not be dereferenced. |
+ // (The first entry is the null pointer because a |std::map| is ordered.) |
+ it++; |
+ out->append("\"0\":\"[unknown]\""); |
+ |
+ for (; it != type_ids_.end(); it++) { |
+ // Type IDs in the trace are strings, write them as stringified keys of |
+ // a dictionary. The type name string does not need to be escaped for the |
+ // json to valid, because type names have to be valid C++ identifiers, |
+ // which cannot contain quotes, backslashes, or control characters. |
+ const char* type_name = demangler.Demangle(it->first); |
+ SStringPrintf(&stringify_buffer, ",\"%d\":\"%s\"", it->second, type_name); |
Primiano Tucci (use gerrit)
2015/11/23 15:46:48
use EscapeJSONString ?
I can already see the day s
Ruud van Asseldonk
2015/11/23 18:23:26
Done.
|
+ out->append(stringify_buffer); |
+ } |
+ |
+ out->append("}"); // End the type names dictionary. |
+} |
+ |
+void TypeNameDeduplicator::EstimateTraceMemoryOverhead( |
+ TraceEventMemoryOverhead* overhead) { |
+ // The size here is only an estimate; it fails to take into account the size |
+ // of the tree nodes for the map, but as an estimate this should be fine. |
+ size_t map_size = type_ids_.size() * sizeof(std::pair<const char*, int>); |
+ |
+ overhead->Add("TypeNameDeduplicator", |
+ sizeof(TypeNameDeduplicator) + map_size); |
+} |
+ |
+} // namespace trace_event |
+} // namespace base |