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

Simplify lazy semantics #760

Merged
merged 9 commits into from
Nov 30, 2021
Merged

Simplify lazy semantics #760

merged 9 commits into from
Nov 30, 2021

Conversation

kayceesrk
Copy link
Contributor

Simplify lazy and fix a bug based on discussions from #749 and #750.

  • Mark lazy as not concurrency (domains, systhreads, fibers) safe.
  • Remove RacyLazy exception. Any concurrent use of lazy value may raise Undefined exception.
  • Remove domain-local id to distinguish concurrent and recursive forcing.
  • Remove try_force.

The commit also fixes a bug to prevent short-circuiting forcing_tag values.

We need to bootstrap to remove references to RacyLazy from the bootstrap binaries. After bootstrap, the primitive
caml_ml_domain_unique_token should be removed from the runtime.

* Mark lazy as not concurrency (domains, systhreads, fibers) safe.
* Remove RacyLazy exception. Any concurrent use of lazy value may raise
Undefined exception.
* Remove domain-local id to distinguish concurrent and recursive
forcing.
* Remove try_force.

The commit also fixes a bug to prevent short-circuiting forcing_tag
values.

We need to bootstrap to remove references to `RacyLazy` from the
bootstrap binaries. After bootstrap, the primitive
`caml_ml_domain_unique_token` should be removed from the runtime.
@kayceesrk
Copy link
Contributor Author

@gasche would appreciate your review.

Copy link
Contributor

@gasche gasche left a comment

Choose a reason for hiding this comment

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

Thanks for the ping! (I don't get notifications for ocaml-multicore/)

The change looks correct to me. It does simplify the implementation.

The documentation is changed so that Lazy.force is "unspecified" (but safe) in the case of concurrent forcing. I think we could be more precise, and will try to make some proposals.

The PR comes with some changes in the testsuite, some for backward-compatibility, some (dividing iteration counts by 10 or removing some cpu_relax() call) that seem to come from performance considerations, I'm not sure which/why.

runtime/domain.c Show resolved Hide resolved
runtime/obj.c Outdated Show resolved Hide resolved
runtime/sys.c Outdated Show resolved Hide resolved
@gasche
Copy link
Contributor

gasche commented Nov 29, 2021

... after thinking more about it, I think that the current non-documentation of concurrent-forcing behavior is okay.

stdlib/lazy.mli Outdated Show resolved Hide resolved
Copy link
Contributor

@gadmm gadmm left a comment

Choose a reason for hiding this comment

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

I have more questions about this code now that I understand it better. Some comments are not about behaviour introduced by this PR, feel free to address them later/separately.

stdlib/camlinternalLazy.ml Show resolved Hide resolved
stdlib/camlinternalLazy.ml Show resolved Hide resolved
Import trunk changes for flambda

Co-authored-by: Guillaume Munch-Maccagnoni <Guillaume.Munch-Maccagnoni@Inria.fr>
@kayceesrk
Copy link
Contributor Author

Also, thanks @gasche and @gadmm for your high-quality reviews.

@kayceesrk
Copy link
Contributor Author

The failures are due to line number differences in the backtrace tests. I've already fixed these twice in this PR :-| I'll wait until the review on the changes reaches a fixed point, and then I shall fix the failing tests.

@gasche
Copy link
Contributor

gasche commented Nov 30, 2021

My high-level impression is that we should try to merge a "good first part" version of this PR, that simplifies the current implementation and does not introduce any new bugs, and then have a separate, second discussion about how to safely read concurrently-modified tags. (I suspect we may not be out of surprises there: many other parts of the runtime read tags, how safe are they with respect to concurrent mutation?)

@gasche
Copy link
Contributor

gasche commented Nov 30, 2021

To continue on my previous line of thought: I think we could cut the current PR to the commit before "Add new primitive to atomically read tag", and get this merged right away, and then have a dedicated discussion on the memory-safety to make sure that we properly address the issue.

(@kayceesrk : just checking that you know about make promote DIR=... to auto-fix line numbers and in generate test outputs in the testsuite.)

@gadmm
Copy link
Contributor

gadmm commented Nov 30, 2021

I think we're there right after changing lazy_..._switch to lazy_..._cond or to what @gasche proposed, and changing obj_tag to address @xavierleroy's concern. It's an easy fix so no need to delay the last part of this PR.

@gasche
Copy link
Contributor

gasche commented Nov 30, 2021

What about the lazy-tag checks in other parts of the runtime?

  • compare.c, hash.c: I think they need an atomic read to handle Forward_tag safely
  • extern.c: this logic can run concurrently with another mutator, but iirc. we decided that it is unspecified what happens in this case (but no crashes); I think the current code will not crash if it reads the tags wrong, at worst it will incorrectly shortcut a pointer in the serialized result. No change seems required.
  • finalise.c: no change is required
  • minor_gc.c, major_gc.c, weak.c: no change required as iirc. no mutators can run concurrently with the GC

@bluddy
Copy link
Contributor

bluddy commented Nov 30, 2021

compare.c, hash.c: I think they need an atomic read to handle Forward_tag safely

Why? Worst case you get the wrong result (which is fine), but do you get a crash?

@gasche
Copy link
Contributor

gasche commented Nov 30, 2021

I think you are correct: we can get garbage in this case, but no crash, because the block arguments of a lazy value remains well-formed at any point. (With the new policy, specified in the current PR, that lazy values are not thread-safe, this is fine. Previously we tried to make them shareable, as long as only there is no racy force.)

@kayceesrk
Copy link
Contributor Author

Based on the recommendations, I have

  1. Removed the new primitive to atomically read tag and made obj_tag load the tag using acquire.
  2. Incorporated @gasche's suggestion for inline_lazy_force_switch

just checking that you know about make promote DIR=... to auto-fix line numbers and in generate test outputs in the testsuite.

I did not know this. Thanks for pointing this out.

Copy link
Contributor

@gadmm gadmm left a comment

Choose a reason for hiding this comment

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

LGTM. I would just add a comment (below).

runtime/obj.c Show resolved Hide resolved
@gasche
Copy link
Contributor

gasche commented Nov 30, 2021

(Note: my inline_lazy_switch suggestion requires massaging from the matching+backend people; if we merge as-is, as I think is reasonable, I will open an issue to track this.)

@gadmm
Copy link
Contributor

gadmm commented Nov 30, 2021

(Note: my inline_lazy_switch suggestion requires massaging from the matching+backend people; if we merge as-is, as I think is reasonable, I will open an issue to track this.)

Or that could be used as an incentive to explore an implementation that does not mutate tags!

@kayceesrk
Copy link
Contributor Author

Will merge when the CI turns green. Thanks @gasche, @gadmm and @xavierleroy.

@kayceesrk kayceesrk merged commit 213044b into 5.00 Nov 30, 2021
sadiqj pushed a commit to sadiqj/ocaml that referenced this pull request Jan 10, 2022
…ticore/lazy_simplify

Simplify lazy semantics
ctk21 pushed a commit to ctk21/ocaml that referenced this pull request Jan 11, 2022
…ticore/lazy_simplify

Simplify lazy semantics
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants