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

add support for indexing in @atomic macro #54707

Merged
merged 17 commits into from
Jul 7, 2024

Conversation

kalmarek
Copy link
Contributor

@kalmarek kalmarek commented Jun 6, 2024

Following the discussion in #54642

Implemented:

  • modifyindex_atomic!, swapindex_atomic!, replaceindex_atomic! for GenericMemory
  • getindex_atomic, setindex_atomic!, setindexonce_atomic! for GenericMemory
  • add support for references in @atomic macros
  • add support for vararg indices in @atomic macros
  • tests
  • update docstrings with example usage
  • [ ] update Atomics section of the manual (?)
  • news

@oscardssmith @vtjnash

New @atomic transformations implemented here:

julia> @macroexpand (@atomic a[i1,i2])
:(Base.getindex_atomic(a, :sequentially_consistent, i1, i2))

julia> @macroexpand (@atomic order a[i1,i2])
:(Base.getindex_atomic(a, order, i1, i2))

julia> @macroexpand (@atomic a[i1,i2] = 2.0)
:(Base.setindex_atomic!(a, :sequentially_consistent, 2.0, i1, i2))

julia> @macroexpand (@atomic order a[i1,i2] = 2.0)
:(Base.setindex_atomic!(a, order, 2.0, i1, i2))

julia> @macroexpand (@atomicswap a[i1,i2] = 2.0)
:(Base.swapindex_atomic!(a, :sequentially_consistent, 2.0, i1, i2))

julia> @macroexpand (@atomicswap order a[i1,i2] = 2.0)
:(Base.swapindex_atomic!(a, order, 2.0, i1, i2))

julia> @macroexpand (@atomic a[i1,i2] += 2.0)
:((Base.modifyindex_atomic!(a, :sequentially_consistent, +, 2.0, i1, i2))[2])

julia> @macroexpand (@atomic order a[i1,i2] += 2.0)
:((Base.modifyindex_atomic!(a, order, +, 2.0, i1, i2))[2])

julia> @macroexpand (@atomiconce a[i1,i2] = 2.0)
:(Base.setindexonce_atomic!(a, :sequentially_consistent, :sequentially_consistent, 2.0, i1, i2))

julia> @macroexpand (@atomiconce o1 o2 a[i1,i2] = 2.0)
:(Base.setindexonce_atomic!(a, o1, o2, 2.0, i1, i2))

julia> @macroexpand (@atomicreplace a[i1,i2] (2.0=>3.0))
:(Base.replaceindex_atomic!(a, :sequentially_consistent, :sequentially_consistent, 2.0, 3.0, i1, i2))

julia> @macroexpand (@atomicreplace o1 o2 a[i1,i2] (2.0=>3.0))
:(Base.replaceindex_atomic!(a, o1, o2, 2.0, 3.0, i1, i2))

base/genericmemory.jl Outdated Show resolved Hide resolved
@oscardssmith oscardssmith added needs tests Unit tests are required for this change needs docs Documentation for this change is required needs news A NEWS entry is required for this change labels Jun 6, 2024
@oscardssmith
Copy link
Member

