Pre-RFC: Introducing `std::thread::pause`


#1
  • Feature Name: pause_instruction
  • Start Date: 2015-08-06
  • RFC PR: (leave this empty)
  • Rust Issue: (leave this empty)

Summary

Introduce the std::thread::pause function that resembles the x86 PAUSE instruction.

Motivation

The x86 PAUSE instruction is semantically equivalent to nop, but:

  • may save energy consumption;
  • may yield resources to another hyper-thread in the same core; and
  • may provide hints for processors to satisfy memory ordering constraints with a lower cost.

For this reason, Intel specifically advises to use the x86 PAUSE instruction inside a spin lock’s loop.

By introducing the std::thread::pause function in Rust, one can implement more efficient spin locks in pure Rust.

Detailed design

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn pause() {
    asm!("PAUSE");
}

Drawbacks

The Standard Library becomes larger, increasing the maintenance cost. The maintenance cost may be bigger than it seems, since LLVM does not support such pause function on-the-shelf. The Standard Library has to maintain architecture-specific implementations of pause.

Alternatives

Do not introduce the std::thread::pause.

  • No more maintenance cost.
  • but no support for efficient implementation of spin locks.
  • If pausing is absolutely necessary, use std::thread::sleep_ms(0) instead, with some performance penalty.

Unresolved questions

How to effectively maintain architecture-specific implementations for the std::thread::pause?


#2

What other architectures have a similar instruction?


#3

ARM - YIELD

PowerPC - depends on the subarchitecture

(edit: I had the wrong instruction for ARM)


#4

Is std::thread::yield_now the same thing?


#5

No. yield_now yields to the OS’s scheduler (OS level threading). PAUSE/YIELD yield to the CPU’s scheduler (hyperthreading). yield_now introduces a context switch and the PAUSE/YIELD instructions just hint to the CPU that “now would be a good time to do something else”.


#6

I like the idea, but don’t like the name. Despite being the name of the x86 instruction, the word pause is very generic, and makes me think of either sleeping for a fixed time or until an external signal arrives. Maybe consider a name like yield_cpu, which suggests it is similar to yield_now but also indicates how it is different.

You should clarify whether the function would be defined for all architectures (even if it is an actual nop in some).


#7

Ditto - the posix pause(2) function has quite different semantics (“pause until a signal arrives, perhaps indefinitely”), and it would be terrible to confuse the two (as I initially did when seeing “std::thread::pause”).


#8

Linux call this relax() internally. It also explicitly has compiler memory barrier semantics, but I don’t know if that applies here.


#9

This StackOverflow post suggest why it may not be a good idea to have this operation. It suggests that the placement of the instruction is important to its operation, and may be different on different processors. Therefore, the spin-lock should be coded in explicit assembly code, preferably provided by a library.