Examples

Code examples demonstrating XVector library usage via the public C API.

XVector provides two ways to run vector search on MX1:

Approach Description When to Use
XVector C API (this page) Direct C API for KNN exact search Custom applications, fine-grained control
XFaiss Drop-in Faiss replacement with MU acceleration Existing Faiss workflows, IVF indexes

The xvector-examples package includes a complete KNN example that demonstrates exact nearest neighbor search using the XVector C API.

Compared to the raw XArith/PXL approach, XVector handles device kernel loading, data partitioning, task scheduling, and result merging internally:

Aspect XArith/PXL (raw) XVector C API
Device kernel Write and compile manually Built-in
Memory management Manual PXL alloc/free xvecCreateBuffer / xvecDestroyBuffer
Data partitioning Manual NDArray setup Automatic
Result merging Manual per-task merge Automatic
API style C++ (PXL + device headers) Pure C (xvec_*.h)

Build

Extract and build the example:

tar -xzf xvector-examples-0.1.2.tar.gz
cd xvector-examples-0.1.2/knn
mkdir build && cd build
cmake ..
make

If xvector is not installed at the default path (/opt/xvector), specify the install location:

cmake -DCMAKE_PREFIX_PATH=/path/to/xvector ..

The CMake configuration is minimal — find_package(xvector) and link against xvector::xvector:

cmake_minimum_required(VERSION 3.11)
project(xvector_knn_example VERSION 1.0.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(xvector REQUIRED)

add_executable(knn_xvector main.cpp)
target_link_libraries(knn_xvector PRIVATE xvector::xvector)

Run

./knn_xvector                         # run with defaults
./knn_xvector --dim 128 --vectors 1000000 --k 10   # custom parameters

The mubin kernel binary is auto-detected from <exe_dir>/bin/, <exe_dir>/../bin/, or /opt/xvector/bin/.

Options:

Option Default Description
--dim N 1024 Vector dimension
--vectors N 100000 Number of dataset vectors
--queries N 10 Number of query vectors
--k N 5 Number of nearest neighbors
--dist l2\|ip\|all all Distance metric

Environment Variables:

Variable Default Description
XVECTOR_MUBIN_PATH (auto) Path to xvector_kernel.mubin
DEVICEID 0 Device ID
NUMSUB 24 Number of subsystems
TASKCOUNT 192 Task count for parallelism

Sample Output

XVector KNN Example

Config: dim=1024 vectors=100000 queries=10 k=5 numSub=24 taskCount=192

Generating random test data... done

KNN L2 Test (vectors=100000, queries=10, dim=1024, k=5)
[xvector] Index loaded: ...
[xvector] Search: ...

KNN DOT_PRODUCT Test (vectors=100000, queries=10, dim=1024, k=5)
[xvector] Index loaded: ...
[xvector] Search: ...

Code Walkthrough

The full example (knn/main.cpp) follows a straightforward flow: create context, load data, search, read results.

Headers

#include <xvector/xvec_buffer.h>
#include <xvector/xvec_context.h>
#include <xvector/xvec_knn_exact.h>
#include <xvector/xvec_types.h>

1. Create Execution Context

The execution context connects to the MX1 device and loads the built-in kernel binary:

xvecExecutionContextTag* ctx = nullptr;
xvecStatus status = xvecCreateContext(&ctx, deviceId, mubinPath);
if (status != XVEC_SUCCESS) {
    // handle error
}

// Configure parallelism
xvecSetContextProperty(ctx, "numSub", "24");
xvecSetContextProperty(ctx, "taskCount", "192");

For RAII-style resource management, wrap handles in std::unique_ptr with custom deleters. See the full example for ContextDeleter, BufferDeleter, and KnnExactIndexDeleter patterns.

2. Load Index from Raw Vectors

Load a dataset of float32 vectors into a KNN exact index:

xvecKnnExactIndexTag* index = nullptr;
xvecKnnExactLoadIndexFromRawVectors(
    ctx,
    dataset,       // const float* — contiguous float32 array
    vectorCount,   // number of vectors
    dim,           // vector dimension
    XVEC_DISTANCE_L2,  // or XVEC_DISTANCE_DOT_PRODUCT
    &index);

3. Prepare Query Vectors

Create a buffer and copy query vectors into it:

size_t queryBufSize = sizeof(float) * queryCount * dim;

xvecBufferTag* queryBuf = nullptr;
xvecCreateBuffer(ctx, queryBufSize, &queryBuf);

void* queryData = nullptr;
xvecGetBufferData(queryBuf, &queryData);
memcpy(queryData, queryVectors, queryBufSize);

Build the search query and execute:

xvecKnnExactSearchQueryFloat32 searchQuery{};
searchQuery.dimension       = dim;
searchQuery.queryVectorCount = queryCount;
searchQuery.queryVectorsBufferHandle = queryBuf;
searchQuery.topK            = k;

// Allocate result buffer
size_t resultBufSize = sizeof(xvecKnnExactSearchResultFloat32) * queryCount * k;
xvecBufferTag* resultBuf = nullptr;
xvecCreateBuffer(ctx, resultBufSize, &resultBuf);

// Run search
xvecKnnExactSearch(ctx, index, &searchQuery, resultBuf, nullptr);

5. Cleanup

Destroy resources in reverse order:

xvecDestroyBuffer(ctx, resultBuf);
xvecDestroyBuffer(ctx, queryBuf);
xvecKnnExactDestroyIndex(ctx, index);
xvecDestroyContext(ctx);

Next Steps