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 |
KNN Exact Search
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_ptrwith custom deleters. See the full example forContextDeleter,BufferDeleter, andKnnExactIndexDeleterpatterns.
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);
4. Execute Search
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
- XFaiss — Faiss drop-in replacement for IVF-Flat, IVF-RaBitQ, and Flat indexes
- XVector API Reference — Full C API reference