Index: components/tracing/docs/adding_memory_infra_tracing.md |
diff --git a/components/tracing/docs/adding_memory_infra_tracing.md b/components/tracing/docs/adding_memory_infra_tracing.md |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f60f65e7f5a41a2125ebf1eebb26ea42f6b3e6fd |
--- /dev/null |
+++ b/components/tracing/docs/adding_memory_infra_tracing.md |
@@ -0,0 +1,178 @@ |
+# Adding MemoryInfra Tracing to a Component |
+ |
+If you have a component that manages memory allocations, you should be |
+registering and tracking those allocations with Chrome's MemoryInfra system. |
+This lets you: |
+ |
+ * See an overview of your allocations, giving insight into total size and |
+ breakdown. |
+ * Understand how your allocations change over time and how they are impacted by |
+ other parts of Chrome. |
+ * Catch regressions in your component's allocations size by setting up |
+ telemetry tests which monitor your allocation sizes under certain |
+ circumstances. |
+ |
+Some existing components that use MemoryInfra: |
+ |
+ * **Discardable Memory**: Tracks usage of discardable memory throughout Chrome. |
+ * **GPU**: Tracks OpenGL and other GPU object allocations. |
+ * **V8**: Tracks the heap size for JS. |
+ |
+[TOC] |
+ |
+## Overview |
+ |
+In order to hook into Chrome's MemoryInfra system, your component needs to do |
+two things: |
+ |
+ 1. Create a [`MemoryDumpProvider`][mdp] for your component. |
+ 2. Register and unregister you dump provider with the |
+ [`MemoryDumpManager`][mdm]. |
+ |
+[mdp]: https://chromium.googlesource.com/chromium/src/+/master/base/trace_event/memory_dump_provider.h |
+[mdm]: https://chromium.googlesource.com/chromium/src/+/master/base/trace_event/memory_dump_manager.h |
+ |
+## Creating a Memory Dump Provider |
+ |
+You can implement a [`MemoryDumpProvider`][mdp] as a stand-alone class, or as an |
+additional interface on an existing class. For example, this interface is |
+frequently implemented on classes which manage a pool of allocations (see |
+[`cc::ResourcePool`][resource-pool] for an example). |
+ |
+A `MemoryDumpProvider` has one basic job, to implement `OnMemoryDump`. This |
+function is responsible for iterating over the resources allocated or tracked by |
+your component, and creating a [`MemoryAllocatorDump`][mem-alloc-dump] for each |
+using [`ProcessMemoryDump::CreateAllocatorDump`][pmd]. A simple example: |
+ |
+```cpp |
+bool MyComponent::OnMemoryDump(const MemoryDumpArgs& args, |
+ ProcessMemoryDump* process_memory_dump) { |
+ for (const auto& allocation : my_allocations_) { |
+ auto* dump = process_memory_dump->CreateAllocatorDump( |
+ "path/to/my/component/allocation_" + allocation.id().ToString()); |
+ dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, |
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes, |
+ allocation.size_bytes()); |
+ |
+ // While you will typically have a kNameSize entry, you can add additional |
+ // entries to your dump with free-form names. In this example we also dump |
+ // an object's "free_size", assuming the object may not be entirely in use. |
+ dump->AddScalar("free_size", |
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes, |
+ allocation.free_size_bytes()); |
+ } |
+} |
+``` |
+ |
+For many components, this may be all that is needed. See |
+[Handling Shared Memory Allocations](#Handling-Shared-Memory-Allocations) and |
+[Suballocations](#Suballocations) for information on more complex use cases. |
+ |
+[resource-pool]: https://chromium.googlesource.com/chromium/src/+/master/cc/resources/resource_pool.h |
+[mem-alloc-dump]: https://chromium.googlesource.com/chromium/src/+/master/base/trace_event/memory_allocator_dump.h |
+[pmd]: https://chromium.googlesource.com/chromium/src/+/master/base/trace_event/process_memory_dump.h |
+ |
+## Registering a Memory Dump Provider |
+ |
+Once you have created a [`MemoryDumpProvider`][mdp], you need to register it |
+with the [`MemoryDumpManager`][mdm] before the system can start polling it for |
+memory information. Registration is generally straightforward, and involves |
+calling `MemoryDumpManager::RegisterDumpProvider`: |
+ |
+```cpp |
+// Each process uses a singleton |MemoryDumpManager|. |
+base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( |
+ my_memory_dump_provider_, my_single_thread_task_runner_); |
+``` |
+ |
+In the above code, `my_memory_dump_provider_` is the `MemoryDumpProvider` |
+outlined in the previous section. `my_single_thread_task_runner_` is more |
+complex and may be a number of things: |
+ |
+ * Most commonly, if your component is always used from the main message loop, |
+ `my_single_thread_task_runner_` may just be |
+ [`base::ThreadTaskRunnerHandle::Get()`][task-runner-handle]. |
+ * If your component already uses a custom `base::SingleThreadTaskRunner` for |
+ executing tasks on a specific thread, you should likely use this runner. |
+ |
+[task-runner-handle]: https://chromium.googlesource.com/chromium/src/+/master/base/thread_task_runner_handle.h |
+ |
+## Unregistration |
+ |
+Unregistration must happen on the thread belonging to the |
+`SingleThreadTaskRunner` provided at registration time. Unregistering on another |
+thread can lead to race conditions if tracing is active when the provider is |
+unregistered. |
+ |
+```cpp |
+base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( |
+ my_memory_dump_provider_); |
+``` |
+ |
+## Handling Shared Memory Allocations |
+ |
+When an allocation is shared between two components, it may be useful to dump |
+the allocation in both components, but you also want to avoid double-counting |
+the allocation. This can be achieved using the concept of _ownership edges_. |
+An ownership edge represents that the _source_ memory allocator dump owns a |
+_target_ memory allocator dump. If multiple source dumps own a single target, |
+then the cost of that target allocation will be split between the sources. |
+Additionally, importance can be added to a specific ownership edge, allowing |
+the highest importance source of that edge to claim the entire cost of the |
+target. |
+ |
+In the typical case, you will use [`ProcessMemoryDump`][pmd] to create a shared |
+global allocator dump. This dump will act as the target of all |
+component-specific dumps of a specific resource: |
+ |
+```cpp |
+// Component 1 is going to create a dump, source_mad, for an allocation, |
+// alloc_, which may be shared with other components / processes. |
+MyAllocationType* alloc_; |
+base::trace_event::MemoryAllocatorDump* source_mad; |
+ |
+// Component 1 creates and populates source_mad; |
+... |
+ |
+// In addition to creating a source dump, we must create a global shared |
+// target dump. This dump should be created with a unique global ID which can be |
+// generated any place the allocation is used. I recommend adding a global ID |
+// generation function to the allocation type. |
+base::trace_event::MemoryAllocatorDumpGUID guid(alloc_->GetGUIDString()); |
+ |
+// From this global ID we can generate the parent allocator dump. |
+base::trace_event::MemoryAllocatorDump* target_mad = |
+ process_memory_dump->CreateSharedGlobalAllocatorDump(guid); |
+ |
+// We now create an ownership edge from the source dump to the target dump. |
+// When creating an edge, you can assign an importance to this edge. If all |
+// edges have the same importance, the size of the allocation will be split |
+// between all sources which create a dump for the allocation. If one |
+// edge has higher importance than the others, its soruce will be assigned the |
+// full size of the allocation. |
+const int kImportance = 1; |
+process_memory_dump->AddOwnershipEdge( |
+ source_mad->guid(), target_mad->guid(), kImportance); |
+``` |
+ |
+If an allocation is being shared across process boundaries, it may be useful to |
+generate a global ID which incorporates the ID of the local process, preventing |
+two processes from generating colliding IDs. As it is not recommended to pass a |
+process ID between processes for security reasons, a function |
+`MemoryDumpManager::GetTracingProcessId` is provided which generates a unique ID |
+per process that can be passed with the resource without security concerns. |
+Frequently this ID is used to generate a global ID that is based on the |
+allocated resource's ID combined with the allocating process' tracing ID. |
+ |
+## Suballocations |
+ |
+Another advanced use case involves tracking sub-allocations of a larger |
+allocation. For instance, this is used in |
+[`gpu::gles2::TextureManager`][texture-manager] to dump both the suballocations |
+which make up a texture. To create a suballocation, instead of calling |
+[`ProcessMemoryDump::CreateAllocatorDump`][pmd] to create a |
+[`MemoryAllocatorDump`][mem-alloc-dump], you call |
+[`ProcessMemoryDump::AddSubAllocation`][pmd], providing the ID of the parent |
+allocation as the first parameter. |
+ |
+[texture-manager]: https://chromium.googlesource.com/chromium/src/+/master/gpu/command_buffer/service/texture_manager.cc |