xref: /aosp_15_r20/external/cronet/net/disk_cache/blockfile/stats.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2011 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "net/disk_cache/blockfile/stats.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <bit>
8*6777b538SAndroid Build Coastguard Worker #include <cstdint>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/format_macros.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
14*6777b538SAndroid Build Coastguard Worker 
15*6777b538SAndroid Build Coastguard Worker namespace {
16*6777b538SAndroid Build Coastguard Worker 
17*6777b538SAndroid Build Coastguard Worker const int32_t kDiskSignature = 0xF01427E0;
18*6777b538SAndroid Build Coastguard Worker 
19*6777b538SAndroid Build Coastguard Worker struct OnDiskStats {
20*6777b538SAndroid Build Coastguard Worker   int32_t signature;
21*6777b538SAndroid Build Coastguard Worker   int size;
22*6777b538SAndroid Build Coastguard Worker   int data_sizes[disk_cache::Stats::kDataSizesLength];
23*6777b538SAndroid Build Coastguard Worker   int64_t counters[disk_cache::Stats::MAX_COUNTER];
24*6777b538SAndroid Build Coastguard Worker };
25*6777b538SAndroid Build Coastguard Worker static_assert(sizeof(OnDiskStats) < 512, "needs more than 2 blocks");
26*6777b538SAndroid Build Coastguard Worker 
27*6777b538SAndroid Build Coastguard Worker // WARNING: Add new stats only at the end, or change LoadStats().
28*6777b538SAndroid Build Coastguard Worker const char* const kCounterNames[] = {
29*6777b538SAndroid Build Coastguard Worker   "Open miss",
30*6777b538SAndroid Build Coastguard Worker   "Open hit",
31*6777b538SAndroid Build Coastguard Worker   "Create miss",
32*6777b538SAndroid Build Coastguard Worker   "Create hit",
33*6777b538SAndroid Build Coastguard Worker   "Resurrect hit",
34*6777b538SAndroid Build Coastguard Worker   "Create error",
35*6777b538SAndroid Build Coastguard Worker   "Trim entry",
36*6777b538SAndroid Build Coastguard Worker   "Doom entry",
37*6777b538SAndroid Build Coastguard Worker   "Doom cache",
38*6777b538SAndroid Build Coastguard Worker   "Invalid entry",
39*6777b538SAndroid Build Coastguard Worker   "Open entries",
40*6777b538SAndroid Build Coastguard Worker   "Max entries",
41*6777b538SAndroid Build Coastguard Worker   "Timer",
42*6777b538SAndroid Build Coastguard Worker   "Read data",
43*6777b538SAndroid Build Coastguard Worker   "Write data",
44*6777b538SAndroid Build Coastguard Worker   "Open rankings",
45*6777b538SAndroid Build Coastguard Worker   "Get rankings",
46*6777b538SAndroid Build Coastguard Worker   "Fatal error",
47*6777b538SAndroid Build Coastguard Worker   "Last report",
48*6777b538SAndroid Build Coastguard Worker   "Last report timer",
49*6777b538SAndroid Build Coastguard Worker   "Doom recent entries",
50*6777b538SAndroid Build Coastguard Worker   "unused"
51*6777b538SAndroid Build Coastguard Worker };
52*6777b538SAndroid Build Coastguard Worker static_assert(std::size(kCounterNames) == disk_cache::Stats::MAX_COUNTER,
53*6777b538SAndroid Build Coastguard Worker               "update the names");
54*6777b538SAndroid Build Coastguard Worker 
55*6777b538SAndroid Build Coastguard Worker }  // namespace
56*6777b538SAndroid Build Coastguard Worker 
57*6777b538SAndroid Build Coastguard Worker namespace disk_cache {
58*6777b538SAndroid Build Coastguard Worker 
VerifyStats(OnDiskStats * stats)59*6777b538SAndroid Build Coastguard Worker bool VerifyStats(OnDiskStats* stats) {
60*6777b538SAndroid Build Coastguard Worker   if (stats->signature != kDiskSignature)
61*6777b538SAndroid Build Coastguard Worker     return false;
62*6777b538SAndroid Build Coastguard Worker 
63*6777b538SAndroid Build Coastguard Worker   // We don't want to discard the whole cache every time we have one extra
64*6777b538SAndroid Build Coastguard Worker   // counter; we keep old data if we can.
65*6777b538SAndroid Build Coastguard Worker   if (static_cast<unsigned int>(stats->size) > sizeof(*stats)) {
66*6777b538SAndroid Build Coastguard Worker     memset(stats, 0, sizeof(*stats));
67*6777b538SAndroid Build Coastguard Worker     stats->signature = kDiskSignature;
68*6777b538SAndroid Build Coastguard Worker   } else if (static_cast<unsigned int>(stats->size) != sizeof(*stats)) {
69*6777b538SAndroid Build Coastguard Worker     size_t delta = sizeof(*stats) - static_cast<unsigned int>(stats->size);
70*6777b538SAndroid Build Coastguard Worker     memset(reinterpret_cast<char*>(stats) + stats->size, 0, delta);
71*6777b538SAndroid Build Coastguard Worker     stats->size = sizeof(*stats);
72*6777b538SAndroid Build Coastguard Worker   }
73*6777b538SAndroid Build Coastguard Worker 
74*6777b538SAndroid Build Coastguard Worker   return true;
75*6777b538SAndroid Build Coastguard Worker }
76*6777b538SAndroid Build Coastguard Worker 
77*6777b538SAndroid Build Coastguard Worker Stats::Stats() = default;
78*6777b538SAndroid Build Coastguard Worker 
79*6777b538SAndroid Build Coastguard Worker Stats::~Stats() = default;
80*6777b538SAndroid Build Coastguard Worker 
Init(void * data,int num_bytes,Addr address)81*6777b538SAndroid Build Coastguard Worker bool Stats::Init(void* data, int num_bytes, Addr address) {
82*6777b538SAndroid Build Coastguard Worker   OnDiskStats local_stats;
83*6777b538SAndroid Build Coastguard Worker   OnDiskStats* stats = &local_stats;
84*6777b538SAndroid Build Coastguard Worker   if (!num_bytes) {
85*6777b538SAndroid Build Coastguard Worker     memset(stats, 0, sizeof(local_stats));
86*6777b538SAndroid Build Coastguard Worker     local_stats.signature = kDiskSignature;
87*6777b538SAndroid Build Coastguard Worker     local_stats.size = sizeof(local_stats);
88*6777b538SAndroid Build Coastguard Worker   } else if (num_bytes >= static_cast<int>(sizeof(*stats))) {
89*6777b538SAndroid Build Coastguard Worker     stats = reinterpret_cast<OnDiskStats*>(data);
90*6777b538SAndroid Build Coastguard Worker     if (!VerifyStats(stats)) {
91*6777b538SAndroid Build Coastguard Worker       memset(&local_stats, 0, sizeof(local_stats));
92*6777b538SAndroid Build Coastguard Worker       if (memcmp(stats, &local_stats, sizeof(local_stats))) {
93*6777b538SAndroid Build Coastguard Worker         return false;
94*6777b538SAndroid Build Coastguard Worker       } else {
95*6777b538SAndroid Build Coastguard Worker         // The storage is empty which means that SerializeStats() was never
96*6777b538SAndroid Build Coastguard Worker         // called on the last run. Just re-initialize everything.
97*6777b538SAndroid Build Coastguard Worker         local_stats.signature = kDiskSignature;
98*6777b538SAndroid Build Coastguard Worker         local_stats.size = sizeof(local_stats);
99*6777b538SAndroid Build Coastguard Worker         stats = &local_stats;
100*6777b538SAndroid Build Coastguard Worker       }
101*6777b538SAndroid Build Coastguard Worker     }
102*6777b538SAndroid Build Coastguard Worker   } else {
103*6777b538SAndroid Build Coastguard Worker     return false;
104*6777b538SAndroid Build Coastguard Worker   }
105*6777b538SAndroid Build Coastguard Worker 
106*6777b538SAndroid Build Coastguard Worker   storage_addr_ = address;
107*6777b538SAndroid Build Coastguard Worker 
108*6777b538SAndroid Build Coastguard Worker   memcpy(data_sizes_, stats->data_sizes, sizeof(data_sizes_));
109*6777b538SAndroid Build Coastguard Worker   memcpy(counters_, stats->counters, sizeof(counters_));
110*6777b538SAndroid Build Coastguard Worker 
111*6777b538SAndroid Build Coastguard Worker   // Clean up old value.
112*6777b538SAndroid Build Coastguard Worker   SetCounter(UNUSED, 0);
113*6777b538SAndroid Build Coastguard Worker   return true;
114*6777b538SAndroid Build Coastguard Worker }
115*6777b538SAndroid Build Coastguard Worker 
InitSizeHistogram()116*6777b538SAndroid Build Coastguard Worker void Stats::InitSizeHistogram() {
117*6777b538SAndroid Build Coastguard Worker   // Only generate this histogram for the main cache.
118*6777b538SAndroid Build Coastguard Worker   static bool first_time = true;
119*6777b538SAndroid Build Coastguard Worker   if (!first_time)
120*6777b538SAndroid Build Coastguard Worker     return;
121*6777b538SAndroid Build Coastguard Worker 
122*6777b538SAndroid Build Coastguard Worker   first_time = false;
123*6777b538SAndroid Build Coastguard Worker   for (int& data_size : data_sizes_) {
124*6777b538SAndroid Build Coastguard Worker     // This is a good time to fix any inconsistent data. The count should be
125*6777b538SAndroid Build Coastguard Worker     // always positive, but if it's not, reset the value now.
126*6777b538SAndroid Build Coastguard Worker     if (data_size < 0)
127*6777b538SAndroid Build Coastguard Worker       data_size = 0;
128*6777b538SAndroid Build Coastguard Worker   }
129*6777b538SAndroid Build Coastguard Worker }
130*6777b538SAndroid Build Coastguard Worker 
StorageSize()131*6777b538SAndroid Build Coastguard Worker int Stats::StorageSize() {
132*6777b538SAndroid Build Coastguard Worker   // If we have more than 512 bytes of counters, change kDiskSignature so we
133*6777b538SAndroid Build Coastguard Worker   // don't overwrite something else (LoadStats must fail).
134*6777b538SAndroid Build Coastguard Worker   static_assert(sizeof(OnDiskStats) <= 256 * 2, "use more blocks");
135*6777b538SAndroid Build Coastguard Worker   return 256 * 2;
136*6777b538SAndroid Build Coastguard Worker }
137*6777b538SAndroid Build Coastguard Worker 
ModifyStorageStats(int32_t old_size,int32_t new_size)138*6777b538SAndroid Build Coastguard Worker void Stats::ModifyStorageStats(int32_t old_size, int32_t new_size) {
139*6777b538SAndroid Build Coastguard Worker   // We keep a counter of the data block size on an array where each entry is
140*6777b538SAndroid Build Coastguard Worker   // the adjusted log base 2 of the size. The first entry counts blocks of 256
141*6777b538SAndroid Build Coastguard Worker   // bytes, the second blocks up to 512 bytes, etc. With 20 entries, the last
142*6777b538SAndroid Build Coastguard Worker   // one stores entries of more than 64 MB
143*6777b538SAndroid Build Coastguard Worker   int new_index = GetStatsBucket(new_size);
144*6777b538SAndroid Build Coastguard Worker   int old_index = GetStatsBucket(old_size);
145*6777b538SAndroid Build Coastguard Worker 
146*6777b538SAndroid Build Coastguard Worker   if (new_size)
147*6777b538SAndroid Build Coastguard Worker     data_sizes_[new_index]++;
148*6777b538SAndroid Build Coastguard Worker 
149*6777b538SAndroid Build Coastguard Worker   if (old_size)
150*6777b538SAndroid Build Coastguard Worker     data_sizes_[old_index]--;
151*6777b538SAndroid Build Coastguard Worker }
152*6777b538SAndroid Build Coastguard Worker 
OnEvent(Counters an_event)153*6777b538SAndroid Build Coastguard Worker void Stats::OnEvent(Counters an_event) {
154*6777b538SAndroid Build Coastguard Worker   DCHECK(an_event >= MIN_COUNTER && an_event < MAX_COUNTER);
155*6777b538SAndroid Build Coastguard Worker   counters_[an_event]++;
156*6777b538SAndroid Build Coastguard Worker }
157*6777b538SAndroid Build Coastguard Worker 
SetCounter(Counters counter,int64_t value)158*6777b538SAndroid Build Coastguard Worker void Stats::SetCounter(Counters counter, int64_t value) {
159*6777b538SAndroid Build Coastguard Worker   DCHECK(counter >= MIN_COUNTER && counter < MAX_COUNTER);
160*6777b538SAndroid Build Coastguard Worker   counters_[counter] = value;
161*6777b538SAndroid Build Coastguard Worker }
162*6777b538SAndroid Build Coastguard Worker 
GetCounter(Counters counter) const163*6777b538SAndroid Build Coastguard Worker int64_t Stats::GetCounter(Counters counter) const {
164*6777b538SAndroid Build Coastguard Worker   DCHECK(counter >= MIN_COUNTER && counter < MAX_COUNTER);
165*6777b538SAndroid Build Coastguard Worker   return counters_[counter];
166*6777b538SAndroid Build Coastguard Worker }
167*6777b538SAndroid Build Coastguard Worker 
GetItems(StatsItems * items)168*6777b538SAndroid Build Coastguard Worker void Stats::GetItems(StatsItems* items) {
169*6777b538SAndroid Build Coastguard Worker   std::pair<std::string, std::string> item;
170*6777b538SAndroid Build Coastguard Worker   for (int i = 0; i < kDataSizesLength; i++) {
171*6777b538SAndroid Build Coastguard Worker     item.first = base::StringPrintf("Size%02d", i);
172*6777b538SAndroid Build Coastguard Worker     item.second = base::StringPrintf("0x%08x", data_sizes_[i]);
173*6777b538SAndroid Build Coastguard Worker     items->push_back(item);
174*6777b538SAndroid Build Coastguard Worker   }
175*6777b538SAndroid Build Coastguard Worker 
176*6777b538SAndroid Build Coastguard Worker   for (int i = MIN_COUNTER; i < MAX_COUNTER; i++) {
177*6777b538SAndroid Build Coastguard Worker     item.first = kCounterNames[i];
178*6777b538SAndroid Build Coastguard Worker     item.second = base::StringPrintf("0x%" PRIx64, counters_[i]);
179*6777b538SAndroid Build Coastguard Worker     items->push_back(item);
180*6777b538SAndroid Build Coastguard Worker   }
181*6777b538SAndroid Build Coastguard Worker }
182*6777b538SAndroid Build Coastguard Worker 
ResetRatios()183*6777b538SAndroid Build Coastguard Worker void Stats::ResetRatios() {
184*6777b538SAndroid Build Coastguard Worker   SetCounter(OPEN_HIT, 0);
185*6777b538SAndroid Build Coastguard Worker   SetCounter(OPEN_MISS, 0);
186*6777b538SAndroid Build Coastguard Worker   SetCounter(RESURRECT_HIT, 0);
187*6777b538SAndroid Build Coastguard Worker   SetCounter(CREATE_HIT, 0);
188*6777b538SAndroid Build Coastguard Worker }
189*6777b538SAndroid Build Coastguard Worker 
GetLargeEntriesSize()190*6777b538SAndroid Build Coastguard Worker int Stats::GetLargeEntriesSize() {
191*6777b538SAndroid Build Coastguard Worker   int total = 0;
192*6777b538SAndroid Build Coastguard Worker   // data_sizes_[20] stores values between 512 KB and 1 MB (see comment before
193*6777b538SAndroid Build Coastguard Worker   // GetStatsBucket()).
194*6777b538SAndroid Build Coastguard Worker   for (int bucket = 20; bucket < kDataSizesLength; bucket++)
195*6777b538SAndroid Build Coastguard Worker     total += data_sizes_[bucket] * GetBucketRange(bucket);
196*6777b538SAndroid Build Coastguard Worker 
197*6777b538SAndroid Build Coastguard Worker   return total;
198*6777b538SAndroid Build Coastguard Worker }
199*6777b538SAndroid Build Coastguard Worker 
SerializeStats(void * data,int num_bytes,Addr * address)200*6777b538SAndroid Build Coastguard Worker int Stats::SerializeStats(void* data, int num_bytes, Addr* address) {
201*6777b538SAndroid Build Coastguard Worker   OnDiskStats* stats = reinterpret_cast<OnDiskStats*>(data);
202*6777b538SAndroid Build Coastguard Worker   if (num_bytes < static_cast<int>(sizeof(*stats)))
203*6777b538SAndroid Build Coastguard Worker     return 0;
204*6777b538SAndroid Build Coastguard Worker 
205*6777b538SAndroid Build Coastguard Worker   stats->signature = kDiskSignature;
206*6777b538SAndroid Build Coastguard Worker   stats->size = sizeof(*stats);
207*6777b538SAndroid Build Coastguard Worker   memcpy(stats->data_sizes, data_sizes_, sizeof(data_sizes_));
208*6777b538SAndroid Build Coastguard Worker   memcpy(stats->counters, counters_, sizeof(counters_));
209*6777b538SAndroid Build Coastguard Worker 
210*6777b538SAndroid Build Coastguard Worker   *address = storage_addr_;
211*6777b538SAndroid Build Coastguard Worker   return sizeof(*stats);
212*6777b538SAndroid Build Coastguard Worker }
213*6777b538SAndroid Build Coastguard Worker 
GetBucketRange(size_t i) const214*6777b538SAndroid Build Coastguard Worker int Stats::GetBucketRange(size_t i) const {
215*6777b538SAndroid Build Coastguard Worker   CHECK_LE(i, static_cast<size_t>(kDataSizesLength));
216*6777b538SAndroid Build Coastguard Worker   if (i < 2)
217*6777b538SAndroid Build Coastguard Worker     return static_cast<int>(1024 * i);
218*6777b538SAndroid Build Coastguard Worker 
219*6777b538SAndroid Build Coastguard Worker   if (i < 12)
220*6777b538SAndroid Build Coastguard Worker     return static_cast<int>(2048 * (i - 1));
221*6777b538SAndroid Build Coastguard Worker 
222*6777b538SAndroid Build Coastguard Worker   if (i < 17)
223*6777b538SAndroid Build Coastguard Worker     return static_cast<int>(4096 * (i - 11)) + 20 * 1024;
224*6777b538SAndroid Build Coastguard Worker 
225*6777b538SAndroid Build Coastguard Worker   int n = 64 * 1024;
226*6777b538SAndroid Build Coastguard Worker 
227*6777b538SAndroid Build Coastguard Worker   i -= 17;
228*6777b538SAndroid Build Coastguard Worker   n <<= i;
229*6777b538SAndroid Build Coastguard Worker   return n;
230*6777b538SAndroid Build Coastguard Worker }
231*6777b538SAndroid Build Coastguard Worker 
232*6777b538SAndroid Build Coastguard Worker // The array will be filled this way:
233*6777b538SAndroid Build Coastguard Worker //  index      size
234*6777b538SAndroid Build Coastguard Worker //    0       [0, 1024)
235*6777b538SAndroid Build Coastguard Worker //    1    [1024, 2048)
236*6777b538SAndroid Build Coastguard Worker //    2    [2048, 4096)
237*6777b538SAndroid Build Coastguard Worker //    3      [4K, 6K)
238*6777b538SAndroid Build Coastguard Worker //      ...
239*6777b538SAndroid Build Coastguard Worker //   10     [18K, 20K)
240*6777b538SAndroid Build Coastguard Worker //   11     [20K, 24K)
241*6777b538SAndroid Build Coastguard Worker //   12     [24k, 28K)
242*6777b538SAndroid Build Coastguard Worker //      ...
243*6777b538SAndroid Build Coastguard Worker //   15     [36k, 40K)
244*6777b538SAndroid Build Coastguard Worker //   16     [40k, 64K)
245*6777b538SAndroid Build Coastguard Worker //   17     [64K, 128K)
246*6777b538SAndroid Build Coastguard Worker //   18    [128K, 256K)
247*6777b538SAndroid Build Coastguard Worker //      ...
248*6777b538SAndroid Build Coastguard Worker //   23      [4M, 8M)
249*6777b538SAndroid Build Coastguard Worker //   24      [8M, 16M)
250*6777b538SAndroid Build Coastguard Worker //   25     [16M, 32M)
251*6777b538SAndroid Build Coastguard Worker //   26     [32M, 64M)
252*6777b538SAndroid Build Coastguard Worker //   27     [64M, ...)
GetStatsBucket(int32_t size)253*6777b538SAndroid Build Coastguard Worker int Stats::GetStatsBucket(int32_t size) {
254*6777b538SAndroid Build Coastguard Worker   if (size < 1024)
255*6777b538SAndroid Build Coastguard Worker     return 0;
256*6777b538SAndroid Build Coastguard Worker 
257*6777b538SAndroid Build Coastguard Worker   // 10 slots more, until 20K.
258*6777b538SAndroid Build Coastguard Worker   if (size < 20 * 1024)
259*6777b538SAndroid Build Coastguard Worker     return size / 2048 + 1;
260*6777b538SAndroid Build Coastguard Worker 
261*6777b538SAndroid Build Coastguard Worker   // 5 slots more, from 20K to 40K.
262*6777b538SAndroid Build Coastguard Worker   if (size < 40 * 1024)
263*6777b538SAndroid Build Coastguard Worker     return (size - 20 * 1024) / 4096 + 11;
264*6777b538SAndroid Build Coastguard Worker 
265*6777b538SAndroid Build Coastguard Worker   // From this point on, use a logarithmic scale.
266*6777b538SAndroid Build Coastguard Worker   int result = std::bit_width<uint32_t>(size);
267*6777b538SAndroid Build Coastguard Worker 
268*6777b538SAndroid Build Coastguard Worker   static_assert(kDataSizesLength > 16, "update the scale");
269*6777b538SAndroid Build Coastguard Worker   if (result >= kDataSizesLength)
270*6777b538SAndroid Build Coastguard Worker     result = kDataSizesLength - 1;
271*6777b538SAndroid Build Coastguard Worker 
272*6777b538SAndroid Build Coastguard Worker   return result;
273*6777b538SAndroid Build Coastguard Worker }
274*6777b538SAndroid Build Coastguard Worker 
GetRatio(Counters hit,Counters miss) const275*6777b538SAndroid Build Coastguard Worker int Stats::GetRatio(Counters hit, Counters miss) const {
276*6777b538SAndroid Build Coastguard Worker   int64_t ratio = GetCounter(hit) * 100;
277*6777b538SAndroid Build Coastguard Worker   if (!ratio)
278*6777b538SAndroid Build Coastguard Worker     return 0;
279*6777b538SAndroid Build Coastguard Worker 
280*6777b538SAndroid Build Coastguard Worker   ratio /= (GetCounter(hit) + GetCounter(miss));
281*6777b538SAndroid Build Coastguard Worker   return static_cast<int>(ratio);
282*6777b538SAndroid Build Coastguard Worker }
283*6777b538SAndroid Build Coastguard Worker 
284*6777b538SAndroid Build Coastguard Worker }  // namespace disk_cache
285