chromium/ash/wm/overview/overview_metrics.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/wm/overview/overview_metrics.h"

#include <string>

#include "ash/public/cpp/window_properties.h"
#include "ash/shell.h"
#include "ash/wm/desks/desk.h"
#include "ash/wm/desks/desks_controller.h"
#include "ash/wm/overview/overview_constants.h"
#include "base/location.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/task_traits.h"
#include "base/time/time.h"
#include "ui/aura/window.h"
#include "ui/compositor/presentation_time_recorder.h"

namespace ash {
namespace {

int GetNumWindowsOnAllDesks() {
  int num_windows_found = 0;
  for (const auto& desk : DesksController::Get()->desks()) {
    for (const auto& window : desk->GetAllAssociatedWindows()) {
      if (!window->GetProperty(kHideInDeskMiniViewKey)) {
        ++num_windows_found;
      }
    }
  }
  for (const auto& root_window : Shell::Get()->GetAllRootWindows()) {
    num_windows_found += DesksController::Get()
                             ->GetVisibleOnAllDesksWindowsOnRoot(root_window)
                             .size();
  }
  return num_windows_found;
}

std::string GetPresentationTimeMetricNameWithDeskBar(
    int num_windows,
    std::string_view enter_exit_label) {
  constexpr int kNumWindowsOverflowBoundary = 10;
  const std::string num_windows_suffix =
      num_windows > kNumWindowsOverflowBoundary
          ? "MoreThan" + base::NumberToString(kNumWindowsOverflowBoundary)
          : base::NumberToString(num_windows);
  return base::StrCat({"Ash.Overview.", enter_exit_label,
                       ".PresentationTime.WithDeskBarAndNumWindows",
                       num_windows_suffix});
}

void RecordPresentationTimeMetricsWithDeskBar(
    std::unique_ptr<ui::PresentationTimeRecorder> enter_recorder,
    std::unique_ptr<ui::PresentationTimeRecorder> exit_recorder,
    DeskBarVisibility desk_bar_visibility,
    const std::string& enter_metric_name,
    const std::string& exit_metric_name) {
  constexpr base::TimeDelta kMinLatency = base::Milliseconds(1);
  constexpr int kNumBuckets = 50;

  // Only record for `kShownImmediately` because that's the only case where the
  // desk bar's rendering was a part of the first frame's overall presentation
  // latency when entering overview.
  if (desk_bar_visibility == DeskBarVisibility::kShownImmediately) {
    const std::optional<base::TimeDelta> enter_latency =
        enter_recorder->GetAverageLatency();
    if (enter_latency) {
      base::UmaHistogramCustomTimes(
          enter_metric_name, *enter_latency, kMinLatency,
          kOverviewEnterExitPresentationMaxLatency, kNumBuckets);
    }
  }

  // If the desk bar is present, that means it plays a factor in the latency
  // when exiting overview, regardless of whether the desk bar was rendered
  // immediately or after the enter animation completed.
  if (desk_bar_visibility != DeskBarVisibility::kNotShown) {
    const std::optional<base::TimeDelta> exit_latency =
        exit_recorder->GetAverageLatency();
    if (exit_latency) {
      base::UmaHistogramCustomTimes(
          exit_metric_name, *exit_latency, kMinLatency,
          kOverviewEnterExitPresentationMaxLatency, kNumBuckets);
    }
  }
}

}  // namespace

constexpr char kOverviewStartActionHistogram[] = "Ash.Overview.StartAction";
constexpr char kOverviewEndActionHistogram[] = "Ash.Overview.EndAction";

void RecordOverviewStartAction(OverviewStartAction type) {
  UMA_HISTOGRAM_ENUMERATION(kOverviewStartActionHistogram, type);
}

void RecordOverviewEndAction(OverviewEndAction type) {
  UMA_HISTOGRAM_ENUMERATION(kOverviewEndActionHistogram, type);
}

void SchedulePresentationTimeMetricsWithDeskBar(
    std::unique_ptr<ui::PresentationTimeRecorder> enter_recorder,
    std::unique_ptr<ui::PresentationTimeRecorder> exit_recorder,
    DeskBarVisibility desk_bar_visibility) {
  const size_t num_windows = GetNumWindowsOnAllDesks();
  // This function is currently called when exiting overview mode (before the
  // presentation time for the exit is known). Rather than seeking the exact
  // moment the exit-overview frame is presented, it's simpler to just record
  // the metric after the maximum expected frame latency since metric recording
  // is not an urgent operation.
  base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
      FROM_HERE,
      base::BindOnce(
          &RecordPresentationTimeMetricsWithDeskBar, std::move(enter_recorder),
          std::move(exit_recorder), desk_bar_visibility,
          GetPresentationTimeMetricNameWithDeskBar(num_windows, "Enter"),
          GetPresentationTimeMetricNameWithDeskBar(num_windows, "Exit")),
      // For safety, wait twice the maximum expected latency before reading the
      // measurement. Anything longer than
      // `kOverviewEnterExitPresentationMaxLatency` goes in the overflow bucket
      // anyways.
      kOverviewEnterExitPresentationMaxLatency * 2);
}

}  // namespace ash