// 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 "ui/latency/windowed_analyzer.h" namespace ui { void FrameRegionResult::AsValueInto( base::trace_event::TracedValue* state) const { state->SetDouble("value", value); state->SetDouble("start", window_begin.since_origin().InMillisecondsF()); state->SetDouble("duration", (window_end - window_begin).InMillisecondsF()); } namespace frame_metrics { WindowedAnalyzer::WindowedAnalyzer( const WindowedAnalyzerClient* client, const SharedWindowedAnalyzerClient* shared_client) : client_(client), shared_client_(shared_client) { window_queue_.reserve(shared_client->max_window_size); } WindowedAnalyzer::~WindowedAnalyzer() = default; void WindowedAnalyzer::ResetWorstValues() { results_.reset(); } void WindowedAnalyzer::ResetHistory() { total_weight_ = 0; accumulator_ = 0; root_accumulator_ = 0; square_accumulator_ = Accumulator96b(); window_queue_.resize(0); } void WindowedAnalyzer::AddSample(uint32_t value, uint32_t weight, uint64_t weighted_value, uint64_t weighted_root, const Accumulator96b& weighted_square) { DCHECK_GT(weight, 0u); DCHECK_EQ(weighted_value, static_cast(weight) * value); // Remove old values from the accumulators. if (window_queue_.size() >= shared_client_->max_window_size) { const uint32_t old_value = window_queue_.front().value; const uint32_t old_weight = window_queue_.front().weight; window_queue_.pop_front(); // Re-calculate some of the old values here. Although squared and root are // passed in, we've only stored the original value to reduce memory usage. total_weight_ -= old_weight; accumulator_ -= static_cast(old_weight) * old_value; // Casting the whole rhs is important to ensure rounding happens at a place // equivalent to when it was added. root_accumulator_ -= static_cast( old_weight * std::sqrt(static_cast(old_value) << kFixedPointRootShift)); square_accumulator_.Subtract(Accumulator96b(old_value, old_weight)); } // Verify overflow isn't an issue. // square_accumulator_ has DCHECKs internally, so we don't worry about // checking that here. DCHECK_LT(weighted_value, std::numeric_limits::max() - accumulator_); DCHECK_LT(weighted_root, std::numeric_limits::max() - root_accumulator_); DCHECK_LT(weight, std::numeric_limits::max() - total_weight_); window_queue_.push_back({value, weight}); total_weight_ += weight; accumulator_ += weighted_value; root_accumulator_ += weighted_root; square_accumulator_.Add(weighted_square); if (window_queue_.size() >= shared_client_->max_window_size) { bool initialize_results = !results_; if (initialize_results) results_.emplace(); UpdateWorst(accumulator_, &results_->mean, initialize_results); UpdateWorst(root_accumulator_, &results_->root, initialize_results); UpdateWorst(square_accumulator_, &results_->square, initialize_results); } } FrameRegionResult WindowedAnalyzer::ComputeWorstMean() const { FrameRegionResult result; if (results_) { result = results_->mean; } else { UpdateWorst(accumulator_, &result, true); } result.value = client_->TransformResult(result.value); return result; } FrameRegionResult WindowedAnalyzer::ComputeWorstRMS() const { FrameRegionResult result; if (results_) { result = results_->square; } else { UpdateWorst(square_accumulator_, &result, true); } result.value = client_->TransformResult(std::sqrt(result.value)); return result; } FrameRegionResult WindowedAnalyzer::ComputeWorstSMR() const { FrameRegionResult result; if (results_) { result = results_->root; } else { UpdateWorst(root_accumulator_, &result, true); } result.value = client_->TransformResult((result.value * result.value) / kFixedPointRootMultiplier); return result; } void WindowedAnalyzer::AsValueInto( base::trace_event::TracedValue* state) const { FrameRegionResult region; region = ComputeWorstMean(); state->BeginDictionary("worst_mean"); region.AsValueInto(state); state->EndDictionary(); region = ComputeWorstSMR(); state->BeginDictionary("worst_smr"); region.AsValueInto(state); state->EndDictionary(); region = ComputeWorstRMS(); state->BeginDictionary("worst_rms"); region.AsValueInto(state); state->EndDictionary(); } } // namespace frame_metrics } // namespace ui