servo/components/constellation/process_manager.rs
webbeef aef8537d75
Make the memory reporting multi-process aware (#35863)
So far the memory reporter aggregates reports from all processes, and
runs the system reporter only in the main process. Instead it is
desirable to have per-process reports. We do so by:
- creating a ProcessReports struct that holds includes the pid in
addition to the reports themselves.
- running the system memory reporter also in content processes.
- updating the about:memory page to create one report per process, and
add useful information like the pid and the urls loaded in a given
process.

<!-- Please describe your changes on the following line: -->


---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by
`[X]` when the step is complete, and replace `___` with appropriate
data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors


![image](https://github.com/user-attachments/assets/0bafe140-539d-4d6a-8316-639309a22d4a)

Signed-off-by: webbeef <me@webbeef.org>
2025-04-05 05:42:12 +00:00

79 lines
2.2 KiB
Rust

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::process::Child;
use crossbeam_channel::{Receiver, Select};
use log::{debug, warn};
use profile_traits::mem::{ProfilerChan, ProfilerMsg};
pub enum Process {
Unsandboxed(Child),
Sandboxed(u32),
}
impl Process {
fn pid(&self) -> u32 {
match self {
Self::Unsandboxed(child) => child.id(),
Self::Sandboxed(pid) => *pid,
}
}
fn wait(&mut self) {
match self {
Self::Unsandboxed(child) => {
let _ = child.wait();
},
Self::Sandboxed(_pid) => {
// TODO: use nix::waitpid() on supported platforms.
warn!("wait() is not yet implemented for sandboxed processes.");
},
}
}
}
type ProcessReceiver = Receiver<Result<(), ipc_channel::Error>>;
pub(crate) struct ProcessManager {
processes: Vec<(Process, ProcessReceiver)>,
mem_profiler_chan: ProfilerChan,
}
impl ProcessManager {
pub fn new(mem_profiler_chan: ProfilerChan) -> Self {
Self {
processes: vec![],
mem_profiler_chan,
}
}
pub fn add(&mut self, receiver: ProcessReceiver, process: Process) {
debug!("Adding process pid={}", process.pid());
self.processes.push((process, receiver));
}
pub fn register<'a>(&'a self, select: &mut Select<'a>) {
for (_, receiver) in &self.processes {
select.recv(receiver);
}
}
pub fn receiver_at(&self, index: usize) -> &ProcessReceiver {
let (_, receiver) = &self.processes[index];
receiver
}
pub fn remove(&mut self, index: usize) {
let (mut process, _) = self.processes.swap_remove(index);
debug!("Removing process pid={}", process.pid());
// Unregister this process system memory profiler
self.mem_profiler_chan
.send(ProfilerMsg::UnregisterReporter(format!(
"system-content-{}",
process.pid()
)));
process.wait();
}
}