Skip to content

Commit 3d89bb5

Browse files
authored
Minor changes to the ProcessRootNode work packet (#1327)
Renamed `ProcessRootNode` to `ProcessRootNodes` because it obviously processes multiple roots. If no objects are enqueued, we do not blindly create empty `ScanObjects` work packets. During nursery GC, it is likely that many root edges point to mature nodes, and mature objects are not enqueued during nursery GC. We also added eBPF trace points to show how many roots are there in a ProcessRootNodes work packet, and how many objects are actually enqueued.
1 parent 54fd3f8 commit 3d89bb5

File tree

5 files changed

+34
-13
lines changed

5 files changed

+34
-13
lines changed

src/scheduler/gc_work.rs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -756,7 +756,7 @@ impl<VM: VMBinding, DPE: ProcessEdgesWork<VM = VM>, PPE: ProcessEdgesWork<VM = V
756756
crate::memory_manager::add_work_packet(
757757
self.mmtk,
758758
WorkBucketStage::PinningRootsTrace,
759-
ProcessRootNode::<VM, PPE, DPE>::new(nodes, WorkBucketStage::Closure),
759+
ProcessRootNodes::<VM, PPE, DPE>::new(nodes, WorkBucketStage::Closure),
760760
);
761761
}
762762

@@ -765,7 +765,7 @@ impl<VM: VMBinding, DPE: ProcessEdgesWork<VM = VM>, PPE: ProcessEdgesWork<VM = V
765765
crate::memory_manager::add_work_packet(
766766
self.mmtk,
767767
WorkBucketStage::TPinningClosure,
768-
ProcessRootNode::<VM, PPE, PPE>::new(nodes, WorkBucketStage::TPinningClosure),
768+
ProcessRootNodes::<VM, PPE, PPE>::new(nodes, WorkBucketStage::TPinningClosure),
769769
);
770770
}
771771
}
@@ -1071,7 +1071,7 @@ impl<E: ProcessEdgesWork, P: Plan<VM = E::VM> + PlanTraceObject<E::VM>> GCWork<E
10711071
/// - If `O2OPE` may move objects, then this `ProcessRootsNode<VM, R2OPE, O2OPE>` work packet
10721072
/// will only pin the objects in `roots` (because `R2OPE` must not move objects anyway), but
10731073
/// not their descendents.
1074-
pub(crate) struct ProcessRootNode<
1074+
pub(crate) struct ProcessRootNodes<
10751075
VM: VMBinding,
10761076
R2OPE: ProcessEdgesWork<VM = VM>,
10771077
O2OPE: ProcessEdgesWork<VM = VM>,
@@ -1082,7 +1082,7 @@ pub(crate) struct ProcessRootNode<
10821082
}
10831083

