mmtk/scheduler/
work.rs

1use super::worker::*;
2use crate::plan::tracing::gc_work::root::DefaultRootsWorkFactory;
3use crate::vm::{RootsWorkFactory, VMBinding};
4use crate::{mmtk::MMTK, plan::tracing::Trace};
5#[cfg(feature = "work_packet_stats")]
6use std::any::{type_name, TypeId};
7
8/// This defines a GC work packet which are assigned to the [`GCWorker`]s by the scheduler.
9/// Work packets carry payloads that indicate the work to be done. For example, a work packet may
10/// contain a pointer to a stack that must be scanned, or it may contain a large buffer of pointers
11/// that need to be traced, or it might contain a range of static variables to be scanned, etc. The size
12/// of the work packet will need to consider at least two points of tension: the work packet must be large
13/// enough to ensure that the costs of managing the work packets do not dominate, and the packet must be
14/// small enough that good load balancing is achieved.
15pub trait GCWork<VM: VMBinding>: 'static + Send {
16    /// Define the work for this packet. However, this is not supposed to be called directly.
17    /// Usually `do_work_with_stat()` should be used.
18    ///
19    /// Most work packets are polled and executed in the worker's main loop ([`GCWorker::run`])
20    /// using `do_work_with_stat`.  If `do_work` is called directly during the execution of another
21    /// work packet, bypassing `do_work_with_stat()`, this work packet will not be counted into the
22    /// number of work packets executed, and the execution time of this work packet will be counted
23    /// as part of the execution time of the other work packet.  Only call this method directly if
24    /// this is what you intend.  But you should always consider adding the work packet
25    /// into a bucket so that other GC workers can execute it in parallel, unless the context-
26    /// switching overhead is a problem.
27    fn do_work(&mut self, worker: &mut GCWorker<VM>, mmtk: &'static MMTK<VM>);
28
29    /// Do work and collect statistics. This internally calls `do_work()`. In most cases,
30    /// this should be called rather than `do_work()` so that MMTk can correctly collect
31    /// statistics for the work packets.
32    /// If the feature "work_packet_stats" is not enabled, this call simply forwards the call
33    /// to `do_work()`.
34    fn do_work_with_stat(&mut self, worker: &mut GCWorker<VM>, mmtk: &'static MMTK<VM>) {
35        debug!("{}", std::any::type_name::<Self>());
36        debug_assert!(!worker.tls.0.0.is_null(), "TLS must be set correctly for a GC worker before the worker does any work. GC Worker {} has no valid tls.", worker.ordinal);
37
38        #[cfg(feature = "work_packet_stats")]
39        // Start collecting statistics
40        let stat = {
41            let mut worker_stat = worker.shared.borrow_stat_mut();
42            worker_stat.measure_work(TypeId::of::<Self>(), type_name::<Self>(), mmtk)
43        };
44
45        // Do the actual work
46        self.do_work(worker, mmtk);
47
48        #[cfg(feature = "work_packet_stats")]
49        // Finish collecting statistics
50        {
51            let mut worker_stat = worker.shared.borrow_stat_mut();
52            stat.end_of_work(&mut worker_stat);
53        }
54    }
55
56    /// Get the compile-time static type name for the work packet.
57    fn get_type_name(&self) -> &'static str {
58        std::any::type_name::<Self>()
59    }
60}
61
62use crate::plan::Plan;
63
64/// This trait provides a group of associated types that are needed to
65/// create GC work packets for a certain plan. For example, `GCWorkScheduler.schedule_common_work()`
66/// needs this trait to schedule different work packets. For certain plans,
67/// they may need to provide several types that implement this trait, e.g. one for
68/// nursery GC, one for mature GC.
69///
70/// Note: Because `GCWorkContext` is often used as parameters of implementations of `GCWork`, we
71/// let GCWorkContext require `Send + 'static`.  Since `GCWorkContext` is just a group of
72/// associated types, its implementations should not have any actual fields other than
73/// `PhantomData`, and will automatically have `Send + 'static`.
74pub trait GCWorkContext: Send + 'static {
75    type VM: VMBinding;
76    type PlanType: Plan<VM = Self::VM>;
77
78    // FIXME: We should use `SFTTrace` as the default value for `DefaultTrace`, and
79    // `UnsupportedTrace` for `PinningTrace`.  However, this requires `associated_type_defaults`
80    // which has not yet been stablized. See: https://github.com/rust-lang/rust/issues/29661
81
82    /// The [`Trace`] implementation to use for tracing edges that do not have special pinning
83    /// requirements.  Concrete plans and spaces may choose to move or not to move the objects the
84    /// traced edges point to.
85    type DefaultTrace: Trace<VM = Self::VM>;
86
87    /// The [`Trace`] implementation to use for tracing edges that must not be updated (i.e. the
88    /// objects the traced edges pointed to must not be moved).  This is used for implementing
89    /// pinning roots and transitive pinning roots.
90    ///
91    /// -   For non-transitive pinning roots, [`Self::PinningTrace`] will be used to trace the edges
92    ///     from roots to objects, but their descendents will be traced using
93    ///     [`Self::DefaultTrace`].
94    /// -   For transitive pinning roots, [`Self::PinningTrace`] will be used to trace the edges
95    ///     from roots to objects, and will also be used to trace the outgoing edges of all objects
96    ///     reachable from transitive pinning roots.
97    ///
98    /// If a plan does not support object pinning, it should use [`UnsupportedTrace`] for this type
99    /// member.
100    ///
101    /// [`UnsupportedTrace`]: crate::plan::tracing::UnsupportedTrace
102    type PinningTrace: Trace<VM = Self::VM>;
103
104    /// Create an instance of [`RootsWorkFactory`] for root scanning in the current GC.
105    ///
106    /// The default implementation creates [`DefaultRootsWorkFactory`] which is sufficient for
107    /// stop-the-world tracing GC.  Plans that need custom [`RootsWorkFactory`] implementations can
108    /// override this method.
109    fn make_roots_work_factory(
110        mmtk: &'static MMTK<Self::VM>,
111    ) -> impl RootsWorkFactory<<Self::VM as VMBinding>::VMSlot> {
112        DefaultRootsWorkFactory::<Self::VM, Self::DefaultTrace, Self::PinningTrace>::new(mmtk)
113    }
114}