blob: 795832ba478ab3ac26b29371370a9a7335c361d5 [file] [log] [blame]
// Copyright 2020 the V8 project 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 V8_HEAP_CPPGC_STATS_COLLECTOR_H_
#define V8_HEAP_CPPGC_STATS_COLLECTOR_H_
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "src/base/macros.h"
#include "src/base/platform/time.h"
namespace cppgc {
namespace internal {
// Sink for various time and memory statistics.
class V8_EXPORT_PRIVATE StatsCollector final {
public:
// POD to hold interesting data accumulated during a garbage collection cycle.
//
// The event is always fully populated when looking at previous events but
// may only be partially populated when looking at the current event.
struct Event final {
// Marked bytes collected during marking.
size_t marked_bytes = 0;
};
// Observer for allocated object size. May be used to implement heap growing
// heuristics.
class AllocationObserver {
public:
// Called after observing at least
// StatsCollector::kAllocationThresholdBytes changed bytes through
// allocation or explicit free. Reports both, negative and positive
// increments, to allow observer to decide whether absolute values or only
// the deltas is interesting.
//
// May trigger GC.
virtual void AllocatedObjectSizeIncreased(size_t) = 0;
virtual void AllocatedObjectSizeDecreased(size_t) = 0;
// Called when the exact size of allocated object size is known. In
// practice, this is after marking when marked bytes == allocated bytes.
//
// Must not trigger GC synchronously.
virtual void ResetAllocatedObjectSize(size_t) = 0;
};
// Observers are implemented using virtual calls. Avoid notifications below
// reasonably interesting sizes.
static constexpr size_t kAllocationThresholdBytes = 1024;
StatsCollector() = default;
StatsCollector(const StatsCollector&) = delete;
StatsCollector& operator=(const StatsCollector&) = delete;
void RegisterObserver(AllocationObserver*);
void UnregisterObserver(AllocationObserver*);
void NotifyAllocation(size_t);
void NotifyExplicitFree(size_t);
// Safepoints should only be invoked when garabge collections are possible.
// This is necessary as increments and decrements are reported as close to
// their actual allocation/reclamation as possible.
void NotifySafePointForConservativeCollection();
// Indicates a new garbage collection cycle.
void NotifyMarkingStarted();
// Indicates that marking of the current garbage collection cycle is
// completed.
void NotifyMarkingCompleted(size_t marked_bytes);
// Indicates the end of a garbage collection cycle. This means that sweeping
// is finished at this point.
const Event& NotifySweepingCompleted();
// Size of live objects in bytes on the heap. Based on the most recent marked
// bytes and the bytes allocated since last marking.
size_t allocated_object_size() const;
double GetRecentAllocationSpeedInBytesPerMs() const;
private:
enum class GarbageCollectionState : uint8_t {
kNotRunning,
kMarking,
kSweeping
};
// Invokes |callback| for all registered observers.
template <typename Callback>
void ForAllAllocationObservers(Callback callback);
void AllocatedObjectSizeSafepointImpl();
// Allocated bytes since the end of marking. These bytes are reset after
// marking as they are accounted in marked_bytes then. May be negative in case
// an object was explicitly freed that was marked as live in the previous
// cycle.
int64_t allocated_bytes_since_end_of_marking_ = 0;
v8::base::TimeTicks time_of_last_end_of_marking_ = v8::base::TimeTicks::Now();
// Counters for allocation and free. The individual values are never negative
// but their delta may be because of the same reason the overall
// allocated_bytes_since_end_of_marking_ may be negative. Keep integer
// arithmetic for simplicity.
int64_t allocated_bytes_since_safepoint_ = 0;
int64_t explicitly_freed_bytes_since_safepoint_ = 0;
// vector to allow fast iteration of observers. Register/Unregisters only
// happens on startup/teardown.
std::vector<AllocationObserver*> allocation_observers_;
GarbageCollectionState gc_state_ = GarbageCollectionState::kNotRunning;
// The event being filled by the current GC cycle between NotifyMarkingStarted
// and NotifySweepingFinished.
Event current_;
// The previous GC event which is populated at NotifySweepingFinished.
Event previous_;
};
template <typename Callback>
void StatsCollector::ForAllAllocationObservers(Callback callback) {
for (AllocationObserver* observer : allocation_observers_) {
callback(observer);
}
}
} // namespace internal
} // namespace cppgc
#endif // V8_HEAP_CPPGC_STATS_COLLECTOR_H_