// Copyright 2020 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_PERFORMANCE_MANAGER_PUBLIC_V8_MEMORY_V8_DETAILED_MEMORY_H_ #define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_V8_MEMORY_V8_DETAILED_MEMORY_H_ #include <optional> #include <string> #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/sequence_checker.h" #include "base/task/sequenced_task_runner.h" #include "base/time/time.h" #include "base/types/pass_key.h" namespace performance_manager { namespace execution_context { class ExecutionContext; } // namespace execution_context class Graph; class FrameNode; class ProcessNode; class WorkerNode; namespace v8_memory { // Classes that query each renderer process for the amount of memory used by V8 // in each frame. // // To start sampling create a V8DetailedMemoryRequest object that specifies how // often to request a memory measurement. Delete the object when you no longer // need measurements. Measurement involves some overhead so choose the lowest // sampling frequency your use case needs. Performance Manager will use the // highest sampling frequency that any caller requests, and stop measurements // entirely when no more request objects exist. // // When measurements are available Performance Manager attaches them to // V8DetailedMemoryExecutionContextData and V8DetailedMemoryProcessData objects // that can be retrieved with V8DetailedMemoryExecutionContextData's // ForFrameNode, ForWorkerNode and ForExecutionContext, and // V8DetailedMemoryProcessData's ForProcessNode. V8DetailedMemoryProcessData // objects can be cleaned up when V8DetailedMemoryRequest objects are deleted // so callers must save the measurements they are interested in before // releasing their V8DetailedMemoryRequest. // // Callers can be notified when a request is available by implementing // V8DetailedMemoryObserver. // // V8DetailedMemoryRequest, V8DetailedMemoryExecutionContextData and // V8DetailedMemoryProcessData must all be accessed on the graph sequence, and // V8DetailedMemoryObserver::OnV8MemoryMeasurementAvailable will be called on // this sequence. To request memory measurements from another sequence use the // wrappers in v8_detailed_memory_any_seq.h. // // Usage: // // Take a memory measurement every 30 seconds and register an observer for the // results: // // class Observer : public V8DetailedMemoryObserver { // public: // // Called on the PM sequence for each process. // void OnV8MemoryMeasurementAvailable( // const ProcessNode* process_node, // const V8DetailedMemoryProcessData* data) override { // DCHECK(data); // LOG(INFO) << "Process " << process_node->GetProcessId() << // " reported " << data->detached_v8_bytes_used() << // " bytes of V8 memory that wasn't associated with a frame."; // LOG(INFO) << "Process " << process_node->GetProcessId() << // " reported " << data->shared_v8_bytes_used() << // " bytes of V8 memory that are shared between all frames"; // for (auto* frame_node : process_node->GetFrameNodes()) { // auto* frame_data = // V8DetailedMemoryExecutionContextData::ForFrame(frame_node); // if (frame_data) { // LOG(INFO) << "Frame " << frame_node->GetFrameToken().value() << // " reported " << frame_data->v8_bytes_used() << // " bytes of V8 memory in its main world."; // } // } // } // }; // // class MemoryMonitor { // public: // MemoryMonitor() { // PerformanceManager::CallOnGraph(FROM_HERE, // base::BindOnce(&Start, base::Unretained(this))); // } // // void Start(Graph* graph) { // DCHECK_ON_GRAPH_SEQUENCE(graph); // // // Creating a V8DetailedMemoryRequest with the |graph| parameter // // automatically starts measurements. // request_ = std::make_unique<V8DetailedMemoryRequest>( // base::Seconds(30), graph); // observer_ = std::make_unique<Observer>(); // request_->AddObserver(observer_.get()); // } // // void Stop(Graph* graph) { // DCHECK_ON_GRAPH_SEQUENCE(graph); // // // |observer_| must be removed from |request_| before deleting it. // // Afterwards they can be deleted in any order. // request_->RemoveObserver(observer_.get()); // observer_.reset(); // // // Measurements stop when |request_| is deleted. // request_.reset(); // } // // private: // std::unique_ptr<V8DetailedMemoryRequest> request_; // std::unique_ptr<Observer> observer_; // }; ////////////////////////////////////////////////////////////////////////////// // The following classes report results from memory measurements. class V8DetailedMemoryExecutionContextData { … }; class V8DetailedMemoryProcessData { … }; class V8DetailedMemoryObserver : public base::CheckedObserver { … }; ////////////////////////////////////////////////////////////////////////////// // The following classes create requests for memory measurements. class V8DetailedMemoryDecorator; class V8DetailedMemoryRequestAnySeq; class V8DetailedMemoryRequestOneShot; class V8DetailedMemoryRequestQueue; class V8DetailedMemoryRequest { … }; class V8DetailedMemoryRequestOneShotAnySeq; class V8DetailedMemoryRequestOneShot final : public V8DetailedMemoryObserver { … }; ////////////////////////////////////////////////////////////////////////////// // The following internal functions are exposed in the header for testing. namespace internal { // Enables or disables MeasurementMode::kEagerModeForTesting. Creating eager // measurement requests can have a high performance penalty so this should only // be enabled in tests. void SetEagerMemoryMeasurementEnabledForTesting(bool enable); } // namespace internal } // namespace v8_memory } // namespace performance_manager #endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_V8_MEMORY_V8_DETAILED_MEMORY_H_