10841084
impl<VM: VMBinding, R2OPE: ProcessEdgesWork<VM = VM>, O2OPE: ProcessEdgesWork<VM = VM>>
1085-
ProcessRootNode<VM, R2OPE, O2OPE>
1085+
ProcessRootNodes<VM, R2OPE, O2OPE>
10861086
{
10871087
pub fn new(nodes: Vec<ObjectReference>, bucket: WorkBucketStage) -> Self {
10881088
Self {
@@ -1094,10 +1094,10 @@ impl<VM: VMBinding, R2OPE: ProcessEdgesWork<VM = VM>, O2OPE: ProcessEdgesWork<VM
10941094
}
10951095

10961096
impl<VM: VMBinding, R2OPE: ProcessEdgesWork<VM = VM>, O2OPE: ProcessEdgesWork<VM = VM>> GCWork<VM>
1097-
for ProcessRootNode<VM, R2OPE, O2OPE>
1097+
for ProcessRootNodes<VM, R2OPE, O2OPE>
10981098
{
10991099
fn do_work(&mut self, worker: &mut GCWorker<VM>, mmtk: &'static MMTK<VM>) {
1100-
trace!("ProcessRootNode");
1100+
trace!("ProcessRootNodes");
11011101

11021102
#[cfg(feature = "sanity")]
11031103
{
@@ -1109,15 +1109,17 @@ impl<VM: VMBinding, R2OPE: ProcessEdgesWork<VM = VM>, O2OPE: ProcessEdgesWork<VM
11091109
}
11101110
}
11111111

1112+
let num_roots = self.roots.len();
1113+
11121114
// This step conceptually traces the edges from root slots to the objects they point to.
11131115
// However, VMs that deliver root objects instead of root slots are incapable of updating
11141116
// root slots. Therefore, we call `trace_object` on those objects, and assert the GC
11151117
// doesn't move those objects because we cannot store the updated references back to the
11161118
// slots.
11171119
//
1118-
// The `scanned_root_objects` variable will hold those root objects which are traced for the
1120+
// The `root_objects_to_scan` variable will hold those root objects which are traced for the
11191121
// first time. We will create a work packet for scanning those roots.
1120-
let scanned_root_objects = {
1122+
let root_objects_to_scan = {
11211123
// We create an instance of E to use its `trace_object` method and its object queue.
11221124
let mut process_edges_work =
11231125
R2OPE::new(vec![], true, mmtk, WorkBucketStage::PinningRootsTrace);
@@ -1137,11 +1139,16 @@ impl<VM: VMBinding, R2OPE: ProcessEdgesWork<VM = VM>, O2OPE: ProcessEdgesWork<VM
11371139
process_edges_work.nodes.take()
11381140
};
11391141

1140-
let process_edges_work = O2OPE::new(vec![], false, mmtk, self.bucket);
1141-
let work = process_edges_work.create_scan_work(scanned_root_objects);
1142-
crate::memory_manager::add_work_packet(mmtk, self.bucket, work);
1142+
let num_enqueued_nodes = root_objects_to_scan.len();
1143+
probe!(mmtk, process_root_nodes, num_roots, num_enqueued_nodes);
1144+
1145+
if !root_objects_to_scan.is_empty() {
1146+
let process_edges_work = O2OPE::new(vec![], false, mmtk, self.bucket);
1147+
let work = process_edges_work.create_scan_work(root_objects_to_scan);
1148+
crate::memory_manager::add_work_packet(mmtk, self.bucket, work);
1149+
}
11431150

1144-
trace!("ProcessRootNode End");
1151+
trace!("ProcessRootNodes End");
11451152
}
11461153
}
11471154

src/util/sanity/sanity_checker.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ impl<P: Plan> GCWork<P::VM> for ScheduleSanityGC<P> {
9696
);
9797
}
9898
for roots in &sanity_checker.root_nodes {
99-
scheduler.work_buckets[WorkBucketStage::Closure].add(ProcessRootNode::<
99+
scheduler.work_buckets[WorkBucketStage::Closure].add(ProcessRootNodes::<
100100
P::VM,
101101
SanityGCProcessEdges<P::VM>,
102102
SanityGCProcessEdges<P::VM>,

tools/tracing/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ Currently, the core provides the following tracepoints.
3535
- `mmtk:roots(kind: int, len: int)`: reporing roots to mmtk-core during root scanning. `kind` can
3636
be 0, 1 or 2 for normal roots, pinning roots and transitively pinning roots, respectively.
3737
`len` is the number of slots or nodes reported.
38+
- `mmtk:process_root_nodes(num_roots: int, num_enqueued_nodes: int)`: a ProcessRootNodes work
39+
packet which processes root edges represented as object references to the target objects.
3840
- `mmtk:process_slots(num_slots: int, is_roots: bool)`: an invocation of the `process_slots`
3941
method. The first argument is the number of slots to be processed, and the second argument is
4042
whether these slots are root slots.

tools/tracing/timeline/capture.bt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ usdt:$MMTK:mmtk:roots {
8787
}
8888
}
8989

90+
usdt:$MMTK:mmtk:process_root_nodes {
91+
if (@enable_print) {
92+
printf("process_root_nodes,meta,%d,%lu,%lu,%lu\n", tid, nsecs, arg0, arg1);
93+
}
94+
}
95+
9096
usdt:$MMTK:mmtk:process_slots {
9197
if (@enable_print) {
9298
printf("process_slots,meta,%d,%lu,%lu,%lu\n", tid, nsecs, arg0, arg1);

tools/tracing/timeline/visualize.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,12 @@ def enrich_meta(self, name, tid, ts, gc, wp, args):
212212

213213
roots_list.append(root_dict)
214214

215+
case "process_root_nodes":
216+
wp["args"] |= {
217+
"num_roots": int(args[0]),
218+
"num_enqueued_nodes": int(args[1]),
219+
}
220+
215221
case "process_slots":
216222
wp["args"] |= {
217223
# Group args by "process_slots" and "scan_objects" because a ProcessEdgesWork

0 commit comments

Comments
 (0)