File: frame_eviction_manager.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (146 lines) | stat: -rw-r--r-- 5,059 bytes parent folder | download | duplicates (6)
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_VIZ_CLIENT_FRAME_EVICTION_MANAGER_H_
#define COMPONENTS_VIZ_CLIENT_FRAME_EVICTION_MANAGER_H_

#include <stddef.h>

#include <list>
#include <map>
#include <memory>
#include <optional>
#include <utility>

#include "base/gtest_prod_util.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/memory/post_delayed_memory_reduction_task.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/singleton.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/default_tick_clock.h"
#include "base/time/tick_clock.h"
#include "base/timer/timer.h"
#include "base/trace_event/memory_dump_provider.h"
#include "base/trace_event/memory_dump_request_args.h"
#include "components/viz/client/viz_client_export.h"

#if BUILDFLAG(IS_ANDROID)
#include "base/android/pre_freeze_background_memory_trimmer.h"
#endif

namespace viz {

class FrameEvictionManagerClient {
 public:
  virtual ~FrameEvictionManagerClient() = default;
  virtual void EvictCurrentFrame() = 0;
};

// This class is responsible for globally managing which renderers keep their
// compositor frame when offscreen. We actively discard compositor frames for
// offscreen tabs, but keep a minimum amount, as an LRU cache, to make switching
// between a small set of tabs faster. The limit is a soft limit, because
// clients can lock their frame to prevent it from being discarded, e.g. if the
// tab is visible, or while capturing a screenshot.
class VIZ_CLIENT_EXPORT FrameEvictionManager
    : public base::trace_event::MemoryDumpProvider {
 public:
  // Pauses frame eviction within its scope.
  class VIZ_CLIENT_EXPORT ScopedPause {
   public:
    ScopedPause();

    ScopedPause(const ScopedPause&) = delete;
    ScopedPause& operator=(const ScopedPause&) = delete;

    ~ScopedPause();
  };

  static FrameEvictionManager* GetInstance();

  FrameEvictionManager(const FrameEvictionManager&) = delete;
  FrameEvictionManager& operator=(const FrameEvictionManager&) = delete;

  void AddFrame(FrameEvictionManagerClient*, bool locked);
  void RemoveFrame(FrameEvictionManagerClient*);
  void LockFrame(FrameEvictionManagerClient*);
  void UnlockFrame(FrameEvictionManagerClient*);

  size_t GetMaxNumberOfSavedFrames() const;

  // For testing only
  void set_max_number_of_saved_frames(size_t max_number_of_saved_frames) {
    max_number_of_saved_frames_ = max_number_of_saved_frames;
  }

  // React on memory pressure events to adjust the number of cached frames.
  // Please make this private when crbug.com/443824 has been fixed.
  void OnMemoryPressure(
      base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);

  // Purges all unlocked frames, allowing us to reclaim resources.
  void PurgeAllUnlockedFrames();

  // Chosen arbitrarily, didn't show regressions in metrics during a field trial
  // in 2023. Should ideally be higher than a common time to switch between
  // tabs. The reasoning is that if a tab isn't switched to in this delay, then
  // it's unlikeky to soon be.
  static constexpr base::TimeDelta kPeriodicCullingDelay = base::Minutes(5);

 private:
  friend struct base::DefaultSingletonTraits<FrameEvictionManager>;
  FRIEND_TEST_ALL_PREFIXES(FrameEvictionManagerTest, PeriodicCulling);

  FrameEvictionManager();
  ~FrameEvictionManager() override;

  void StartFrameCullingTimer();
  void CullUnlockedFrames(size_t saved_frame_limit);
#if BUILDFLAG(IS_ANDROID)
  void CullOldUnlockedFrames(base::MemoryReductionTaskContext task_type);
#else
  void CullOldUnlockedFrames();
#endif

  void PurgeMemory(int percentage);

  // Pauses/unpauses frame eviction.
  void Pause();
  void Unpause();

  void RegisterUnlockedFrame(FrameEvictionManagerClient* frame);

  // Inject mock versions for testing.
  void SetOverridesForTesting(
      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
      const base::TickClock* clock);

  bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
                    base::trace_event::ProcessMemoryDump* pmd) override;

  // Listens for system under pressure notifications and adjusts number of
  // cached frames accordingly.
  std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;

  std::map<FrameEvictionManagerClient*, size_t> locked_frames_;
  // {FrameEvictionManagerClient, Last Unlock() time}, ordered with the most
  // recent first.
  std::list<std::pair<FrameEvictionManagerClient*, base::TimeTicks>>
      unlocked_frames_;
  size_t max_number_of_saved_frames_;

  // Counter of the outstanding pauses.
  int pause_count_ = 0;

  // Argument of the last CullUnlockedFrames call while paused.
  std::optional<size_t> pending_unlocked_frame_limit_;

  base::OneShotDelayedBackgroundTimer idle_frame_culling_timer_;
  raw_ptr<const base::TickClock> clock_ = base::DefaultTickClock::GetInstance();
};

}  // namespace viz

#endif  // COMPONENTS_VIZ_CLIENT_FRAME_EVICTION_MANAGER_H_