Skip to content

Commit

Permalink
#silifuzz Use RDPID instruction to get CPUID if available. This saves…
Browse files Browse the repository at this point in the history
… about 20ns per snapshot execution.

This CL was tested on an 8-core AMD cloud VM:

Benchmark                   Time(ns)        CPU(ns)     Iterations
------------------------------------------------------------------
BM_nolibc_GetCPUId                 1.95           1.95    26545270
BM_nolibc_GetCPUId                 1.89           1.89    33611922
BM_nolibc_GetCPUId                 1.89           1.89    33762844
BM_nolibc_GetCPUId                 1.91           1.91    32848973
BM_nolibc_GetCPUId                 1.89           1.89    33694179
BM_nolibc_GetCPUId                 1.89           1.89    33843338
BM_nolibc_GetCPUId                 1.96           1.96    33985658
BM_nolibc_GetCPUId                 1.88           1.88    33932995
BM_nolibc_GetCPUId                 1.89           1.88    33195933
BM_nolibc_GetCPUId                 1.88           1.88    34041251
BM_nolibc_GetCPUId                 1.90           1.90    33954450
BM_nolibc_GetCPUId_mean            1.90           1.90   363416813
BM_nolibc_GetCPUId_stddev          0.025          0.025  363416813

base CL 625806098:

Benchmark                   Time(ns)        CPU(ns)     Iterations
------------------------------------------------------------------
BM_nolibc_GetCPUId                22.3           22.2      2639063
BM_nolibc_GetCPUId                22.2           22.1      2642065
BM_nolibc_GetCPUId                22.1           22.1      2614901
BM_nolibc_GetCPUId                22.2           22.1      2632161
BM_nolibc_GetCPUId                22.1           22.1      2640895
BM_nolibc_GetCPUId                22.2           22.2      2606530
BM_nolibc_GetCPUId                22.1           22.1      2642683
BM_nolibc_GetCPUId                22.1           22.0      2641231
BM_nolibc_GetCPUId                22.1           22.1      2632380
BM_nolibc_GetCPUId                22.2           22.1      2646701
BM_nolibc_GetCPUId                22.1           22.1      2631796
BM_nolibc_GetCPUId                22.1           22.2      2632026
BM_nolibc_GetCPUId_mean           22.1           22.1     31602432
BM_nolibc_GetCPUId_stddev          0.069          0.050   31602432

PiperOrigin-RevId: 625850853
  • Loading branch information
dougkwan authored and copybara-github committed Apr 18, 2024
1 parent a1c20f2 commit 70ffb0f
Showing 1 changed file with 63 additions and 37 deletions.
100 changes: 63 additions & 37 deletions util/x86_64/cpu_id.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,60 +21,86 @@
#include "./util/x86_cpuid.h"

namespace silifuzz {
namespace {

enum RDTSCPState {
kUnknownRDTSCP = 0,
kNoRDTSCP = 1,
kYesRDTSCP = 2,
};
// Fall back to these if no special instructions are available to
// get CPUID quickly.
extern int GetCPUIdUsingSyscall();
extern int GetCPUAffinityNoSyscall();

std::atomic<RDTSCPState> has_rdtscp;
namespace {

inline bool HasRDTSCPImpl() {
X86CPUIDResult res;
X86CPUID(0x80000001U, &res);
constexpr uint32_t kRDTSCPBit = 1U << 27;
return (res.edx & kRDTSCPBit) != 0;
}
// wrapper functions that choose the actual implementation the first time
// GetCPUId*() are called.
int InitializeGetCPUId();
int InitializeGetCPUIdNoSyscall();

bool HasRDTSCP() {
RDTSCPState state = has_rdtscp.load(std::memory_order_relaxed);
if (state == kUnknownRDTSCP) {
state = HasRDTSCPImpl() ? kYesRDTSCP : kNoRDTSCP;
has_rdtscp.store(state, std::memory_order_relaxed);
}
return state == kYesRDTSCP;
}
// Function pointers to the best implementation of GetCPUID*() that
// we can use on the current platform. These are initialized when
// one of GetCPUID() and GetCPUIDNoSyscall() is called the first time.
typedef int (*GetCPUIDFunctionPtr)();
std::atomic<GetCPUIDFunctionPtr> get_cpuid_impl = InitializeGetCPUId;
std::atomic<GetCPUIDFunctionPtr> get_cpuid_no_syscall_impl =
InitializeGetCPUIdNoSyscall;

// The Linux kernel fills in TSC auxiliary MSR with CPU core ID information,
// which is readable using RDTSCP instruction.
inline int GetCPUIdUsingRDTSCP() {
int GetCPUIdUsingRDTSCP() {
uint32_t ecx;
asm volatile("rdtscp" : "=c"(ecx) : /* no input*/ : "%eax", "%edx");
// Lower 12 bits contain CPU ID.
return ecx & 0xfff;
}

} // namespace
int GetCPUIdUsingRDPID() {
uint64_t tsc_aux;
asm volatile("rdpid %0" : "=r"(tsc_aux) : /* no input*/);
// Lower 12 bits contain CPU ID.
return tsc_aux & 0xfff;
}

extern int GetCPUIdUsingSyscall();
extern int GetCPUAffinityNoSyscall();
// Initializes implementation function pointers for both GetCPUID() and
// GetCPUIDNoSyscall().
void InitializeCommon() {
X86CPUIDResult res;

int GetCPUId() {
if (HasRDTSCP()) {
return GetCPUIdUsingRDTSCP();
} else {
return GetCPUIdUsingSyscall();
// Prefer RDPID over RDTSCP if available.
X86CPUID(0x7U, &res);
constexpr uint32_t kRDPIDBit = 1U << 22;
if ((res.ecx & kRDPIDBit) != 0) {
// Data races are benign as writes to function pointers are idempotent.
// We can use atomic::exchange if we ever use a thread sanitizer.
get_cpuid_impl.store(GetCPUIdUsingRDPID);
get_cpuid_no_syscall_impl.store(GetCPUIdUsingRDPID);
return;
}

X86CPUID(0x80000001U, &res);
constexpr uint32_t kRDTSCPBit = 1U << 27;
if ((res.edx & kRDTSCPBit) != 0) {
get_cpuid_impl.store(GetCPUIdUsingRDTSCP);
get_cpuid_no_syscall_impl.store(GetCPUIdUsingRDTSCP);
return;
}

// No special instructions available, use slow methods.
get_cpuid_impl.store(GetCPUIdUsingSyscall);
get_cpuid_no_syscall_impl.store(GetCPUAffinityNoSyscall);
}

int InitializeGetCPUId() {
InitializeCommon();
return (*get_cpuid_impl.load(std::memory_order_relaxed))();
}

int InitializeGetCPUIdNoSyscall() {
InitializeCommon();
return (*get_cpuid_no_syscall_impl.load(std::memory_order_relaxed))();
}

} // namespace

int GetCPUId() { return (*get_cpuid_impl.load(std::memory_order_relaxed))(); }

int GetCPUIdNoSyscall() {
if (HasRDTSCP()) {
return GetCPUIdUsingRDTSCP();
} else {
return GetCPUAffinityNoSyscall();
}
return (*get_cpuid_no_syscall_impl.load(std::memory_order_relaxed))();
}

} // namespace silifuzz

0 comments on commit 70ffb0f

Please sign in to comment.