Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion jvector-native/src/main/c/jvector_simd.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ __m512i maskEighthBit;

__attribute__((constructor))
void initialize_constants() {
if (check_compatibility()) {
if (check_avx512_compatibility()) {
initialIndexRegister = _mm512_setr_epi32(-16, -15, -14, -13, -12, -11, -10, -9,
-8, -7, -6, -5, -4, -3, -2, -1);
indexIncrement = _mm512_set1_epi32(16);
Expand Down
2 changes: 1 addition & 1 deletion jvector-native/src/main/c/jvector_simd.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#define VECTOR_SIMD_DOT_H

// check CPU support
bool check_compatibility(void);
bool check_avx512_compatibility(void);

//F32
float dot_product_f32(int preferred_size, const float* a, int aoffset, const float* b, int boffset, int length);
Expand Down
29 changes: 11 additions & 18 deletions jvector-native/src/main/c/jvector_simd_check.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,14 @@
#include <cpuid.h>
#include "jvector_simd.h"

bool check_compatibility(void) {
unsigned int eax, ebx, ecx, edx;
bool avx512f_supported = false, avx512cd_supported = false,
avx512bw_supported = false, avx512dq_supported = false,
avx512vl_supported = false;

// Check for AVX-512 Foundation (AVX-512F) and other AVX-512 features:
// These are indicated by various bits of EBX from leaf 7, sub-leaf 0.
if (__get_cpuid_count(7, 0, &eax, &ebx, &ecx, &edx)) {
avx512f_supported = ebx & (1 << 16); // AVX-512F
avx512cd_supported = ebx & (1 << 28); // AVX-512CD
avx512bw_supported = ebx & (1 << 30); // AVX-512BW
avx512dq_supported = ebx & (1 << 17); // AVX-512DQ
avx512vl_supported = ebx & (1 << 31); // AVX-512VL
}

return avx512f_supported && avx512cd_supported && avx512bw_supported && avx512dq_supported && avx512vl_supported;
}
bool check_avx512_compatibility(void) {
/* __builtin_cpu_init required when this is used in ifunc
resolver/__attribute__((constructor)) context, otherwise the CPU
features may not be detected correctly. */
__builtin_cpu_init();
return (__builtin_cpu_supports("avx512f") &&
__builtin_cpu_supports("avx512cd") &&
__builtin_cpu_supports("avx512dq") &&
__builtin_cpu_supports("avx512bw") &&
__builtin_cpu_supports("avx512vl"));
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public NativeVectorizationProvider() {
if (!libraryLoaded) {
throw new UnsupportedOperationException("Failed to load supporting native library.");
}
if (!NativeSimdOps.check_compatibility()) {
if (!NativeSimdOps.check_avx512_compatibility()) {
throw new UnsupportedOperationException("Native SIMD operations are not supported on this platform due to missing CPU support.");
}
this.vectorUtilSupport = new NativeVectorUtilSupport();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,55 +96,55 @@ public static int __bool_true_false_are_defined() {
return __bool_true_false_are_defined;
}

private static class check_compatibility {
private static class check_avx512_compatibility {
public static final FunctionDescriptor DESC = FunctionDescriptor.of(
NativeSimdOps.C_BOOL );

public static final MemorySegment ADDR = NativeSimdOps.findOrThrow("check_compatibility");
public static final MemorySegment ADDR = NativeSimdOps.findOrThrow("check_avx512_compatibility");

public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC, Linker.Option.critical(true));
}

/**
* Function descriptor for:
* {@snippet lang=c :
* _Bool check_compatibility()
* _Bool check_avx512_compatibility()
* }
*/
public static FunctionDescriptor check_compatibility$descriptor() {
return check_compatibility.DESC;
public static FunctionDescriptor check_avx512_compatibility$descriptor() {
return check_avx512_compatibility.DESC;
}

/**
* Downcall method handle for:
* {@snippet lang=c :
* _Bool check_compatibility()
* _Bool check_avx512_compatibility()
* }
*/
public static MethodHandle check_compatibility$handle() {
return check_compatibility.HANDLE;
public static MethodHandle check_avx512_compatibility$handle() {
return check_avx512_compatibility.HANDLE;
}

/**
* Address for:
* {@snippet lang=c :
* _Bool check_compatibility()
* _Bool check_avx512_compatibility()
* }
*/
public static MemorySegment check_compatibility$address() {
return check_compatibility.ADDR;
public static MemorySegment check_avx512_compatibility$address() {
return check_avx512_compatibility.ADDR;
}

/**
* {@snippet lang=c :
* _Bool check_compatibility()
* _Bool check_avx512_compatibility()
* }
*/
public static boolean check_compatibility() {
var mh$ = check_compatibility.HANDLE;
public static boolean check_avx512_compatibility() {
var mh$ = check_avx512_compatibility.HANDLE;
try {
if (TRACE_DOWNCALLS) {
traceDowncall("check_compatibility");
traceDowncall("check_avx512_compatibility");
}
return (boolean)mh$.invokeExact();
} catch (Throwable ex$) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright DataStax, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.github.jbellis.jvector.vector.cnative;

import org.junit.Assume;
import org.junit.Test;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

import static org.junit.Assert.assertEquals;

public class NativeSimdOpsTest {

/**
* Reads /proc/cpuinfo and returns true if all AVX-512 flags required by
* check_avx512_compatibility() are present: avx512f, avx512cd, avx512dq,
* avx512bw, avx512vl.
*/
private static boolean cpuinfoReportsAvx512() throws IOException {
List<String> lines = Files.readAllLines(Path.of("/proc/cpuinfo"));
List<String> required = List.of("avx512f", "avx512cd", "avx512dq", "avx512bw", "avx512vl");
for (String line : lines) {
if (line.startsWith("flags")) {
String[] flags = line.split("\\s+");
List<String> flagList = List.of(flags);
return flagList.containsAll(required);
}
}
return false;
}

@Test
public void testCheckAvx512CompatibilityMatchesCpuinfo() throws IOException {
boolean libraryLoaded = LibraryLoader.loadJvector();
Assume.assumeTrue("Native jvector library not available; skipping AVX-512 check", libraryLoaded);

boolean expectedFromCpuinfo = cpuinfoReportsAvx512();
boolean actualFromNative = NativeSimdOps.check_avx512_compatibility();

assertEquals(
"check_avx512_compatibility() should match AVX-512 flag presence in /proc/cpuinfo",
expectedFromCpuinfo,
actualFromNative);
}
}
Loading