microsoft / microsoft/DiskANN

Target Features Mismatch Finder

Open
#1,373 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
Rust
Stars
1.9k
Forks
454
Avg merge
3d 22h
Merged PRs (30d)
35

Description

Compiling x86 binaries capable of running AVX-512 is currently a large game of inline and target-features whack-a-mole. As with all Rust code, enabling higher level architecture than the compilation target (e.g. AVX-512 when the binary is compiled for [`x86-64-v3`](https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels)) requires annotating functions with the correct [target features](https://rust-lang.github.io/rfcs/2045-target-feature.html).

When `target_feature(enable = "...")` is used to annotate a function `foo`, then all functions **inlined** into `foo` inherit those target features. Calling a non-inlined function from `foo` can cause those target feature to get lost.

Currently, we use [architecture tokens](https://github.com/microsoft/DiskANN/blob/600c2b95d8eea274c7e40fef19690f673a2926e7/diskann-wide/src/arch/mod.rs#L735-L737) to apply [target features](https://github.com/microsoft/DiskANN/blob/600c2b95d8eea274c7e40fef19690f673a2926e7/diskann-wide/src/arch/x86_64/v4/mod.rs#L292-L302) to closures and other types implementing the `Target[1-3]?` traits.

The problem arises when functions are not inlined into the immediate callsite. As an example, if you apply the following diff
```
diff --git a/diskann-wide/src/lib.rs b/diskann-wide/src/lib.rs
index 4f6ca5c9..da8e4762 100644
--- a/diskann-wide/src/lib.rs
+++ b/diskann-wide/src/lib.rs
@@ -236,6 +236,26 @@ pub(crate) mod helpers;
#[cfg(test)]
pub(crate) mod test_utils;

+alias!(f32s = ::f32x16);
+
+pub fn uninlined_context(x: f32s, y: f32s) -> f32s {
+ let z = x + y;
+ let z = z * z;
+ z
+}
+
+pub fn inlined_context(x: f32s, y: f32s) -> f32s {
+ let arch = x.arch();
+ arch.run2(
+ |a: f32s, b: f32s| {
+ let z = a + b;
+ z * z
+ },
+ x,
+ y,
+ )
+}
+
///////////
// Tests //
//////////
```
And compile the resulting assembly, we get
```asm
vmovaps zmm0, zmmword ptr [rsi]
vaddps zmm0, zmm0, zmmword ptr [rdx]
vmulps zmm0, zmm0, zmm0
vmovaps zmmword ptr [rdi], zmm0
vzeroupper
ret
```
when `unapplied_features` is called from `inlined_context` but
```asm
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset rbp, -16
mov rbp, rsp
.cfi_def_cfa_register rbp
push rbx
and rsp, -64
sub rsp, 256
.cfi_offset rbx, -24
mov rbx, rdi
vmovaps ymm0, ymmword ptr [rsi]
vmovaps ymm1, ymmword ptr [rsi + 32]
vmovaps ymm2, ymmword ptr [rdx]
vmovaps ymm3, ymmword ptr [rdx + 32]
vmovaps ymmword ptr [rsp + 32], ymm1
vmovaps ymmword ptr [rsp], ymm0
vmovaps ymmword ptr [rsp + 96], ymm3
vmovaps ymmword ptr [rsp + 64], ymm2
lea rdi, [rsp + 128]
mov rsi, rsp
lea rdx, [rsp + 64]
vzeroupper
call core::core_arch::x86::avx512f::_mm512_add_ps
vmovaps ymm0, ymmword ptr [rsp + 128]
vmovaps ymm1, ymmword ptr [rsp + 160]
vmovaps ymmword ptr [rsp + 32], ymm1
vmovaps ymmword ptr [rsp], ymm0
vmovaps ymmword ptr [rsp + 96], ymm1
vmovaps ymmword ptr [rsp + 64], ymm0
mov rsi, rsp
lea rdx, [rsp + 64]
mov rdi, rbx
vzeroupper
call core::core_arch::x86::avx512f::_mm512_mul_ps
mov rax, rbx
lea rsp, [rbp - 8]
pop rbx
pop rbp
.cfi_def_cfa rsp, 8
ret
```
when it is not. What's happening in the latter case is that `unapplied_features` is not compiled with `avx512f`, and thus calls to `core::core_arch::x86::avx512f::_mm512_add_ps` and `core::core_arch::x86::avx512f::_mm512_mul_ps` (which require that feature) cannot be inlined.

This leads to a dramatic performance cliff when we accidentally fall out of the proper target features.

Fortunately, it should be pretty straight-forward to write tooling to detect this situation. All we really need to do (in theory) is disassemble compiled binaries and look for uninlined calls to the `starch` intrinsics. That can at least either put us in the ballpark of something that got missed, or give use higher confidence that we got everything.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the architecture-token code in diskann-wide/src/arch/mod.rs and the target-feature implementations in diskann-wide/src/arch/x86_64/v4/mod.rs. Compile the example from diskann-wide/src/lib.rs and compare the generated assembly for inlined and uninlined calls. Done means tooling can flag uninlined calls to starch intrinsics that may have lost their required target features.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
performance, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.