Skip to content

Commit

Permalink
Merge branch 'master' into fix/modbuf-global-gc-bug
Browse files Browse the repository at this point in the history
  • Loading branch information
k-sareen authored Jan 6, 2025
2 parents e862642 + c0f9788 commit 2884f6d
Show file tree
Hide file tree
Showing 48 changed files with 759 additions and 259 deletions.
3 changes: 3 additions & 0 deletions .github/scripts/ci-common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ cargo_toml=$project_root/Cargo.toml

dummyvm_toml=$project_root/docs/dummyvm/Cargo.toml

# Pin certain deps for our MSRV
cargo update -p [email protected] --precise 0.5.5 # This can be removed once we move to Rust 1.81 or newer

# Repeat a command for all the features. Requires the command as one argument (with double quotes)
for_all_features() {
# without mutually exclusive features
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/minimal-tests-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ jobs:
target:
- { os: ubuntu-22.04, triple: x86_64-unknown-linux-gnu }
- { os: ubuntu-22.04, triple: i686-unknown-linux-gnu }
- { os: macos-12, triple: x86_64-apple-darwin }
- { os: macos-15, triple: x86_64-apple-darwin }
rust: ${{ fromJson(needs.setup-test-matrix.outputs.rust )}}

name: style-check/${{ matrix.target.triple }}/${{ matrix.rust }}
Expand Down
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
0.30.0 (2024-12-20)
===

## What's Changed

### policy
* Allow setting object metadata for VM space objects. Expose VO bit under a feature. by @qinsoon in https://github.com/mmtk/mmtk-core/pull/1248

### Misc
* Fix clippy warnings for Rust 1.83 by @wks in https://github.com/mmtk/mmtk-core/pull/1242
* Annotate mmap ranges using PR_SET_VMA by @wks in https://github.com/mmtk/mmtk-core/pull/1236
* Fix warnings for lifetime in MmapAnnotation impl by @qinsoon in https://github.com/mmtk/mmtk-core/pull/1244
* Collect live bytes per space, and report by space by @qinsoon in https://github.com/mmtk/mmtk-core/pull/1238
* Minor changes for debugging. by @wks in https://github.com/mmtk/mmtk-core/pull/1245
* Use macos-15 for style check by @qinsoon in https://github.com/mmtk/mmtk-core/pull/1249
* Check the option before aggregating live bytes data. Panic if the option is enabled on malloc space. by @qinsoon in https://github.com/mmtk/mmtk-core/pull/1250


**Full Changelog**: https://github.com/mmtk/mmtk-core/compare/v0.29.0...v0.30.0

0.29.0 (2024-11-08)
===

Expand Down
24 changes: 19 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mmtk"
version = "0.29.0"
version = "0.30.0"
authors = ["The MMTk Developers <>"]
edition = "2021"
license = "MIT OR Apache-2.0"
Expand Down Expand Up @@ -38,7 +38,7 @@ log = { version = "0.4", features = ["max_level_trace", "release_max_level_off"]
memoffset = "0.9"
mimalloc-sys = { version = "0.1.6", optional = true }
# MMTk macros - we have to specify a version here in order to publish the crate, even though we use the dependency from a local path.
mmtk-macros = { version="0.29.0", path = "macros/" }
mmtk-macros = { version="0.30.0", path = "macros/" }
num_cpus = "1.8"
num-traits = "0.2"
pfm = { version = "0.1.1", optional = true }
Expand Down Expand Up @@ -172,13 +172,27 @@ work_packet_stats = []
# Count the malloc'd memory into the heap size
malloc_counted_size = []

# Count the size of all live objects in GC
count_live_bytes_in_gc = []

# Workaround a problem where bpftrace scripts (see tools/tracing/timeline/capture.bt) cannot
# capture the type names of work packets.
bpftrace_workaround = []

# Disable mmap annotations.
# All invocations of `mmap` in mmtk-core are accompanied by calls of `prctl` with
# `PR_SET_VMA_ANON_NAME` to annotate the mmap ranges with human-readable names. It is enabled by
# default and should work fine even with large heap sizes. However, if this is causing problems,
# users can disable such annotations by enabling this Cargo feature.
no_mmap_annotation = []

# Allow the binding to access Valid Object (VO) bit.
# MMTk uses VO bit to identify a valid object. Thus VO bit is carefully managed by MMTk in cooperation with the binding.
# So normally this feature is not needed, and its use should be discouraged.
# However, in rare cases, a binding may want to directly access and manipulate VO bit. For example, a binding cannot cooperate
# with MMTk to identify each object for setting the VO bit. This is usually due to the limitation of the VM.
# In such cases, a binding may use this feature and manipulate the VO bit to their needs. The binding's manipulation on VO bit
# may violate MMTk's semantics, and may result in undefined behaviors for VO bit related APIs. This feature should
# only be used if you understand how VO bit works internally. Use at your own risk.
vo_bit_access = []

# Do not modify the following line - ci-common.sh matches it
# -- Mutally exclusive features --
# Only one feature from each group can be provided. Otherwise build will fail.
Expand Down
2 changes: 1 addition & 1 deletion docs/team/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ MMTk releases include MMTk core and the officially supported bindings. They shar
The current releases include the following bindings:
* OpenJDK
* JikesRVM
* Julia

The current releases do not include the following bindings:
* Julia: We have made good progress on the binding development, and we will include it soon.
* Ruby: We have made good progress on the binding development, and we will include it soon.
* V8: We currently lack of resources to work on the binding.

Expand Down
38 changes: 38 additions & 0 deletions docs/userguide/src/migration/prefix.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,44 @@ Notes for the mmtk-core developers:

<!-- Insert new versions here -->

## 0.30.0

### `live_bytes_in_last_gc` becomes a runtime option, and returns a map for live bytes in each space

```admonish tldr
`count_live_bytes_in_gc` is now a runtime option instead of a features (build-time), and we collect
live bytes statistics per space. Correspondingly, `memory_manager::live_bytes_in_last_gc` now returns a map for
live bytes in each space.
```

API changes:

- module `util::options`
+ `Options` includes `count_live_bytes_in_gc`, which defaults to `false`. This can be turned on at run-time.
+ The old `count_live_bytes_in_gc` feature is removed.
- module `memory_manager`
+ `live_bytes_in_last_gc` now returns a `HashMap<&'static str, LiveBytesStats>`. The keys are
strings for space names, and the values are statistics for live bytes in the space.

See also:

- PR: <https://github.com/mmtk/mmtk-core/pull/1238>


### mmap-related functions require annotation

```admonish tldr
Memory-mapping functions in `mmtk::util::memory` now take an additional `MmapAnnotation` argument.
```

API changes:

- module `util::memory`
+ The following functions take an additional `MmapAnnotation` argument.
* `dzmmap`
* `dzmmap_noreplace`
* `mmap_noreserve`

## 0.28.0

### `handle_user_collection_request` returns `bool`
Expand Down
2 changes: 1 addition & 1 deletion macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "mmtk-macros"
# the macro crate uses the same version as mmtk-core
version = "0.29.0"
version = "0.30.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "MMTk macros provides procedural macros used by mmtk-core."
Expand Down
34 changes: 17 additions & 17 deletions src/global_state.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use atomic_refcell::AtomicRefCell;
use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Mutex;
use std::time::Instant;

use atomic_refcell::AtomicRefCell;

/// This stores some global states for an MMTK instance.
/// Some MMTK components like plans and allocators may keep an reference to the struct, and can access it.
// This used to be a part of the `BasePlan`. In that case, any component that accesses
Expand Down Expand Up @@ -45,9 +45,8 @@ pub struct GlobalState {
/// A counteer that keeps tracks of the number of bytes allocated by malloc
#[cfg(feature = "malloc_counted_size")]
pub(crate) malloc_bytes: AtomicUsize,
/// This stores the size in bytes for all the live objects in last GC. This counter is only updated in the GC release phase.
#[cfg(feature = "count_live_bytes_in_gc")]
pub(crate) live_bytes_in_last_gc: AtomicUsize,
/// This stores the live bytes and the used bytes (by pages) for each space in last GC. This counter is only updated in the GC release phase.
pub(crate) live_bytes_in_last_gc: AtomicRefCell<HashMap<&'static str, LiveBytesStats>>,
}

impl GlobalState {
Expand Down Expand Up @@ -183,16 +182,6 @@ impl GlobalState {
pub(crate) fn decrease_malloc_bytes_by(&self, size: usize) {
self.malloc_bytes.fetch_sub(size, Ordering::SeqCst);
}

#[cfg(feature = "count_live_bytes_in_gc")]
pub fn get_live_bytes_in_last_gc(&self) -> usize {
self.live_bytes_in_last_gc.load(Ordering::SeqCst)
}

#[cfg(feature = "count_live_bytes_in_gc")]
pub fn set_live_bytes_in_last_gc(&self, size: usize) {
self.live_bytes_in_last_gc.store(size, Ordering::SeqCst);
}
}

impl Default for GlobalState {
Expand All @@ -213,8 +202,7 @@ impl Default for GlobalState {
allocation_bytes: AtomicUsize::new(0),
#[cfg(feature = "malloc_counted_size")]
malloc_bytes: AtomicUsize::new(0),
#[cfg(feature = "count_live_bytes_in_gc")]
live_bytes_in_last_gc: AtomicUsize::new(0),
live_bytes_in_last_gc: AtomicRefCell::new(HashMap::new()),
}
}
}
Expand All @@ -225,3 +213,15 @@ pub enum GcStatus {
GcPrepare,
GcProper,
}

/// Statistics for the live bytes in the last GC. The statistics is per space.
#[derive(Copy, Clone, Debug)]
pub struct LiveBytesStats {
/// Total accumulated bytes of live objects in the space.
pub live_bytes: usize,
/// Total pages used by the space.
pub used_pages: usize,
/// Total bytes used by the space, computed from `used_pages`.
/// The ratio of live_bytes and used_bytes reflects the utilization of the memory in the space.
pub used_bytes: usize,
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub(crate) use mmtk::MMAPPER;
pub use mmtk::MMTK;

mod global_state;
pub use crate::global_state::LiveBytesStats;

mod policy;

Expand Down
18 changes: 11 additions & 7 deletions src/memory_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ use crate::vm::slot::MemorySlice;
use crate::vm::ReferenceGlue;
use crate::vm::VMBinding;

use std::collections::HashMap;

/// Initialize an MMTk instance. A VM should call this method after creating an [`crate::MMTK`]
/// instance but before using any of the methods provided in MMTk (except `process()` and `process_bulk()`).
///
Expand Down Expand Up @@ -531,16 +533,18 @@ pub fn free_bytes<VM: VMBinding>(mmtk: &MMTK<VM>) -> usize {
mmtk.get_plan().get_free_pages() << LOG_BYTES_IN_PAGE
}

/// Return the size of all the live objects in bytes in the last GC. MMTk usually accounts for memory in pages.
/// Return a hash map for live bytes statistics in the last GC for each space.
///
/// MMTk usually accounts for memory in pages by each space.
/// This is a special method that we count the size of every live object in a GC, and sum up the total bytes.
/// We provide this method so users can compare with `used_bytes` (which does page accounting), and know if
/// the heap is fragmented.
/// We provide this method so users can use [`crate::LiveBytesStats`] to know if
/// the space is fragmented.
/// The value returned by this method is only updated when we finish tracing in a GC. A recommended timing
/// to call this method is at the end of a GC (e.g. when the runtime is about to resume threads).
#[cfg(feature = "count_live_bytes_in_gc")]
pub fn live_bytes_in_last_gc<VM: VMBinding>(mmtk: &MMTK<VM>) -> usize {
use std::sync::atomic::Ordering;
mmtk.state.live_bytes_in_last_gc.load(Ordering::SeqCst)
pub fn live_bytes_in_last_gc<VM: VMBinding>(
mmtk: &MMTK<VM>,
) -> HashMap<&'static str, crate::LiveBytesStats> {
mmtk.state.live_bytes_in_last_gc.borrow().clone()
}

/// Return the starting address of the heap. *Note that currently MMTk uses
Expand Down
70 changes: 70 additions & 0 deletions src/mmtk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::util::address::ObjectReference;
use crate::util::analysis::AnalysisManager;
use crate::util::finalizable_processor::FinalizableProcessor;
use crate::util::heap::gc_trigger::GCTrigger;
use crate::util::heap::layout::heap_parameters::MAX_SPACES;
use crate::util::heap::layout::vm_layout::VMLayout;
use crate::util::heap::layout::{self, Mmapper, VMMap};
use crate::util::heap::HeapMeta;
Expand All @@ -26,6 +27,7 @@ use crate::util::statistics::stats::Stats;
use crate::vm::ReferenceGlue;
use crate::vm::VMBinding;
use std::cell::UnsafeCell;
use std::collections::HashMap;
use std::default::Default;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
Expand Down Expand Up @@ -526,4 +528,72 @@ impl<VM: VMBinding> MMTK<VM> {
space.enumerate_objects(&mut enumerator);
})
}

/// Aggregate a hash map of live bytes per space with the space stats to produce
/// a map of live bytes stats for the spaces.
pub(crate) fn aggregate_live_bytes_in_last_gc(
&self,
live_bytes_per_space: [usize; MAX_SPACES],
) -> HashMap<&'static str, crate::LiveBytesStats> {
use crate::policy::space::Space;
let mut ret = HashMap::new();
self.get_plan().for_each_space(&mut |space: &dyn Space<VM>| {
let space_name = space.get_name();
let space_idx = space.get_descriptor().get_index();
let used_pages = space.reserved_pages();
if used_pages != 0 {
let used_bytes = crate::util::conversions::pages_to_bytes(used_pages);
let live_bytes = live_bytes_per_space[space_idx];
debug_assert!(
live_bytes <= used_bytes,
"Live bytes of objects in {} ({} bytes) is larger than used pages ({} bytes), something is wrong.",
space_name, live_bytes, used_bytes
);
ret.insert(space_name, crate::LiveBytesStats {
live_bytes,
used_pages,
used_bytes,
});
}
});
ret
}

/// Print VM maps. It will print the memory ranges used by spaces as well as some attributes of
/// the spaces.
///
/// - "I": The space is immortal. Its objects will never die.
/// - "N": The space is non-movable. Its objects will never move.
///
/// Arguments:
/// * `out`: the place to print the VM maps.
/// * `space_name`: If `None`, print all spaces;
/// if `Some(n)`, only print the space whose name is `n`.
pub fn debug_print_vm_maps(
&self,
out: &mut impl std::fmt::Write,
space_name: Option<&str>,
) -> Result<(), std::fmt::Error> {
let mut result_so_far = Ok(());
self.get_plan().for_each_space(&mut |space| {
if result_so_far.is_ok()
&& (space_name.is_none() || space_name == Some(space.get_name()))
{
result_so_far = crate::policy::space::print_vm_map(space, out);
}
});
result_so_far
}

/// Initialize object metadata for a VM space object.
/// Objects in the VM space are allocated/managed by the binding. This function provides a way for
/// the binding to set object metadata in MMTk for an object in the space.
#[cfg(feature = "vm_space")]
pub fn initialize_vm_space_object(&self, object: crate::util::ObjectReference) {
use crate::policy::sft::SFT;
self.get_plan()
.base()
.vm_space
.initialize_object_metadata(object, false)
}
}
2 changes: 1 addition & 1 deletion src/plan/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ pub struct CreateSpecificPlanArgs<'a, VM: VMBinding> {
pub global_side_metadata_specs: Vec<SideMetadataSpec>,
}

