Skip to content

Commit

Permalink
Merge pull request #212 from amosproj/garbage-collection
Browse files Browse the repository at this point in the history
Garbage collection
  • Loading branch information
fhilgers authored Jan 15, 2025
2 parents aeb5a78 + 34c0f82 commit 43e7285
Show file tree
Hide file tree
Showing 37 changed files with 1,006 additions and 12 deletions.
19 changes: 19 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# SPDX-FileCopyrightText: 2025 Felix Hilgers <[email protected]>
#
# SPDX-License-Identifier: MIT

[submodule "rust/garbage-collection/art"]
path = rust/garbage-collection/art
url = https://android.googlesource.com/platform/art
[submodule "rust/garbage-collection/bionic"]
path = rust/garbage-collection/bionic
url = https://android.googlesource.com/platform/bionic
[submodule "rust/garbage-collection/external/tinyxml2"]
path = rust/garbage-collection/external/tinyxml2
url = https://android.googlesource.com/platform/external/tinyxml2
[submodule "rust/garbage-collection/external/fmtlib"]
path = rust/garbage-collection/external/fmtlib
url = https://android.googlesource.com/platform/external/fmtlib
[submodule "rust/garbage-collection/system/libbase"]
path = rust/garbage-collection/system/libbase
url = https://android.googlesource.com/platform/system/libbase
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ package de.amosproj3.ziofa.ui.configuration.utils

import de.amosproj3.ziofa.client.Configuration

val EMPTY_CONFIGURATION = Configuration(null, null, listOf(), null, null)
val EMPTY_CONFIGURATION = Configuration(null, null, listOf(), null, null, null)
18 changes: 18 additions & 0 deletions frontend/client/src/main/java/de/amosproj3/ziofa/client/Client.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ data class Configuration(
val uprobes: List<UprobeConfig>,
val jniReferences: JniReferencesConfig?,
val sysSigquit: SysSigquitConfig?,
val gc: GcConfig?,
)

data class VfsWriteConfig(val entries: Map<UInt, ULong>)
Expand All @@ -25,6 +26,8 @@ data class JniReferencesConfig(val pids: List<UInt>)

data class SysSigquitConfig(val pids: List<UInt>)

data object GcConfig

sealed class Event {
data class VfsWrite(
val pid: UInt,
Expand Down Expand Up @@ -62,6 +65,21 @@ sealed class Event {
val timeStamp: ULong,
val targetPid: ULong,
) : Event()

data class Gc(
val pid: UInt,
val tid: UInt,
var targetFootprint: ULong,
var numBytesAllocated: ULong,
var gcsCompleted: UInt,
var gcCause: UInt,
var durationNs: ULong,
var freedObjects: ULong,
var freedBytes: Long,
var freedLosObjects: ULong,
var freedLosBytes: Long,
var pauseTimes: List<ULong>,
) : Event()
}

data class Process(val pid: UInt, val ppid: UInt, val state: String, val cmd: Command?)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ object RustClient : Client {
uprobes = listOf(),
jniReferences = JniReferencesConfig(pids = listOf()),
sysSigquit = SysSigquitConfig(pids = listOf()),
gc = GcConfig,
)

override suspend fun serverCount(): Flow<UInt> = flow {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,21 @@ private fun uniffi.shared.Event.into() =
timeStamp = d.v1.timeStamp,
targetPid = d.v1.targetPid,
)
is EventData.Gc ->
Event.Gc(
pid = d.v1.pid,
tid = d.v1.tid,
targetFootprint = d.v1.targetFootprint,
numBytesAllocated = d.v1.numBytesAllocated,
gcsCompleted = d.v1.gcsCompleted,
gcCause = d.v1.gcCause,
durationNs = d.v1.durationNs,
freedObjects = d.v1.freedObjects,
freedBytes = d.v1.freedBytes,
freedLosObjects = d.v1.freedLosObjects,
freedLosBytes = d.v1.freedLosBytes,
pauseTimes = d.v1.pauseTimes,
)
null -> null
}

Expand All @@ -89,6 +104,7 @@ private fun uniffi.shared.Configuration.into() =
},
jniReferences = jniReferences?.let { JniReferencesConfig(pids = it.pids) },
sysSigquit = sysSigquit?.let { SysSigquitConfig(pids = it.pids) },
gc = gc?.let { GcConfig },
)

