File: page_flip_watchdog.cc

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (109 lines) | stat: -rw-r--r-- 3,620 bytes parent folder | download | duplicates (4)
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/ozone/platform/drm/gpu/page_flip_watchdog.h"

#include <cstdint>

#include "ash/constants/ash_switches.h"
#include "base/containers/ring_buffer.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/syslog_logging.h"

namespace ui {

PageFlipWatchdog::PageFlipWatchdog() {
  plane_assignment_flake_threshold = ash::switches::IsRevenBranding()
                                         ? kFlexPlaneAssignmentFlakeThreshold
                                         : kPlaneAssignmentFlakeThreshold;
}

PageFlipWatchdog::~PageFlipWatchdog() = default;

void PageFlipWatchdog::OnSuccessfulPageFlip() {
  page_flip_status_tracker_.SaveToBuffer(true);
}

void PageFlipWatchdog::CrashOnFailedPlaneAssignment() {
  page_flip_status_tracker_.SaveToBuffer(false);
  failed_page_flip_counter_++;

  // Wait until the log of recent page flips is full to avoid crashing
  // too early.
  if (page_flip_status_tracker_.CurrentIndex() <
      page_flip_status_tracker_.BufferSize())
    return;

  bool last_page_flip_status = true;
  uint32_t flakes = 0;
  uint32_t failures = 0;
  for (auto iter = page_flip_status_tracker_.Begin(); iter; ++iter) {
    bool page_flip_status = **iter;
    if (page_flip_status && !last_page_flip_status)
      flakes += 1;
    if (!page_flip_status)
      failures += 1;
    last_page_flip_status = page_flip_status;
  }

  if (flakes >= plane_assignment_flake_threshold) {
    // Experiment to find good threshold for Flex device.
    // TODO(crbug.com/371609830): finalize this threshold
    // upon experiment completion.
    if (ash::switches::IsRevenBranding()) {
      UMA_HISTOGRAM_EXACT_LINEAR("Platform.FlexPageFlipFlakes", flakes, 11);
    }
    LOG(FATAL) << "Plane assignment has flaked " << flakes
               << " times, but the threshold is "
               << plane_assignment_flake_threshold
               << ". Crashing the GPU process.";
  }

  if (failures >= kPlaneAssignmentMaximumFailures) {
    LOG(FATAL) << "Plane assignment has failed " << failures << "/"
               << page_flip_status_tracker_.BufferSize()
               << " times, but the threshold is "
               << kPlaneAssignmentMaximumFailures
               << ". Crashing the GPU process.";
  }
}

void PageFlipWatchdog::ArmForFailedCommit() {
  page_flip_status_tracker_.SaveToBuffer(false);
  failed_page_flip_counter_++;
  StartCrashGpuTimer();
}

void PageFlipWatchdog::Disarm() {
  failed_page_flip_counter_ = 0;
  page_flip_status_tracker_.Clear();

  if (crash_gpu_timer_.IsRunning()) {
    crash_gpu_timer_.Stop();
    SYSLOG(INFO)
        << "Detected a modeset attempt after " << failed_page_flip_counter_
        << " failed page flips. Aborting GPU process self-destruct with "
        << crash_gpu_timer_.desired_run_time() - base::TimeTicks::Now()
        << " to spare.";
  }
}

void PageFlipWatchdog::StartCrashGpuTimer() {
  if (!crash_gpu_timer_.IsRunning()) {
    DCHECK_GE(failed_page_flip_counter_, 1);
    LOG(WARNING) << "Initiating GPU process self-destruct in "
                 << kWaitForModesetTimeout
                 << " unless a modeset attempt is detected.";

    crash_gpu_timer_.Start(
        FROM_HERE, kWaitForModesetTimeout, base::BindOnce([] {
          LOG(FATAL) << "Failed to modeset within " << kWaitForModesetTimeout
                     << " of the first page flip failure. Crashing GPU "
                        "process.";
        }));
  }
}

}  // namespace ui