impl<'a, VM: VMBinding> CreateSpecificPlanArgs<'a, VM> {
impl<VM: VMBinding> CreateSpecificPlanArgs<'_, VM> {
/// Get a PlanCreateSpaceArgs that can be used to create a space
pub fn get_space_args(
&mut self,
Expand Down
1 change: 0 additions & 1 deletion src/plan/markcompact/gc_work.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ impl<VM: VMBinding> GCWork<VM> for UpdateReferences<VM> {
mmtk.slot_logger.reset();

// We do two passes of transitive closures. We clear the live bytes from the first pass.
#[cfg(feature = "count_live_bytes_in_gc")]
mmtk.scheduler
.worker_group
.get_and_clear_worker_live_bytes();
Expand Down
2 changes: 0 additions & 2 deletions src/plan/mutator_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ impl<VM: VMBinding> std::fmt::Debug for MutatorConfig<VM> {
/// A mutator is a per-thread data structure that manages allocations and barriers. It is usually highly coupled with the language VM.
/// It is recommended for MMTk users 1) to have a mutator struct of the same layout in the thread local storage that can be accessed efficiently,
/// and 2) to implement fastpath allocation and barriers for the mutator in the VM side.
// We are trying to make this struct fixed-sized so that VM bindings can easily define a type to have the exact same layout as this struct.
// Currently Mutator is fixed sized, and we should try keep this invariant:
// - Allocators are fixed-length arrays of allocators.
Expand Down Expand Up @@ -256,7 +255,6 @@ impl<VM: VMBinding> Mutator<VM> {

/// Each GC plan should provide their implementation of a MutatorContext. *Note that this trait is no longer needed as we removed
/// per-plan mutator implementation and we will remove this trait as well in the future.*
// TODO: We should be able to remove this trait, as we removed per-plan mutator implementation, and there is no other type that implements this trait.
// The Mutator struct above is the only type that implements this trait. We should be able to merge them.
pub trait MutatorContext<VM: VMBinding>: Send + 'static {
Expand Down
Loading

0 comments on commit 2884f6d

Please sign in to comment.