other than the comment above this looks good! (it is missing an implementation of getindex_atomic which we need because the regular getindex doesn't have a place to pass an order)

@kalmarek
Copy link
Contributor Author

kalmarek commented Jun 7, 2024

@oscardssmith I'm not sure about the semantics of the suggested getindex_atomic. One can write a completely generic

function getindex_atomic(mem::GenericMemory, i::Int, order=default_access_order(mem))
    memref = memoryref(mem, i, @_boundscheck)
    return memoryrefget(memref, i, order, @_boundscheck)
end

but there's nothing atomic about the function, except the order argument. Is this what you meant?

@oscardssmith
Copy link
Member

The point is just that (but probably restricted to AtomicMemory since

julia> m = Memory{Int}(undef, 5);

julia> Base.memoryrefget(memoryref(m, 1), :acquire, false)
ERROR: ConcurrencyViolationError("memoryrefget: non-atomic memory cannot be accessed atomically")
Stacktrace:
 [1] top-level scope
   @ REPL[3]:1

The reason we need this function is for the user to be able to provide a stricter order than :monotonic

@kalmarek
Copy link
Contributor Author

kalmarek commented Jun 7, 2024

@oscardssmith thanks for the clarification;

Alongside modifyindex_atomic!, swapindex_atomic! and replaceindex_atomic! I've also implemented

  • getindex_atomic(::GenericMemory, i, ...)
  • setindex_atomic!(::GenericMemory, i, ...) and
  • setindexonce_atomic!(::GenericMemory, i, ...).

I added some converts (val isa T ? val : convert(T, val)::T) those *index methods and the support for indexing in @atomic macro with the semantics as in the opening comment.

Please have a look and comment!

I'll write/update docstrings once the code is approved.

@kalmarek kalmarek changed the title implement (modify|swap|replace)index! for GenericMemory add support for indexing in @atomic macro Jun 7, 2024
test/atomics.jl Outdated Show resolved Hide resolved
@oscardssmith
Copy link
Member

This looks great to me! We definitely need more tests (and review from @vtjnash to make sure that all of the default orders etc are correct).

@kalmarek
Copy link
Contributor Author

kalmarek commented Jun 7, 2024

the default orderings are the ones from the existing cases of @atomic macro.

@kalmarek
Copy link
Contributor Author

@vtjnash could you have a look at the proposed changes?
In particular the choices of orderings for the @atomic macro.
Do we need even more tests?

@oscardssmith what kind of docs should be written?

To me the docstring of the atomic macro is already too long, asking rather for a paragraph in the atomics part of the manual.

@oscardssmith
Copy link
Member

I think this does need some docs under the @atomic macro, e.g.

  @atomic m[i] = new
  @atomic m[i] += addend
  @atomic :release m[i] = new
  @atomic :acquire_release m[i] += addend

but I agree with you that the docstring is already pretty long, but I kind of think that it is necessary to at least list the transforms that the macro does.

@kalmarek
Copy link
Contributor Author

@oscardssmith @vtjnash I've updated docstrings and added NEWS entry. Please let me know if something else needs to be done/changed (i.e. please review :).

To me it seems ready to merge!

base/genericmemory.jl Outdated Show resolved Hide resolved
base/genericmemory.jl Outdated Show resolved Hide resolved
base/expr.jl Outdated Show resolved Hide resolved
base/expr.jl Outdated Show resolved Hide resolved
@vchuravy
Copy link
Member

Would be nice to check that Atomix.jl still works and can be used as a backwards compatible layer to get this functionality on older Julia versions.

@vchuravy vchuravy mentioned this pull request Jun 27, 2024
4 tasks
@kalmarek
Copy link
Contributor Author

@vchuravy I was actually thinking about spinning this functionality into a small package for julia-1.11, but merging into Atomix.jl would be even better. My only hesitation is that this package has not seen any activity in 2 years and was mostly developed by the brilliant tkf who left the community. Is it worth the effort?

@vchuravy
Copy link
Member

Atomix is actively used and @maleadt or I have commit privileges.

@kalmarek kalmarek requested a review from vtjnash June 30, 2024 22:11
@nsajko nsajko added the feature Indicates new feature / enhancement requests label Jul 1, 2024
@kalmarek
Copy link
Contributor Author

kalmarek commented Jul 2, 2024

@oscardssmith @vtjnash please let me know what else need to be done here.

@nsajko, since you have access to lables I think that needs news, needs docs and needs tests are satisfied and could be removed.

@nsajko nsajko removed needs tests Unit tests are required for this change needs docs Documentation for this change is required needs news A NEWS entry is required for this change labels Jul 2, 2024
@oscardssmith
Copy link
Member

IMO this is ready to merge, but I do want @vtjnash to have a last lock

@oscardssmith oscardssmith merged commit 23dabef into JuliaLang:master Jul 7, 2024
7 checks passed
@oscardssmith
Copy link
Member

Thanks so much for doing this!

@vtjnash
Copy link
Sponsor Member

vtjnash commented Jul 8, 2024

Awesome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
arrays [a, r, r, a, y, s] atomics feature Indicates new feature / enhancement requests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants