summaryrefslogtreecommitdiff
path: root/chromium/base/metrics/ukm_source_id.cc
blob: 0b2a8baf29601b00e0c7edc5e03335562862fbdf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// 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 "base/metrics/ukm_source_id.h"

#include <cmath>

#include "base/atomic_sequence_num.h"
#include "base/check_op.h"
#include "base/rand_util.h"

namespace base {

namespace {

const int64_t kLowBitsMask = (INT64_C(1) << 32) - 1;

int64_t GetNumTypeBits() {
  return std::ceil(
      std::log2(static_cast<int64_t>(UkmSourceId::Type::kMaxValue) + 1));
}

}  // namespace

// static
UkmSourceId UkmSourceId::New() {
  // Generate some bits which are unique to this process, so we can generate
  // IDs independently in different processes. IDs generated by this method may
  // collide, but it should be sufficiently rare enough to not impact data
  // quality.
  const static int64_t process_id_bits =
      static_cast<int64_t>(RandUint64()) & ~kLowBitsMask;
  // Generate some bits which are unique within the process, using a counter.
  static AtomicSequenceNumber seq;
  UkmSourceId local_id =
      FromOtherId(seq.GetNext() + 1, UkmSourceId::Type::DEFAULT);
  // Combine the local and process bits to generate a unique ID.
  return UkmSourceId((local_id.value_ & kLowBitsMask) | process_id_bits);
}

// static
UkmSourceId UkmSourceId::FromOtherId(int64_t other_id, UkmSourceId::Type type) {
  // Note on syntax: std::ceil and std::log2 are not constexpr functions thus
  // these variables cannot be initialized statically in the global scope above.
  // Function static initialization here is thread safe; so they are initialized
  // at most once.
  static const int64_t kNumTypeBits = GetNumTypeBits();
  static const int64_t kTypeMask = (INT64_C(1) << kNumTypeBits) - 1;

  const int64_t type_bits = static_cast<int64_t>(type);
  DCHECK_EQ(type_bits, type_bits & kTypeMask);
  // Stores the type of the source ID in its lower bits, and shift the rest of
  // the ID to make room. This could cause the original ID to overflow, but
  // that should be rare enough that it won't matter for UKM's purposes.
  return UkmSourceId((other_id << kNumTypeBits) | type_bits);
}

UkmSourceId::Type UkmSourceId::GetType() const {
  static const int64_t kNumTypeBits = GetNumTypeBits();
  static const int64_t kTypeMask = (INT64_C(1) << kNumTypeBits) - 1;
  return static_cast<UkmSourceId::Type>(value_ & kTypeMask);
}

}  // namespace base