• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Chromium Authors
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/allocator/partition_allocator/starscan/stats_collector.h"
6 
7 #include "base/allocator/partition_allocator/partition_alloc_base/time/time.h"
8 #include "base/allocator/partition_allocator/starscan/logging.h"
9 #include "base/allocator/partition_allocator/starscan/stats_reporter.h"
10 
11 namespace partition_alloc::internal {
12 
StatsCollector(const char * process_name,size_t quarantine_last_size)13 StatsCollector::StatsCollector(const char* process_name,
14                                size_t quarantine_last_size)
15     : process_name_(process_name),
16       quarantine_last_size_(quarantine_last_size) {}
17 
18 StatsCollector::~StatsCollector() = default;
19 
GetOverallTime() const20 base::TimeDelta StatsCollector::GetOverallTime() const {
21   return GetTimeImpl<Context::kMutator>(mutator_trace_events_,
22                                         MutatorId::kOverall) +
23          GetTimeImpl<Context::kScanner>(scanner_trace_events_,
24                                         ScannerId::kOverall);
25 }
26 
ReportTracesAndHists(partition_alloc::StatsReporter & reporter) const27 void StatsCollector::ReportTracesAndHists(
28     partition_alloc::StatsReporter& reporter) const {
29   ReportTracesAndHistsImpl<Context::kMutator>(reporter, mutator_trace_events_);
30   ReportTracesAndHistsImpl<Context::kScanner>(reporter, scanner_trace_events_);
31   ReportSurvivalRate(reporter);
32 }
33 
34 template <Context context>
GetTimeImpl(const DeferredTraceEventMap<context> & event_map,IdType<context> id) const35 base::TimeDelta StatsCollector::GetTimeImpl(
36     const DeferredTraceEventMap<context>& event_map,
37     IdType<context> id) const {
38   base::TimeDelta overall;
39   for (const auto& tid_and_events : event_map.get_underlying_map_unsafe()) {
40     const auto& events = tid_and_events.second;
41     const auto& event = events[static_cast<size_t>(id)];
42     overall += (event.end_time - event.start_time);
43   }
44   return overall;
45 }
46 
47 template <Context context>
ReportTracesAndHistsImpl(partition_alloc::StatsReporter & reporter,const DeferredTraceEventMap<context> & event_map) const48 void StatsCollector::ReportTracesAndHistsImpl(
49     partition_alloc::StatsReporter& reporter,
50     const DeferredTraceEventMap<context>& event_map) const {
51   std::array<base::TimeDelta, static_cast<size_t>(IdType<context>::kNumIds)>
52       accumulated_events{};
53   // First, report traces and accumulate each trace scope to report UMA hists.
54   for (const auto& tid_and_events : event_map.get_underlying_map_unsafe()) {
55     const internal::base::PlatformThreadId tid = tid_and_events.first;
56     const auto& events = tid_and_events.second;
57     PA_DCHECK(accumulated_events.size() == events.size());
58     for (size_t id = 0; id < events.size(); ++id) {
59       const auto& event = events[id];
60       if (event.start_time.is_null()) {
61         // If start_time is null, the event was never triggered, e.g. safepoint
62         // bailed out if started at the end of scanning.
63         PA_DCHECK(event.end_time.is_null());
64         continue;
65       }
66       reporter.ReportTraceEvent(static_cast<IdType<context>>(id), tid,
67                                 event.start_time.ToInternalValue(),
68                                 event.end_time.ToInternalValue());
69       accumulated_events[id] += (event.end_time - event.start_time);
70     }
71   }
72   // Report UMA if process_name is set.
73   if (!process_name_)
74     return;
75   for (size_t id = 0; id < accumulated_events.size(); ++id) {
76     if (accumulated_events[id].is_zero())
77       continue;
78     reporter.ReportStats(ToUMAString(static_cast<IdType<context>>(id)).c_str(),
79                          accumulated_events[id].InMicroseconds());
80   }
81 }
82 
ReportSurvivalRate(partition_alloc::StatsReporter & reporter) const83 void StatsCollector::ReportSurvivalRate(
84     partition_alloc::StatsReporter& reporter) const {
85   const double survived_rate =
86       static_cast<double>(survived_quarantine_size()) / quarantine_last_size_;
87   reporter.ReportSurvivedQuarantineSize(survived_quarantine_size());
88   reporter.ReportSurvivedQuarantinePercent(survived_rate);
89   PA_PCSCAN_VLOG(2) << "quarantine size: " << quarantine_last_size_ << " -> "
90                     << survived_quarantine_size()
91                     << ", swept bytes: " << swept_size()
92                     << ", survival rate: " << survived_rate;
93   if (discarded_quarantine_size_)
94     PA_PCSCAN_VLOG(2) << "discarded quarantine size: "
95                       << discarded_quarantine_size_;
96 }
97 
98 template base::TimeDelta StatsCollector::GetTimeImpl(
99     const DeferredTraceEventMap<Context::kMutator>&,
100     IdType<Context::kMutator>) const;
101 template base::TimeDelta StatsCollector::GetTimeImpl(
102     const DeferredTraceEventMap<Context::kScanner>&,
103     IdType<Context::kScanner>) const;
104 
105 template void StatsCollector::ReportTracesAndHistsImpl(
106     partition_alloc::StatsReporter& reporter,
107     const DeferredTraceEventMap<Context::kMutator>&) const;
108 template void StatsCollector::ReportTracesAndHistsImpl(
109     partition_alloc::StatsReporter& reporter,
110     const DeferredTraceEventMap<Context::kScanner>&) const;
111 
112 }  // namespace partition_alloc::internal
113