1// Copyright 2015 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/trace_event/heap_profiler_type_name_deduplicator.h" 6 7#include <stddef.h> 8#include <stdlib.h> 9#include <string> 10#include <utility> 11 12#include "base/json/string_escape.h" 13#include "base/strings/stringprintf.h" 14#include "base/trace_event/trace_event_memory_overhead.h" 15 16namespace base { 17namespace trace_event { 18 19namespace { 20 21// Extract directory name if |type_name| was file name. Otherwise, return 22// |type_name|. 23StringPiece ExtractDirNameFromFileName(const char* type_name) { 24 StringPiece result(type_name); 25 size_t last_seperator = result.find_last_of("\\/"); 26 27 // If |type_name| was a not a file path, the seperator will not be found, so 28 // the whole type name is returned. 29 if (last_seperator == StringPiece::npos) 30 return result; 31 32 // Remove the file name from the path. 33 result.remove_suffix(result.length() - last_seperator); 34 35 // Remove the parent directory references. 36 const char kParentDirectory[] = ".."; 37 const size_t kParentDirectoryLength = 3; // '../' or '..\'. 38 while (result.starts_with(kParentDirectory)) { 39 result.remove_prefix(kParentDirectoryLength); 40 } 41 return result; 42} 43 44} // namespace 45 46TypeNameDeduplicator::TypeNameDeduplicator() { 47 // A null pointer has type ID 0 ("unknown type"); 48 type_ids_.insert(std::make_pair(nullptr, 0)); 49} 50 51TypeNameDeduplicator::~TypeNameDeduplicator() {} 52 53int TypeNameDeduplicator::Insert(const char* type_name) { 54 auto result = type_ids_.insert(std::make_pair(type_name, 0)); 55 auto& elem = result.first; 56 bool did_not_exist_before = result.second; 57 58 if (did_not_exist_before) { 59 // The type IDs are assigned sequentially and they are zero-based, so 60 // |size() - 1| is the ID of the new element. 61 elem->second = static_cast<int>(type_ids_.size() - 1); 62 } 63 64 return elem->second; 65} 66 67void TypeNameDeduplicator::AppendAsTraceFormat(std::string* out) const { 68 out->append("{"); // Begin the type names dictionary. 69 70 auto it = type_ids_.begin(); 71 std::string buffer; 72 73 // Write the first entry manually; the null pointer must not be dereferenced. 74 // (The first entry is the null pointer because a |std::map| is ordered.) 75 it++; 76 out->append("\"0\":\"[unknown]\""); 77 78 for (; it != type_ids_.end(); it++) { 79 // Type IDs in the trace are strings, write them as stringified keys of 80 // a dictionary. 81 SStringPrintf(&buffer, ",\"%d\":", it->second); 82 83 // TODO(ssid): crbug.com/594803 the type name is misused for file name in 84 // some cases. 85 StringPiece type_info = ExtractDirNameFromFileName(it->first); 86 87 // |EscapeJSONString| appends, it does not overwrite |buffer|. 88 bool put_in_quotes = true; 89 EscapeJSONString(type_info, put_in_quotes, &buffer); 90 out->append(buffer); 91 } 92 93 out->append("}"); // End the type names dictionary. 94} 95 96void TypeNameDeduplicator::EstimateTraceMemoryOverhead( 97 TraceEventMemoryOverhead* overhead) { 98 // The size here is only an estimate; it fails to take into account the size 99 // of the tree nodes for the map, but as an estimate this should be fine. 100 size_t map_size = type_ids_.size() * sizeof(std::pair<const char*, int>); 101 102 overhead->Add("TypeNameDeduplicator", 103 sizeof(TypeNameDeduplicator) + map_size); 104} 105 106} // namespace trace_event 107} // namespace base 108