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/string_split.h" 14 #include "base/strings/stringprintf.h" 15 #include "base/trace_event/memory_usage_estimator.h" 16 #include "base/trace_event/trace_event.h" 17 #include "base/trace_event/trace_event_memory_overhead.h" 18 19 namespace base { 20 namespace trace_event { 21 22 namespace { 23 24 // If |type_name| is file name then extract directory name. Or if |type_name| is 25 // category name, then disambiguate multple categories and remove 26 // "disabled-by-default" prefix if present. 27 StringPiece ExtractCategoryFromTypeName(const char* type_name) { 28 StringPiece result(type_name); 29 size_t last_seperator = result.find_last_of("\\/"); 30 31 // If |type_name| was a not a file path, the seperator will not be found, so 32 // the whole type name is returned. 33 if (last_seperator == StringPiece::npos) { 34 // Use the first the category name if it has ",". 35 size_t first_comma_position = result.find(','); 36 if (first_comma_position != StringPiece::npos) 37 result = result.substr(0, first_comma_position); 38 if (result.starts_with(TRACE_DISABLED_BY_DEFAULT(""))) 39 result.remove_prefix(sizeof(TRACE_DISABLED_BY_DEFAULT("")) - 1); 40 return result; 41 } 42 43 // Remove the file name from the path. 44 result.remove_suffix(result.length() - last_seperator); 45 46 // Remove the parent directory references. 47 const char kParentDirectory[] = ".."; 48 const size_t kParentDirectoryLength = 3; // '../' or '..\'. 49 while (result.starts_with(kParentDirectory)) { 50 result.remove_prefix(kParentDirectoryLength); 51 } 52 return result; 53 } 54 55 } // namespace 56 57 TypeNameDeduplicator::TypeNameDeduplicator() { 58 // A null pointer has type ID 0 ("unknown type"); 59 type_ids_.insert(std::make_pair(nullptr, 0)); 60 } 61 62 TypeNameDeduplicator::~TypeNameDeduplicator() {} 63 64 int TypeNameDeduplicator::Insert(const char* type_name) { 65 auto result = type_ids_.insert(std::make_pair(type_name, 0)); 66 auto& elem = result.first; 67 bool did_not_exist_before = result.second; 68 69 if (did_not_exist_before) { 70 // The type IDs are assigned sequentially and they are zero-based, so 71 // |size() - 1| is the ID of the new element. 72 elem->second = static_cast<int>(type_ids_.size() - 1); 73 } 74 75 return elem->second; 76 } 77 78 void TypeNameDeduplicator::AppendAsTraceFormat(std::string* out) const { 79 out->append("{"); // Begin the type names dictionary. 80 81 auto it = type_ids_.begin(); 82 std::string buffer; 83 84 // Write the first entry manually; the null pointer must not be dereferenced. 85 // (The first entry is the null pointer because a |std::map| is ordered.) 86 it++; 87 out->append("\"0\":\"[unknown]\""); 88 89 for (; it != type_ids_.end(); it++) { 90 // Type IDs in the trace are strings, write them as stringified keys of 91 // a dictionary. 92 SStringPrintf(&buffer, ",\"%d\":", it->second); 93 94 // TODO(ssid): crbug.com/594803 the type name is misused for file name in 95 // some cases. 96 StringPiece type_info = ExtractCategoryFromTypeName(it->first); 97 98 // |EscapeJSONString| appends, it does not overwrite |buffer|. 99 bool put_in_quotes = true; 100 EscapeJSONString(type_info, put_in_quotes, &buffer); 101 out->append(buffer); 102 } 103 104 out->append("}"); // End the type names dictionary. 105 } 106 107 void TypeNameDeduplicator::EstimateTraceMemoryOverhead( 108 TraceEventMemoryOverhead* overhead) { 109 size_t memory_usage = EstimateMemoryUsage(type_ids_); 110 overhead->Add("TypeNameDeduplicator", 111 sizeof(TypeNameDeduplicator) + memory_usage); 112 } 113 114 } // namespace trace_event 115 } // namespace base 116