Chromium Code Reviews| 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 |