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

Document when to use std::thread::yield_now vs. std::sync::atomic::spin_loop_hint #55418

Closed
frewsxcv opened this issue Oct 27, 2018 · 8 comments · Fixed by #59664
Closed

Document when to use std::thread::yield_now vs. std::sync::atomic::spin_loop_hint #55418

frewsxcv opened this issue Oct 27, 2018 · 8 comments · Fixed by #59664
Labels
A-docs Area: documentation for any part of the project, including the compiler, standard library, and tools C-enhancement Category: An issue proposing an enhancement or a PR with one. P-medium Medium priority

Comments

@frewsxcv
Copy link
Member

On the surface, these functions seem very similar. When is it appropriate to use one vs. the other?

@frewsxcv frewsxcv added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. A-docs Area: documentation for any part of the project, including the compiler, standard library, and tools C-enhancement Category: An issue proposing an enhancement or a PR with one. labels Oct 27, 2018
@frewsxcv
Copy link
Member Author

@rust-lang/libs Anyone able to describe the differences and use-cases for these functions? I'd be willing to add docs for this, I just don't know when to use either

@alexcrichton
Copy link
Member

My understanding for these two functions is:

  • Both are probably not needed in general. While yield_now can be a debugging utility in some situations they're largely only needed when writing some form of a spin loop.
  • The spin_loop_hint function is for very tight spin loops. It is ideally used in situations where you know that a contended lock is held by another thread and you're sure the other thread is running on a different CPU. If the other thread holding a lock (or whatever condition is being waited on in a spin loop) isn't actually running then spinning with this function will eat the entire time slice allocated for the OS until that thread starts running again. This is a CPU instruction on some platforms, and a noop on other platforms.
  • The yield_now function invokes the OS scheduler, asking the current thread to basically be put into the back of the run queue. This is best for spin loops where you're pretty certain the lock/condition will become available soon, but you're not sure if the thread holding the lock is running or not.

I believe the general wisdom is that on lock contention you spin_loop_hint for a bit, then yield_now a little bit, and finally sleep for real. All of these are pretty advanced functions, though, and the documentation should be very clear that these are largely just current-practice-guidelines and benchmarking and further understanding is highly encouraged

@steveklabnik steveklabnik added P-medium Medium priority and removed T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels Dec 27, 2018
@briansmith
Copy link
Contributor

One use case for spin_loop_hint is a bunch of threads blocked on CPUID. CPUID potentially needs a large number of cycles to execute but it is also executed in performance-sensitive code (graphics, crypto, etc.) where a full yield_now() or sleep() would not be wanted.

@DevQps
Copy link
Contributor

DevQps commented Mar 30, 2019

@frewsxcv Are you still interested in writing docs for this?

@frewsxcv
Copy link
Member Author

@DevQps I still don't feel confident to write them given my current level of understanding with these APIs. But if you want to try, go for it!

@DevQps
Copy link
Contributor

DevQps commented Apr 1, 2019

@frewsxcv I will give it a try! I am sure others will correct me if I write some things that are wrong :) I hope I'll be able to deliver a PR somewhere this week.

@DevQps
Copy link
Contributor

DevQps commented Apr 3, 2019

@alexcrichton It seems like you always pop up on my screen when people are talking about technical details so I thought you might be the right man for this question :)

When diving into the details of spin_loop_hint I found this:

#[inline]
#[stable(feature = "spin_loop_hint", since = "1.24.0")]
pub fn spin_loop_hint() {
    spin_loop()
}

So basically spin_loop_hint does a call to spin_loop which is defined like this:

#[inline]
#[unstable(feature = "renamed_spin_loop", issue = "55002")]
pub fn spin_loop() {
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    unsafe {
        asm!("pause" ::: "memory" : "volatile");
    }

    #[cfg(target_arch = "aarch64")]
    unsafe {
        asm!("yield" ::: "memory" : "volatile");
    }
}

Question:

  • What is the difference in semantics between spin_loop and spin_loop_hint? Or to ask it differently, why should we not deprecate spin_loop_hint and only use spin_loop? The documentation of both functions is exactly the same as well. (Aside spin_loop being experimental). Or we could maybe re-export spin_loop as spin_loop_hint in std::sync::atomic?

@DevQps
Copy link
Contributor

DevQps commented Apr 3, 2019

@alexcrichton @frewsxcv I did an attempt! I hope it clarifies some things. I didn't edit the yield_now documentation to not bloat the documentation there too much. But if that is desired as well, please let me know. The pull is here: #59664

Centril added a commit to Centril/rust that referenced this issue Apr 3, 2019
… r=alexcrichton

Updated the documentation of spin_loop and spin_loop_hint

# Description

- Updated the description of `core::hints::spin_loop`
- Updated the description of `core::async::spin_loop_hint`

Both documentation is rewritten to better reflect when one should prefer using a busy-wait spin-loop (and the `spin_loop` and `spin_loop_hint` functions) over `yield_now`. It also dives a little bit deeper on what the function actually does.

closes rust-lang#55418
Centril added a commit to Centril/rust that referenced this issue Apr 3, 2019
… r=alexcrichton

Updated the documentation of spin_loop and spin_loop_hint

# Description

- Updated the description of `core::hints::spin_loop`
- Updated the description of `core::async::spin_loop_hint`

Both documentation is rewritten to better reflect when one should prefer using a busy-wait spin-loop (and the `spin_loop` and `spin_loop_hint` functions) over `yield_now`. It also dives a little bit deeper on what the function actually does.

closes rust-lang#55418
Centril added a commit to Centril/rust that referenced this issue Apr 3, 2019
… r=alexcrichton

Updated the documentation of spin_loop and spin_loop_hint

# Description

- Updated the description of `core::hints::spin_loop`
- Updated the description of `core::async::spin_loop_hint`

Both documentation is rewritten to better reflect when one should prefer using a busy-wait spin-loop (and the `spin_loop` and `spin_loop_hint` functions) over `yield_now`. It also dives a little bit deeper on what the function actually does.

closes rust-lang#55418
Centril added a commit to Centril/rust that referenced this issue Apr 3, 2019
… r=alexcrichton

Updated the documentation of spin_loop and spin_loop_hint

# Description

- Updated the description of `core::hints::spin_loop`
- Updated the description of `core::async::spin_loop_hint`

Both documentation is rewritten to better reflect when one should prefer using a busy-wait spin-loop (and the `spin_loop` and `spin_loop_hint` functions) over `yield_now`. It also dives a little bit deeper on what the function actually does.

closes rust-lang#55418
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-docs Area: documentation for any part of the project, including the compiler, standard library, and tools C-enhancement Category: An issue proposing an enhancement or a PR with one. P-medium Medium priority
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants