// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
module memory_instrumentation.mojom;
import "mojo/public/mojom/base/big_string.mojom";
import "mojo/public/mojom/base/process_id.mojom";
import "mojo/public/mojom/base/time.mojom";
// Common structs:
enum DumpType {
PERIODIC_INTERVAL,
EXPLICITLY_TRIGGERED,
SUMMARY_ONLY
};
enum LevelOfDetail {
BACKGROUND,
LIGHT,
DETAILED
};
// Tells the MemoryDumpProvider(s) if they should try to make the result
// more deterministic by forcing garbage collection.
enum Determinism {
NONE,
FORCE_GC
};
enum ProcessType {
OTHER,
BROWSER,
RENDERER,
GPU,
UTILITY,
PLUGIN,
ARC
};
enum MemoryMapOption {
// Do not fetch any information about mapped regions in the virtual address
// space.
NONE,
// Only fetch information on code modules, e.g. Chrome Binary, system
// libraries.
MODULES,
// Fetch information for every single mapped region.
FULL
};
// These structs are internal only (only for the communication between
// the service and the ClientProcess library).
// See corresponding types in //base/trace_event for comments.
struct RequestArgs {
uint64 dump_guid;
DumpType dump_type;
LevelOfDetail level_of_detail;
Determinism determinism;
};
struct RawAllocatorDumpEdge {
uint64 source_id;
uint64 target_id;
int32 importance;
bool overridable;
};
union RawAllocatorDumpEntryValue {
uint64 value_uint64;
string value_string;
};
struct RawAllocatorDumpEntry {
string name;
string units;
RawAllocatorDumpEntryValue value;
};
struct RawAllocatorDump {
uint64 id;
string absolute_name;
bool weak;
LevelOfDetail level_of_detail;
array<RawAllocatorDumpEntry> entries;
};
struct RawProcessMemoryDump {
LevelOfDetail level_of_detail;
array<RawAllocatorDumpEdge> allocator_dump_edges;
array<RawAllocatorDump> allocator_dumps;
};
struct VmRegion {
const uint32 kProtectionFlagsRead = 4;
const uint32 kProtectionFlagsWrite = 2;
const uint32 kProtectionFlagsExec = 1;
const uint32 kProtectionFlagsMayshare = 128;
uint64 start_address;
uint64 size_in_bytes;
uint64 module_timestamp;
// Unique module debug identifier to retrieve debug information.
string module_debugid;
string module_debug_path;
uint32 protection_flags;
string mapped_file;
// private_dirty_resident + private_clean_resident + shared_dirty_resident +
// shared_clean_resident = resident set size.
uint64 byte_stats_private_dirty_resident;
uint64 byte_stats_private_clean_resident;
uint64 byte_stats_shared_dirty_resident;
uint64 byte_stats_shared_clean_resident;
uint64 byte_stats_swapped;
uint64 byte_locked;
// For multiprocess accounting.
uint64 byte_stats_proportional_resident;
};
// Platform-specific data that will be used to compute the
// PrivateMemoryFootprint.
struct PlatformPrivateFootprint {
uint64 phys_footprint_bytes = 0;
// macOS 10.12+
uint64 internal_bytes = 0;
// macOS [all versions]
uint64 compressed_bytes = 0;
uint64 rss_anon_bytes = 0;
// Linux, Android, ChromeOS
uint64 vm_swap_bytes = 0;
// On Windows,
uint64 private_bytes = 0;
// On iOS,
// TBD: https://crbug.com/714961
};
struct RawOSMemDump {
uint32 resident_set_kb = 0;
// peak_resident_set_kb is an experimental field. Please do not use it until
// crbug.com/957978 reaches to a conclusion.
uint32 peak_resident_set_kb = 0;
bool is_peak_rss_resettable = false;
PlatformPrivateFootprint platform_private_footprint;
array<VmRegion> memory_maps;
// Each bit corresponds to a page. The bit is set if the page
// is mapped and resident in memory.
array<uint8> native_library_pages_bitmap;
};
// These structs are public:
struct OSMemDump {
uint32 resident_set_kb = 0;
// The peak resident set size as observed by the kernel. This is currently
// reported on Linux and Android only. Also, this is an experimental field.
// Please do not use it until crbug.com/957978 reaches to a conclusion.
uint32 peak_resident_set_kb = 0;
// Indicates whether the above peak_resident_set_kb is the peak from the start
// of the process or from the previous memory dump.
bool is_peak_rss_resettable = false;
// This is roughly private, anonymous, non-discardable, resident or swapped
// memory in kilobytes. For more details, see https://goo.gl/3kPb9S.
uint32 private_footprint_kb = 0;
// This is roughly non-private, anonymous, non-discardable, resident memory
// in kilobytes. For more details, see https://goo.gl/3kPb9S.
uint32 shared_footprint_kb = 0;
// This is private swapped memory in kilobytes reported on Linux and Android
// only.
[EnableIf=private_swap_info]
uint32 private_footprint_swap_kb = 0;
};
// This struct contains information about a particular allocator dump
// (e.g. cc/resource_memory).
struct AllocatorMemDump {
// The entries for the allocator which are of scalar types (i.e. not strings).
// Examples include: effective_size, size, object_count.
map<string, uint64> numeric_entries;
// If details were requested for this allocator to include descendants then
// |children| describes the immediate child nodes.
map<string, AllocatorMemDump> children;
};
// This struct is used for the public-facing API
// Coordinator::RequestGlobalMemoryDump().
struct ProcessMemoryDump {
ProcessType process_type;
OSMemDump os_dump;
// Details for each of the Chrome allocators specified by the input args.
// See the |RequestGlobalMemoryDump()| argument |allocator_dump_names|.
map<string, AllocatorMemDump> chrome_allocator_dumps;
// |pid| is necessary to correlate a ProcessMemoryDump with the URLs for the
// process, which is obtained from the ResourceCoordinator service. In a
// future world where both ResourceCoordinator and MemoryInstrumentation are
// less in flux, they will probably be merged into a single service, and this
// parameter can be removed.
mojo_base.mojom.ProcessId pid;
// The name of the primary service running in the process, if any.
string? service_name;
};
// Metrics aggregated across all processes.
struct AggregatedMetrics {
// These values are not always available, -1 when invalid.
int32 native_library_resident_kb = 0;
int32 native_library_resident_not_ordered_kb = 0;
int32 native_library_not_resident_ordered_kb = 0;
};
// This struct is returned by the public-facing API
// Coordinator::RequestGlobalMemoryDump().
struct GlobalMemoryDump {
// This time stamp precedes any of the data captured in |process_dumps|. Since
// dumps are queued, and since at most one dump is captured at a time, the
// start time of a global dump may lag the request time substantially.
mojo_base.mojom.TimeTicks start_time;
array<ProcessMemoryDump> process_dumps;
AggregatedMetrics aggregated_metrics;
};
// This is the interface implemented by the per-process client library. This
// allows a process to contribute to memory-infra dumps. There should be at
// most one instance of this per hosting process.
interface ClientProcess {
// When |success| == true the dump is appended in the process-local trace
// buffer of the target process and an ACK. A summary of the dump is also
// returned in case of success.
RequestChromeMemoryDump(RequestArgs args) =>
(bool success, uint64 dump_id, RawProcessMemoryDump? raw_process_memory_dump);
// Requests an OSMemDump for each pid in |pids|.
// The Memory-infra service deals with two kinds of information:
// 1) Chrome's view of its own memory use (recorded as
// |chrome_allocator_dumps|)
// 2) The OS's view of Chrome's memory use (recorded as OSMemDumps)
// Both of these are collected per process. On most platforms each process
// can make the system calls to collect its own OSMemDump however on some
// platforms *cough* Linux *cough* due to sandboxing only the browser
// process can collect OSMemDumps. This API allows for these two cases.
// On most platforms we send this message to each ClientProcess with
// with one pid - kNullProcessId - meaning return just your own OSMemDump.
// On Linux we call this once on the browser process ClientProcess passing
// the pids for all processes.
// See crbug.com/461788
RequestOSMemoryDump(MemoryMapOption option, array<mojo_base.mojom.ProcessId> pids) =>
(bool success, map<mojo_base.mojom.ProcessId, RawOSMemDump> dumps);
};
struct HeapProfileResult {
mojo_base.mojom.ProcessId pid;
mojo_base.mojom.BigString json;
};
// HeapProfilers expose a single interface to memory_instrumentation, allowing
// the latter to query for heap dumps when necessary.
//
// This interface is NOT implemented in resource_coordinator but by the
// profiling service in chrome/profiler. The profiling service registers itself
// with the Coordinator (see RegisterHeapProfiler) and is invoked when a memory
// dump is requested (via Coordinator::RequestGlobalMemoryDump).
interface HeapProfiler {
// Dumps the memory log of all profiled processes into BigString's.
// The contents of each BigString is a JSON string compatible with
// TRACE_EVENT* macros. Processes that fail to dump will be omitted from
// |result|. When |strip_path_from_mapped_files| is true, only the base name
// of mapped files is emitted. This prevents usernames from sneaking into the
// trace.
// |strip_path_from_mapped_files| should only be true for traces that will be
// uploaded to the crash servers - this strips potential PII, but prevents
// symbolization of local builds.
// |write_proto| will additionally write proto heap profiles to traces.
DumpProcessesForTracing(bool strip_path_from_mapped_files,
bool write_proto) =>
(array<HeapProfileResult> results);
};
// Implemented by resource_coordinator to provide additional information needed
// by the HeapProfiler.
interface HeapProfilerHelper {
// Broadcasts a RequestOSMemoryDump-only request for all registered client
// processes and retrieves only their memory maps.
GetVmRegionsForHeapProfiler(array<mojo_base.mojom.ProcessId> pids) =>
(map<mojo_base.mojom.ProcessId, array<VmRegion>> vm_regions);
};
// The memory-infra service implements this interface. There is one instance for
// the whole system. The coordinator maintains a list of registered client
// processes and polls them whenever a global dump is required.
interface Coordinator {
// Broadcasts a dump request to all registered client processes and returns a
// global dump with details.
// If |dump_type| is SUMMARY_ONLY then details will additionally be returned
// for allocators listed in |allocator_dump_names|. If an entry has a trailing
// "/*" then details will be returned for the named node, and all descendents.
// e.g. { "malloc", "v8/*" } will include details for "malloc", and might
// also include "v8", "v8/main/heap", etc.
// Allocator dumps provide a set of numeric values such as "size",
// "effective_size", etc.
RequestGlobalMemoryDump(DumpType dump_type,
LevelOfDetail level_of_detail,
Determinism determinism,
array<string> allocator_dump_names) =>
(bool success, GlobalMemoryDump? global_memory_dump);
// Sends a dump request to the client process given by the specified pid and
// returns a summarized dump back or null if there was a failure.
RequestGlobalMemoryDumpForPid(mojo_base.mojom.ProcessId pid,
array<string> allocator_dump_names) =>
(bool success, GlobalMemoryDump? global_memory_dump);
// Requesting a null pid is the same as requesting all pids.
// The returned dump only contains OS metrics. |chrome_allocator_dumps| will
// be empty.
RequestPrivateMemoryFootprint(mojo_base.mojom.ProcessId pid) =>
(bool success, GlobalMemoryDump? global_memory_dump);
// Broadcasts a dump request to all registered client processes and injects the
// dump in the trace buffer (if tracing is enabled).
RequestGlobalMemoryDumpAndAppendToTrace(DumpType dump_type,
LevelOfDetail level_of_detail,
Determinism determinism) =>
(bool success, uint64 dump_id);
};
// An interface used by client processes to register themselves with a
// memory_instrumentation::Registry. The implementation must already know the
// calling process. It adds authoritative information about the calling process'
// identity when forwarding the registration to a
// memory_instrumentation::Registry.
interface CoordinatorConnector {
RegisterCoordinatorClient(pending_receiver<Coordinator> receiver,
pending_remote<ClientProcess> client_process);
};