10d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko// Copyright 2015 The Chromium Authors. All rights reserved. 20d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko// Use of this source code is governed by a BSD-style license that can be 30d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko// found in the LICENSE file. 40d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 50d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include "base/trace_event/heap_profiler_type_name_deduplicator.h" 60d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 70d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include <stddef.h> 80d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include <stdlib.h> 90d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include <string> 100d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include <utility> 110d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 120d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include "base/json/string_escape.h" 133a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli#include "base/strings/string_split.h" 140d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include "base/strings/stringprintf.h" 153a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli#include "base/trace_event/memory_usage_estimator.h" 163a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli#include "base/trace_event/trace_event.h" 170d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include "base/trace_event/trace_event_memory_overhead.h" 180d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 190d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenkonamespace base { 200d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenkonamespace trace_event { 210d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 2294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chaveznamespace { 2394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez 243a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// If |type_name| is file name then extract directory name. Or if |type_name| is 253a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// category name, then disambiguate multple categories and remove 263a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli// "disabled-by-default" prefix if present. 273a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay CivelliStringPiece ExtractCategoryFromTypeName(const char* type_name) { 2894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez StringPiece result(type_name); 2994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez size_t last_seperator = result.find_last_of("\\/"); 3094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez 3194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez // If |type_name| was a not a file path, the seperator will not be found, so 3294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez // the whole type name is returned. 333a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli if (last_seperator == StringPiece::npos) { 343a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli // Use the first the category name if it has ",". 353a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli size_t first_comma_position = result.find(','); 363a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli if (first_comma_position != StringPiece::npos) 373a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli result = result.substr(0, first_comma_position); 383a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli if (result.starts_with(TRACE_DISABLED_BY_DEFAULT(""))) 393a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli result.remove_prefix(sizeof(TRACE_DISABLED_BY_DEFAULT("")) - 1); 4094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez return result; 413a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli } 4294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez 4394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez // Remove the file name from the path. 4494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez result.remove_suffix(result.length() - last_seperator); 4594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez 4694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez // Remove the parent directory references. 4794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez const char kParentDirectory[] = ".."; 4894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez const size_t kParentDirectoryLength = 3; // '../' or '..\'. 4994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez while (result.starts_with(kParentDirectory)) { 5094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez result.remove_prefix(kParentDirectoryLength); 5194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez } 5294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez return result; 5394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez} 5494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez 5594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez} // namespace 5694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez 570d205d712abd16eeed2f5d5b1052a367d23a223fAlex VakulenkoTypeNameDeduplicator::TypeNameDeduplicator() { 580d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko // A null pointer has type ID 0 ("unknown type"); 590d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko type_ids_.insert(std::make_pair(nullptr, 0)); 600d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko} 610d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 620d205d712abd16eeed2f5d5b1052a367d23a223fAlex VakulenkoTypeNameDeduplicator::~TypeNameDeduplicator() {} 630d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 640d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenkoint TypeNameDeduplicator::Insert(const char* type_name) { 650d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko auto result = type_ids_.insert(std::make_pair(type_name, 0)); 660d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko auto& elem = result.first; 670d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko bool did_not_exist_before = result.second; 680d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 690d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko if (did_not_exist_before) { 700d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko // The type IDs are assigned sequentially and they are zero-based, so 710d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko // |size() - 1| is the ID of the new element. 720d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko elem->second = static_cast<int>(type_ids_.size() - 1); 730d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko } 740d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 750d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko return elem->second; 760d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko} 770d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 780d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenkovoid TypeNameDeduplicator::AppendAsTraceFormat(std::string* out) const { 790d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko out->append("{"); // Begin the type names dictionary. 800d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 810d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko auto it = type_ids_.begin(); 820d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko std::string buffer; 830d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 840d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko // Write the first entry manually; the null pointer must not be dereferenced. 850d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko // (The first entry is the null pointer because a |std::map| is ordered.) 860d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko it++; 870d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko out->append("\"0\":\"[unknown]\""); 880d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 890d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko for (; it != type_ids_.end(); it++) { 900d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko // Type IDs in the trace are strings, write them as stringified keys of 910d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko // a dictionary. 920d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko SStringPrintf(&buffer, ",\"%d\":", it->second); 930d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 9494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez // TODO(ssid): crbug.com/594803 the type name is misused for file name in 9594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez // some cases. 963a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli StringPiece type_info = ExtractCategoryFromTypeName(it->first); 9794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez 980d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko // |EscapeJSONString| appends, it does not overwrite |buffer|. 990d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko bool put_in_quotes = true; 10094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez EscapeJSONString(type_info, put_in_quotes, &buffer); 1010d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko out->append(buffer); 1020d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko } 1030d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 1040d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko out->append("}"); // End the type names dictionary. 1050d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko} 1060d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 1070d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenkovoid TypeNameDeduplicator::EstimateTraceMemoryOverhead( 1080d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko TraceEventMemoryOverhead* overhead) { 1093a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli size_t memory_usage = EstimateMemoryUsage(type_ids_); 1100d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko overhead->Add("TypeNameDeduplicator", 1113a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli sizeof(TypeNameDeduplicator) + memory_usage); 1120d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko} 1130d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko 1140d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko} // namespace trace_event 1150d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko} // namespace base 116