• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_HEAP_CPPGC_STATS_COLLECTOR_H_
6 #define V8_HEAP_CPPGC_STATS_COLLECTOR_H_
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <vector>
12 
13 #include "src/base/macros.h"
14 #include "src/base/platform/time.h"
15 
16 namespace cppgc {
17 namespace internal {
18 
19 // Sink for various time and memory statistics.
20 class V8_EXPORT_PRIVATE StatsCollector final {
21  public:
22   // POD to hold interesting data accumulated during a garbage collection cycle.
23   //
24   // The event is always fully populated when looking at previous events but
25   // may only be partially populated when looking at the current event.
26   struct Event final {
27     // Marked bytes collected during marking.
28     size_t marked_bytes = 0;
29   };
30 
31   // Observer for allocated object size. May be used to implement heap growing
32   // heuristics.
33   class AllocationObserver {
34    public:
35     // Called after observing at least
36     // StatsCollector::kAllocationThresholdBytes changed bytes through
37     // allocation or explicit free. Reports both, negative and positive
38     // increments, to allow observer to decide whether absolute values or only
39     // the deltas is interesting.
40     //
41     // May trigger GC.
42     virtual void AllocatedObjectSizeIncreased(size_t) = 0;
43     virtual void AllocatedObjectSizeDecreased(size_t) = 0;
44 
45     // Called when the exact size of allocated object size is known. In
46     // practice, this is after marking when marked bytes == allocated bytes.
47     //
48     // Must not trigger GC synchronously.
49     virtual void ResetAllocatedObjectSize(size_t) = 0;
50   };
51 
52   // Observers are implemented using virtual calls. Avoid notifications below
53   // reasonably interesting sizes.
54   static constexpr size_t kAllocationThresholdBytes = 1024;
55 
56   StatsCollector() = default;
57   StatsCollector(const StatsCollector&) = delete;
58   StatsCollector& operator=(const StatsCollector&) = delete;
59 
60   void RegisterObserver(AllocationObserver*);
61   void UnregisterObserver(AllocationObserver*);
62 
63   void NotifyAllocation(size_t);
64   void NotifyExplicitFree(size_t);
65   // Safepoints should only be invoked when garabge collections are possible.
66   // This is necessary as increments and decrements are reported as close to
67   // their actual allocation/reclamation as possible.
68   void NotifySafePointForConservativeCollection();
69 
70   // Indicates a new garbage collection cycle.
71   void NotifyMarkingStarted();
72   // Indicates that marking of the current garbage collection cycle is
73   // completed.
74   void NotifyMarkingCompleted(size_t marked_bytes);
75   // Indicates the end of a garbage collection cycle. This means that sweeping
76   // is finished at this point.
77   const Event& NotifySweepingCompleted();
78 
79   // Size of live objects in bytes  on the heap. Based on the most recent marked
80   // bytes and the bytes allocated since last marking.
81   size_t allocated_object_size() const;
82 
83   double GetRecentAllocationSpeedInBytesPerMs() const;
84 
85  private:
86   enum class GarbageCollectionState : uint8_t {
87     kNotRunning,
88     kMarking,
89     kSweeping
90   };
91 
92   // Invokes |callback| for all registered observers.
93   template <typename Callback>
94   void ForAllAllocationObservers(Callback callback);
95 
96   void AllocatedObjectSizeSafepointImpl();
97 
98   // Allocated bytes since the end of marking. These bytes are reset after
99   // marking as they are accounted in marked_bytes then. May be negative in case
100   // an object was explicitly freed that was marked as live in the previous
101   // cycle.
102   int64_t allocated_bytes_since_end_of_marking_ = 0;
103   v8::base::TimeTicks time_of_last_end_of_marking_ = v8::base::TimeTicks::Now();
104   // Counters for allocation and free. The individual values are never negative
105   // but their delta may be because of the same reason the overall
106   // allocated_bytes_since_end_of_marking_ may be negative. Keep integer
107   // arithmetic for simplicity.
108   int64_t allocated_bytes_since_safepoint_ = 0;
109   int64_t explicitly_freed_bytes_since_safepoint_ = 0;
110 
111   // vector to allow fast iteration of observers. Register/Unregisters only
112   // happens on startup/teardown.
113   std::vector<AllocationObserver*> allocation_observers_;
114 
115   GarbageCollectionState gc_state_ = GarbageCollectionState::kNotRunning;
116 
117   // The event being filled by the current GC cycle between NotifyMarkingStarted
118   // and NotifySweepingFinished.
119   Event current_;
120   // The previous GC event which is populated at NotifySweepingFinished.
121   Event previous_;
122 };
123 
124 template <typename Callback>
ForAllAllocationObservers(Callback callback)125 void StatsCollector::ForAllAllocationObservers(Callback callback) {
126   for (AllocationObserver* observer : allocation_observers_) {
127     callback(observer);
128   }
129 }
130 
131 }  // namespace internal
132 }  // namespace cppgc
133 
134 #endif  // V8_HEAP_CPPGC_STATS_COLLECTOR_H_
135