Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

This PR enables transitively pinning (TP) objects from particular roots for Immix/StickyImmix #897

Merged
merged 32 commits into from
Sep 11, 2023

Conversation

udesou
Copy link
Contributor

@udesou udesou commented Aug 10, 2023

  • A new bucket ImmovableClosure has been created to trace and transitively pin roots, i.e., roots in which no object in its transitive closure is allowed to move.
  • RootsWorkFactory has two new functions create_process_tp_edge_roots_work and create_process_tp_node_roots_work to create work to process these roots.
  • GCWorkContext expects an TPProcessEdges type, which performs the transitively pinning trace (and is unimplemented for unsupported plans).
  • create_process_node_roots_work creates work to process roots in the NodeRootsTrace bucket, which is executed after TPClosure, but any work derived from it is put into the regular Closure bucket, meaning that the binding shouldn't need to pin root nodes.
  • For sticky immix, currently we only support non-moving nursery collections (sticky_immix_non_moving_nursery), but the solution here is to use the TPClosure on the modified buffer constructed from the write barrier (since during nursery collection we do not know if these objects should be transitively pinned or not).

@udesou udesou requested review from qinsoon and wks August 10, 2023 05:15
Copy link
Collaborator

@wks wks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a correctness issue regarding the processing of black (non-transitively pinning) roots. See comments.

src/scheduler/gc_work.rs Outdated Show resolved Hide resolved
src/scheduler/gc_work.rs Outdated Show resolved Hide resolved
src/scheduler/work_bucket.rs Outdated Show resolved Hide resolved
@qinsoon
Copy link
Member

qinsoon commented Aug 13, 2023

I think we should stop using red/black roots in the PR, and in future discussion just to avoid any confusion. As we discussed, we will call it TransitivelyPin, TPin, or TP.

@udesou udesou changed the title This PR enables processing "red" and "black" roots for Immix/StickyImmix This PR enables transitively pinning (TP) objects from particular roots for Immix/StickyImmix Aug 16, 2023
…andle node roots that should be kept it place but their children may move
@udesou udesou requested a review from wks August 24, 2023 04:32
@qinsoon qinsoon marked this pull request as ready for review August 24, 2023 04:49
@wks
Copy link
Collaborator

wks commented Aug 24, 2023

The GCWorkContext trait is just a collection of associated types. The concrete types that implement it should never be instantiated, and is usually implemented with structs that do not have any fields (except PhantomData). It doesn't make sense for its instances to implement Send and 'static. However, some work packets are parameterised with C: GCWorkContext, and Rust uses the type parameters to determine whether the work packet type automatically implement Send.

To workaround this, we can let the GCWorkContext trait require Send + 'static. Because none of its concrete implementations have actual fields, they should automatically implement Send + 'static, too. Then we can remove + Send + 'static from impl<C: GCWorkContext + Send + 'static> GCWork<C::VM> for SomeWorkPacketType<C>

You can cherry-pick this commit: wks@6f79aea

Cherry-pick this commit, instead: wks@1617f54 It fixed more cases and added comments.

@qinsoon
Copy link
Member

qinsoon commented Sep 6, 2023

binding-refs
OPENJDK_BINDING_REPO=udesou/mmtk-openjdk
OPENJDK_BINDING_REF=fix/upstream-api-change-pr897
JIKESRVM_BINDING_REPO=udesou/mmtk-jikesrvm
JIKESRVM_BINDING_REF=fix/upstream-api-change-pr897
V8_BINDING_REPO=udesou/mmtk-v8
V8_BINDING_REF=fix/upstream-api-change-pr897
JULIA_BINDING_REPO=udesou/mmtk-julia
JULIA_BINDING_REF=fix/upstream-api-change-pr897
RUBY_BINDING_REPO=wks/mmtk-ruby
RUBY_BINDING_REF=feature/rb-roots

@qinsoon qinsoon added the PR-testing Run binding tests for the pull request (deprecated: use PR-extended-testing instead) label Sep 6, 2023
@qinsoon
Copy link
Member

qinsoon commented Sep 7, 2023

The Julia tests failed, as the Julia PR did not include the change about its tests so it timed out. I don't know what happened for the Ruby tests.

@udesou
Copy link
Contributor Author

udesou commented Sep 7, 2023

The Julia tests failed, as the Julia PR did not include the change about its tests so it timed out. I don't know what happened for the Ruby tests.

@wks I'm also not familiar with that error. Do you have any idea why the ruby tests failed to run?

@wks
Copy link
Collaborator

wks commented Sep 7, 2023

@wks I'm also not familiar with that error. Do you have any idea why the ruby tests failed to run?

When running binding tests for mmtk-core, I used a Python script to replace the mmtk dependency with a local directory. See: https://github.com/mmtk/mmtk-core/blob/master/.github/scripts/replace-mmtk-dep.py

