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