blob: 3dd16af8c2155081a5ace91c5c717ba7d70bc468 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/tab_count_metrics/tab_count_metrics.h"
#include <limits>
#include "base/logging.h"
#include "base/stl_util.h"
namespace tab_count_metrics {
// These values represent the lower bound for each bucket, and define the
// tab count buckets. The final bucket has no upper bound, and each other
// bucket, i, is bounded above by the lower bound of bucket i + 1.
//
// The buckets were determined from the Tabs.MaxTabsInADay histogram,
// approximating the 25th, 50th, 75th, 95th, and 99th percentiles, but with the
// single and zero tab cases separated.
//
// If adding or removing a bucket, update |kNumTabCountBuckets|,
// |kTabCountBucketMins|, and |kTabCountBucketNames|. If adding,
// removing, or changing bucket ranges, the existing metrics that use these
// functions for emitting histograms should be marked as obsolete, and new
// metrics should be created. This can be accomplished by versioning
// |kTabCountBucketNames|, e.g. ".ByTabCount2.0Tabs", etc., and
// updating the histogram suffixes section of histograms.xml, creating a new
// entry for the new suffixes and marking the old suffixes obsolete.
constexpr size_t kTabCountBucketMins[] = {0, 1, 2, 3, 5, 8, 20, 40};
constexpr const char* kTabBucketNamePrefix[]{".ByTabCount", ".ByLiveTabCount"};
// Text for the tab count portion of metric names. These need to be kept
// in sync with |kTabCountBucketMins|.
constexpr const char* kTabCountBucketNames[]{
".0Tabs", ".1Tab", ".2Tabs", ".3To4Tabs",
".5To7Tabs", ".8To19Tabs", ".20To39Tabs", ".40OrMoreTabs"};
std::string HistogramName(const std::string prefix,
bool live_tabs_only,
size_t bucket) {
static_assert(base::size(kTabCountBucketMins) == kNumTabCountBuckets,
"kTabCountBucketMins must have kNumTabCountBuckets elements.");
static_assert(base::size(kTabCountBucketNames) == kNumTabCountBuckets,
"kTabCountBucketNames must have kNumTabCountBuckets elements.");
DCHECK_LT(bucket, kNumTabCountBuckets);
DCHECK(prefix.length());
return prefix + kTabBucketNamePrefix[live_tabs_only ? 1u : 0u] +
kTabCountBucketNames[bucket];
}
size_t BucketForTabCount(size_t num_tabs) {
for (size_t bucket = 0; bucket < kNumTabCountBuckets; bucket++) {
if (internal::IsInBucket(num_tabs, bucket))
return bucket;
}
// There should be a bucket for any number of tabs >= 0.
NOTREACHED();
return kNumTabCountBuckets;
}
namespace internal {
size_t BucketMin(size_t bucket) {
DCHECK_LT(bucket, kNumTabCountBuckets);
return kTabCountBucketMins[bucket];
}
size_t BucketMax(size_t bucket) {
DCHECK_LT(bucket, kNumTabCountBuckets);
// The last bucket includes everything after the min bucket value.
if (bucket == kNumTabCountBuckets - 1)
return std::numeric_limits<size_t>::max();
return kTabCountBucketMins[bucket + 1] - 1;
}
bool IsInBucket(size_t num_tabs, size_t bucket) {
DCHECK_LT(bucket, kNumTabCountBuckets);
return num_tabs >= BucketMin(bucket) && num_tabs <= BucketMax(bucket);
}
} // namespace internal
} // namespace tab_count_metrics