// 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 #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(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(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(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(value_ & kTypeMask); } } // namespace base