summaryrefslogtreecommitdiff
path: root/chromium/components/metrics/leak_detector/leak_detector.h
blob: 8dcba5e9de24d64dd7570e48340a06cfaadb0c46 (plain)
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// Copyright 2016 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 COMPONENTS_METRICS_LEAK_DETECTOR_LEAK_DETECTOR_H_
#define COMPONENTS_METRICS_LEAK_DETECTOR_LEAK_DETECTOR_H_

#include <stddef.h>
#include <stdint.h>

#include <list>
#include <vector>

#include "base/feature_list.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_checker.h"

namespace base {
template <typename T>
struct DefaultLazyInstanceTraits;
}

namespace metrics {

namespace leak_detector {
class LeakDetectorImpl;
}

// LeakDetector is an interface layer that connects the allocator
// (base::allocator), the leak detector logic (LeakDetectorImpl), and any
// external classes interested in receiving leak reports (extend the Observer
// class).
//
// Only one instance of this class can exist. Access this instance using
// GetInstance(). Do not create an instance of this class directly.
//
// These member functions are thread-safe:
// - AllocHook
// - FreeHook
// - AddObserver
// - RemoveObserver
//
// All other functions must always be called from the same thread. This is
// enforced with a DCHECK.
class LeakDetector {
 public:
  // Contains a report of a detected memory leak.
  struct LeakReport {
    LeakReport();
    LeakReport(const LeakReport& other);
    ~LeakReport();

    size_t alloc_size_bytes;

    // Unlike the CallStack struct, which consists of addresses, this call stack
    // will contain offsets in the executable binary.
    std::vector<uintptr_t> call_stack;
  };

  // Interface for receiving leak reports.
  class Observer {
   public:
    virtual ~Observer() {}

    // Called by leak detector to report a leak.
    virtual void OnLeakFound(const LeakReport& report) = 0;
  };

  // Returns the sole instance, or creates it if it hasn't already been created.
  static LeakDetector* GetInstance();

  // Initializer arguments:
  // sampling_rate:
  //     Pseudorandomly sample a fraction of the incoming allocations and frees,
  //     based on hash values. Setting to 0 means no allocs/frees are sampled.
  //     Setting to 1.0 or more means all allocs/frees are sampled. Anything in
  //     between will result in an approximately that fraction of allocs/frees
  //     being sampled.
  // max_call_stack_unwind_depth:
  //     The max number of call stack frames to unwind.
  // analysis_interval_bytes:
  //     Perform a leak analysis each time this many bytes have been allocated
  //     since the previous analysis.
  // size_suspicion_threshold, call_stack_suspicion_threshold:
  //     A possible leak should be suspected this many times to take action on i
  //     For size analysis, the action is to start profiling by call stack.
  //     For call stack analysis, the action is to generate a leak report.
  void Init(float sampling_rate,
            size_t max_call_stack_unwind_depth,
            uint64_t analysis_interval_bytes,
            uint32_t size_suspicion_threshold,
            uint32_t call_stack_suspicion_threshold);

  // Add |observer| to the list of stored Observers, i.e. |observers_|, to which
  // the leak detector will report leaks.
  void AddObserver(Observer* observer);

  // Remove |observer| from |observers_|.
  void RemoveObserver(Observer* observer);

 private:
  friend base::DefaultLazyInstanceTraits<LeakDetector>;
  FRIEND_TEST_ALL_PREFIXES(LeakDetectorTest, NotifyObservers);

  // Keep these private, as this class is meant to be initialized only through
  // the lazy instance, and never destroyed.
  LeakDetector();
  ~LeakDetector();

  // Allocator hook function that processes each alloc. Performs sampling and
  // unwinds call stack if necessary. Passes the allocated memory |ptr| and
  // allocation size |size| along with call stack info to RecordAlloc().
  static void AllocHook(const void* ptr, size_t size);

  // Allocator hook function that processes each free. Performs sampling and
  // passes the allocation address |ptr| to |impl_|.
  static void FreeHook(const void* ptr);

  // Give an pointer |ptr|, computes a hash of the pointer value and compares it
  // against |sampling_factor_| to determine if it should be sampled. This
  // allows the same pointer to be sampled during both alloc and free.
  bool ShouldSample(const void* ptr) const;

  // Notifies all Observers in |observers_| with the given vector of leak
  // reports.
  void NotifyObservers(const std::vector<LeakReport>& reports);

  // List of observers to notify when there's a leak report.
  // TODO(sque): Consider using ObserverListThreadSafe instead.
  base::ObserverList<Observer> observers_;

  // For atomic access to |observers_|.
  base::Lock observers_lock_;

  // Handles leak detection logic. Must be called under lock as LeakDetectorImpl
  // uses shared resources.
  scoped_ptr<leak_detector::LeakDetectorImpl> impl_;

  // For thread safety.
  base::ThreadChecker thread_checker_;

  // Total number of bytes allocated, computed before sampling.
  size_t total_alloc_size_;

  // The value of |total_alloc_size_| the last time there was a leak analysis,
  // rounded down to the nearest multiple of |analysis_interval_bytes_|.
  size_t last_analysis_alloc_size_;

  // For atomic access to |impl_|, |total_alloc_size_| and
  // |last_analysis_alloc_size_|.
  base::Lock recording_lock_;

  // Perform a leak analysis each time this many bytes have been allocated since
  // the previous analysis.
  size_t analysis_interval_bytes_;

  // When unwinding call stacks, unwind no more than this number of frames.
  size_t max_call_stack_unwind_depth_;

  // Sampling factor used by ShouldSample(). It's full range of values
  // corresponds to the allowable range of |sampling_rate| passed in during
  // initialization: [0.0f, 1.0f] -> [0, UINT64_MAX].
  uint64_t sampling_factor_;

  DISALLOW_COPY_AND_ASSIGN(LeakDetector);
};

}  // namespace metrics

#endif  // COMPONENTS_METRICS_LEAK_DETECTOR_LEAK_DETECTOR_H_