private fun Configuration.into() =
Expand All @@ -106,6 +122,7 @@ private fun Configuration.into() =
},
jniReferences = jniReferences?.let { uniffi.shared.JniReferencesConfig(it.pids) },
sysSigquit = sysSigquit?.let { uniffi.shared.SysSigquitConfig(it.pids) },
gc = gc?.let { uniffi.shared.GcConfig() },
)

private fun uniffi.shared.StringResponse.into() = StringResponse(name)
Expand Down
26 changes: 26 additions & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ members = [
"uniffi-bindgen",
"backend/ebpf-test",
"runner",
"garbage-collection",
]
default-members = [
"xtask",
Expand All @@ -37,6 +38,7 @@ aya = { version = "0.13.1", default-features = false }
aya-ebpf = { version = "0.1.1", default-features = false }
aya-log = { version = "0.2.1", default-features = false }
aya-log-ebpf = { version = "0.1.1", default-features = false }
aya-log-common = "0.1.15"

anyhow = { version = "1", default-features = false }
cargo_metadata = { version = "0.19.1", default-features = false }
Expand All @@ -63,6 +65,7 @@ backend-common = { path = "./backend/common" }
backend-daemon = { path = "./backend/daemon" }
backend-ebpf = { path = "./backend/ebpf" }
runner = { path = "./runner" }
garbage-collection = { path = "./garbage-collection" }
tracing = { version = "0.1.41" }
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
procfs = "0.17.0"
Expand All @@ -88,6 +91,8 @@ ctrlc = "3.4.5"
rustix = { version = "0.38.43" }
tower = { version = "0.5.2" }
hyper-util = { version = "0.1.10", features = ["tokio"] }
clang = "2.0.0"
clang-sys = "1.8.1"

[profile.release.package.backend-ebpf]
debug = 2
Expand Down
1 change: 1 addition & 0 deletions rust/backend/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ user = ["aya"]
[dependencies]
aya = { workspace = true, optional = true }
bytemuck = { workspace = true, features = ["derive"] }
garbage-collection = { workspace = true }

[lib]
path = "src/lib.rs"
16 changes: 16 additions & 0 deletions rust/backend/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
// SPDX-FileCopyrightText: 2024 Felix Hilgers <[email protected]>
// SPDX-FileCopyrightText: 2024 Luca Bretting <[email protected]>
// SPDX-FileCopyrightText: 2024 Tom Weisshuhn <[email protected]>
// SPDX-FileCopyrightText: 2025 Felix Hilgers <[email protected]>
//
// SPDX-License-Identifier: MIT

use bytemuck::{checked::CheckedCastError, AnyBitPattern, CheckedBitPattern};
use garbage_collection::Heap;


pub trait TryFromRaw: Sized {
Expand Down Expand Up @@ -38,6 +40,12 @@ impl TryFromRaw for SysSigquitCall {
}
}

impl TryFromRaw for SysGcCall {
fn try_from_raw(raw: &[u8]) -> Result<Self, CheckedCastError> {
Ok(*bytemuck::checked::try_from_bytes(raw)?)
}
}

#[repr(C)]
#[derive(Debug, Copy, Clone, AnyBitPattern)]
pub struct VfsWriteCall {
Expand Down Expand Up @@ -123,6 +131,14 @@ impl SysSigquitCall {
}
}

#[repr(C)]
#[derive(Debug, Copy, Clone, CheckedBitPattern)]
pub struct SysGcCall {
pub pid: u32,
pub tid: u32,
pub heap: Heap
}

// ----------------------------------
// generate a unique id from pid and tid
#[inline(always)]
Expand Down
1 change: 1 addition & 0 deletions rust/backend/daemon/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ fmmap = { workspace = true }
flume = { workspace = true }
hyper-util = { workspace = true }
tower = { workspace = true }
garbage-collection = { workspace = true, features = ["serialize"] }

[build-dependencies]
cargo_metadata = { workspace = true }
Expand Down
25 changes: 23 additions & 2 deletions rust/backend/daemon/src/collector/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
//
// SPDX-License-Identifier: MIT

use backend_common::{JNICall, JNIMethodName, SysSendmsgCall, VfsWriteCall, SysSigquitCall};
use shared::ziofa::{Event, JniReferencesEvent, SysSendmsgEvent, VfsWriteEvent, SysSigquitEvent};
use backend_common::{JNICall, JNIMethodName, SysGcCall, SysSendmsgCall, SysSigquitCall, VfsWriteCall};
use shared::ziofa::{Event, GcEvent, JniReferencesEvent, SysSendmsgEvent, SysSigquitEvent, VfsWriteEvent};
use shared::ziofa::event::EventData;
use shared::ziofa::jni_references_event::JniMethodName;
mod ring_buf;
Expand Down Expand Up @@ -76,4 +76,25 @@ impl IntoEvent for SysSigquitCall {
}))
}
}
}

