Home | History | Annotate | Download | only in trace_event
      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