This script works by deleting the dependencies.mmtk.git node and adding a dependencies.mmtk.path node. That worked if the Cargo.toml is like what it is in the master branch of mmtk-ruby, i.e. the dependencies.mmtk node has exactly one child, namely git.

However, there is a problem. In my mmtk-ruby PR that changes mmtk-ruby for this PR, I modified Cargo.toml to also include a branch node (See https://github.com/wks/mmtk-ruby/blob/feature/rb-roots/mmtk/Cargo.toml):

[dependencies.mmtk]
features = ["is_mmtk_object", "object_pinning"]

# Uncomment one of the following lines to choose where to find mmtk-core.
#git = "https://github.com/mmtk/mmtk-core.git"  # Use mmtk-core from the official repository.
#path = "../../mmtk-core"  # Use mmtk-core from a local repository.
git = "https://github.com/udesou/mmtk-core"  # Use mmtk-core with rb-roots feature
branch = "feature/rb-roots"

By removing the git node and adding a path node, it will look like

branch = "feature/rb-roots"
path = "/home/wks/projects/mmtk-github/mmtk-core"

branch and path cannot co-exist. Therefore, Cargo complained that "key branch is ignored for dependency (mmtk)."

It is a bug in https://github.com/mmtk/mmtk-core/blob/master/.github/scripts/replace-mmtk-dep.py

@udesou
Copy link
Contributor Author

udesou commented Sep 7, 2023

@wks I'm also not familiar with that error. Do you have any idea why the ruby tests failed to run?

When running binding tests for mmtk-core, I used a Python script to replace the mmtk dependency with a local directory. See: https://github.com/mmtk/mmtk-core/blob/master/.github/scripts/replace-mmtk-dep.py

This script works by deleting the dependencies.mmtk.git node and adding a dependencies.mmtk.path node. That worked if the Cargo.toml is like what it is in the master branch of mmtk-ruby, i.e. the dependencies.mmtk node has exactly one child, namely git.

However, there is a problem. In my mmtk-ruby PR that changes mmtk-ruby for this PR, I modified Cargo.toml to also include a branch node (See https://github.com/wks/mmtk-ruby/blob/feature/rb-roots/mmtk/Cargo.toml):

[dependencies.mmtk]
features = ["is_mmtk_object", "object_pinning"]

# Uncomment one of the following lines to choose where to find mmtk-core.
#git = "https://github.com/mmtk/mmtk-core.git"  # Use mmtk-core from the official repository.
#path = "../../mmtk-core"  # Use mmtk-core from a local repository.
git = "https://github.com/udesou/mmtk-core"  # Use mmtk-core with rb-roots feature
branch = "feature/rb-roots"

By removing the git node and adding a path node, it will look like

branch = "feature/rb-roots"
path = "/home/wks/projects/mmtk-github/mmtk-core"

branch and path cannot co-exist. Therefore, Cargo complained that "key branch is ignored for dependency (mmtk)."

It is a bug in https://github.com/mmtk/mmtk-core/blob/master/.github/scripts/replace-mmtk-dep.py

I see. But the local directory would take the branch node into consideration when rewriting from git to path? i.e., is this just a matter of deleting the branchnode after the rewriting?

@wks
Copy link
Collaborator

wks commented Sep 7, 2023

I see. But the local directory would take the branch node into consideration when rewriting from git to path? i.e., is this just a matter of deleting the branchnode after the rewriting?

Yes. I made a PR to fix it. (#947) Now the script simply remove all of "git", "branch", "version" and "registry".

But it should be easier to just cherry-pick #947 into this PR and run the CI again.

Remove all keys that may specify the location of a dependency since they
may conflict.
@udesou
Copy link
Contributor Author

udesou commented Sep 7, 2023

Done. Thank you @wks!

EDIT: Something still isn't right. Maybe a network error. I'll try rerunning the tests after the other ones finish.

@qinsoon
Copy link
Member

qinsoon commented Sep 7, 2023

EDIT: Something still isn't right.

warning: spurious network error (3 tries remaining): [28] Timeout was reached (Operation too slow. Less than 10 bytes/sec transferred the last 30 seconds)
warning: spurious network error (2 tries remaining): [28] Timeout was reached (Operation too slow. Less than 10 bytes/sec transferred the last 30 seconds)
warning: spurious network error (1 tries remaining): [28] Timeout was reached (Operation too slow. Less than 10 bytes/sec transferred the last 30 seconds)

Seems to be a network issue of the cargo registry. Probably just rerun it later.

@qinsoon
Copy link
Member

qinsoon commented Sep 10, 2023

I ran benchmarks for the PR with OpenJDK/Immix/2.5x MC min heap (plotty link). It measures the impact of the code changes and extra buckets from the PR, but it does not measure the transitively pinning or the pinning roots (as the OpenJDK binding does not use them). The results show there is no slowdown in this PR for introducing transitively pinning.

Mutator time
pr897-mutator

GC time
pr897-gc

Copy link
Member

@qinsoon qinsoon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@udesou udesou added this pull request to the merge queue Sep 11, 2023
Merged via the queue into mmtk:master with commit 61d20e2 Sep 11, 2023
19 of 20 checks passed
@udesou udesou deleted the feature/rb-roots branch September 11, 2023 00:53
wks added a commit to mmtk/mmtk-ruby that referenced this pull request Sep 11, 2023
Related PR: mmtk/mmtk-core#897

Co-authored-by: Eduardo Souza <ledusou@gmail.com>
udesou added a commit to mmtk/mmtk-julia that referenced this pull request Sep 12, 2023
…#99)

Merge after mmtk/mmtk-core#897 to reflect the
API change.

---------

Co-authored-by: Yi Lin <qinsoon@gmail.com>
@wks wks mentioned this pull request Nov 3, 2023
14 tasks
udesou added a commit to mmtk/mmtk-julia that referenced this pull request Feb 12, 2024
This PR adds support for (partially) moving objects in Julia and should
be merged with mmtk/julia#27 and
mmtk/mmtk-core#897.
- It adds support for pinning/unpinning objects and checking if an
object is pinned (the implementation uses a pin bit).
(`mmtk_pin_object`, `mmtk_unpin_object` and `mmtk_is_pinned`)
- It adds support for providing transitively pinned (`tpinned`) roots .
- It implements the `copy` function in `object_model.rs`. Note that
arrays with inlined data must be treated specially, as their `a->data`
pointer needs to be updated after copying.
- It uses Julia's GC bits to store forwarding information and the
object's header to store the forwarding pointer.
- Currently, all stack roots are transitively pinned. Note that we also
need to traverse the `tls->live_tasks` to make sure that any stack root
from these tasks are transitively pinned.
- `scan_julia_object` had to be adapted to cover a few corner cases:
- when an array object contains a pointer to the owner of the data,
`a->data` needs to be updated in case the owner moves.
- the `using` field inside a `jl_module_t` may also be inlined inside
the module, and if that's the case, we need to make sure that field is
updated if the module moves.
- when marking finalizers, traversing the list of malloced arrays, and
the list of live tasks at the end of GC, we need to updated these lists
with objects that have possibly been moved.
- Added a few debug assertions to capture scanning of misaligned objects
and roots.

NB: I've only tested moving immix; sticky immix is still non-moving.

---------

Co-authored-by: Luis Eduardo de Souza Amorim <eduardo@shrew.moma>
Co-authored-by: Luis Eduardo de Souza Amorim <eduardo@bear.moma>
Co-authored-by: mmtkgc-bot <mmtkgc.bot@gmail.com>
mergify bot pushed a commit to mmtk/mmtk-julia that referenced this pull request Feb 12, 2024
This PR adds support for (partially) moving objects in Julia and should
be merged with mmtk/julia#27 and
mmtk/mmtk-core#897.
- It adds support for pinning/unpinning objects and checking if an
object is pinned (the implementation uses a pin bit).
(`mmtk_pin_object`, `mmtk_unpin_object` and `mmtk_is_pinned`)
- It adds support for providing transitively pinned (`tpinned`) roots .
- It implements the `copy` function in `object_model.rs`. Note that
arrays with inlined data must be treated specially, as their `a->data`
pointer needs to be updated after copying.
- It uses Julia's GC bits to store forwarding information and the
object's header to store the forwarding pointer.
- Currently, all stack roots are transitively pinned. Note that we also
need to traverse the `tls->live_tasks` to make sure that any stack root
from these tasks are transitively pinned.
- `scan_julia_object` had to be adapted to cover a few corner cases:
- when an array object contains a pointer to the owner of the data,
`a->data` needs to be updated in case the owner moves.
- the `using` field inside a `jl_module_t` may also be inlined inside
the module, and if that's the case, we need to make sure that field is
updated if the module moves.
- when marking finalizers, traversing the list of malloced arrays, and
the list of live tasks at the end of GC, we need to updated these lists
with objects that have possibly been moved.
- Added a few debug assertions to capture scanning of misaligned objects
and roots.

NB: I've only tested moving immix; sticky immix is still non-moving.

---------

Co-authored-by: Luis Eduardo de Souza Amorim <eduardo@shrew.moma>
Co-authored-by: Luis Eduardo de Souza Amorim <eduardo@bear.moma>
Co-authored-by: mmtkgc-bot <mmtkgc.bot@gmail.com>
(cherry picked from commit 1622162)

# Conflicts:
#	julia/mmtk_julia.c
#	mmtk/Cargo.lock
#	mmtk/Cargo.toml
#	mmtk/api/mmtk.h
#	mmtk/src/julia_scanning.rs
#	mmtk/src/lib.rs
#	mmtk/src/scanning.rs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PR-testing Run binding tests for the pull request (deprecated: use PR-extended-testing instead)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants