1 // Copyright 2020 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 "services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_traced_value.h"
6 
7 #include "base/files/file_path.h"
8 #include "base/format_macros.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/trace_event/memory_dump_manager.h"
11 #include "base/trace_event/traced_value.h"
12 #include "build/build_config.h"
13 
14 namespace memory_instrumentation {
15 
16 using base::trace_event::ProcessMemoryDump;
17 using base::trace_event::TracedValue;
18 
19 namespace {
20 
OsDumpAsValueInto(TracedValue * value,const mojom::OSMemDump & os_dump)21 void OsDumpAsValueInto(TracedValue* value, const mojom::OSMemDump& os_dump) {
22   value->SetString(
23       "private_footprint_bytes",
24       base::StringPrintf(
25           "%" PRIx64,
26           static_cast<uint64_t>(os_dump.private_footprint_kb) * 1024));
27   value->SetString(
28       "peak_resident_set_size",
29       base::StringPrintf(
30           "%" PRIx64,
31           static_cast<uint64_t>(os_dump.peak_resident_set_kb) * 1024));
32   value->SetBoolean("is_peak_rss_resettable", os_dump.is_peak_rss_resettable);
33 }
34 
35 }  // namespace
36 
TracingObserverTracedValue(base::trace_event::TraceLog * trace_log,base::trace_event::MemoryDumpManager * memory_dump_manager)37 TracingObserverTracedValue::TracingObserverTracedValue(
38     base::trace_event::TraceLog* trace_log,
39     base::trace_event::MemoryDumpManager* memory_dump_manager)
40     : TracingObserver(trace_log, memory_dump_manager) {}
41 
42 TracingObserverTracedValue::~TracingObserverTracedValue() = default;
43 
44 // static
AddToTrace(const base::trace_event::MemoryDumpRequestArgs & args,const base::ProcessId pid,std::unique_ptr<TracedValue> traced_value)45 void TracingObserverTracedValue::AddToTrace(
46     const base::trace_event::MemoryDumpRequestArgs& args,
47     const base::ProcessId pid,
48     std::unique_ptr<TracedValue> traced_value) {
49   CHECK_NE(base::trace_event::MemoryDumpType::SUMMARY_ONLY, args.dump_type);
50 
51   traced_value->SetString(
52       "level_of_detail",
53       base::trace_event::MemoryDumpLevelOfDetailToString(args.level_of_detail));
54   const uint64_t dump_guid = args.dump_guid;
55   const char* const event_name =
56       base::trace_event::MemoryDumpTypeToString(args.dump_type);
57   base::trace_event::TraceArguments trace_args("dumps",
58                                                std::move(traced_value));
59   TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID(
60       TRACE_EVENT_PHASE_MEMORY_DUMP,
61       base::trace_event::TraceLog::GetCategoryGroupEnabled(
62           base::trace_event::MemoryDumpManager::kTraceCategory),
63       event_name, trace_event_internal::kGlobalScope, dump_guid, pid,
64       &trace_args, TRACE_EVENT_FLAG_HAS_ID);
65 }
66 
AddChromeDumpToTraceIfEnabled(const base::trace_event::MemoryDumpRequestArgs & args,const base::ProcessId pid,const ProcessMemoryDump * process_memory_dump,const base::TimeTicks & timastamp)67 bool TracingObserverTracedValue::AddChromeDumpToTraceIfEnabled(
68     const base::trace_event::MemoryDumpRequestArgs& args,
69     const base::ProcessId pid,
70     const ProcessMemoryDump* process_memory_dump,
71     const base::TimeTicks& timastamp) {
72   if (!ShouldAddToTrace(args))
73     return false;
74 
75   std::unique_ptr<TracedValue> traced_value = std::make_unique<TracedValue>();
76   process_memory_dump->SerializeAllocatorDumpsInto(traced_value.get());
77 
78   AddToTrace(args, pid, std::move(traced_value));
79 
80   return true;
81 }
82 
AddOsDumpToTraceIfEnabled(const base::trace_event::MemoryDumpRequestArgs & args,const base::ProcessId pid,const mojom::OSMemDump & os_dump,const std::vector<mojom::VmRegionPtr> & memory_maps,const base::TimeTicks & timestamp)83 bool TracingObserverTracedValue::AddOsDumpToTraceIfEnabled(
84     const base::trace_event::MemoryDumpRequestArgs& args,
85     const base::ProcessId pid,
86     const mojom::OSMemDump& os_dump,
87     const std::vector<mojom::VmRegionPtr>& memory_maps,
88     const base::TimeTicks& timestamp) {
89   if (!ShouldAddToTrace(args))
90     return false;
91 
92   std::unique_ptr<TracedValue> traced_value = std::make_unique<TracedValue>();
93 
94   traced_value->BeginDictionary("process_totals");
95   OsDumpAsValueInto(traced_value.get(), os_dump);
96   traced_value->EndDictionary();
97 
98   if (memory_maps.size()) {
99     traced_value->BeginDictionary("process_mmaps");
100     MemoryMapsAsValueInto(memory_maps, traced_value.get(), false);
101     traced_value->EndDictionary();
102   }
103 
104   AddToTrace(args, pid, std::move(traced_value));
105   return true;
106 }
107 
108 // static
MemoryMapsAsValueInto(const std::vector<mojom::VmRegionPtr> & memory_maps,TracedValue * value,bool is_argument_filtering_enabled)109 void TracingObserverTracedValue::MemoryMapsAsValueInto(
110     const std::vector<mojom::VmRegionPtr>& memory_maps,
111     TracedValue* value,
112     bool is_argument_filtering_enabled) {
113   static const char kHexFmt[] = "%" PRIx64;
114 
115   // Refer to the design doc goo.gl/sxfFY8 for the semantics of these fields.
116   value->BeginArray("vm_regions");
117   for (const auto& region : memory_maps) {
118     value->BeginDictionary();
119 
120     value->SetString("sa", base::StringPrintf(kHexFmt, region->start_address));
121     value->SetString("sz", base::StringPrintf(kHexFmt, region->size_in_bytes));
122     if (region->module_timestamp)
123       value->SetString("ts",
124                        base::StringPrintf(kHexFmt, region->module_timestamp));
125     if (!region->module_debugid.empty())
126       value->SetString("id", region->module_debugid);
127     if (!region->module_debug_path.empty()) {
128       value->SetString("df", ApplyPathFiltering(region->module_debug_path,
129                                                 is_argument_filtering_enabled));
130     }
131     value->SetInteger("pf", region->protection_flags);
132 
133     // The module path will be the basename when argument filtering is
134     // activated. The whitelisting implemented for filtering string values
135     // doesn't allow rewriting. Therefore, a different path is produced here
136     // when argument filtering is activated.
137     value->SetString("mf", ApplyPathFiltering(region->mapped_file,
138                                               is_argument_filtering_enabled));
139 
140 // The following stats are only well defined on Linux-derived OSes.
141 #if !defined(OS_MAC) && !defined(OS_WIN)
142     value->BeginDictionary("bs");  // byte stats
143     value->SetString(
144         "pss",
145         base::StringPrintf(kHexFmt, region->byte_stats_proportional_resident));
146     value->SetString(
147         "pd",
148         base::StringPrintf(kHexFmt, region->byte_stats_private_dirty_resident));
149     value->SetString(
150         "pc",
151         base::StringPrintf(kHexFmt, region->byte_stats_private_clean_resident));
152     value->SetString(
153         "sd",
154         base::StringPrintf(kHexFmt, region->byte_stats_shared_dirty_resident));
155     value->SetString(
156         "sc",
157         base::StringPrintf(kHexFmt, region->byte_stats_shared_clean_resident));
158     value->SetString("sw",
159                      base::StringPrintf(kHexFmt, region->byte_stats_swapped));
160     value->EndDictionary();
161 #endif
162 
163     value->EndDictionary();
164   }
165   value->EndArray();
166 }
167 
168 }  // namespace memory_instrumentation
169