impl IntoEvent for SysGcCall {
fn into_event(self) -> Event {
Event {
event_data: Some(EventData::Gc(GcEvent {
pid: self.pid,
tid: self.tid,
target_footprint: self.heap.target_footprint as u64,
num_bytes_allocated: self.heap.num_bytes_allocated as u64,
gcs_completed: self.heap.gcs_completed,
gc_cause: self.heap.gc_cause as u32,
duration_ns: self.heap.duration_ns,
freed_objects: self.heap.freed_objects,
freed_bytes: self.heap.freed_bytes,
freed_los_objects: self.heap.freed_los_objects,
freed_los_bytes: self.heap.freed_los_bytes,
pause_times: self.heap.pause_times.to_vec(),
}))
}
}
}
4 changes: 3 additions & 1 deletion rust/backend/daemon/src/collector/supervisor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ enum CollectorT {
SysSendmsg,
JniCall,
SysSigquit,
Gc,
}

pub struct CollectorSupervisor;
Expand Down Expand Up @@ -49,7 +50,7 @@ impl CollectorRefs {
self.collectors.remove(cell)
}
async fn start_all(&mut self, registry: &EbpfEventRegistry, event_actor: &ActorRef<Event>, supervisor: &ActorCell) -> Result<(), ActorProcessingErr> {
for who in [CollectorT::VfsWrite, CollectorT::SysSendmsg, CollectorT::JniCall, CollectorT::SysSigquit] {
for who in [CollectorT::VfsWrite, CollectorT::SysSendmsg, CollectorT::JniCall, CollectorT::SysSigquit, CollectorT::Gc] {
self.start(who, registry, event_actor, supervisor).await?;
}
Ok(())
Expand All @@ -60,6 +61,7 @@ impl CollectorRefs {
CollectorT::SysSendmsg => start_collector(registry.sys_sendmsg_events.clone(), event_actor.clone(), supervisor.clone()).await?,
CollectorT::JniCall => start_collector(registry.jni_ref_calls.clone(), event_actor.clone(), supervisor.clone()).await?,
CollectorT::SysSigquit => start_collector(registry.sys_sigquit_events.clone(), event_actor.clone(), supervisor.clone()).await?,
CollectorT::Gc => start_collector(registry.gc_events.clone(), event_actor.clone(), supervisor.clone()).await?,
};
self.collectors.insert(actor_ref.get_cell(), who);
Ok(())
Expand Down
6 changes: 5 additions & 1 deletion rust/backend/daemon/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,8 @@ pub fn sock_addr() -> SocketAddr {

pub const OATDUMP_PATH: &str = "/data/local/tmp/dump.json";
pub const ZIOFA_EBPF_PATH: &str = "/sys/fs/bpf/ziofa";
pub const INDEX_PATH: &str = "/data/local/tmp/index";
pub const INDEX_PATH: &str = "/data/local/tmp/index";

// Update via downloading the submodules in rust/garbage-collection
// and running `cargo run --bin parser --features cli`
pub const GC_HEAP_META_JSON: &str = r#"{"target_footprint":{"offset":456,"size":8},"num_bytes_allocated":{"offset":544,"size":8},"gc_cause":{"offset":592,"size":4},"duration_ns":{"offset":600,"size":8},"freed_objects":{"offset":656,"size":8},"freed_bytes":{"offset":664,"size":8},"freed_los_objects":{"offset":672,"size":8},"freed_los_bytes":{"offset":680,"size":8},"gcs_completed":{"offset":1040,"size":4},"pause_times_begin":{"offset":696,"size":8},"pause_times_end":{"offset":704,"size":8}}"#;
Loading

0 comments on commit 43e7285

Please sign in to comment.