blob: 11b419116b3c41226380582b8ac2d5037a6af1bc [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.
#ifndef UI_FRAME_METRICS_FIXED_POINT_H_
#define UI_FRAME_METRICS_FIXED_POINT_H_
#include <cstdint>
#include "base/macros.h"
namespace ui {
namespace frame_metrics {
// Use fixed point math so we can manage our precision explicitly and avoid
// accumulating error in our windowed accumulators.
// The 64-bit accumulators reserve 32-bits for weights, and 32-bits for values.
// The 32-bit values reserve 16 bits before and after the radix point.
constexpr int kFixedPointShift = 16;
constexpr int64_t kFixedPointMultiplier{1LL << kFixedPointShift};
// kFixedPointRootMultiplier is used to shift the bits before taking the square
// root and undoing that shift after squaring in the SMR calculation.
constexpr int kFixedPointRootShift = 32;
constexpr int64_t kFixedPointRootMultiplier{1LL << kFixedPointRootShift};
constexpr int64_t kFixedPointRootMultiplierSqrt{1LL
<< (kFixedPointRootShift / 2)};
// We need a huge range to accumulate values for RMS calculations, which
// need double the range internally compared to the range we are targeting
// after taking the square root of the accumulation.
// This efficiently emulates a 96-bit unsigned integer with weighted
// accumulation operations.
// 32-bits are reserved for weights and 64-bits for squared values.
// Overflow or underflow indicates something is seriously wrong with the higher
// level metrics logic, so this class will DCHECK if it anticipates overflow
// or underflow:
// * It doesn't need to support OVERFLOW since the frame metric classes will
// always reset the entire accumulator before the accumulated weights
// overflow. The accumulated weights correspond to a maximum of the number of
// microseconds since the last reset, which for a 32-bit weight is about
// 1 hour. We will gather and reset results much more often than every hour.
// * It doesn't need to support UNDERFLOW since only the windowed metrics use
// Subtract, and those only subtract values it has already added.
class Accumulator96b {
public:
Accumulator96b() = default;
Accumulator96b(uint32_t value_to_square, uint32_t weight);
void Add(const Accumulator96b& rhs);
void Subtract(const Accumulator96b& rhs);
double ToDouble() const;
public:
uint64_t ms64b{0};
uint32_t ls32b{0};
};
// Convenience function overloads for AsDouble, to help with templated code.
inline double AsDouble(const Accumulator96b& value) {
return value.ToDouble();
}
inline double AsDouble(double value) {
return value;
}
} // namespace frame_metrics
} // namespace ui
#endif // UI_FRAME_METRICS_FIXED_POINT_H_