[M120 Migration][VD] Enable direct rendering for TVPlus
[platform/framework/web/chromium-efl.git] / components / metrics / psi_memory_parser_linux.cc
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 "components/metrics/psi_memory_parser.h"
6
7 #include <stddef.h>
8
9 #include <cinttypes>
10 #include <map>
11 #include <memory>
12 #include <string>
13
14 #include "base/metrics/histogram.h"
15 #include "base/metrics/histogram_functions.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/stringprintf.h"
18 #include "components/metrics/metrics_log_store.h"
19
20 namespace metrics {
21
22 namespace {
23
24 // Periods supported by standard Linux PSI metricvs.
25 constexpr uint32_t kMinCollectionInterval = 10;
26 constexpr uint32_t kMidCollectionInterval = 60;
27 constexpr uint32_t kMaxCollectionInterval = 300;
28
29 constexpr uint32_t kDefaultCollectionInterval = kMinCollectionInterval;
30
31 // Name of the histogram that represents the success and various failure modes
32 // for parsing PSI memory data.
33 const char kParsePSIMemoryHistogramName[] = "ChromeOS.CWP.ParsePSIMemory";
34
35 constexpr base::StringPiece kContentPrefixSome = "some";
36 constexpr base::StringPiece kContentPrefixFull = "full";
37 constexpr base::StringPiece kContentTerminator = " total=";
38 constexpr base::StringPiece kMetricTerminator = " ";
39
40 const char kMetricPrefixFormat[] = "avg%d=";
41
42 }  // namespace
43
44 PSIMemoryParser::PSIMemoryParser(uint32_t period)
45     : period_(kDefaultCollectionInterval) {
46   if (period == kMinCollectionInterval || period == kMidCollectionInterval ||
47       period == kMaxCollectionInterval) {
48     period_ = period;
49   } else {
50     LOG(WARNING) << "Ignoring invalid interval [" << period << "]";
51   }
52
53   metric_prefix_ = base::StringPrintf(kMetricPrefixFormat, period_);
54 }
55
56 PSIMemoryParser::~PSIMemoryParser() = default;
57
58 uint32_t PSIMemoryParser::GetPeriod() const {
59   return period_;
60 }
61
62 int PSIMemoryParser::GetMetricValue(const base::StringPiece& content,
63                                     size_t start,
64                                     size_t end) {
65   size_t value_start;
66   size_t value_end;
67   if (!internal::FindMiddleString(content, start, metric_prefix_,
68                                   kMetricTerminator, &value_start,
69                                   &value_end)) {
70     return -1;
71   }
72   if (value_end > end) {
73     return -1;  // Out of bounds of the search area.
74   }
75
76   double n;
77   const base::StringPiece metric_value_text =
78       content.substr(value_start, value_end - value_start);
79   if (!base::StringToDouble(metric_value_text, &n)) {
80     return -1;  // Unable to convert string to number
81   }
82
83   // Want to multiply by 100, but to avoid integer truncation,
84   // do best-effort rounding.
85   const int preround = static_cast<int>(n * 1000);
86   return (preround + 5) / 10;
87 }
88
89 void PSIMemoryParser::LogParseStatus(ParsePSIMemStatus stat) {
90   constexpr int statCeiling =
91       static_cast<int>(ParsePSIMemStatus::kMaxValue) + 1;
92   base::UmaHistogramExactLinear(kParsePSIMemoryHistogramName,
93                                 static_cast<int>(stat), statCeiling);
94 }
95
96 ParsePSIMemStatus PSIMemoryParser::ParseMetrics(
97     const base::StringPiece& content,
98     int* metric_some,
99     int* metric_full) {
100   size_t str_some_start;
101   size_t str_some_end;
102   size_t str_full_start;
103   size_t str_full_end;
104
105   // Example of content:
106   //  some avg10=0.00 avg60=0.00 avg300=0.00 total=417963
107   //  full avg10=0.00 avg60=0.00 avg300=0.00 total=205933
108   // we will pick one of the columns depending on the colleciton period set
109
110   DCHECK_NE(metric_some, nullptr);
111   DCHECK_NE(metric_full, nullptr);
112
113   if (!internal::FindMiddleString(content, 0, kContentPrefixSome,
114                                   kContentTerminator, &str_some_start,
115                                   &str_some_end)) {
116     return ParsePSIMemStatus::kUnexpectedDataFormat;
117   }
118
119   if (!internal::FindMiddleString(content,
120                                   str_some_end + kContentTerminator.length(),
121                                   kContentPrefixFull, kContentTerminator,
122                                   &str_full_start, &str_full_end)) {
123     return ParsePSIMemStatus::kUnexpectedDataFormat;
124   }
125
126   int compute_some = GetMetricValue(content, str_some_start, str_some_end);
127   if (compute_some < 0) {
128     return ParsePSIMemStatus::kInvalidMetricFormat;
129   }
130
131   int compute_full = GetMetricValue(content, str_full_start, str_full_end);
132   if (compute_full < 0) {
133     return ParsePSIMemStatus::kInvalidMetricFormat;
134   }
135
136   *metric_some = compute_some;
137   *metric_full = compute_full;
138
139   return ParsePSIMemStatus::kSuccess;
140 }
141
142 ParsePSIMemStatus PSIMemoryParser::ParseMetrics(const uint8_t* content,
143                                                 uint32_t len,
144                                                 int* metric_some,
145                                                 int* metric_full) {
146   // The cast below is admittedly sneaky, but inherently safe because
147   // we are translating a const pointer into another const pointer,
148   // and the data sizes of the pointed object are the same.
149   const char* string_content = reinterpret_cast<const char*>(content);
150
151   return ParseMetrics(base::StringPiece(string_content, len), metric_some,
152                       metric_full);
153 }
154
155 namespace internal {
156
157 bool FindMiddleString(const base::StringPiece& content,
158                       size_t search_start,
159                       const base::StringPiece& prefix,
160                       const base::StringPiece& suffix,
161                       size_t* start,
162                       size_t* end) {
163   DCHECK_NE(start, nullptr);
164   DCHECK_NE(end, nullptr);
165
166   size_t compute_start = content.find(prefix, search_start);
167   if (compute_start == std::string::npos) {
168     return false;
169   }
170   compute_start += prefix.length();
171
172   size_t compute_end = content.find(suffix, compute_start);
173   if (compute_end == std::string::npos) {
174     return false;
175   }
176
177   *start = compute_start;
178   *end = compute_end;
179
180   return true;
181 }
182
183 }  // namespace internal
184
185 }  // namespace metrics