Skip to content

Instantly share code, notes, and snippets.

@alifarazz
Last active July 30, 2024 03:47
Show Gist options
  • Save alifarazz/ab90e06e4f5cf0a465eeb4e7a3b32633 to your computer and use it in GitHub Desktop.
Save alifarazz/ab90e06e4f5cf0a465eeb4e7a3b32633 to your computer and use it in GitHub Desktop.
An example for Intel umonitor umwait tpause instructions introduced in Tremont, Alder Lake, Sapphire Rapids architectures
// g++ -O3 -Wall -Wextra -Wconversion -Wshadow -Wpedantic -std=c++20 -march=alderlake umwait.cc -o umwait.elf
// ./umwait.elf or ./umwait.elf w
#include <atomic>
#include <iostream>
#include <latch>
#include <thread>
#include <immintrin.h>
#include <x86intrin.h>
/* NOTE:
* The waiter thread will sometimes wake up even if the memory address isn't
written to. This is called "sporadic wakeups". Just put the umwait in a
loop, and each time check the value of the variable after waking up from
umwait. If the value isn't the one you'd expected, umwait again. If it
is, exit the loop.
* Sometimes the writer thread just doesn't get scheduled on the CPU fast
enough, so a time-out occurs on waiter thread. Increase the timeout amount
for umwait using MSRs and/or wait in a loop.
*/
int main(int argc, char *argv[]) {
const bool writer_wakes_up_waiter = (argc == 2) &&
(*argv[1] == 'w');
alignas(64) static std::atomic<int> shared_data {};
static std::latch lch {2};
std::thread waiter {[&] {
lch.arrive_and_wait();
_umonitor(&shared_data);
auto before = _rdtsc();
constexpr decltype(before) SLEEP_AMOUNT_TSC = 100'000;
_umwait(1, SLEEP_AMOUNT_TSC + before);
auto after = _rdtsc();
if (after - before < SLEEP_AMOUNT_TSC) {
std::cout << "woke up by other thread, value: "
<< shared_data.load(std::memory_order_acquire)
<< std::endl;
} else {
std::cout << "time limit exceeded" << std::endl;
}
}};
std::thread writer {[&] {
lch.arrive_and_wait();
if (writer_wakes_up_waiter) {
for (int i = 0; i < 1000; i++) {
_tpause(1, 1'000 + _rdtsc());
shared_data.store(i, std::memory_order_release);
}
}
}};
waiter.join();
writer.join();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment